xref: /core/vcl/source/filter/graphicfilter2.cxx (revision 267083e9e7768adcd5316851ce51e1cc22d4627e)
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>
25 #include <vcl/outdev.hxx>
26 #include <vcl/graphicfilter.hxx>
27 #include <unotools/ucbstreamhelper.hxx>
28 #include <graphic/GraphicFormatDetector.hxx>
29 
GraphicDescriptor(const INetURLObject & rPath)30 GraphicDescriptor::GraphicDescriptor( const INetURLObject& rPath ) :
31     pFileStm( ::utl::UcbStreamHelper::CreateStream( rPath.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ ).release() ),
32     aPathExt( rPath.GetFileExtension().toAsciiLowerCase() ),
33     bOwnStream( true )
34 {
35 }
36 
GraphicDescriptor(SvStream & rInStream,const OUString * pPath)37 GraphicDescriptor::GraphicDescriptor( SvStream& rInStream, const OUString* pPath) :
38     pFileStm    ( &rInStream ),
39     bOwnStream  ( false )
40 {
41     if ( pPath )
42     {
43         INetURLObject aURL( *pPath );
44         aPathExt = aURL.GetFileExtension().toAsciiLowerCase();
45     }
46 }
47 
~GraphicDescriptor()48 GraphicDescriptor::~GraphicDescriptor()
49 {
50     if ( bOwnStream )
51         delete pFileStm;
52 }
53 
Detect(bool bExtendedInfo)54 bool GraphicDescriptor::Detect( bool bExtendedInfo )
55 {
56     bool bRet = false;
57     if ( pFileStm && !pFileStm->GetError() )
58     {
59         SvStream&      rStm = *pFileStm;
60         SvStreamEndian nOldFormat = rStm.GetEndian();
61 
62         if      ( ImpDetectGIF( rStm, bExtendedInfo ) ) bRet = true;
63         else if ( ImpDetectJPG( rStm, bExtendedInfo ) ) bRet = true;
64         else if ( ImpDetectBMP( rStm, bExtendedInfo ) ) bRet = true;
65         else if ( ImpDetectPNG( rStm, bExtendedInfo ) ) bRet = true;
66         else if ( ImpDetectTIF( rStm, bExtendedInfo ) ) bRet = true;
67         else if ( ImpDetectPCX( rStm ) ) bRet = true;
68         else if ( ImpDetectDXF( rStm, bExtendedInfo ) ) bRet = true;
69         else if ( ImpDetectMET( rStm, bExtendedInfo ) ) bRet = true;
70         else if ( ImpDetectSVM( rStm, bExtendedInfo ) ) bRet = true;
71         else if ( ImpDetectWMF( rStm, bExtendedInfo ) ) bRet = true;
72         else if ( ImpDetectEMF( rStm, bExtendedInfo ) ) bRet = true;
73         else if ( ImpDetectSVG( rStm, bExtendedInfo ) ) bRet = true;
74         else if ( ImpDetectPCT( rStm, bExtendedInfo ) ) bRet = true;
75         else if ( ImpDetectXBM( rStm, bExtendedInfo ) ) bRet = true;
76         else if ( ImpDetectXPM( rStm, bExtendedInfo ) ) bRet = true;
77         else if ( ImpDetectPBM( rStm, bExtendedInfo ) ) bRet = true;
78         else if ( ImpDetectPGM( rStm, bExtendedInfo ) ) bRet = true;
79         else if ( ImpDetectPPM( rStm, bExtendedInfo ) ) bRet = true;
80         else if ( ImpDetectRAS( rStm, bExtendedInfo ) ) bRet = true;
81         else if ( ImpDetectTGA( rStm, bExtendedInfo ) ) bRet = true;
82         else if ( ImpDetectPSD( rStm, bExtendedInfo ) ) bRet = true;
83         else if ( ImpDetectEPS( rStm, bExtendedInfo ) ) bRet = true;
84         else if ( ImpDetectPCD( rStm, bExtendedInfo ) ) bRet = true;
85         else if ( ImpDetectWEBP( rStm, bExtendedInfo ) ) bRet = true;
86 
87         rStm.SetEndian( nOldFormat );
88     }
89     return bRet;
90 }
91 
ImpDetectBMP(SvStream & rStm,bool bExtendedInfo)92 bool GraphicDescriptor::ImpDetectBMP( SvStream& rStm, bool bExtendedInfo )
93 {
94     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, bExtendedInfo );
95     bool bRet = aDetector.detect() && aDetector.checkBMP();
96     if ( bRet )
97         aMetadata = aDetector.getMetadata();
98     return bRet;
99 }
100 
ImpDetectGIF(SvStream & rStm,bool bExtendedInfo)101 bool GraphicDescriptor::ImpDetectGIF( SvStream& rStm, bool bExtendedInfo )
102 {
103     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, bExtendedInfo );
104     bool bRet = aDetector.detect() && aDetector.checkGIF();
105     if ( bRet )
106         aMetadata = aDetector.getMetadata();
107     return bRet;
108 }
109 
110 // returns the next jpeg marker, a return value of 0 represents an error
ImpDetectJPG_GetNextMarker(SvStream & rStm)111 static sal_uInt8 ImpDetectJPG_GetNextMarker( SvStream& rStm )
112 {
113     sal_uInt8 nByte;
114     do
115     {
116         do
117         {
118             rStm.ReadUChar( nByte );
119             if (!rStm.good())   // as 0 is not allowed as marker,
120                 return 0;       // we can use it as errorcode
121         }
122         while ( nByte != 0xff );
123         do
124         {
125             rStm.ReadUChar( nByte );
126             if (!rStm.good())
127                 return 0;
128         }
129         while( nByte == 0xff );
130     }
131     while( nByte == 0 );        // 0xff00 represents 0xff and not a marker,
132                                 // the marker detection has to be restarted.
133     return nByte;
134 }
135 
ImpDetectJPG(SvStream & rStm,bool bExtendedInfo)136 bool GraphicDescriptor::ImpDetectJPG( SvStream& rStm,  bool bExtendedInfo )
137 {
138     sal_uInt32  nTemp32 = 0;
139     bool    bRet = false;
140 
141     sal_uInt64 nStmPos = rStm.Tell();
142 
143     rStm.SetEndian( SvStreamEndian::BIG );
144     rStm.ReadUInt32( nTemp32 );
145 
146     // compare upper 24 bits
147     if( 0xffd8ff00 == ( nTemp32 & 0xffffff00 ) )
148     {
149         aMetadata.mnFormat = GraphicFileFormat::JPG;
150         bRet = true;
151 
152         if ( bExtendedInfo )
153         {
154             rStm.SeekRel( -2 );
155 
156             ErrCode nError( rStm.GetError() );
157 
158             bool bScanFailure = false;
159             bool bScanFinished = false;
160             MapMode aMap;
161 
162             while (!bScanFailure && !bScanFinished && rStm.good())
163             {
164                 sal_uInt8 nMarker = ImpDetectJPG_GetNextMarker( rStm );
165                 switch( nMarker )
166                 {
167                     // fixed size marker, not having a two byte length parameter
168                     case 0xd0 :     // RST0
169                     case 0xd1 :
170                     case 0xd2 :
171                     case 0xd3 :
172                     case 0xd4 :
173                     case 0xd5 :
174                     case 0xd6 :
175                     case 0xd7 :     // RST7
176                     case 0x01 :     // TEM
177                     break;
178 
179                     case 0xd8 :     // SOI (has already been checked, there should not be a second one)
180                     case 0x00 :     // marker is invalid, we should stop now
181                         bScanFailure = true;
182                     break;
183 
184                     case 0xd9 :     // EOI
185                         bScanFinished = true;
186                     break;
187 
188                     // per default we assume marker segments containing a length parameter
189                     default :
190                     {
191                         sal_uInt16 nLength = 0;
192                         rStm.ReadUInt16( nLength );
193 
194                         if ( nLength < 2 )
195                             bScanFailure = true;
196                         else
197                         {
198                             sal_uInt64 nNextMarkerPos = rStm.Tell() + nLength - 2;
199                             switch( nMarker )
200                             {
201                                 case 0xe0 : // APP0 Marker
202                                 {
203                                     if ( nLength == 16 )
204                                     {
205                                         sal_Int32 nIdentifier = 0;
206                                         rStm.ReadInt32( nIdentifier );
207                                         if ( nIdentifier == 0x4a464946 )    // JFIF Identifier
208                                         {
209                                             sal_uInt8   nStringTerminator = 0;
210                                             sal_uInt8   nMajorRevision = 0;
211                                             sal_uInt8   nMinorRevision = 0;
212                                             sal_uInt8   nUnits = 0;
213                                             sal_uInt16  nHorizontalResolution = 0;
214                                             sal_uInt16  nVerticalResolution = 0;
215                                             sal_uInt8   nHorzThumbnailPixelCount = 0;
216                                             sal_uInt8   nVertThumbnailPixelCount = 0;
217 
218                                             rStm.ReadUChar( nStringTerminator )
219                                                 .ReadUChar( nMajorRevision )
220                                                 .ReadUChar( nMinorRevision )
221                                                 .ReadUChar( nUnits )
222                                                 .ReadUInt16( nHorizontalResolution )
223                                                 .ReadUInt16( nVerticalResolution )
224                                                 .ReadUChar( nHorzThumbnailPixelCount )
225                                                 .ReadUChar( nVertThumbnailPixelCount );
226 
227                                             // setting the logical size
228                                             if ( nUnits && nHorizontalResolution && nVerticalResolution )
229                                             {
230                                                 aMap.SetMapUnit( nUnits == 1 ? MapUnit::MapInch : MapUnit::MapCM );
231                                                 aMap.SetScaleX( Fraction( 1, nHorizontalResolution ) );
232                                                 aMap.SetScaleY( Fraction( 1, nVerticalResolution ) );
233                                                 aMetadata.maLogSize = OutputDevice::LogicToLogic( aMetadata.maPixSize, aMap, MapMode( MapUnit::Map100thMM ) );
234                                             }
235                                         }
236                                     }
237                                 }
238                                 break;
239 
240                                 // Start of Frame Markers
241                                 case 0xc0 : // SOF0
242                                 case 0xc1 : // SOF1
243                                 case 0xc2 : // SOF2
244                                 case 0xc3 : // SOF3
245                                 case 0xc5 : // SOF5
246                                 case 0xc6 : // SOF6
247                                 case 0xc7 : // SOF7
248                                 case 0xc9 : // SOF9
249                                 case 0xca : // SOF10
250                                 case 0xcb : // SOF11
251                                 case 0xcd : // SOF13
252                                 case 0xce : // SOF14
253                                 case 0xcf : // SOF15
254                                 {
255                                     sal_uInt8   nSamplePrecision = 0;
256                                     sal_uInt16  nNumberOfLines = 0;
257                                     sal_uInt16  nSamplesPerLine = 0;
258                                     sal_uInt8   nNumberOfImageComponents = 0;
259                                     sal_uInt8   nComponentsIdentifier = 0;
260                                     sal_uInt8   nSamplingFactor = 0;
261                                     sal_uInt8   nQuantizationTableDestinationSelector = 0;
262                                     rStm.ReadUChar( nSamplePrecision )
263                                         .ReadUInt16( nNumberOfLines )
264                                         .ReadUInt16( nSamplesPerLine )
265                                         .ReadUChar( nNumberOfImageComponents )
266                                         .ReadUChar( nComponentsIdentifier )
267                                         .ReadUChar( nSamplingFactor )
268                                         .ReadUChar( nQuantizationTableDestinationSelector );
269                                     aMetadata.mnNumberOfImageComponents = nNumberOfImageComponents;
270 
271                                     // nSamplingFactor (lower nibble: vertical,
272                                     // upper nibble: horizontal) is unused
273 
274                                     aMetadata.maPixSize.setHeight( nNumberOfLines );
275                                     aMetadata.maPixSize.setWidth( nSamplesPerLine );
276                                     aMetadata.mnBitsPerPixel = ( nNumberOfImageComponents == 3 ? 24 : nNumberOfImageComponents == 1 ? 8 : 0 );
277                                     aMetadata.mnPlanes = 1;
278 
279                                     if (aMap.GetMapUnit() != MapUnit::MapPixel)
280                                         // We already know the DPI, but the
281                                         // pixel size arrived later, so do the
282                                         // conversion again.
283                                         aMetadata.maLogSize = OutputDevice::LogicToLogic(
284                                             aMetadata.maPixSize, aMap, MapMode(MapUnit::Map100thMM));
285 
286                                     bScanFinished = true;
287                                 }
288                                 break;
289                             }
290                             rStm.Seek( nNextMarkerPos );
291                         }
292                     }
293                     break;
294                 }
295             }
296             rStm.SetError( nError );
297         }
298     }
299     rStm.Seek( nStmPos );
300     return bRet;
301 }
302 
ImpDetectPCD(SvStream & rStm,bool)303 bool GraphicDescriptor::ImpDetectPCD( SvStream& rStm, bool )
304 {
305     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, false /*bExtendedInfo*/ );
306     bool bRet = aDetector.detect() && aDetector.checkPCD();
307     if ( bRet )
308         aMetadata = aDetector.getMetadata();
309     return bRet;
310 }
311 
ImpDetectPCX(SvStream & rStm)312 bool GraphicDescriptor::ImpDetectPCX( SvStream& rStm )
313 {
314     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, true /*bExtendedInfo*/ );
315     bool bRet = aDetector.detect() && aDetector.checkPCX();
316     if ( bRet )
317         aMetadata = aDetector.getMetadata();
318     return bRet;
319 }
320 
ImpDetectPNG(SvStream & rStm,bool bExtendedInfo)321 bool GraphicDescriptor::ImpDetectPNG( SvStream& rStm, bool bExtendedInfo )
322 {
323     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, bExtendedInfo );
324     bool bRet = aDetector.detect() && aDetector.checkPNG();
325     if ( bRet )
326         aMetadata = aDetector.getMetadata();
327     return bRet;
328 }
329 
ImpDetectTIF(SvStream & rStm,bool bExtendedInfo)330 bool GraphicDescriptor::ImpDetectTIF( SvStream& rStm, bool bExtendedInfo )
331 {
332     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, bExtendedInfo );
333     bool bRet = aDetector.detect() && aDetector.checkTIF();
334     if ( bRet )
335         aMetadata = aDetector.getMetadata();
336     return bRet;
337 }
338 
ImpDetectXBM(SvStream & rStm,bool)339 bool GraphicDescriptor::ImpDetectXBM( SvStream& rStm, bool )
340 {
341     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, false /* bExtendedInfo */ );
342     bool bRet = aDetector.detect() && aDetector.checkXBM();
343     if ( bRet )
344         aMetadata = aDetector.getMetadata();
345     return bRet;
346 }
347 
ImpDetectXPM(SvStream & rStm,bool)348 bool GraphicDescriptor::ImpDetectXPM( SvStream& rStm, bool )
349 {
350     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, false /* bExtendedInfo */ );
351     bool bRet = aDetector.detect() && aDetector.checkXPM();
352     if ( bRet )
353         aMetadata = aDetector.getMetadata();
354     return bRet;
355 }
356 
ImpDetectPBM(SvStream & rStm,bool)357 bool GraphicDescriptor::ImpDetectPBM( SvStream& rStm, bool )
358 {
359     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, false /* bExtendedInfo */ );
360     bool bRet = aDetector.detect() && aDetector.checkPBM();
361     if ( bRet )
362         aMetadata = aDetector.getMetadata();
363     return bRet;
364 }
365 
ImpDetectPGM(SvStream & rStm,bool)366 bool GraphicDescriptor::ImpDetectPGM( SvStream& rStm, bool )
367 {
368     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, false /* bExtendedInfo */ );
369     bool bRet = aDetector.detect() && aDetector.checkPGM();
370     if ( bRet )
371         aMetadata = aDetector.getMetadata();
372     return bRet;
373 }
374 
ImpDetectPPM(SvStream & rStm,bool)375 bool GraphicDescriptor::ImpDetectPPM( SvStream& rStm, bool )
376 {
377     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, false /* bExtendedInfo */ );
378     bool bRet = aDetector.detect() && aDetector.checkPPM();
379     if ( bRet )
380         aMetadata = aDetector.getMetadata();
381     return bRet;
382 }
383 
ImpDetectRAS(SvStream & rStm,bool)384 bool GraphicDescriptor::ImpDetectRAS( SvStream& rStm, bool )
385 {
386     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, false /* bExtendedInfo */ );
387     bool bRet = aDetector.detect() && aDetector.checkRAS();
388     if ( bRet )
389         aMetadata = aDetector.getMetadata();
390     return bRet;
391 }
392 
ImpDetectTGA(SvStream & rStm,bool)393 bool GraphicDescriptor::ImpDetectTGA( SvStream& rStm, bool )
394 {
395     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, false /* bExtendedInfo */ );
396     bool bRet = aDetector.detect() && aDetector.checkTGA();
397     if ( bRet )
398         aMetadata = aDetector.getMetadata();
399     return bRet;
400 }
401 
ImpDetectPSD(SvStream & rStm,bool bExtendedInfo)402 bool GraphicDescriptor::ImpDetectPSD( SvStream& rStm, bool bExtendedInfo )
403 {
404     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, bExtendedInfo );
405     bool bRet = aDetector.detect() && aDetector.checkPSD();
406     if ( bRet )
407         aMetadata = aDetector.getMetadata();
408     return bRet;
409 }
410 
ImpDetectEPS(SvStream & rStm,bool)411 bool GraphicDescriptor::ImpDetectEPS( SvStream& rStm, bool )
412 {
413     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, false /*bExtendedInfo*/ );
414     bool bRet = aDetector.detect() && aDetector.checkEPS();
415     if ( bRet )
416         aMetadata = aDetector.getMetadata();
417     return bRet;
418 }
419 
ImpDetectDXF(SvStream & rStm,bool)420 bool GraphicDescriptor::ImpDetectDXF( SvStream& rStm, bool )
421 {
422     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, false /*bExtendedInfo*/ );
423     bool bRet = aDetector.detect() && aDetector.checkDXF();
424     if ( bRet )
425         aMetadata = aDetector.getMetadata();
426     return bRet;
427 }
428 
ImpDetectMET(SvStream & rStm,bool)429 bool GraphicDescriptor::ImpDetectMET( SvStream& rStm, bool )
430 {
431     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, false /*bExtendedInfo*/ );
432     bool bRet = aDetector.detect() && aDetector.checkMET();
433     if ( bRet )
434         aMetadata = aDetector.getMetadata();
435     return bRet;
436 }
437 
ImpDetectPCT(SvStream & rStm,bool)438 bool GraphicDescriptor::ImpDetectPCT( SvStream& rStm, bool )
439 {
440     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, false /*bExtendedInfo*/ );
441     bool bRet = aDetector.detect() && aDetector.checkPCT();
442     if ( bRet )
443         aMetadata = aDetector.getMetadata();
444     return bRet;
445 }
446 
ImpDetectSVM(SvStream & rStm,bool bExtendedInfo)447 bool GraphicDescriptor::ImpDetectSVM( SvStream& rStm, bool bExtendedInfo )
448 {
449     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, bExtendedInfo );
450     bool bRet = aDetector.detect() && aDetector.checkSVM();
451     if ( bRet )
452         aMetadata = aDetector.getMetadata();
453     return bRet;
454 }
455 
ImpDetectWMF(SvStream & rStm,bool)456 bool GraphicDescriptor::ImpDetectWMF(SvStream& rStm, bool /*bExtendedInfo*/)
457 {
458     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, false /*bExtendedInfo*/ );
459     bool bRet = aDetector.detect() && aDetector.checkWMF();
460     if ( bRet )
461         aMetadata = aDetector.getMetadata();
462     return bRet;
463 }
464 
ImpDetectEMF(SvStream & rStm,bool bExtendedInfo)465 bool GraphicDescriptor::ImpDetectEMF(SvStream& rStm, bool bExtendedInfo)
466 {
467     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, bExtendedInfo );
468     bool bRet = aDetector.detect() && aDetector.checkEMF();
469     if ( bRet )
470         aMetadata = aDetector.getMetadata();
471     return bRet;
472 }
473 
ImpDetectSVG(SvStream & rStm,bool)474 bool GraphicDescriptor::ImpDetectSVG( SvStream& rStm, bool /*bExtendedInfo*/ )
475 {
476     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, false /*bExtendedInfo*/ );
477     bool bRet = aDetector.detect() && aDetector.checkSVG();
478     if ( bRet )
479         aMetadata = aDetector.getMetadata();
480     return bRet;
481 }
482 
ImpDetectWEBP(SvStream & rStm,bool bExtendedInfo)483 bool GraphicDescriptor::ImpDetectWEBP( SvStream& rStm, bool bExtendedInfo )
484 {
485     vcl::GraphicFormatDetector aDetector( rStm, aPathExt, bExtendedInfo );
486     bool bRet = aDetector.detect() && aDetector.checkWEBP();
487     if ( bRet )
488         aMetadata = aDetector.getMetadata();
489     return bRet;
490 }
491 
GetImportFormatShortName(GraphicFileFormat nFormat)492 OUString GraphicDescriptor::GetImportFormatShortName( GraphicFileFormat nFormat )
493 {
494     return vcl::getImportFormatShortName( nFormat );
495 }
496 
497 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
498