1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <string.h> 21 #include <tools/stream.hxx> 22 #include <tools/fract.hxx> 23 #include <tools/urlobj.hxx> 24 #include <TypeSerializer.hxx> 25 #include <vcl/outdev.hxx> 26 #include <vcl/graphicfilter.hxx> 27 #include <unotools/ucbstreamhelper.hxx> 28 #include "graphicfilter_internal.hxx" 29 30 #define DATA_SIZE 640 31 32 GraphicDescriptor::GraphicDescriptor( const INetURLObject& rPath ) : 33 pFileStm( ::utl::UcbStreamHelper::CreateStream( rPath.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ ).release() ), 34 aPathExt( rPath.GetFileExtension().toAsciiLowerCase() ), 35 bOwnStream( true ) 36 { 37 ImpConstruct(); 38 } 39 40 GraphicDescriptor::GraphicDescriptor( SvStream& rInStream, const OUString* pPath) : 41 pFileStm ( &rInStream ), 42 bOwnStream ( false ) 43 { 44 ImpConstruct(); 45 46 if ( pPath ) 47 { 48 INetURLObject aURL( *pPath ); 49 aPathExt = aURL.GetFileExtension().toAsciiLowerCase(); 50 } 51 } 52 53 GraphicDescriptor::~GraphicDescriptor() 54 { 55 if ( bOwnStream ) 56 delete pFileStm; 57 } 58 59 bool GraphicDescriptor::Detect( bool bExtendedInfo ) 60 { 61 bool bRet = false; 62 if ( pFileStm && !pFileStm->GetError() ) 63 { 64 SvStream& rStm = *pFileStm; 65 SvStreamEndian nOldFormat = rStm.GetEndian(); 66 67 if ( ImpDetectGIF( rStm, bExtendedInfo ) ) bRet = true; 68 else if ( ImpDetectJPG( rStm, bExtendedInfo ) ) bRet = true; 69 else if ( ImpDetectBMP( rStm, bExtendedInfo ) ) bRet = true; 70 else if ( ImpDetectPNG( rStm, bExtendedInfo ) ) bRet = true; 71 else if ( ImpDetectTIF( rStm, bExtendedInfo ) ) bRet = true; 72 else if ( ImpDetectPCX( rStm ) ) bRet = true; 73 else if ( ImpDetectDXF( rStm, bExtendedInfo ) ) bRet = true; 74 else if ( ImpDetectMET( rStm, bExtendedInfo ) ) bRet = true; 75 else if ( ImpDetectSVM( rStm, bExtendedInfo ) ) bRet = true; 76 else if ( ImpDetectWMF( rStm, bExtendedInfo ) ) bRet = true; 77 else if ( ImpDetectEMF( rStm, bExtendedInfo ) ) bRet = true; 78 else if ( ImpDetectSVG( rStm, bExtendedInfo ) ) bRet = true; 79 else if ( ImpDetectPCT( rStm, bExtendedInfo ) ) bRet = true; 80 else if ( ImpDetectXBM( rStm, bExtendedInfo ) ) bRet = true; 81 else if ( ImpDetectXPM( rStm, bExtendedInfo ) ) bRet = true; 82 else if ( ImpDetectPBM( rStm, bExtendedInfo ) ) bRet = true; 83 else if ( ImpDetectPGM( rStm, bExtendedInfo ) ) bRet = true; 84 else if ( ImpDetectPPM( rStm, bExtendedInfo ) ) bRet = true; 85 else if ( ImpDetectRAS( rStm, bExtendedInfo ) ) bRet = true; 86 else if ( ImpDetectTGA( rStm, bExtendedInfo ) ) bRet = true; 87 else if ( ImpDetectPSD( rStm, bExtendedInfo ) ) bRet = true; 88 else if ( ImpDetectEPS( rStm, bExtendedInfo ) ) bRet = true; 89 else if ( ImpDetectPCD( rStm, bExtendedInfo ) ) bRet = true; 90 91 rStm.SetEndian( nOldFormat ); 92 } 93 return bRet; 94 } 95 96 void GraphicDescriptor::ImpConstruct() 97 { 98 nFormat = GraphicFileFormat::NOT; 99 nBitsPerPixel = 0; 100 nPlanes = 0; 101 mnNumberOfImageComponents = 0; 102 bIsTransparent = false; 103 bIsAlpha = false; 104 } 105 106 bool GraphicDescriptor::ImpDetectBMP( SvStream& rStm, bool bExtendedInfo ) 107 { 108 sal_uInt16 nTemp16 = 0; 109 bool bRet = false; 110 sal_Int32 nStmPos = rStm.Tell(); 111 112 rStm.SetEndian( SvStreamEndian::LITTLE ); 113 rStm.ReadUInt16( nTemp16 ); 114 115 // OS/2-BitmapArray 116 if ( nTemp16 == 0x4142 ) 117 { 118 rStm.SeekRel( 0x0c ); 119 rStm.ReadUInt16( nTemp16 ); 120 } 121 122 // Bitmap 123 if ( nTemp16 == 0x4d42 ) 124 { 125 nFormat = GraphicFileFormat::BMP; 126 bRet = true; 127 128 if ( bExtendedInfo ) 129 { 130 sal_uInt32 nTemp32; 131 sal_uInt32 nCompression; 132 133 // up to first info 134 rStm.SeekRel( 0x10 ); 135 136 // Pixel width 137 rStm.ReadUInt32( nTemp32 ); 138 aPixSize.setWidth( nTemp32 ); 139 140 // Pixel height 141 rStm.ReadUInt32( nTemp32 ); 142 aPixSize.setHeight( nTemp32 ); 143 144 // Planes 145 rStm.ReadUInt16( nTemp16 ); 146 nPlanes = nTemp16; 147 148 // BitCount 149 rStm.ReadUInt16( nTemp16 ); 150 nBitsPerPixel = nTemp16; 151 152 // Compression 153 rStm.ReadUInt32( nTemp32 ); 154 nCompression = nTemp32; 155 156 // logical width 157 rStm.SeekRel( 4 ); 158 rStm.ReadUInt32( nTemp32 ); 159 if ( nTemp32 ) 160 aLogSize.setWidth( ( aPixSize.Width() * 100000 ) / nTemp32 ); 161 162 // logical height 163 rStm.ReadUInt32( nTemp32 ); 164 if ( nTemp32 ) 165 aLogSize.setHeight( ( aPixSize.Height() * 100000 ) / nTemp32 ); 166 167 // further validation, check for rational values 168 if ( ( nBitsPerPixel > 24 ) || ( nCompression > 3 ) ) 169 { 170 nFormat = GraphicFileFormat::NOT; 171 bRet = false; 172 } 173 } 174 } 175 rStm.Seek( nStmPos ); 176 return bRet; 177 } 178 179 bool GraphicDescriptor::ImpDetectGIF( SvStream& rStm, bool bExtendedInfo ) 180 { 181 sal_uInt32 n32 = 0; 182 sal_uInt16 n16 = 0; 183 bool bRet = false; 184 sal_uInt8 cByte = 0; 185 186 sal_Int32 nStmPos = rStm.Tell(); 187 rStm.SetEndian( SvStreamEndian::LITTLE ); 188 rStm.ReadUInt32( n32 ); 189 190 if ( n32 == 0x38464947 ) 191 { 192 rStm.ReadUInt16( n16 ); 193 if ( ( n16 == 0x6137 ) || ( n16 == 0x6139 ) ) 194 { 195 nFormat = GraphicFileFormat::GIF; 196 bRet = true; 197 198 if ( bExtendedInfo ) 199 { 200 sal_uInt16 nTemp16 = 0; 201 202 // Pixel width 203 rStm.ReadUInt16( nTemp16 ); 204 aPixSize.setWidth( nTemp16 ); 205 206 // Pixel height 207 rStm.ReadUInt16( nTemp16 ); 208 aPixSize.setHeight( nTemp16 ); 209 210 // Bits/Pixel 211 rStm.ReadUChar( cByte ); 212 nBitsPerPixel = ( ( cByte & 112 ) >> 4 ) + 1; 213 } 214 } 215 } 216 rStm.Seek( nStmPos ); 217 return bRet; 218 } 219 220 // returns the next jpeg marker, a return value of 0 represents an error 221 static sal_uInt8 ImpDetectJPG_GetNextMarker( SvStream& rStm ) 222 { 223 sal_uInt8 nByte; 224 do 225 { 226 do 227 { 228 rStm.ReadUChar( nByte ); 229 if (!rStm.good()) // as 0 is not allowed as marker, 230 return 0; // we can use it as errorcode 231 } 232 while ( nByte != 0xff ); 233 do 234 { 235 rStm.ReadUChar( nByte ); 236 if (!rStm.good()) 237 return 0; 238 } 239 while( nByte == 0xff ); 240 } 241 while( nByte == 0 ); // 0xff00 represents 0xff and not a marker, 242 // the marker detection has to be restarted. 243 return nByte; 244 } 245 246 bool GraphicDescriptor::ImpDetectJPG( SvStream& rStm, bool bExtendedInfo ) 247 { 248 sal_uInt32 nTemp32 = 0; 249 bool bRet = false; 250 251 sal_Int32 nStmPos = rStm.Tell(); 252 253 rStm.SetEndian( SvStreamEndian::BIG ); 254 rStm.ReadUInt32( nTemp32 ); 255 256 // compare upper 24 bits 257 if( 0xffd8ff00 == ( nTemp32 & 0xffffff00 ) ) 258 { 259 nFormat = GraphicFileFormat::JPG; 260 bRet = true; 261 262 if ( bExtendedInfo ) 263 { 264 rStm.SeekRel( -2 ); 265 266 ErrCode nError( rStm.GetError() ); 267 268 bool bScanFailure = false; 269 bool bScanFinished = false; 270 MapMode aMap; 271 272 while (!bScanFailure && !bScanFinished && rStm.good()) 273 { 274 sal_uInt8 nMarker = ImpDetectJPG_GetNextMarker( rStm ); 275 switch( nMarker ) 276 { 277 // fixed size marker, not having a two byte length parameter 278 case 0xd0 : // RST0 279 case 0xd1 : 280 case 0xd2 : 281 case 0xd3 : 282 case 0xd4 : 283 case 0xd5 : 284 case 0xd6 : 285 case 0xd7 : // RST7 286 case 0x01 : // TEM 287 break; 288 289 case 0xd8 : // SOI (has already been checked, there should not be a second one) 290 case 0x00 : // marker is invalid, we should stop now 291 bScanFailure = true; 292 break; 293 294 case 0xd9 : // EOI 295 bScanFinished = true; 296 break; 297 298 // per default we assume marker segments containing a length parameter 299 default : 300 { 301 sal_uInt16 nLength = 0; 302 rStm.ReadUInt16( nLength ); 303 304 if ( nLength < 2 ) 305 bScanFailure = true; 306 else 307 { 308 sal_uInt32 nNextMarkerPos = rStm.Tell() + nLength - 2; 309 switch( nMarker ) 310 { 311 case 0xe0 : // APP0 Marker 312 { 313 if ( nLength == 16 ) 314 { 315 sal_Int32 nIdentifier = 0; 316 rStm.ReadInt32( nIdentifier ); 317 if ( nIdentifier == 0x4a464946 ) // JFIF Identifier 318 { 319 sal_uInt8 nStringTerminator = 0; 320 sal_uInt8 nMajorRevision = 0; 321 sal_uInt8 nMinorRevision = 0; 322 sal_uInt8 nUnits = 0; 323 sal_uInt16 nHorizontalResolution = 0; 324 sal_uInt16 nVerticalResolution = 0; 325 sal_uInt8 nHorzThumbnailPixelCount = 0; 326 sal_uInt8 nVertThumbnailPixelCount = 0; 327 328 rStm.ReadUChar( nStringTerminator ) 329 .ReadUChar( nMajorRevision ) 330 .ReadUChar( nMinorRevision ) 331 .ReadUChar( nUnits ) 332 .ReadUInt16( nHorizontalResolution ) 333 .ReadUInt16( nVerticalResolution ) 334 .ReadUChar( nHorzThumbnailPixelCount ) 335 .ReadUChar( nVertThumbnailPixelCount ); 336 337 // setting the logical size 338 if ( nUnits && nHorizontalResolution && nVerticalResolution ) 339 { 340 aMap.SetMapUnit( nUnits == 1 ? MapUnit::MapInch : MapUnit::MapCM ); 341 aMap.SetScaleX( Fraction( 1, nHorizontalResolution ) ); 342 aMap.SetScaleY( Fraction( 1, nVerticalResolution ) ); 343 aLogSize = OutputDevice::LogicToLogic( aPixSize, aMap, MapMode( MapUnit::Map100thMM ) ); 344 } 345 } 346 } 347 } 348 break; 349 350 // Start of Frame Markers 351 case 0xc0 : // SOF0 352 case 0xc1 : // SOF1 353 case 0xc2 : // SOF2 354 case 0xc3 : // SOF3 355 case 0xc5 : // SOF5 356 case 0xc6 : // SOF6 357 case 0xc7 : // SOF7 358 case 0xc9 : // SOF9 359 case 0xca : // SOF10 360 case 0xcb : // SOF11 361 case 0xcd : // SOF13 362 case 0xce : // SOF14 363 case 0xcf : // SOF15 364 { 365 sal_uInt8 nSamplePrecision = 0; 366 sal_uInt16 nNumberOfLines = 0; 367 sal_uInt16 nSamplesPerLine = 0; 368 sal_uInt8 nNumberOfImageComponents = 0; 369 sal_uInt8 nComponentsIdentifier = 0; 370 sal_uInt8 nSamplingFactor = 0; 371 sal_uInt8 nQuantizationTableDestinationSelector = 0; 372 rStm.ReadUChar( nSamplePrecision ) 373 .ReadUInt16( nNumberOfLines ) 374 .ReadUInt16( nSamplesPerLine ) 375 .ReadUChar( nNumberOfImageComponents ) 376 .ReadUChar( nComponentsIdentifier ) 377 .ReadUChar( nSamplingFactor ) 378 .ReadUChar( nQuantizationTableDestinationSelector ); 379 mnNumberOfImageComponents = nNumberOfImageComponents; 380 381 // nSamplingFactor (lower nibble: vertical, 382 // upper nibble: horizontal) is unused 383 384 aPixSize.setHeight( nNumberOfLines ); 385 aPixSize.setWidth( nSamplesPerLine ); 386 nBitsPerPixel = ( nNumberOfImageComponents == 3 ? 24 : nNumberOfImageComponents == 1 ? 8 : 0 ); 387 nPlanes = 1; 388 389 if (aMap.GetMapUnit() != MapUnit::MapPixel) 390 // We already know the DPI, but the 391 // pixel size arrived later, so do the 392 // conversion again. 393 aLogSize = OutputDevice::LogicToLogic( 394 aPixSize, aMap, MapMode(MapUnit::Map100thMM)); 395 396 bScanFinished = true; 397 } 398 break; 399 } 400 rStm.Seek( nNextMarkerPos ); 401 } 402 } 403 break; 404 } 405 } 406 rStm.SetError( nError ); 407 } 408 } 409 rStm.Seek( nStmPos ); 410 return bRet; 411 } 412 413 bool GraphicDescriptor::ImpDetectPCD( SvStream& rStm, bool ) 414 { 415 bool bRet = false; 416 417 sal_Int32 nStmPos = rStm.Tell(); 418 rStm.SetEndian( SvStreamEndian::LITTLE ); 419 420 sal_uInt32 nTemp32 = 0; 421 sal_uInt16 nTemp16 = 0; 422 sal_uInt8 cByte = 0; 423 424 rStm.SeekRel( 2048 ); 425 rStm.ReadUInt32( nTemp32 ); 426 rStm.ReadUInt16( nTemp16 ); 427 rStm.ReadUChar( cByte ); 428 429 if ( ( nTemp32 == 0x5f444350 ) && 430 ( nTemp16 == 0x5049 ) && 431 ( cByte == 0x49 ) ) 432 { 433 nFormat = GraphicFileFormat::PCD; 434 bRet = true; 435 } 436 rStm.Seek( nStmPos ); 437 return bRet; 438 } 439 440 bool GraphicDescriptor::ImpDetectPCX( SvStream& rStm ) 441 { 442 // ! Because 0x0a can be interpreted as LF too ... 443 // we can't be sure that this special sign represent a PCX file only. 444 // Every Ascii file is possible here :-( 445 // We must detect the whole header. 446 447 bool bRet = false; 448 sal_uInt8 cByte = 0; 449 450 sal_Int32 nStmPos = rStm.Tell(); 451 rStm.SetEndian( SvStreamEndian::LITTLE ); 452 rStm.ReadUChar( cByte ); 453 454 if ( cByte == 0x0a ) 455 { 456 nFormat = GraphicFileFormat::PCX; 457 458 sal_uInt16 nTemp16; 459 sal_uInt16 nXmin; 460 sal_uInt16 nXmax; 461 sal_uInt16 nYmin; 462 sal_uInt16 nYmax; 463 sal_uInt16 nDPIx; 464 sal_uInt16 nDPIy; 465 466 rStm.SeekRel( 1 ); 467 468 // compression 469 rStm.ReadUChar( cByte ); 470 471 bRet = (cByte==0 || cByte ==1); 472 if (bRet) 473 { 474 // Bits/Pixel 475 rStm.ReadUChar( cByte ); 476 nBitsPerPixel = cByte; 477 478 // image dimensions 479 rStm.ReadUInt16( nTemp16 ); 480 nXmin = nTemp16; 481 rStm.ReadUInt16( nTemp16 ); 482 nYmin = nTemp16; 483 rStm.ReadUInt16( nTemp16 ); 484 nXmax = nTemp16; 485 rStm.ReadUInt16( nTemp16 ); 486 nYmax = nTemp16; 487 488 aPixSize.setWidth( nXmax - nXmin + 1 ); 489 aPixSize.setHeight( nYmax - nYmin + 1 ); 490 491 // resolution 492 rStm.ReadUInt16( nTemp16 ); 493 nDPIx = nTemp16; 494 rStm.ReadUInt16( nTemp16 ); 495 nDPIy = nTemp16; 496 497 // set logical size 498 MapMode aMap( MapUnit::MapInch, Point(), 499 Fraction( 1, nDPIx ), Fraction( 1, nDPIy ) ); 500 aLogSize = OutputDevice::LogicToLogic( aPixSize, aMap, 501 MapMode( MapUnit::Map100thMM ) ); 502 503 // number of color planes 504 cByte = 5; // Illegal value in case of EOF. 505 rStm.SeekRel( 49 ); 506 rStm.ReadUChar( cByte ); 507 nPlanes = cByte; 508 509 bRet = (nPlanes<=4); 510 } 511 } 512 513 rStm.Seek( nStmPos ); 514 return bRet; 515 } 516 517 bool GraphicDescriptor::ImpDetectPNG( SvStream& rStm, bool bExtendedInfo ) 518 { 519 sal_uInt32 nTemp32 = 0; 520 bool bRet = false; 521 522 sal_Int32 nStmPos = rStm.Tell(); 523 rStm.SetEndian( SvStreamEndian::BIG ); 524 rStm.ReadUInt32( nTemp32 ); 525 526 if ( nTemp32 == 0x89504e47 ) 527 { 528 rStm.ReadUInt32( nTemp32 ); 529 if ( nTemp32 == 0x0d0a1a0a ) 530 { 531 nFormat = GraphicFileFormat::PNG; 532 bRet = true; 533 534 if ( bExtendedInfo ) 535 { 536 do { 537 sal_uInt8 cByte = 0; 538 539 // IHDR-Chunk 540 rStm.SeekRel( 8 ); 541 542 // width 543 rStm.ReadUInt32( nTemp32 ); 544 if (!rStm.good()) 545 break; 546 aPixSize.setWidth( nTemp32 ); 547 548 // height 549 rStm.ReadUInt32( nTemp32 ); 550 if (!rStm.good()) 551 break; 552 aPixSize.setHeight( nTemp32 ); 553 554 // Bits/Pixel 555 rStm.ReadUChar( cByte ); 556 if (!rStm.good()) 557 break; 558 nBitsPerPixel = cByte; 559 560 // Colour type - check whether it supports alpha values 561 sal_uInt8 cColType = 0; 562 rStm.ReadUChar( cColType ); 563 if (!rStm.good()) 564 break; 565 bIsAlpha = bIsTransparent = ( cColType == 4 || cColType == 6 ); 566 567 // Planes always 1; 568 // compression always 569 nPlanes = 1; 570 571 sal_uInt32 nLen32 = 0; 572 nTemp32 = 0; 573 574 rStm.SeekRel( 7 ); 575 576 // read up to the start of the image 577 rStm.ReadUInt32( nLen32 ); 578 rStm.ReadUInt32( nTemp32 ); 579 while( ( nTemp32 != 0x49444154 ) && rStm.good() ) 580 { 581 if ( nTemp32 == 0x70485973 ) // physical pixel dimensions 582 { 583 sal_uLong nXRes; 584 sal_uLong nYRes; 585 586 // horizontal resolution 587 nTemp32 = 0; 588 rStm.ReadUInt32( nTemp32 ); 589 nXRes = nTemp32; 590 591 // vertical resolution 592 nTemp32 = 0; 593 rStm.ReadUInt32( nTemp32 ); 594 nYRes = nTemp32; 595 596 // unit 597 cByte = 0; 598 rStm.ReadUChar( cByte ); 599 600 if ( cByte ) 601 { 602 if ( nXRes ) 603 aLogSize.setWidth( (aPixSize.Width() * 100000) / nXRes ); 604 605 if ( nYRes ) 606 aLogSize.setHeight( (aPixSize.Height() * 100000) / nYRes ); 607 } 608 609 nLen32 -= 9; 610 } 611 else if ( nTemp32 == 0x74524e53 ) // transparency 612 { 613 bIsTransparent = true; 614 bIsAlpha = ( cColType != 0 && cColType != 2 ); 615 } 616 617 // skip forward to next chunk 618 rStm.SeekRel( 4 + nLen32 ); 619 rStm.ReadUInt32( nLen32 ); 620 rStm.ReadUInt32( nTemp32 ); 621 } 622 } while (false); 623 } 624 } 625 } 626 rStm.Seek( nStmPos ); 627 return bRet; 628 } 629 630 bool GraphicDescriptor::ImpDetectTIF( SvStream& rStm, bool bExtendedInfo ) 631 { 632 bool bRet = false; 633 sal_uInt8 cByte1 = 0; 634 sal_uInt8 cByte2 = 1; 635 636 sal_Int32 nStmPos = rStm.Tell(); 637 rStm.ReadUChar( cByte1 ); 638 rStm.ReadUChar( cByte2 ); 639 if ( cByte1 == cByte2 ) 640 { 641 bool bDetectOk = false; 642 643 if ( cByte1 == 0x49 ) 644 { 645 rStm.SetEndian( SvStreamEndian::LITTLE ); 646 bDetectOk = true; 647 } 648 else if ( cByte1 == 0x4d ) 649 { 650 rStm.SetEndian( SvStreamEndian::BIG ); 651 bDetectOk = true; 652 } 653 654 if ( bDetectOk ) 655 { 656 sal_uInt16 nTemp16 = 0; 657 658 rStm.ReadUInt16( nTemp16 ); 659 if ( nTemp16 == 0x2a ) 660 { 661 nFormat = GraphicFileFormat::TIF; 662 bRet = true; 663 664 if ( bExtendedInfo ) 665 { 666 sal_uLong nCount; 667 sal_uLong nMax = DATA_SIZE - 48; 668 sal_uInt32 nTemp32 = 0; 669 670 // Offset of the first IFD 671 rStm.ReadUInt32( nTemp32 ); 672 nCount = nTemp32 + 2; 673 rStm.SeekRel( nCount - 0x08 ); 674 675 if ( nCount < nMax ) 676 { 677 bool bOk = false; 678 679 // read tags till we find Tag256 ( Width ) 680 // do not read more bytes than DATA_SIZE 681 rStm.ReadUInt16( nTemp16 ); 682 while ( nTemp16 != 256 ) 683 { 684 bOk = nCount < nMax; 685 if ( !bOk ) 686 { 687 break; 688 } 689 rStm.SeekRel( 10 ); 690 rStm.ReadUInt16( nTemp16 ); 691 nCount += 12; 692 } 693 694 if ( bOk ) 695 { 696 // width 697 rStm.ReadUInt16( nTemp16 ); 698 rStm.SeekRel( 4 ); 699 if ( nTemp16 == 3 ) 700 { 701 rStm.ReadUInt16( nTemp16 ); 702 aPixSize.setWidth( nTemp16 ); 703 rStm.SeekRel( 2 ); 704 } 705 else 706 { 707 rStm.ReadUInt32( nTemp32 ); 708 aPixSize.setWidth( nTemp32 ); 709 } 710 711 // height 712 rStm.SeekRel( 2 ); 713 rStm.ReadUInt16( nTemp16 ); 714 rStm.SeekRel( 4 ); 715 if ( nTemp16 == 3 ) 716 { 717 rStm.ReadUInt16( nTemp16 ); 718 aPixSize.setHeight( nTemp16 ); 719 rStm.SeekRel( 2 ); 720 } 721 else 722 { 723 rStm.ReadUInt32( nTemp32 ); 724 aPixSize.setHeight( nTemp32 ); 725 } 726 727 // Bits/Pixel 728 rStm.ReadUInt16( nTemp16 ); 729 if ( nTemp16 == 258 ) 730 { 731 rStm.SeekRel( 6 ); 732 rStm.ReadUInt16( nTemp16 ); 733 nBitsPerPixel = nTemp16; 734 rStm.SeekRel( 2 ); 735 } 736 else 737 rStm.SeekRel( -2 ); 738 739 // compression 740 rStm.ReadUInt16( nTemp16 ); 741 if ( nTemp16 == 259 ) 742 { 743 rStm.SeekRel( 6 ); 744 rStm.ReadUInt16( nTemp16 ); // compression 745 rStm.SeekRel( 2 ); 746 } 747 else 748 rStm.SeekRel( -2 ); 749 } 750 } 751 } 752 } 753 } 754 } 755 rStm.Seek( nStmPos ); 756 return bRet; 757 } 758 759 bool GraphicDescriptor::ImpDetectXBM( SvStream&, bool ) 760 { 761 bool bRet = aPathExt.startsWith( "xbm" ); 762 if (bRet) 763 nFormat = GraphicFileFormat::XBM; 764 765 return bRet; 766 } 767 768 bool GraphicDescriptor::ImpDetectXPM( SvStream&, bool ) 769 { 770 bool bRet = aPathExt.startsWith( "xpm" ); 771 if (bRet) 772 nFormat = GraphicFileFormat::XPM; 773 774 return bRet; 775 } 776 777 bool GraphicDescriptor::ImpDetectPBM( SvStream& rStm, bool ) 778 { 779 bool bRet = false; 780 781 // check file extension first, as this trumps the 2 ID bytes 782 if ( aPathExt.startsWith( "pbm" ) ) 783 bRet = true; 784 else 785 { 786 sal_Int32 nStmPos = rStm.Tell(); 787 sal_uInt8 nFirst = 0, nSecond = 0; 788 rStm.ReadUChar( nFirst ).ReadUChar( nSecond ); 789 if ( nFirst == 'P' && ( ( nSecond == '1' ) || ( nSecond == '4' ) ) ) 790 bRet = true; 791 rStm.Seek( nStmPos ); 792 } 793 794 if ( bRet ) 795 nFormat = GraphicFileFormat::PBM; 796 797 return bRet; 798 } 799 800 bool GraphicDescriptor::ImpDetectPGM( SvStream& rStm, bool ) 801 { 802 bool bRet = false; 803 804 if ( aPathExt.startsWith( "pgm" ) ) 805 bRet = true; 806 else 807 { 808 sal_uInt8 nFirst = 0, nSecond = 0; 809 sal_Int32 nStmPos = rStm.Tell(); 810 rStm.ReadUChar( nFirst ).ReadUChar( nSecond ); 811 if ( nFirst == 'P' && ( ( nSecond == '2' ) || ( nSecond == '5' ) ) ) 812 bRet = true; 813 rStm.Seek( nStmPos ); 814 } 815 816 if ( bRet ) 817 nFormat = GraphicFileFormat::PGM; 818 819 return bRet; 820 } 821 822 bool GraphicDescriptor::ImpDetectPPM( SvStream& rStm, bool ) 823 { 824 bool bRet = false; 825 826 if ( aPathExt.startsWith( "ppm" ) ) 827 bRet = true; 828 else 829 { 830 sal_uInt8 nFirst = 0, nSecond = 0; 831 sal_Int32 nStmPos = rStm.Tell(); 832 rStm.ReadUChar( nFirst ).ReadUChar( nSecond ); 833 if ( nFirst == 'P' && ( ( nSecond == '3' ) || ( nSecond == '6' ) ) ) 834 bRet = true; 835 rStm.Seek( nStmPos ); 836 } 837 838 if ( bRet ) 839 nFormat = GraphicFileFormat::PPM; 840 841 return bRet; 842 } 843 844 bool GraphicDescriptor::ImpDetectRAS( SvStream& rStm, bool ) 845 { 846 sal_uInt32 nMagicNumber = 0; 847 bool bRet = false; 848 sal_Int32 nStmPos = rStm.Tell(); 849 rStm.SetEndian( SvStreamEndian::BIG ); 850 rStm.ReadUInt32( nMagicNumber ); 851 if ( nMagicNumber == 0x59a66a95 ) 852 { 853 nFormat = GraphicFileFormat::RAS; 854 bRet = true; 855 } 856 rStm.Seek( nStmPos ); 857 return bRet; 858 } 859 860 bool GraphicDescriptor::ImpDetectTGA( SvStream&, bool ) 861 { 862 bool bRet = aPathExt.startsWith( "tga" ); 863 if (bRet) 864 nFormat = GraphicFileFormat::TGA; 865 866 return bRet; 867 } 868 869 bool GraphicDescriptor::ImpDetectPSD( SvStream& rStm, bool bExtendedInfo ) 870 { 871 bool bRet = false; 872 873 sal_uInt32 nMagicNumber = 0; 874 sal_Int32 nStmPos = rStm.Tell(); 875 rStm.SetEndian( SvStreamEndian::BIG ); 876 rStm.ReadUInt32( nMagicNumber ); 877 if ( nMagicNumber == 0x38425053 ) 878 { 879 sal_uInt16 nVersion = 0; 880 rStm.ReadUInt16( nVersion ); 881 if ( nVersion == 1 ) 882 { 883 bRet = true; 884 if ( bExtendedInfo ) 885 { 886 sal_uInt16 nChannels = 0; 887 sal_uInt32 nRows = 0; 888 sal_uInt32 nColumns = 0; 889 sal_uInt16 nDepth = 0; 890 sal_uInt16 nMode = 0; 891 rStm.SeekRel( 6 ); // Pad 892 rStm.ReadUInt16( nChannels ).ReadUInt32( nRows ).ReadUInt32( nColumns ).ReadUInt16( nDepth ).ReadUInt16( nMode ); 893 if ( ( nDepth == 1 ) || ( nDepth == 8 ) || ( nDepth == 16 ) ) 894 { 895 nBitsPerPixel = ( nDepth == 16 ) ? 8 : nDepth; 896 switch ( nChannels ) 897 { 898 case 4 : 899 case 3 : 900 nBitsPerPixel = 24; 901 [[fallthrough]]; 902 case 2 : 903 case 1 : 904 aPixSize.setWidth( nColumns ); 905 aPixSize.setHeight( nRows ); 906 break; 907 default: 908 bRet = false; 909 } 910 } 911 else 912 bRet = false; 913 } 914 } 915 } 916 917 if ( bRet ) 918 nFormat = GraphicFileFormat::PSD; 919 rStm.Seek( nStmPos ); 920 return bRet; 921 } 922 923 bool GraphicDescriptor::ImpDetectEPS( SvStream& rStm, bool ) 924 { 925 // check the EPS preview and the file extension 926 sal_uInt32 nFirstLong = 0; 927 sal_uInt8 nFirstBytes[20] = {}; 928 bool bRet = false; 929 930 sal_Int32 nStmPos = rStm.Tell(); 931 rStm.SetEndian( SvStreamEndian::BIG ); 932 rStm.ReadUInt32( nFirstLong ); 933 rStm.SeekRel( -4 ); 934 rStm.ReadBytes( &nFirstBytes, 20 ); 935 936 if ( ( nFirstLong == 0xC5D0D3C6 ) || aPathExt.startsWith( "eps" ) || 937 ( ImplSearchEntry( nFirstBytes, reinterpret_cast<sal_uInt8 const *>("%!PS-Adobe"), 10, 10 ) 938 && ImplSearchEntry( &nFirstBytes[15], reinterpret_cast<sal_uInt8 const *>("EPS"), 3, 3 ) ) ) 939 { 940 nFormat = GraphicFileFormat::EPS; 941 bRet = true; 942 } 943 rStm.Seek( nStmPos ); 944 return bRet; 945 } 946 947 bool GraphicDescriptor::ImpDetectDXF( SvStream&, bool ) 948 { 949 bool bRet = aPathExt.startsWith( "dxf" ); 950 if (bRet) 951 nFormat = GraphicFileFormat::DXF; 952 953 return bRet; 954 } 955 956 bool GraphicDescriptor::ImpDetectMET( SvStream&, bool ) 957 { 958 bool bRet = aPathExt.startsWith( "met" ); 959 if (bRet) 960 nFormat = GraphicFileFormat::MET; 961 962 return bRet; 963 } 964 965 bool GraphicDescriptor::ImpDetectPCT( SvStream& rStm, bool ) 966 { 967 bool bRet = aPathExt.startsWith( "pct" ); 968 if (bRet) 969 nFormat = GraphicFileFormat::PCT; 970 else 971 { 972 sal_uInt64 const nStreamPos = rStm.Tell(); 973 sal_uInt64 const nStreamLen = rStm.remainingSize(); 974 if (isPCT(rStm, nStreamPos, nStreamLen)) 975 { 976 bRet = true; 977 nFormat = GraphicFileFormat::PCT; 978 } 979 rStm.Seek(nStreamPos); 980 } 981 982 return bRet; 983 } 984 985 bool GraphicDescriptor::ImpDetectSVM( SvStream& rStm, bool bExtendedInfo ) 986 { 987 sal_uInt32 n32 = 0; 988 bool bRet = false; 989 sal_uInt8 cByte = 0; 990 991 sal_Int32 nStmPos = rStm.Tell(); 992 rStm.SetEndian( SvStreamEndian::LITTLE ); 993 rStm.ReadUInt32( n32 ); 994 if ( n32 == 0x44475653 ) 995 { 996 cByte = 0; 997 rStm.ReadUChar( cByte ); 998 if ( cByte == 0x49 ) 999 { 1000 nFormat = GraphicFileFormat::SVM; 1001 bRet = true; 1002 1003 if ( bExtendedInfo ) 1004 { 1005 sal_uInt32 nTemp32; 1006 sal_uInt16 nTemp16; 1007 1008 rStm.SeekRel( 0x04 ); 1009 1010 // width 1011 nTemp32 = 0; 1012 rStm.ReadUInt32( nTemp32 ); 1013 aLogSize.setWidth( nTemp32 ); 1014 1015 // height 1016 nTemp32 = 0; 1017 rStm.ReadUInt32( nTemp32 ); 1018 aLogSize.setHeight( nTemp32 ); 1019 1020 // read MapUnit and determine PrefSize 1021 nTemp16 = 0; 1022 rStm.ReadUInt16( nTemp16 ); 1023 aLogSize = OutputDevice::LogicToLogic( aLogSize, 1024 MapMode( static_cast<MapUnit>(nTemp16) ), 1025 MapMode( MapUnit::Map100thMM ) ); 1026 } 1027 } 1028 } 1029 else 1030 { 1031 rStm.SeekRel( -4 ); 1032 n32 = 0; 1033 rStm.ReadUInt32( n32 ); 1034 1035 if( n32 == 0x4D4C4356 ) 1036 { 1037 sal_uInt16 nTmp16 = 0; 1038 1039 rStm.ReadUInt16( nTmp16 ); 1040 1041 if( nTmp16 == 0x4654 ) 1042 { 1043 nFormat = GraphicFileFormat::SVM; 1044 bRet = true; 1045 1046 if( bExtendedInfo ) 1047 { 1048 MapMode aMapMode; 1049 1050 rStm.SeekRel( 0x06 ); 1051 ReadMapMode( rStm, aMapMode ); 1052 TypeSerializer aSerializer(rStm); 1053 aSerializer.readSize(aLogSize); 1054 aLogSize = OutputDevice::LogicToLogic( aLogSize, aMapMode, MapMode( MapUnit::Map100thMM ) ); 1055 } 1056 } 1057 } 1058 } 1059 rStm.Seek( nStmPos ); 1060 return bRet; 1061 } 1062 1063 bool GraphicDescriptor::ImpDetectWMF( SvStream&, bool ) 1064 { 1065 bool bRet = aPathExt.startsWith( "wmf" ); 1066 if (bRet) 1067 nFormat = GraphicFileFormat::WMF; 1068 1069 return bRet; 1070 } 1071 1072 bool GraphicDescriptor::ImpDetectEMF( SvStream& rStm, bool bExtendedInfo ) 1073 { 1074 sal_uInt32 nRecordType = 0; 1075 bool bRet = false; 1076 1077 sal_Int32 nStmPos = rStm.Tell(); 1078 rStm.SetEndian( SvStreamEndian::LITTLE ); 1079 rStm.ReadUInt32( nRecordType ); 1080 1081 if ( nRecordType == 0x00000001 ) 1082 { 1083 sal_uInt32 nHeaderSize = 0; 1084 sal_Int32 nBoundLeft = 0, nBoundTop = 0, nBoundRight = 0, nBoundBottom = 0; 1085 sal_Int32 nFrameLeft = 0, nFrameTop = 0, nFrameRight = 0, nFrameBottom = 0; 1086 sal_uInt32 nSignature = 0; 1087 1088 rStm.ReadUInt32( nHeaderSize ); 1089 rStm.ReadInt32( nBoundLeft ); 1090 rStm.ReadInt32( nBoundTop ); 1091 rStm.ReadInt32( nBoundRight ); 1092 rStm.ReadInt32( nBoundBottom ); 1093 rStm.ReadInt32( nFrameLeft ); 1094 rStm.ReadInt32( nFrameTop ); 1095 rStm.ReadInt32( nFrameRight ); 1096 rStm.ReadInt32( nFrameBottom ); 1097 rStm.ReadUInt32( nSignature ); 1098 1099 if ( nSignature == 0x464d4520 ) 1100 { 1101 nFormat = GraphicFileFormat::EMF; 1102 bRet = true; 1103 1104 if ( bExtendedInfo ) 1105 { 1106 // size in pixels 1107 aPixSize.setWidth( nBoundRight - nBoundLeft + 1 ); 1108 aPixSize.setHeight( nBoundBottom - nBoundTop + 1 ); 1109 1110 // size in 0.01mm units 1111 aLogSize.setWidth( nFrameRight - nFrameLeft + 1 ); 1112 aLogSize.setHeight( nFrameBottom - nFrameTop + 1 ); 1113 } 1114 } 1115 } 1116 1117 rStm.Seek( nStmPos ); 1118 return bRet; 1119 } 1120 1121 bool GraphicDescriptor::ImpDetectSVG( SvStream& /*rStm*/, bool /*bExtendedInfo*/ ) 1122 { 1123 bool bRet = aPathExt.startsWith( "svg" ); 1124 if (bRet) 1125 nFormat = GraphicFileFormat::SVG; 1126 1127 return bRet; 1128 } 1129 1130 OUString GraphicDescriptor::GetImportFormatShortName( GraphicFileFormat nFormat ) 1131 { 1132 const char *pKeyName = nullptr; 1133 1134 switch( nFormat ) 1135 { 1136 case GraphicFileFormat::BMP : pKeyName = "bmp"; break; 1137 case GraphicFileFormat::GIF : pKeyName = "gif"; break; 1138 case GraphicFileFormat::JPG : pKeyName = "jpg"; break; 1139 case GraphicFileFormat::PCD : pKeyName = "pcd"; break; 1140 case GraphicFileFormat::PCX : pKeyName = "pcx"; break; 1141 case GraphicFileFormat::PNG : pKeyName = "png"; break; 1142 case GraphicFileFormat::XBM : pKeyName = "xbm"; break; 1143 case GraphicFileFormat::XPM : pKeyName = "xpm"; break; 1144 case GraphicFileFormat::PBM : pKeyName = "pbm"; break; 1145 case GraphicFileFormat::PGM : pKeyName = "pgm"; break; 1146 case GraphicFileFormat::PPM : pKeyName = "ppm"; break; 1147 case GraphicFileFormat::RAS : pKeyName = "ras"; break; 1148 case GraphicFileFormat::TGA : pKeyName = "tga"; break; 1149 case GraphicFileFormat::PSD : pKeyName = "psd"; break; 1150 case GraphicFileFormat::EPS : pKeyName = "eps"; break; 1151 case GraphicFileFormat::TIF : pKeyName = "tif"; break; 1152 case GraphicFileFormat::DXF : pKeyName = "dxf"; break; 1153 case GraphicFileFormat::MET : pKeyName = "met"; break; 1154 case GraphicFileFormat::PCT : pKeyName = "pct"; break; 1155 case GraphicFileFormat::SVM : pKeyName = "svm"; break; 1156 case GraphicFileFormat::WMF : pKeyName = "wmf"; break; 1157 case GraphicFileFormat::EMF : pKeyName = "emf"; break; 1158 case GraphicFileFormat::SVG : pKeyName = "svg"; break; 1159 default: assert(false); 1160 } 1161 1162 return OUString::createFromAscii(pKeyName); 1163 } 1164 1165 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1166
