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