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 <TypeSerializer.hxx>
25 #include <vcl/outdev.hxx>
26 #include <vcl/graphicfilter.hxx>
29 
30 #define DATA_SIZE 640
31 
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 
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 
97 {
99  nBitsPerPixel = 0;
100  nPlanes = 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  {
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  {
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  {
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
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  {
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.
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 
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  {
434  bRet = true;
435  }
436  rStm.Seek( nStmPos );
437  return bRet;
438 }
439 
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  {
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 ) );
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  {
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  {
662  bRet = true;
663 
664  if ( bExtendedInfo )
665  {
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 
760 {
761  bool bRet = aPathExt.startsWith( "xbm" );
762  if (bRet)
764 
765  return bRet;
766 }
767 
769 {
770  bool bRet = aPathExt.startsWith( "xpm" );
771  if (bRet)
773 
774  return bRet;
775 }
776 
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 )
796 
797  return bRet;
798 }
799 
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 )
818 
819  return bRet;
820 }
821 
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 )
840 
841  return bRet;
842 }
843 
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  {
854  bRet = true;
855  }
856  rStm.Seek( nStmPos );
857  return bRet;
858 }
859 
861 {
862  bool bRet = aPathExt.startsWith( "tga" );
863  if (bRet)
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 )
919  rStm.Seek( nStmPos );
920  return bRet;
921 }
922 
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  {
941  bRet = true;
942  }
943  rStm.Seek( nStmPos );
944  return bRet;
945 }
946 
948 {
949  bool bRet = aPathExt.startsWith( "dxf" );
950  if (bRet)
952 
953  return bRet;
954 }
955 
957 {
958  bool bRet = aPathExt.startsWith( "met" );
959  if (bRet)
961 
962  return bRet;
963 }
964 
966 {
967  bool bRet = aPathExt.startsWith( "pct" );
968  if (bRet)
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;
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  {
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 );
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  {
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 
1064 {
1065  bool bRet = aPathExt.startsWith( "wmf" );
1066  if (bRet)
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  {
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)
1126 
1127  return bRet;
1128 }
1129 
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: */
long Width() const
GraphicDescriptor(const GraphicDescriptor &)=delete
URL aURL
bool ImpDetectPCX(SvStream &rStm)
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1668
long Height() const
sal_uIntPtr sal_uLong
bool ImpDetectEMF(SvStream &rStm, bool bExtendedInfo)
bool ImpDetectBMP(SvStream &rStm, bool bExtendedInfo)
bool isPCT(SvStream &rStream, sal_uLong nStreamPos, sal_uLong nStreamLen)
sal_uInt64 Seek(sal_uInt64 nPos)
bool ImpDetectMET(SvStream &rStm, bool bExtendedInfo)
bool ImpDetectPSD(SvStream &rStm, bool bExtendedInfo)
bool ImpDetectGIF(SvStream &rStm, bool bExtendedInfo)
sal_uInt64 SeekRel(sal_Int64 nPos)
bool ImpDetectPBM(SvStream &rStm, bool bExtendedInfo)
bool ImpDetectPGM(SvStream &rStm, bool bExtendedInfo)
NONE
static sal_uInt8 ImpDetectJPG_GetNextMarker(SvStream &rStm)
HashMap_OWString_Interface aMap
bool ImpDetectPCD(SvStream &rStm, bool bExtendedInfo)
ErrCode GetError() const
sal_uInt8 mnNumberOfImageComponents
sal_uInt8 * ImplSearchEntry(sal_uInt8 *pSource, sal_uInt8 const *pDest, sal_uLong nComp, sal_uLong nSize)
int nCount
bool ImpDetectTGA(SvStream &rStm, bool bExtendedInfo)
bool ImpDetectPPM(SvStream &rStm, bool bExtendedInfo)
sal_uInt64 remainingSize()
void readSize(Size &rSize)
bool ImpDetectEPS(SvStream &rStm, bool bExtendedInfo)
void SetMapUnit(MapUnit eUnit)
Definition: mapmod.cxx:97
SvStream & ReadUInt32(sal_uInt32 &rUInt32)
bool ImpDetectDXF(SvStream &rStm, bool bExtendedInfo)
static OUString GetImportFormatShortName(GraphicFileFormat nFormat)
void SetScaleX(const Fraction &rScaleX)
Definition: mapmod.cxx:108
bool ImpDetectPCT(SvStream &rStm, bool bExtendedInfo)
bool ImpDetectXBM(SvStream &rStm, bool bExtendedInfo)
StreamMode
#define DATA_SIZE
void SetScaleY(const Fraction &rScaleY)
Definition: mapmod.cxx:115
void SetError(ErrCode nErrorCode)
SvStream & ReadUChar(unsigned char &rChar)
MapUnit GetMapUnit() const
Definition: mapmod.cxx:168
sal_Int16 nVersion
bool ImpDetectWMF(SvStream &rStm, bool bExtendedInfo)
GraphicFileFormat
SvStream & ReadInt32(sal_Int32 &rInt32)
uno::Reference< io::XStream > CreateStream(uno::Reference< embed::XStorage > const &xStorage, OUString const &rFilename)
std::size_t ReadBytes(void *pData, std::size_t nSize)
SvStreamEndian GetEndian() const
bool ImpDetectSVM(SvStream &rStm, bool bExtendedInfo)
unsigned char sal_uInt8
GraphicFileFormat nFormat
bool ImpDetectJPG(SvStream &rStm, bool bExtendedInfo)
bool ImpDetectRAS(SvStream &rStm, bool bExtendedInfo)
void SetEndian(SvStreamEndian SvStreamEndian)
OUString GetFileExtension() const
sal_uInt64 Tell() const
bool ImpDetectXPM(SvStream &rStm, bool bExtendedInfo)
bool good() const
bool ImpDetectTIF(SvStream &rStm, bool bExtendedInfo)
SvStreamEndian
SvStream & ReadMapMode(SvStream &rIStm, MapMode &rMapMode)
Definition: mapmod.cxx:136
bool ImpDetectSVG(SvStream &rStm, bool bExtendedInfo)
bool ImpDetectPNG(SvStream &rStm, bool bExtendedInfo)
sal_Int32 const nLength
bool Detect(bool bExtendedInfo=false)
starts the detection
sal_uInt16 nBitsPerPixel
void setWidth(long nWidth)
READ
void setHeight(long nHeight)