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 <vcl/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  sal_uInt32 nXPelsPerMeter = 0;
160  if ( nTemp32 )
161  {
162  aLogSize.setWidth( ( aPixSize.Width() * 100000 ) / nTemp32 );
163  nXPelsPerMeter = nTemp32;
164  }
165 
166  // logical height
167  rStm.ReadUInt32( nTemp32 );
168  sal_uInt32 nYPelsPerMeter = 0;
169  if ( nTemp32 )
170  {
171  aLogSize.setHeight( ( aPixSize.Height() * 100000 ) / nTemp32 );
172  nYPelsPerMeter = nTemp32;
173  }
174 
175  // further validation, check for rational values
176  if ( ( nBitsPerPixel > 24 ) || ( nCompression > 3 ) )
177  {
179  bRet = false;
180  }
181 
182  if (bRet && nXPelsPerMeter && nYPelsPerMeter)
183  {
185  = MapMode(MapUnit::MapMM, Point(), Fraction(1000, nXPelsPerMeter),
186  Fraction(1000, nYPelsPerMeter));
187 
189  }
190  }
191  }
192  rStm.Seek( nStmPos );
193  return bRet;
194 }
195 
196 bool GraphicDescriptor::ImpDetectGIF( SvStream& rStm, bool bExtendedInfo )
197 {
198  sal_uInt32 n32 = 0;
199  bool bRet = false;
200 
201  sal_Int32 nStmPos = rStm.Tell();
202  rStm.SetEndian( SvStreamEndian::LITTLE );
203  rStm.ReadUInt32( n32 );
204 
205  if ( n32 == 0x38464947 )
206  {
207  sal_uInt16 n16 = 0;
208  rStm.ReadUInt16( n16 );
209  if ( ( n16 == 0x6137 ) || ( n16 == 0x6139 ) )
210  {
212  bRet = true;
213 
214  if ( bExtendedInfo )
215  {
216  sal_uInt16 nTemp16 = 0;
217  sal_uInt8 cByte = 0;
218 
219  // Pixel width
220  rStm.ReadUInt16( nTemp16 );
221  aPixSize.setWidth( nTemp16 );
222 
223  // Pixel height
224  rStm.ReadUInt16( nTemp16 );
225  aPixSize.setHeight( nTemp16 );
226 
227  // Bits/Pixel
228  rStm.ReadUChar( cByte );
229  nBitsPerPixel = ( ( cByte & 112 ) >> 4 ) + 1;
230  }
231  }
232  }
233  rStm.Seek( nStmPos );
234  return bRet;
235 }
236 
237 // returns the next jpeg marker, a return value of 0 represents an error
239 {
240  sal_uInt8 nByte;
241  do
242  {
243  do
244  {
245  rStm.ReadUChar( nByte );
246  if (!rStm.good()) // as 0 is not allowed as marker,
247  return 0; // we can use it as errorcode
248  }
249  while ( nByte != 0xff );
250  do
251  {
252  rStm.ReadUChar( nByte );
253  if (!rStm.good())
254  return 0;
255  }
256  while( nByte == 0xff );
257  }
258  while( nByte == 0 ); // 0xff00 represents 0xff and not a marker,
259  // the marker detection has to be restarted.
260  return nByte;
261 }
262 
263 bool GraphicDescriptor::ImpDetectJPG( SvStream& rStm, bool bExtendedInfo )
264 {
265  sal_uInt32 nTemp32 = 0;
266  bool bRet = false;
267 
268  sal_Int32 nStmPos = rStm.Tell();
269 
270  rStm.SetEndian( SvStreamEndian::BIG );
271  rStm.ReadUInt32( nTemp32 );
272 
273  // compare upper 24 bits
274  if( 0xffd8ff00 == ( nTemp32 & 0xffffff00 ) )
275  {
277  bRet = true;
278 
279  if ( bExtendedInfo )
280  {
281  rStm.SeekRel( -2 );
282 
283  ErrCode nError( rStm.GetError() );
284 
285  bool bScanFailure = false;
286  bool bScanFinished = false;
287  MapMode aMap;
288 
289  while (!bScanFailure && !bScanFinished && rStm.good())
290  {
291  sal_uInt8 nMarker = ImpDetectJPG_GetNextMarker( rStm );
292  switch( nMarker )
293  {
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;
305 
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;
310 
311  case 0xd9 : // EOI
312  bScanFinished = true;
313  break;
314 
315  // per default we assume marker segments containing a length parameter
316  default :
317  {
318  sal_uInt16 nLength = 0;
319  rStm.ReadUInt16( nLength );
320 
321  if ( nLength < 2 )
322  bScanFailure = true;
323  else
324  {
325  sal_uInt32 nNextMarkerPos = rStm.Tell() + nLength - 2;
326  switch( nMarker )
327  {
328  case 0xe0 : // APP0 Marker
329  {
330  if ( nLength == 16 )
331  {
332  sal_Int32 nIdentifier = 0;
333  rStm.ReadInt32( nIdentifier );
334  if ( nIdentifier == 0x4a464946 ) // JFIF Identifier
335  {
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;
344 
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 );
353 
354  // setting the logical size
355  if ( nUnits && nHorizontalResolution && nVerticalResolution )
356  {
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 ) );
361  }
362  }
363  }
364  }
365  break;
366 
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
381  {
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;
397 
398  // nSamplingFactor (lower nibble: vertical,
399  // upper nibble: horizontal) is unused
400 
401  aPixSize.setHeight( nNumberOfLines );
402  aPixSize.setWidth( nSamplesPerLine );
403  nBitsPerPixel = ( nNumberOfImageComponents == 3 ? 24 : nNumberOfImageComponents == 1 ? 8 : 0 );
404  nPlanes = 1;
405 
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.
411  aPixSize, aMap, MapMode(MapUnit::Map100thMM));
412 
413  bScanFinished = true;
414  }
415  break;
416  }
417  rStm.Seek( nNextMarkerPos );
418  }
419  }
420  break;
421  }
422  }
423  rStm.SetError( nError );
424  }
425  }
426  rStm.Seek( nStmPos );
427  return bRet;
428 }
429 
431 {
432  bool bRet = false;
433 
434  sal_Int32 nStmPos = rStm.Tell();
435  rStm.SetEndian( SvStreamEndian::LITTLE );
436 
437  sal_uInt32 nTemp32 = 0;
438  sal_uInt16 nTemp16 = 0;
439  sal_uInt8 cByte = 0;
440 
441  rStm.SeekRel( 2048 );
442  rStm.ReadUInt32( nTemp32 );
443  rStm.ReadUInt16( nTemp16 );
444  rStm.ReadUChar( cByte );
445 
446  if ( ( nTemp32 == 0x5f444350 ) &&
447  ( nTemp16 == 0x5049 ) &&
448  ( cByte == 0x49 ) )
449  {
451  bRet = true;
452  }
453  rStm.Seek( nStmPos );
454  return bRet;
455 }
456 
458 {
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.
463 
464  bool bRet = false;
465  sal_uInt8 cByte = 0;
466 
467  sal_Int32 nStmPos = rStm.Tell();
468  rStm.SetEndian( SvStreamEndian::LITTLE );
469  rStm.ReadUChar( cByte );
470 
471  if ( cByte == 0x0a )
472  {
474 
475  rStm.SeekRel( 1 );
476 
477  // compression
478  rStm.ReadUChar( cByte );
479 
480  bRet = (cByte==0 || cByte ==1);
481  if (bRet)
482  {
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;
490 
491  // Bits/Pixel
492  rStm.ReadUChar( cByte );
493  nBitsPerPixel = cByte;
494 
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;
504 
505  aPixSize.setWidth( nXmax - nXmin + 1 );
506  aPixSize.setHeight( nYmax - nYmin + 1 );
507 
508  // resolution
509  rStm.ReadUInt16( nTemp16 );
510  nDPIx = nTemp16;
511  rStm.ReadUInt16( nTemp16 );
512  nDPIy = nTemp16;
513 
514  // set logical size
515  MapMode aMap( MapUnit::MapInch, Point(),
516  Fraction( 1, nDPIx ), Fraction( 1, nDPIy ) );
518  MapMode( MapUnit::Map100thMM ) );
519 
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;
525 
526  bRet = (nPlanes<=4);
527  }
528  }
529 
530  rStm.Seek( nStmPos );
531  return bRet;
532 }
533 
534 bool GraphicDescriptor::ImpDetectPNG( SvStream& rStm, bool bExtendedInfo )
535 {
536  sal_uInt32 nTemp32 = 0;
537  bool bRet = false;
538 
539  sal_Int32 nStmPos = rStm.Tell();
540  rStm.SetEndian( SvStreamEndian::BIG );
541  rStm.ReadUInt32( nTemp32 );
542 
543  if ( nTemp32 == 0x89504e47 )
544  {
545  rStm.ReadUInt32( nTemp32 );
546  if ( nTemp32 == 0x0d0a1a0a )
547  {
549  bRet = true;
550 
551  if ( bExtendedInfo )
552  {
553  do {
554  sal_uInt8 cByte = 0;
555 
556  // IHDR-Chunk
557  rStm.SeekRel( 8 );
558 
559  // width
560  rStm.ReadUInt32( nTemp32 );
561  if (!rStm.good())
562  break;
563  aPixSize.setWidth( nTemp32 );
564 
565  // height
566  rStm.ReadUInt32( nTemp32 );
567  if (!rStm.good())
568  break;
569  aPixSize.setHeight( nTemp32 );
570 
571  // Bits/Pixel
572  rStm.ReadUChar( cByte );
573  if (!rStm.good())
574  break;
575  nBitsPerPixel = cByte;
576 
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 );
583 
584  // Planes always 1;
585  // compression always
586  nPlanes = 1;
587 
588  sal_uInt32 nLen32 = 0;
589  nTemp32 = 0;
590 
591  rStm.SeekRel( 7 );
592 
593  // read up to the start of the image
594  rStm.ReadUInt32( nLen32 );
595  rStm.ReadUInt32( nTemp32 );
596  while( ( nTemp32 != 0x49444154 ) && rStm.good() )
597  {
598  if ( nTemp32 == 0x70485973 ) // physical pixel dimensions
599  {
600  sal_uLong nXRes;
601  sal_uLong nYRes;
602 
603  // horizontal resolution
604  nTemp32 = 0;
605  rStm.ReadUInt32( nTemp32 );
606  nXRes = nTemp32;
607 
608  // vertical resolution
609  nTemp32 = 0;
610  rStm.ReadUInt32( nTemp32 );
611  nYRes = nTemp32;
612 
613  // unit
614  cByte = 0;
615  rStm.ReadUChar( cByte );
616 
617  if ( cByte )
618  {
619  if ( nXRes )
620  aLogSize.setWidth( (aPixSize.Width() * 100000) / nXRes );
621 
622  if ( nYRes )
623  aLogSize.setHeight( (aPixSize.Height() * 100000) / nYRes );
624  }
625 
626  nLen32 -= 9;
627  }
628  else if ( nTemp32 == 0x74524e53 ) // transparency
629  {
630  bIsTransparent = true;
631  bIsAlpha = ( cColType != 0 && cColType != 2 );
632  }
633 
634  // skip forward to next chunk
635  rStm.SeekRel( 4 + nLen32 );
636  rStm.ReadUInt32( nLen32 );
637  rStm.ReadUInt32( nTemp32 );
638  }
639  } while (false);
640  }
641  }
642  }
643  rStm.Seek( nStmPos );
644  return bRet;
645 }
646 
647 bool GraphicDescriptor::ImpDetectTIF( SvStream& rStm, bool bExtendedInfo )
648 {
649  bool bRet = false;
650  sal_uInt8 cByte1 = 0;
651  sal_uInt8 cByte2 = 1;
652 
653  sal_Int32 nStmPos = rStm.Tell();
654  rStm.ReadUChar( cByte1 );
655  rStm.ReadUChar( cByte2 );
656  if ( cByte1 == cByte2 )
657  {
658  bool bDetectOk = false;
659 
660  if ( cByte1 == 0x49 )
661  {
662  rStm.SetEndian( SvStreamEndian::LITTLE );
663  bDetectOk = true;
664  }
665  else if ( cByte1 == 0x4d )
666  {
667  rStm.SetEndian( SvStreamEndian::BIG );
668  bDetectOk = true;
669  }
670 
671  if ( bDetectOk )
672  {
673  sal_uInt16 nTemp16 = 0;
674 
675  rStm.ReadUInt16( nTemp16 );
676  if ( nTemp16 == 0x2a )
677  {
679  bRet = true;
680 
681  if ( bExtendedInfo )
682  {
684  sal_uLong nMax = DATA_SIZE - 48;
685  sal_uInt32 nTemp32 = 0;
686 
687  // Offset of the first IFD
688  rStm.ReadUInt32( nTemp32 );
689  nCount = nTemp32 + 2;
690  rStm.SeekRel( nCount - 0x08 );
691 
692  if ( nCount < nMax )
693  {
694  bool bOk = false;
695 
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 )
700  {
701  bOk = nCount < nMax;
702  if ( !bOk )
703  {
704  break;
705  }
706  rStm.SeekRel( 10 );
707  rStm.ReadUInt16( nTemp16 );
708  nCount += 12;
709  }
710 
711  if ( bOk )
712  {
713  // width
714  rStm.ReadUInt16( nTemp16 );
715  rStm.SeekRel( 4 );
716  if ( nTemp16 == 3 )
717  {
718  rStm.ReadUInt16( nTemp16 );
719  aPixSize.setWidth( nTemp16 );
720  rStm.SeekRel( 2 );
721  }
722  else
723  {
724  rStm.ReadUInt32( nTemp32 );
725  aPixSize.setWidth( nTemp32 );
726  }
727 
728  // height
729  rStm.SeekRel( 2 );
730  rStm.ReadUInt16( nTemp16 );
731  rStm.SeekRel( 4 );
732  if ( nTemp16 == 3 )
733  {
734  rStm.ReadUInt16( nTemp16 );
735  aPixSize.setHeight( nTemp16 );
736  rStm.SeekRel( 2 );
737  }
738  else
739  {
740  rStm.ReadUInt32( nTemp32 );
741  aPixSize.setHeight( nTemp32 );
742  }
743 
744  // Bits/Pixel
745  rStm.ReadUInt16( nTemp16 );
746  if ( nTemp16 == 258 )
747  {
748  rStm.SeekRel( 6 );
749  rStm.ReadUInt16( nTemp16 );
750  nBitsPerPixel = nTemp16;
751  rStm.SeekRel( 2 );
752  }
753  else
754  rStm.SeekRel( -2 );
755 
756  // compression
757  rStm.ReadUInt16( nTemp16 );
758  if ( nTemp16 == 259 )
759  {
760  rStm.SeekRel( 6 );
761  rStm.ReadUInt16( nTemp16 ); // compression
762  rStm.SeekRel( 2 );
763  }
764  else
765  rStm.SeekRel( -2 );
766  }
767  }
768  }
769  }
770  }
771  }
772  rStm.Seek( nStmPos );
773  return bRet;
774 }
775 
777 {
778  bool bRet = aPathExt.startsWith( "xbm" );
779  if (bRet)
781 
782  return bRet;
783 }
784 
786 {
787  bool bRet = aPathExt.startsWith( "xpm" );
788  if (bRet)
790 
791  return bRet;
792 }
793 
795 {
796  bool bRet = false;
797 
798  // check file extension first, as this trumps the 2 ID bytes
799  if ( aPathExt.startsWith( "pbm" ) )
800  bRet = true;
801  else
802  {
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 );
809  }
810 
811  if ( bRet )
813 
814  return bRet;
815 }
816 
818 {
819  bool bRet = false;
820 
821  if ( aPathExt.startsWith( "pgm" ) )
822  bRet = true;
823  else
824  {
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 );
831  }
832 
833  if ( bRet )
835 
836  return bRet;
837 }
838 
840 {
841  bool bRet = false;
842 
843  if ( aPathExt.startsWith( "ppm" ) )
844  bRet = true;
845  else
846  {
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 );
853  }
854 
855  if ( bRet )
857 
858  return bRet;
859 }
860 
862 {
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 )
869  {
871  bRet = true;
872  }
873  rStm.Seek( nStmPos );
874  return bRet;
875 }
876 
878 {
879  bool bRet = aPathExt.startsWith( "tga" );
880  if (bRet)
882 
883  return bRet;
884 }
885 
886 bool GraphicDescriptor::ImpDetectPSD( SvStream& rStm, bool bExtendedInfo )
887 {
888  bool bRet = false;
889 
890  sal_uInt32 nMagicNumber = 0;
891  sal_Int32 nStmPos = rStm.Tell();
892  rStm.SetEndian( SvStreamEndian::BIG );
893  rStm.ReadUInt32( nMagicNumber );
894  if ( nMagicNumber == 0x38425053 )
895  {
896  sal_uInt16 nVersion = 0;
897  rStm.ReadUInt16( nVersion );
898  if ( nVersion == 1 )
899  {
900  bRet = true;
901  if ( bExtendedInfo )
902  {
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 ) )
911  {
912  nBitsPerPixel = ( nDepth == 16 ) ? 8 : nDepth;
913  switch ( nChannels )
914  {
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;
926  }
927  }
928  else
929  bRet = false;
930  }
931  }
932  }
933 
934  if ( bRet )
936  rStm.Seek( nStmPos );
937  return bRet;
938 }
939 
941 {
942  // check the EPS preview and the file extension
943  sal_uInt32 nFirstLong = 0;
944  sal_uInt8 nFirstBytes[20] = {};
945  bool bRet = false;
946 
947  sal_Int32 nStmPos = rStm.Tell();
948  rStm.SetEndian( SvStreamEndian::BIG );
949  rStm.ReadUInt32( nFirstLong );
950  rStm.SeekRel( -4 );
951  rStm.ReadBytes( &nFirstBytes, 20 );
952 
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 ) ) )
956  {
958  bRet = true;
959  }
960  rStm.Seek( nStmPos );
961  return bRet;
962 }
963 
965 {
966  bool bRet = aPathExt.startsWith( "dxf" );
967  if (bRet)
969 
970  return bRet;
971 }
972 
974 {
975  bool bRet = aPathExt.startsWith( "met" );
976  if (bRet)
978 
979  return bRet;
980 }
981 
983 {
984  bool bRet = aPathExt.startsWith( "pct" );
985  if (bRet)
987  else
988  {
989  sal_uInt64 const nStreamPos = rStm.Tell();
990  sal_uInt64 const nStreamLen = rStm.remainingSize();
991  if (isPCT(rStm, nStreamPos, nStreamLen))
992  {
993  bRet = true;
995  }
996  rStm.Seek(nStreamPos);
997  }
998 
999  return bRet;
1000 }
1001 
1002 bool GraphicDescriptor::ImpDetectSVM( SvStream& rStm, bool bExtendedInfo )
1003 {
1004  sal_uInt32 n32 = 0;
1005  bool bRet = false;
1006 
1007  sal_Int32 nStmPos = rStm.Tell();
1008  rStm.SetEndian( SvStreamEndian::LITTLE );
1009  rStm.ReadUInt32( n32 );
1010  if ( n32 == 0x44475653 )
1011  {
1012  sal_uInt8 cByte = 0;
1013  rStm.ReadUChar( cByte );
1014  if ( cByte == 0x49 )
1015  {
1017  bRet = true;
1018 
1019  if ( bExtendedInfo )
1020  {
1021  sal_uInt32 nTemp32;
1022  sal_uInt16 nTemp16;
1023 
1024  rStm.SeekRel( 0x04 );
1025 
1026  // width
1027  nTemp32 = 0;
1028  rStm.ReadUInt32( nTemp32 );
1029  aLogSize.setWidth( nTemp32 );
1030 
1031  // height
1032  nTemp32 = 0;
1033  rStm.ReadUInt32( nTemp32 );
1034  aLogSize.setHeight( nTemp32 );
1035 
1036  // read MapUnit and determine PrefSize
1037  nTemp16 = 0;
1038  rStm.ReadUInt16( nTemp16 );
1040  MapMode( static_cast<MapUnit>(nTemp16) ),
1041  MapMode( MapUnit::Map100thMM ) );
1042  }
1043  }
1044  }
1045  else
1046  {
1047  rStm.SeekRel( -4 );
1048  n32 = 0;
1049  rStm.ReadUInt32( n32 );
1050 
1051  if( n32 == 0x4D4C4356 )
1052  {
1053  sal_uInt16 nTmp16 = 0;
1054 
1055  rStm.ReadUInt16( nTmp16 );
1056 
1057  if( nTmp16 == 0x4654 )
1058  {
1060  bRet = true;
1061 
1062  if( bExtendedInfo )
1063  {
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 ) );
1070  }
1071  }
1072  }
1073  }
1074  rStm.Seek( nStmPos );
1075  return bRet;
1076 }
1077 
1079 {
1080  bool bRet = aPathExt.startsWith( "wmf" );
1081  if (bRet)
1083 
1084  return bRet;
1085 }
1086 
1087 bool GraphicDescriptor::ImpDetectEMF( SvStream& rStm, bool bExtendedInfo )
1088 {
1089  sal_uInt32 nRecordType = 0;
1090  bool bRet = false;
1091 
1092  sal_Int32 nStmPos = rStm.Tell();
1093  rStm.SetEndian( SvStreamEndian::LITTLE );
1094  rStm.ReadUInt32( nRecordType );
1095 
1096  if ( nRecordType == 0x00000001 )
1097  {
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;
1102 
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 );
1113 
1114  if ( nSignature == 0x464d4520 )
1115  {
1117  bRet = true;
1118 
1119  if ( bExtendedInfo )
1120  {
1121  // size in pixels
1122  aPixSize.setWidth( nBoundRight - nBoundLeft + 1 );
1123  aPixSize.setHeight( nBoundBottom - nBoundTop + 1 );
1124 
1125  // size in 0.01mm units
1126  aLogSize.setWidth( nFrameRight - nFrameLeft + 1 );
1127  aLogSize.setHeight( nFrameBottom - nFrameTop + 1 );
1128  }
1129  }
1130  }
1131 
1132  rStm.Seek( nStmPos );
1133  return bRet;
1134 }
1135 
1136 bool GraphicDescriptor::ImpDetectSVG( SvStream& /*rStm*/, bool /*bExtendedInfo*/ )
1137 {
1138  bool bRet = aPathExt.startsWith( "svg" );
1139  if (bRet)
1141 
1142  return bRet;
1143 }
1144 
1146 {
1147  const char *pKeyName = nullptr;
1148 
1149  switch( nFormat )
1150  {
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);
1175  }
1176 
1177  return OUString::createFromAscii(pKeyName);
1178 }
1179 
1180 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
GraphicDescriptor(const GraphicDescriptor &)=delete
URL aURL
bool ImpDetectPCX(SvStream &rStm)
void setWidth(tools::Long nWidth)
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1466
void readMapMode(MapMode &rMapMode)
tools::Long getWidth() 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
std::optional< Size > maPreferredLogSize
bool ImpDetectPCD(SvStream &rStm, bool bExtendedInfo)
ErrCode GetError() const
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
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)
tools::Long getHeight() const
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
tools::Long Width() const
void SetScaleY(const Fraction &rScaleY)
Definition: mapmod.cxx:115
void SetError(ErrCode nErrorCode)
SvStream & ReadUChar(unsigned char &rChar)
MapUnit GetMapUnit() const
Definition: mapmod.cxx:136
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
tools::Long Height() const
sal_uInt64 Tell() const
bool ImpDetectXPM(SvStream &rStm, bool bExtendedInfo)
bool good() const
bool ImpDetectTIF(SvStream &rStm, bool bExtendedInfo)
void setHeight(tools::Long nHeight)
SvStreamEndian
bool ImpDetectSVG(SvStream &rStm, bool bExtendedInfo)
bool ImpDetectPNG(SvStream &rStm, bool bExtendedInfo)
std::optional< MapMode > maPreferredMapMode
sal_Int32 nLength
bool Detect(bool bExtendedInfo=false)
starts the detection
sal_uInt16 nBitsPerPixel
READ