bump product version to 7.2.5.1
[LibreOffice.git] / vcl / source / filter / graphicfilter2.cxx
blob5666497ce08fc9c0b359a4fee76f00bc874aa2dd
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <string.h>
21 #include <tools/stream.hxx>
22 #include <tools/fract.hxx>
23 #include <tools/urlobj.hxx>
24 #include <vcl/TypeSerializer.hxx>
25 #include <vcl/outdev.hxx>
26 #include <vcl/graphicfilter.hxx>
27 #include <unotools/ucbstreamhelper.hxx>
28 #include "graphicfilter_internal.hxx"
30 #define DATA_SIZE 640
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 )
37 ImpConstruct();
40 GraphicDescriptor::GraphicDescriptor( SvStream& rInStream, const OUString* pPath) :
41 pFileStm ( &rInStream ),
42 bOwnStream ( false )
44 ImpConstruct();
46 if ( pPath )
48 INetURLObject aURL( *pPath );
49 aPathExt = aURL.GetFileExtension().toAsciiLowerCase();
53 GraphicDescriptor::~GraphicDescriptor()
55 if ( bOwnStream )
56 delete pFileStm;
59 bool GraphicDescriptor::Detect( bool bExtendedInfo )
61 bool bRet = false;
62 if ( pFileStm && !pFileStm->GetError() )
64 SvStream& rStm = *pFileStm;
65 SvStreamEndian nOldFormat = rStm.GetEndian();
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;
91 rStm.SetEndian( nOldFormat );
93 return bRet;
96 void GraphicDescriptor::ImpConstruct()
98 nFormat = GraphicFileFormat::NOT;
99 nBitsPerPixel = 0;
100 nPlanes = 0;
101 mnNumberOfImageComponents = 0;
102 bIsTransparent = false;
103 bIsAlpha = false;
106 bool GraphicDescriptor::ImpDetectBMP( SvStream& rStm, bool bExtendedInfo )
108 sal_uInt16 nTemp16 = 0;
109 bool bRet = false;
110 sal_Int32 nStmPos = rStm.Tell();
112 rStm.SetEndian( SvStreamEndian::LITTLE );
113 rStm.ReadUInt16( nTemp16 );
115 // OS/2-BitmapArray
116 if ( nTemp16 == 0x4142 )
118 rStm.SeekRel( 0x0c );
119 rStm.ReadUInt16( nTemp16 );
122 // Bitmap
123 if ( nTemp16 == 0x4d42 )
125 nFormat = GraphicFileFormat::BMP;
126 bRet = true;
128 if ( bExtendedInfo )
130 sal_uInt32 nTemp32;
131 sal_uInt32 nCompression;
133 // up to first info
134 rStm.SeekRel( 0x10 );
136 // Pixel width
137 rStm.ReadUInt32( nTemp32 );
138 aPixSize.setWidth( nTemp32 );
140 // Pixel height
141 rStm.ReadUInt32( nTemp32 );
142 aPixSize.setHeight( nTemp32 );
144 // Planes
145 rStm.ReadUInt16( nTemp16 );
146 nPlanes = nTemp16;
148 // BitCount
149 rStm.ReadUInt16( nTemp16 );
150 nBitsPerPixel = nTemp16;
152 // Compression
153 rStm.ReadUInt32( nTemp32 );
154 nCompression = nTemp32;
156 // logical width
157 rStm.SeekRel( 4 );
158 rStm.ReadUInt32( nTemp32 );
159 sal_uInt32 nXPelsPerMeter = 0;
160 if ( nTemp32 )
162 aLogSize.setWidth( ( aPixSize.Width() * 100000 ) / nTemp32 );
163 nXPelsPerMeter = nTemp32;
166 // logical height
167 rStm.ReadUInt32( nTemp32 );
168 sal_uInt32 nYPelsPerMeter = 0;
169 if ( nTemp32 )
171 aLogSize.setHeight( ( aPixSize.Height() * 100000 ) / nTemp32 );
172 nYPelsPerMeter = nTemp32;
175 // further validation, check for rational values
176 if ( ( nBitsPerPixel > 24 ) || ( nCompression > 3 ) )
178 nFormat = GraphicFileFormat::NOT;
179 bRet = false;
182 if (bRet && nXPelsPerMeter && nYPelsPerMeter)
184 maPreferredMapMode
185 = MapMode(MapUnit::MapMM, Point(), Fraction(1000, nXPelsPerMeter),
186 Fraction(1000, nYPelsPerMeter));
188 maPreferredLogSize = Size(aPixSize.getWidth(), aPixSize.getHeight());
192 rStm.Seek( nStmPos );
193 return bRet;
196 bool GraphicDescriptor::ImpDetectGIF( SvStream& rStm, bool bExtendedInfo )
198 sal_uInt32 n32 = 0;
199 bool bRet = false;
201 sal_Int32 nStmPos = rStm.Tell();
202 rStm.SetEndian( SvStreamEndian::LITTLE );
203 rStm.ReadUInt32( n32 );
205 if ( n32 == 0x38464947 )
207 sal_uInt16 n16 = 0;
208 rStm.ReadUInt16( n16 );
209 if ( ( n16 == 0x6137 ) || ( n16 == 0x6139 ) )
211 nFormat = GraphicFileFormat::GIF;
212 bRet = true;
214 if ( bExtendedInfo )
216 sal_uInt16 nTemp16 = 0;
217 sal_uInt8 cByte = 0;
219 // Pixel width
220 rStm.ReadUInt16( nTemp16 );
221 aPixSize.setWidth( nTemp16 );
223 // Pixel height
224 rStm.ReadUInt16( nTemp16 );
225 aPixSize.setHeight( nTemp16 );
227 // Bits/Pixel
228 rStm.ReadUChar( cByte );
229 nBitsPerPixel = ( ( cByte & 112 ) >> 4 ) + 1;
233 rStm.Seek( nStmPos );
234 return bRet;
237 // returns the next jpeg marker, a return value of 0 represents an error
238 static sal_uInt8 ImpDetectJPG_GetNextMarker( SvStream& rStm )
240 sal_uInt8 nByte;
245 rStm.ReadUChar( nByte );
246 if (!rStm.good()) // as 0 is not allowed as marker,
247 return 0; // we can use it as errorcode
249 while ( nByte != 0xff );
252 rStm.ReadUChar( nByte );
253 if (!rStm.good())
254 return 0;
256 while( nByte == 0xff );
258 while( nByte == 0 ); // 0xff00 represents 0xff and not a marker,
259 // the marker detection has to be restarted.
260 return nByte;
263 bool GraphicDescriptor::ImpDetectJPG( SvStream& rStm, bool bExtendedInfo )
265 sal_uInt32 nTemp32 = 0;
266 bool bRet = false;
268 sal_Int32 nStmPos = rStm.Tell();
270 rStm.SetEndian( SvStreamEndian::BIG );
271 rStm.ReadUInt32( nTemp32 );
273 // compare upper 24 bits
274 if( 0xffd8ff00 == ( nTemp32 & 0xffffff00 ) )
276 nFormat = GraphicFileFormat::JPG;
277 bRet = true;
279 if ( bExtendedInfo )
281 rStm.SeekRel( -2 );
283 ErrCode nError( rStm.GetError() );
285 bool bScanFailure = false;
286 bool bScanFinished = false;
287 MapMode aMap;
289 while (!bScanFailure && !bScanFinished && rStm.good())
291 sal_uInt8 nMarker = ImpDetectJPG_GetNextMarker( rStm );
292 switch( nMarker )
294 // fixed size marker, not having a two byte length parameter
295 case 0xd0 : // RST0
296 case 0xd1 :
297 case 0xd2 :
298 case 0xd3 :
299 case 0xd4 :
300 case 0xd5 :
301 case 0xd6 :
302 case 0xd7 : // RST7
303 case 0x01 : // TEM
304 break;
306 case 0xd8 : // SOI (has already been checked, there should not be a second one)
307 case 0x00 : // marker is invalid, we should stop now
308 bScanFailure = true;
309 break;
311 case 0xd9 : // EOI
312 bScanFinished = true;
313 break;
315 // per default we assume marker segments containing a length parameter
316 default :
318 sal_uInt16 nLength = 0;
319 rStm.ReadUInt16( nLength );
321 if ( nLength < 2 )
322 bScanFailure = true;
323 else
325 sal_uInt32 nNextMarkerPos = rStm.Tell() + nLength - 2;
326 switch( nMarker )
328 case 0xe0 : // APP0 Marker
330 if ( nLength == 16 )
332 sal_Int32 nIdentifier = 0;
333 rStm.ReadInt32( nIdentifier );
334 if ( nIdentifier == 0x4a464946 ) // JFIF Identifier
336 sal_uInt8 nStringTerminator = 0;
337 sal_uInt8 nMajorRevision = 0;
338 sal_uInt8 nMinorRevision = 0;
339 sal_uInt8 nUnits = 0;
340 sal_uInt16 nHorizontalResolution = 0;
341 sal_uInt16 nVerticalResolution = 0;
342 sal_uInt8 nHorzThumbnailPixelCount = 0;
343 sal_uInt8 nVertThumbnailPixelCount = 0;
345 rStm.ReadUChar( nStringTerminator )
346 .ReadUChar( nMajorRevision )
347 .ReadUChar( nMinorRevision )
348 .ReadUChar( nUnits )
349 .ReadUInt16( nHorizontalResolution )
350 .ReadUInt16( nVerticalResolution )
351 .ReadUChar( nHorzThumbnailPixelCount )
352 .ReadUChar( nVertThumbnailPixelCount );
354 // setting the logical size
355 if ( nUnits && nHorizontalResolution && nVerticalResolution )
357 aMap.SetMapUnit( nUnits == 1 ? MapUnit::MapInch : MapUnit::MapCM );
358 aMap.SetScaleX( Fraction( 1, nHorizontalResolution ) );
359 aMap.SetScaleY( Fraction( 1, nVerticalResolution ) );
360 aLogSize = OutputDevice::LogicToLogic( aPixSize, aMap, MapMode( MapUnit::Map100thMM ) );
365 break;
367 // Start of Frame Markers
368 case 0xc0 : // SOF0
369 case 0xc1 : // SOF1
370 case 0xc2 : // SOF2
371 case 0xc3 : // SOF3
372 case 0xc5 : // SOF5
373 case 0xc6 : // SOF6
374 case 0xc7 : // SOF7
375 case 0xc9 : // SOF9
376 case 0xca : // SOF10
377 case 0xcb : // SOF11
378 case 0xcd : // SOF13
379 case 0xce : // SOF14
380 case 0xcf : // SOF15
382 sal_uInt8 nSamplePrecision = 0;
383 sal_uInt16 nNumberOfLines = 0;
384 sal_uInt16 nSamplesPerLine = 0;
385 sal_uInt8 nNumberOfImageComponents = 0;
386 sal_uInt8 nComponentsIdentifier = 0;
387 sal_uInt8 nSamplingFactor = 0;
388 sal_uInt8 nQuantizationTableDestinationSelector = 0;
389 rStm.ReadUChar( nSamplePrecision )
390 .ReadUInt16( nNumberOfLines )
391 .ReadUInt16( nSamplesPerLine )
392 .ReadUChar( nNumberOfImageComponents )
393 .ReadUChar( nComponentsIdentifier )
394 .ReadUChar( nSamplingFactor )
395 .ReadUChar( nQuantizationTableDestinationSelector );
396 mnNumberOfImageComponents = nNumberOfImageComponents;
398 // nSamplingFactor (lower nibble: vertical,
399 // upper nibble: horizontal) is unused
401 aPixSize.setHeight( nNumberOfLines );
402 aPixSize.setWidth( nSamplesPerLine );
403 nBitsPerPixel = ( nNumberOfImageComponents == 3 ? 24 : nNumberOfImageComponents == 1 ? 8 : 0 );
404 nPlanes = 1;
406 if (aMap.GetMapUnit() != MapUnit::MapPixel)
407 // We already know the DPI, but the
408 // pixel size arrived later, so do the
409 // conversion again.
410 aLogSize = OutputDevice::LogicToLogic(
411 aPixSize, aMap, MapMode(MapUnit::Map100thMM));
413 bScanFinished = true;
415 break;
417 rStm.Seek( nNextMarkerPos );
420 break;
423 rStm.SetError( nError );
426 rStm.Seek( nStmPos );
427 return bRet;
430 bool GraphicDescriptor::ImpDetectPCD( SvStream& rStm, bool )
432 bool bRet = false;
434 sal_Int32 nStmPos = rStm.Tell();
435 rStm.SetEndian( SvStreamEndian::LITTLE );
437 sal_uInt32 nTemp32 = 0;
438 sal_uInt16 nTemp16 = 0;
439 sal_uInt8 cByte = 0;
441 rStm.SeekRel( 2048 );
442 rStm.ReadUInt32( nTemp32 );
443 rStm.ReadUInt16( nTemp16 );
444 rStm.ReadUChar( cByte );
446 if ( ( nTemp32 == 0x5f444350 ) &&
447 ( nTemp16 == 0x5049 ) &&
448 ( cByte == 0x49 ) )
450 nFormat = GraphicFileFormat::PCD;
451 bRet = true;
453 rStm.Seek( nStmPos );
454 return bRet;
457 bool GraphicDescriptor::ImpDetectPCX( SvStream& rStm )
459 // ! Because 0x0a can be interpreted as LF too ...
460 // we can't be sure that this special sign represent a PCX file only.
461 // Every Ascii file is possible here :-(
462 // We must detect the whole header.
464 bool bRet = false;
465 sal_uInt8 cByte = 0;
467 sal_Int32 nStmPos = rStm.Tell();
468 rStm.SetEndian( SvStreamEndian::LITTLE );
469 rStm.ReadUChar( cByte );
471 if ( cByte == 0x0a )
473 nFormat = GraphicFileFormat::PCX;
475 rStm.SeekRel( 1 );
477 // compression
478 rStm.ReadUChar( cByte );
480 bRet = (cByte==0 || cByte ==1);
481 if (bRet)
483 sal_uInt16 nTemp16;
484 sal_uInt16 nXmin;
485 sal_uInt16 nXmax;
486 sal_uInt16 nYmin;
487 sal_uInt16 nYmax;
488 sal_uInt16 nDPIx;
489 sal_uInt16 nDPIy;
491 // Bits/Pixel
492 rStm.ReadUChar( cByte );
493 nBitsPerPixel = cByte;
495 // image dimensions
496 rStm.ReadUInt16( nTemp16 );
497 nXmin = nTemp16;
498 rStm.ReadUInt16( nTemp16 );
499 nYmin = nTemp16;
500 rStm.ReadUInt16( nTemp16 );
501 nXmax = nTemp16;
502 rStm.ReadUInt16( nTemp16 );
503 nYmax = nTemp16;
505 aPixSize.setWidth( nXmax - nXmin + 1 );
506 aPixSize.setHeight( nYmax - nYmin + 1 );
508 // resolution
509 rStm.ReadUInt16( nTemp16 );
510 nDPIx = nTemp16;
511 rStm.ReadUInt16( nTemp16 );
512 nDPIy = nTemp16;
514 // set logical size
515 MapMode aMap( MapUnit::MapInch, Point(),
516 Fraction( 1, nDPIx ), Fraction( 1, nDPIy ) );
517 aLogSize = OutputDevice::LogicToLogic( aPixSize, aMap,
518 MapMode( MapUnit::Map100thMM ) );
520 // number of color planes
521 cByte = 5; // Illegal value in case of EOF.
522 rStm.SeekRel( 49 );
523 rStm.ReadUChar( cByte );
524 nPlanes = cByte;
526 bRet = (nPlanes<=4);
530 rStm.Seek( nStmPos );
531 return bRet;
534 bool GraphicDescriptor::ImpDetectPNG( SvStream& rStm, bool bExtendedInfo )
536 sal_uInt32 nTemp32 = 0;
537 bool bRet = false;
539 sal_Int32 nStmPos = rStm.Tell();
540 rStm.SetEndian( SvStreamEndian::BIG );
541 rStm.ReadUInt32( nTemp32 );
543 if ( nTemp32 == 0x89504e47 )
545 rStm.ReadUInt32( nTemp32 );
546 if ( nTemp32 == 0x0d0a1a0a )
548 nFormat = GraphicFileFormat::PNG;
549 bRet = true;
551 if ( bExtendedInfo )
553 do {
554 sal_uInt8 cByte = 0;
556 // IHDR-Chunk
557 rStm.SeekRel( 8 );
559 // width
560 rStm.ReadUInt32( nTemp32 );
561 if (!rStm.good())
562 break;
563 aPixSize.setWidth( nTemp32 );
565 // height
566 rStm.ReadUInt32( nTemp32 );
567 if (!rStm.good())
568 break;
569 aPixSize.setHeight( nTemp32 );
571 // Bits/Pixel
572 rStm.ReadUChar( cByte );
573 if (!rStm.good())
574 break;
575 nBitsPerPixel = cByte;
577 // Colour type - check whether it supports alpha values
578 sal_uInt8 cColType = 0;
579 rStm.ReadUChar( cColType );
580 if (!rStm.good())
581 break;
582 bIsAlpha = bIsTransparent = ( cColType == 4 || cColType == 6 );
584 // Planes always 1;
585 // compression always
586 nPlanes = 1;
588 sal_uInt32 nLen32 = 0;
589 nTemp32 = 0;
591 rStm.SeekRel( 7 );
593 // read up to the start of the image
594 rStm.ReadUInt32( nLen32 );
595 rStm.ReadUInt32( nTemp32 );
596 while( ( nTemp32 != 0x49444154 ) && rStm.good() )
598 if ( nTemp32 == 0x70485973 ) // physical pixel dimensions
600 sal_uLong nXRes;
601 sal_uLong nYRes;
603 // horizontal resolution
604 nTemp32 = 0;
605 rStm.ReadUInt32( nTemp32 );
606 nXRes = nTemp32;
608 // vertical resolution
609 nTemp32 = 0;
610 rStm.ReadUInt32( nTemp32 );
611 nYRes = nTemp32;
613 // unit
614 cByte = 0;
615 rStm.ReadUChar( cByte );
617 if ( cByte )
619 if ( nXRes )
620 aLogSize.setWidth( (aPixSize.Width() * 100000) / nXRes );
622 if ( nYRes )
623 aLogSize.setHeight( (aPixSize.Height() * 100000) / nYRes );
626 nLen32 -= 9;
628 else if ( nTemp32 == 0x74524e53 ) // transparency
630 bIsTransparent = true;
631 bIsAlpha = ( cColType != 0 && cColType != 2 );
634 // skip forward to next chunk
635 rStm.SeekRel( 4 + nLen32 );
636 rStm.ReadUInt32( nLen32 );
637 rStm.ReadUInt32( nTemp32 );
639 } while (false);
643 rStm.Seek( nStmPos );
644 return bRet;
647 bool GraphicDescriptor::ImpDetectTIF( SvStream& rStm, bool bExtendedInfo )
649 bool bRet = false;
650 sal_uInt8 cByte1 = 0;
651 sal_uInt8 cByte2 = 1;
653 sal_Int32 nStmPos = rStm.Tell();
654 rStm.ReadUChar( cByte1 );
655 rStm.ReadUChar( cByte2 );
656 if ( cByte1 == cByte2 )
658 bool bDetectOk = false;
660 if ( cByte1 == 0x49 )
662 rStm.SetEndian( SvStreamEndian::LITTLE );
663 bDetectOk = true;
665 else if ( cByte1 == 0x4d )
667 rStm.SetEndian( SvStreamEndian::BIG );
668 bDetectOk = true;
671 if ( bDetectOk )
673 sal_uInt16 nTemp16 = 0;
675 rStm.ReadUInt16( nTemp16 );
676 if ( nTemp16 == 0x2a )
678 nFormat = GraphicFileFormat::TIF;
679 bRet = true;
681 if ( bExtendedInfo )
683 sal_uLong nCount;
684 sal_uLong nMax = DATA_SIZE - 48;
685 sal_uInt32 nTemp32 = 0;
687 // Offset of the first IFD
688 rStm.ReadUInt32( nTemp32 );
689 nCount = nTemp32 + 2;
690 rStm.SeekRel( nCount - 0x08 );
692 if ( nCount < nMax )
694 bool bOk = false;
696 // read tags till we find Tag256 ( Width )
697 // do not read more bytes than DATA_SIZE
698 rStm.ReadUInt16( nTemp16 );
699 while ( nTemp16 != 256 )
701 bOk = nCount < nMax;
702 if ( !bOk )
704 break;
706 rStm.SeekRel( 10 );
707 rStm.ReadUInt16( nTemp16 );
708 nCount += 12;
711 if ( bOk )
713 // width
714 rStm.ReadUInt16( nTemp16 );
715 rStm.SeekRel( 4 );
716 if ( nTemp16 == 3 )
718 rStm.ReadUInt16( nTemp16 );
719 aPixSize.setWidth( nTemp16 );
720 rStm.SeekRel( 2 );
722 else
724 rStm.ReadUInt32( nTemp32 );
725 aPixSize.setWidth( nTemp32 );
728 // height
729 rStm.SeekRel( 2 );
730 rStm.ReadUInt16( nTemp16 );
731 rStm.SeekRel( 4 );
732 if ( nTemp16 == 3 )
734 rStm.ReadUInt16( nTemp16 );
735 aPixSize.setHeight( nTemp16 );
736 rStm.SeekRel( 2 );
738 else
740 rStm.ReadUInt32( nTemp32 );
741 aPixSize.setHeight( nTemp32 );
744 // Bits/Pixel
745 rStm.ReadUInt16( nTemp16 );
746 if ( nTemp16 == 258 )
748 rStm.SeekRel( 6 );
749 rStm.ReadUInt16( nTemp16 );
750 nBitsPerPixel = nTemp16;
751 rStm.SeekRel( 2 );
753 else
754 rStm.SeekRel( -2 );
756 // compression
757 rStm.ReadUInt16( nTemp16 );
758 if ( nTemp16 == 259 )
760 rStm.SeekRel( 6 );
761 rStm.ReadUInt16( nTemp16 ); // compression
762 rStm.SeekRel( 2 );
764 else
765 rStm.SeekRel( -2 );
772 rStm.Seek( nStmPos );
773 return bRet;
776 bool GraphicDescriptor::ImpDetectXBM( SvStream&, bool )
778 bool bRet = aPathExt.startsWith( "xbm" );
779 if (bRet)
780 nFormat = GraphicFileFormat::XBM;
782 return bRet;
785 bool GraphicDescriptor::ImpDetectXPM( SvStream&, bool )
787 bool bRet = aPathExt.startsWith( "xpm" );
788 if (bRet)
789 nFormat = GraphicFileFormat::XPM;
791 return bRet;
794 bool GraphicDescriptor::ImpDetectPBM( SvStream& rStm, bool )
796 bool bRet = false;
798 // check file extension first, as this trumps the 2 ID bytes
799 if ( aPathExt.startsWith( "pbm" ) )
800 bRet = true;
801 else
803 sal_Int32 nStmPos = rStm.Tell();
804 sal_uInt8 nFirst = 0, nSecond = 0;
805 rStm.ReadUChar( nFirst ).ReadUChar( nSecond );
806 if ( nFirst == 'P' && ( ( nSecond == '1' ) || ( nSecond == '4' ) ) )
807 bRet = true;
808 rStm.Seek( nStmPos );
811 if ( bRet )
812 nFormat = GraphicFileFormat::PBM;
814 return bRet;
817 bool GraphicDescriptor::ImpDetectPGM( SvStream& rStm, bool )
819 bool bRet = false;
821 if ( aPathExt.startsWith( "pgm" ) )
822 bRet = true;
823 else
825 sal_uInt8 nFirst = 0, nSecond = 0;
826 sal_Int32 nStmPos = rStm.Tell();
827 rStm.ReadUChar( nFirst ).ReadUChar( nSecond );
828 if ( nFirst == 'P' && ( ( nSecond == '2' ) || ( nSecond == '5' ) ) )
829 bRet = true;
830 rStm.Seek( nStmPos );
833 if ( bRet )
834 nFormat = GraphicFileFormat::PGM;
836 return bRet;
839 bool GraphicDescriptor::ImpDetectPPM( SvStream& rStm, bool )
841 bool bRet = false;
843 if ( aPathExt.startsWith( "ppm" ) )
844 bRet = true;
845 else
847 sal_uInt8 nFirst = 0, nSecond = 0;
848 sal_Int32 nStmPos = rStm.Tell();
849 rStm.ReadUChar( nFirst ).ReadUChar( nSecond );
850 if ( nFirst == 'P' && ( ( nSecond == '3' ) || ( nSecond == '6' ) ) )
851 bRet = true;
852 rStm.Seek( nStmPos );
855 if ( bRet )
856 nFormat = GraphicFileFormat::PPM;
858 return bRet;
861 bool GraphicDescriptor::ImpDetectRAS( SvStream& rStm, bool )
863 sal_uInt32 nMagicNumber = 0;
864 bool bRet = false;
865 sal_Int32 nStmPos = rStm.Tell();
866 rStm.SetEndian( SvStreamEndian::BIG );
867 rStm.ReadUInt32( nMagicNumber );
868 if ( nMagicNumber == 0x59a66a95 )
870 nFormat = GraphicFileFormat::RAS;
871 bRet = true;
873 rStm.Seek( nStmPos );
874 return bRet;
877 bool GraphicDescriptor::ImpDetectTGA( SvStream&, bool )
879 bool bRet = aPathExt.startsWith( "tga" );
880 if (bRet)
881 nFormat = GraphicFileFormat::TGA;
883 return bRet;
886 bool GraphicDescriptor::ImpDetectPSD( SvStream& rStm, bool bExtendedInfo )
888 bool bRet = false;
890 sal_uInt32 nMagicNumber = 0;
891 sal_Int32 nStmPos = rStm.Tell();
892 rStm.SetEndian( SvStreamEndian::BIG );
893 rStm.ReadUInt32( nMagicNumber );
894 if ( nMagicNumber == 0x38425053 )
896 sal_uInt16 nVersion = 0;
897 rStm.ReadUInt16( nVersion );
898 if ( nVersion == 1 )
900 bRet = true;
901 if ( bExtendedInfo )
903 sal_uInt16 nChannels = 0;
904 sal_uInt32 nRows = 0;
905 sal_uInt32 nColumns = 0;
906 sal_uInt16 nDepth = 0;
907 sal_uInt16 nMode = 0;
908 rStm.SeekRel( 6 ); // Pad
909 rStm.ReadUInt16( nChannels ).ReadUInt32( nRows ).ReadUInt32( nColumns ).ReadUInt16( nDepth ).ReadUInt16( nMode );
910 if ( ( nDepth == 1 ) || ( nDepth == 8 ) || ( nDepth == 16 ) )
912 nBitsPerPixel = ( nDepth == 16 ) ? 8 : nDepth;
913 switch ( nChannels )
915 case 4 :
916 case 3 :
917 nBitsPerPixel = 24;
918 [[fallthrough]];
919 case 2 :
920 case 1 :
921 aPixSize.setWidth( nColumns );
922 aPixSize.setHeight( nRows );
923 break;
924 default:
925 bRet = false;
928 else
929 bRet = false;
934 if ( bRet )
935 nFormat = GraphicFileFormat::PSD;
936 rStm.Seek( nStmPos );
937 return bRet;
940 bool GraphicDescriptor::ImpDetectEPS( SvStream& rStm, bool )
942 // check the EPS preview and the file extension
943 sal_uInt32 nFirstLong = 0;
944 sal_uInt8 nFirstBytes[20] = {};
945 bool bRet = false;
947 sal_Int32 nStmPos = rStm.Tell();
948 rStm.SetEndian( SvStreamEndian::BIG );
949 rStm.ReadUInt32( nFirstLong );
950 rStm.SeekRel( -4 );
951 rStm.ReadBytes( &nFirstBytes, 20 );
953 if ( ( nFirstLong == 0xC5D0D3C6 ) || aPathExt.startsWith( "eps" ) ||
954 ( ImplSearchEntry( nFirstBytes, reinterpret_cast<sal_uInt8 const *>("%!PS-Adobe"), 10, 10 )
955 && ImplSearchEntry( &nFirstBytes[15], reinterpret_cast<sal_uInt8 const *>("EPS"), 3, 3 ) ) )
957 nFormat = GraphicFileFormat::EPS;
958 bRet = true;
960 rStm.Seek( nStmPos );
961 return bRet;
964 bool GraphicDescriptor::ImpDetectDXF( SvStream&, bool )
966 bool bRet = aPathExt.startsWith( "dxf" );
967 if (bRet)
968 nFormat = GraphicFileFormat::DXF;
970 return bRet;
973 bool GraphicDescriptor::ImpDetectMET( SvStream&, bool )
975 bool bRet = aPathExt.startsWith( "met" );
976 if (bRet)
977 nFormat = GraphicFileFormat::MET;
979 return bRet;
982 bool GraphicDescriptor::ImpDetectPCT( SvStream& rStm, bool )
984 bool bRet = aPathExt.startsWith( "pct" );
985 if (bRet)
986 nFormat = GraphicFileFormat::PCT;
987 else
989 sal_uInt64 const nStreamPos = rStm.Tell();
990 sal_uInt64 const nStreamLen = rStm.remainingSize();
991 if (isPCT(rStm, nStreamPos, nStreamLen))
993 bRet = true;
994 nFormat = GraphicFileFormat::PCT;
996 rStm.Seek(nStreamPos);
999 return bRet;
1002 bool GraphicDescriptor::ImpDetectSVM( SvStream& rStm, bool bExtendedInfo )
1004 sal_uInt32 n32 = 0;
1005 bool bRet = false;
1007 sal_Int32 nStmPos = rStm.Tell();
1008 rStm.SetEndian( SvStreamEndian::LITTLE );
1009 rStm.ReadUInt32( n32 );
1010 if ( n32 == 0x44475653 )
1012 sal_uInt8 cByte = 0;
1013 rStm.ReadUChar( cByte );
1014 if ( cByte == 0x49 )
1016 nFormat = GraphicFileFormat::SVM;
1017 bRet = true;
1019 if ( bExtendedInfo )
1021 sal_uInt32 nTemp32;
1022 sal_uInt16 nTemp16;
1024 rStm.SeekRel( 0x04 );
1026 // width
1027 nTemp32 = 0;
1028 rStm.ReadUInt32( nTemp32 );
1029 aLogSize.setWidth( nTemp32 );
1031 // height
1032 nTemp32 = 0;
1033 rStm.ReadUInt32( nTemp32 );
1034 aLogSize.setHeight( nTemp32 );
1036 // read MapUnit and determine PrefSize
1037 nTemp16 = 0;
1038 rStm.ReadUInt16( nTemp16 );
1039 aLogSize = OutputDevice::LogicToLogic( aLogSize,
1040 MapMode( static_cast<MapUnit>(nTemp16) ),
1041 MapMode( MapUnit::Map100thMM ) );
1045 else
1047 rStm.SeekRel( -4 );
1048 n32 = 0;
1049 rStm.ReadUInt32( n32 );
1051 if( n32 == 0x4D4C4356 )
1053 sal_uInt16 nTmp16 = 0;
1055 rStm.ReadUInt16( nTmp16 );
1057 if( nTmp16 == 0x4654 )
1059 nFormat = GraphicFileFormat::SVM;
1060 bRet = true;
1062 if( bExtendedInfo )
1064 MapMode aMapMode;
1065 rStm.SeekRel( 0x06 );
1066 TypeSerializer aSerializer(rStm);
1067 aSerializer.readMapMode(aMapMode);
1068 aSerializer.readSize(aLogSize);
1069 aLogSize = OutputDevice::LogicToLogic( aLogSize, aMapMode, MapMode( MapUnit::Map100thMM ) );
1074 rStm.Seek( nStmPos );
1075 return bRet;
1078 bool GraphicDescriptor::ImpDetectWMF( SvStream&, bool )
1080 bool bRet = aPathExt.startsWith( "wmf" );
1081 if (bRet)
1082 nFormat = GraphicFileFormat::WMF;
1084 return bRet;
1087 bool GraphicDescriptor::ImpDetectEMF( SvStream& rStm, bool bExtendedInfo )
1089 sal_uInt32 nRecordType = 0;
1090 bool bRet = false;
1092 sal_Int32 nStmPos = rStm.Tell();
1093 rStm.SetEndian( SvStreamEndian::LITTLE );
1094 rStm.ReadUInt32( nRecordType );
1096 if ( nRecordType == 0x00000001 )
1098 sal_uInt32 nHeaderSize = 0;
1099 sal_Int32 nBoundLeft = 0, nBoundTop = 0, nBoundRight = 0, nBoundBottom = 0;
1100 sal_Int32 nFrameLeft = 0, nFrameTop = 0, nFrameRight = 0, nFrameBottom = 0;
1101 sal_uInt32 nSignature = 0;
1103 rStm.ReadUInt32( nHeaderSize );
1104 rStm.ReadInt32( nBoundLeft );
1105 rStm.ReadInt32( nBoundTop );
1106 rStm.ReadInt32( nBoundRight );
1107 rStm.ReadInt32( nBoundBottom );
1108 rStm.ReadInt32( nFrameLeft );
1109 rStm.ReadInt32( nFrameTop );
1110 rStm.ReadInt32( nFrameRight );
1111 rStm.ReadInt32( nFrameBottom );
1112 rStm.ReadUInt32( nSignature );
1114 if ( nSignature == 0x464d4520 )
1116 nFormat = GraphicFileFormat::EMF;
1117 bRet = true;
1119 if ( bExtendedInfo )
1121 // size in pixels
1122 aPixSize.setWidth( nBoundRight - nBoundLeft + 1 );
1123 aPixSize.setHeight( nBoundBottom - nBoundTop + 1 );
1125 // size in 0.01mm units
1126 aLogSize.setWidth( nFrameRight - nFrameLeft + 1 );
1127 aLogSize.setHeight( nFrameBottom - nFrameTop + 1 );
1132 rStm.Seek( nStmPos );
1133 return bRet;
1136 bool GraphicDescriptor::ImpDetectSVG( SvStream& /*rStm*/, bool /*bExtendedInfo*/ )
1138 bool bRet = aPathExt.startsWith( "svg" );
1139 if (bRet)
1140 nFormat = GraphicFileFormat::SVG;
1142 return bRet;
1145 OUString GraphicDescriptor::GetImportFormatShortName( GraphicFileFormat nFormat )
1147 const char *pKeyName = nullptr;
1149 switch( nFormat )
1151 case GraphicFileFormat::BMP : pKeyName = "bmp"; break;
1152 case GraphicFileFormat::GIF : pKeyName = "gif"; break;
1153 case GraphicFileFormat::JPG : pKeyName = "jpg"; break;
1154 case GraphicFileFormat::PCD : pKeyName = "pcd"; break;
1155 case GraphicFileFormat::PCX : pKeyName = "pcx"; break;
1156 case GraphicFileFormat::PNG : pKeyName = "png"; break;
1157 case GraphicFileFormat::XBM : pKeyName = "xbm"; break;
1158 case GraphicFileFormat::XPM : pKeyName = "xpm"; break;
1159 case GraphicFileFormat::PBM : pKeyName = "pbm"; break;
1160 case GraphicFileFormat::PGM : pKeyName = "pgm"; break;
1161 case GraphicFileFormat::PPM : pKeyName = "ppm"; break;
1162 case GraphicFileFormat::RAS : pKeyName = "ras"; break;
1163 case GraphicFileFormat::TGA : pKeyName = "tga"; break;
1164 case GraphicFileFormat::PSD : pKeyName = "psd"; break;
1165 case GraphicFileFormat::EPS : pKeyName = "eps"; break;
1166 case GraphicFileFormat::TIF : pKeyName = "tif"; break;
1167 case GraphicFileFormat::DXF : pKeyName = "dxf"; break;
1168 case GraphicFileFormat::MET : pKeyName = "met"; break;
1169 case GraphicFileFormat::PCT : pKeyName = "pct"; break;
1170 case GraphicFileFormat::SVM : pKeyName = "svm"; break;
1171 case GraphicFileFormat::WMF : pKeyName = "wmf"; break;
1172 case GraphicFileFormat::EMF : pKeyName = "emf"; break;
1173 case GraphicFileFormat::SVG : pKeyName = "svg"; break;
1174 default: assert(false);
1177 return OUString::createFromAscii(pKeyName);
1180 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */