build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / filter / graphicfilter.cxx
blob7ac1ecee075e6ee973f09a720de541b7593acaa5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_folders.h>
22 #include <osl/mutex.hxx>
23 #include <comphelper/processfactory.hxx>
24 #include <comphelper/string.hxx>
25 #include <ucbhelper/content.hxx>
26 #include <cppuhelper/implbase.hxx>
27 #include <tools/fract.hxx>
28 #include <tools/stream.hxx>
29 #include <tools/urlobj.hxx>
30 #include <tools/zcodec.hxx>
31 #include <vcl/dibtools.hxx>
32 #include <vcl/salctype.hxx>
33 #include <vcl/pngread.hxx>
34 #include <vcl/pngwrite.hxx>
35 #include <vcl/svgdata.hxx>
36 #include <vcl/virdev.hxx>
37 #include <vcl/svapp.hxx>
38 #include <osl/file.hxx>
39 #include <vcl/graphicfilter.hxx>
40 #include <vcl/FilterConfigItem.hxx>
41 #include <vcl/wmf.hxx>
42 #include <vcl/settings.hxx>
43 #include "igif/gifread.hxx"
44 #include "ipdf/pdfread.hxx"
45 #include "jpeg/jpeg.hxx"
46 #include "ixbm/xbmread.hxx"
47 #include "ixpm/xpmread.hxx"
48 #include "sgffilt.hxx"
49 #include "osl/module.hxx"
50 #include <com/sun/star/uno/Reference.h>
51 #include <com/sun/star/awt/Size.hpp>
52 #include <com/sun/star/uno/XInterface.hpp>
53 #include <com/sun/star/uno/XWeak.hpp>
54 #include <com/sun/star/uno/XAggregation.hpp>
55 #include <com/sun/star/lang/XTypeProvider.hpp>
56 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
57 #include <com/sun/star/io/XActiveDataSource.hpp>
58 #include <com/sun/star/io/XOutputStream.hpp>
59 #include <com/sun/star/svg/XSVGWriter.hpp>
60 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
61 #include <com/sun/star/xml/sax/Writer.hpp>
62 #include <com/sun/star/ucb/CommandAbortedException.hpp>
63 #include <unotools/ucbstreamhelper.hxx>
64 #include <rtl/bootstrap.hxx>
65 #include <rtl/instance.hxx>
66 #include <vcl/metaact.hxx>
67 #include <vector>
68 #include <memory>
70 #include "FilterConfigCache.hxx"
71 #include "graphicfilter_internal.hxx"
73 #define PMGCHUNG_msOG 0x6d734f47 // Microsoft Office Animated GIF
75 using comphelper::string::getTokenCount;
77 typedef ::std::vector< GraphicFilter* > FilterList_impl;
78 static FilterList_impl* pFilterHdlList = nullptr;
80 static ::osl::Mutex& getListMutex()
82 static ::osl::Mutex s_aListProtection;
83 return s_aListProtection;
86 class ImpFilterOutputStream : public ::cppu::WeakImplHelper< css::io::XOutputStream >
88 protected:
90 SvStream& mrStm;
92 virtual void SAL_CALL writeBytes( const css::uno::Sequence< sal_Int8 >& rData )
93 throw (css::io::NotConnectedException, css::io::BufferSizeExceededException, css::io::IOException, css::uno::RuntimeException, std::exception) override
94 { mrStm.WriteBytes(rData.getConstArray(), rData.getLength()); }
95 virtual void SAL_CALL flush()
96 throw (css::io::NotConnectedException, css::io::BufferSizeExceededException, css::io::IOException, css::uno::RuntimeException, std::exception) override
97 { mrStm.Flush(); }
98 virtual void SAL_CALL closeOutput() throw(std::exception) override {}
100 public:
102 explicit ImpFilterOutputStream( SvStream& rStm ) : mrStm( rStm ) {}
105 #ifndef DISABLE_EXPORT
107 static bool DirEntryExists( const INetURLObject& rObj )
109 bool bExists = false;
113 ::ucbhelper::Content aCnt( rObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
114 css::uno::Reference< css::ucb::XCommandEnvironment >(),
115 comphelper::getProcessComponentContext() );
117 bExists = aCnt.isDocument();
119 catch(const css::ucb::CommandAbortedException&)
121 SAL_WARN( "vcl.filter", "CommandAbortedException" );
123 catch(const css::ucb::ContentCreationException&)
125 SAL_WARN( "vcl.filter", "ContentCreationException" );
127 catch( ... )
129 SAL_WARN( "vcl.filter", "Any other exception" );
131 return bExists;
134 static void KillDirEntry( const OUString& rMainUrl )
138 ::ucbhelper::Content aCnt( rMainUrl,
139 css::uno::Reference< css::ucb::XCommandEnvironment >(),
140 comphelper::getProcessComponentContext() );
142 aCnt.executeCommand( "delete",
143 css::uno::makeAny( true ) );
145 catch(const css::ucb::CommandAbortedException&)
147 SAL_WARN( "vcl.filter", "CommandAbortedException" );
149 catch( ... )
151 SAL_WARN( "vcl.filter", "Any other exception" );
155 #endif // !DISABLE_EXPORT
157 // Helper functions
159 sal_uInt8* ImplSearchEntry( sal_uInt8* pSource, sal_uInt8 const * pDest, sal_uLong nComp, sal_uLong nSize )
161 while ( nComp-- >= nSize )
163 sal_uLong i;
164 for ( i = 0; i < nSize; i++ )
166 if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
167 break;
169 if ( i == nSize )
170 return pSource;
171 pSource++;
173 return nullptr;
176 inline OUString ImpGetExtension( const OUString &rPath )
178 OUString aExt;
179 INetURLObject aURL( rPath );
180 aExt = aURL.GetFileExtension().toAsciiUpperCase();
181 return aExt;
184 bool isPCT(SvStream& rStream, sal_uLong nStreamPos, sal_uLong nStreamLen)
186 sal_uInt8 sBuf[3];
187 // store number format
188 SvStreamEndian oldNumberFormat = rStream.GetEndian();
189 sal_uInt32 nOffset; // in MS documents the pict format is used without the first 512 bytes
190 for ( nOffset = 0; ( nOffset <= 512 ) && ( ( nStreamPos + nOffset + 14 ) <= nStreamLen ); nOffset += 512 )
192 short y1,x1,y2,x2;
193 bool bdBoxOk = true;
195 rStream.Seek( nStreamPos + nOffset);
196 // size of the pict in version 1 pict ( 2bytes) : ignored
197 rStream.SeekRel(2);
198 // bounding box (bytes 2 -> 9)
199 rStream.SetEndian(SvStreamEndian::BIG);
200 rStream.ReadInt16( y1 ).ReadInt16( x1 ).ReadInt16( y2 ).ReadInt16( x2 );
201 rStream.SetEndian(oldNumberFormat); // reset format
203 if (x1 > x2 || y1 > y2 || // bad bdbox
204 (x1 == x2 && y1 == y2) || // 1 pixel picture
205 x2-x1 > 2048 || y2-y1 > 2048 ) // picture abnormally big
206 bdBoxOk = false;
208 // read version op
209 rStream.ReadBytes(sBuf, 3);
210 // see http://developer.apple.com/legacy/mac/library/documentation/mac/pdf/Imaging_With_QuickDraw/Appendix_A.pdf
211 // normal version 2 - page A23 and A24
212 if ( sBuf[ 0 ] == 0x00 && sBuf[ 1 ] == 0x11 && sBuf[ 2 ] == 0x02)
213 return true;
214 // normal version 1 - page A25
215 else if (sBuf[ 0 ] == 0x11 && sBuf[ 1 ] == 0x01 && bdBoxOk)
216 return true;
218 return false;
221 /*************************************************************************
223 * ImpPeekGraphicFormat()
225 * Description:
226 * This function is two-fold:
227 * 1.) Start reading file, determine the file format:
228 * Input parameters:
229 * rPath - file path
230 * rFormatExtension - content matter
231 * bTest - set false
232 * Output parameters:
233 * Return value - true if success
234 * rFormatExtension - on success: normal file extension in capitals
235 * 2.) Start reading file, verify file format
236 * Input parameters:
237 * rPath - file path
238 * rFormatExtension - normal file extension in capitals
239 * bTest - set true
240 * Output parameters:
241 * Return value - false, if cannot verify the file type
242 * passed to the function
243 * true, when the format is PROBABLY verified or
244 * WHEN THE FORMAT IS NOT KNOWN!
246 *************************************************************************/
248 static bool ImpPeekGraphicFormat( SvStream& rStream, OUString& rFormatExtension, bool bTest )
250 sal_uInt8 sFirstBytes[ 256 ];
251 sal_uLong nFirstLong(0), nSecondLong(0);
252 sal_uLong nStreamPos = rStream.Tell();
254 rStream.Seek( STREAM_SEEK_TO_END );
255 sal_uLong nStreamLen = rStream.Tell() - nStreamPos;
256 rStream.Seek( nStreamPos );
258 if ( !nStreamLen )
260 SvLockBytes* pLockBytes = rStream.GetLockBytes();
261 if ( pLockBytes )
262 pLockBytes->SetSynchronMode();
264 rStream.Seek( STREAM_SEEK_TO_END );
265 nStreamLen = rStream.Tell() - nStreamPos;
266 rStream.Seek( nStreamPos );
269 if (!nStreamLen)
271 return false; // this prevents at least a STL assertion
273 else if (nStreamLen >= 256)
275 // load first 256 bytes into a buffer
276 sal_uLong nRead = rStream.ReadBytes(sFirstBytes, 256);
277 if (nRead < 256)
278 nStreamLen = nRead;
280 else
282 nStreamLen = rStream.ReadBytes(sFirstBytes, nStreamLen);
286 if (rStream.GetError())
287 return false;
289 for (sal_uLong i = nStreamLen; i < 256; ++i)
290 sFirstBytes[i] = 0;
292 // Accommodate the first 8 bytes in nFirstLong, nSecondLong
293 // Big-Endian:
294 for (int i = 0; i < 4; ++i)
296 nFirstLong=(nFirstLong<<8)|(sal_uLong)sFirstBytes[i];
297 nSecondLong=(nSecondLong<<8)|(sal_uLong)sFirstBytes[i+4];
300 // The following variable is used when bTest == true. It remains false
301 // if the format (rFormatExtension) has not yet been set.
302 bool bSomethingTested = false;
304 // Now the different formats are checked. The order *does* matter. e.g. a MET file
305 // could also go through the BMP test, however, a BMP file can hardly go through the MET test.
306 // So MET should be tested prior to BMP. However, theoretically a BMP file could conceivably
307 // go through the MET test. These problems are of course not only in MET and BMP.
308 // Therefore, in the case of a format check (bTest == true) we only test *exactly* this
309 // format. Everything else could have fatal consequences, for example if the user says it is
310 // a BMP file (and it is a BMP) file, and the file would go through the MET test ...
311 //--------------------------- MET ------------------------------------
312 if( !bTest || rFormatExtension.startsWith( "MET" ) )
314 bSomethingTested=true;
315 if( sFirstBytes[2] == 0xd3 )
317 rStream.SetEndian( SvStreamEndian::BIG );
318 rStream.Seek( nStreamPos );
319 sal_uInt16 nFieldSize;
320 sal_uInt8 nMagic;
321 bool bOK=true;
322 rStream.ReadUInt16( nFieldSize ).ReadUChar( nMagic );
323 for (int i=0; i<3; i++) {
324 if (nFieldSize<6) { bOK=false; break; }
325 if (nStreamLen < rStream.Tell() + nFieldSize ) { bOK=false; break; }
326 rStream.SeekRel(nFieldSize-3);
327 rStream.ReadUInt16( nFieldSize ).ReadUChar( nMagic );
328 if (nMagic!=0xd3) { bOK=false; break; }
330 rStream.SetEndian( SvStreamEndian::LITTLE );
331 if (bOK && !rStream.GetError()) {
332 rFormatExtension = "MET";
333 return true;
338 //--------------------------- BMP ------------------------------------
339 if( !bTest || rFormatExtension.startsWith( "BMP" ) )
341 sal_uInt8 nOffs;
343 bSomethingTested=true;
345 // We're possibly also able to read an OS/2 bitmap array
346 // ('BA'), therefore we must adjust the offset to discover the
347 // first bitmap in the array
348 if ( sFirstBytes[0] == 0x42 && sFirstBytes[1] == 0x41 )
349 nOffs = 14;
350 else
351 nOffs = 0;
353 // Now we initially test on 'BM'
354 if ( sFirstBytes[0+nOffs]==0x42 && sFirstBytes[1+nOffs]==0x4d )
357 // OS/2 can set the Reserved flags to a value other than 0
358 // (which they really should not do...);
359 // In this case we test the size of the BmpInfoHeaders
360 if ( ( sFirstBytes[6+nOffs]==0x00 &&
361 sFirstBytes[7+nOffs]==0x00 &&
362 sFirstBytes[8+nOffs]==0x00 &&
363 sFirstBytes[9+nOffs]==0x00 ) ||
364 sFirstBytes[14+nOffs] == 0x28 ||
365 sFirstBytes[14+nOffs] == 0x0c )
367 rFormatExtension = "BMP";
368 return true;
373 //--------------------------- WMF/EMF ------------------------------------
375 if( !bTest ||
376 rFormatExtension.startsWith( "WMF" ) ||
377 rFormatExtension.startsWith( "EMF" ) )
379 bSomethingTested = true;
381 if ( nFirstLong==0xd7cdc69a || nFirstLong==0x01000900 )
383 rFormatExtension = "WMF";
384 return true;
386 else if( nFirstLong == 0x01000000 && sFirstBytes[ 40 ] == 0x20 && sFirstBytes[ 41 ] == 0x45 &&
387 sFirstBytes[ 42 ] == 0x4d && sFirstBytes[ 43 ] == 0x46 )
389 rFormatExtension = "EMF";
390 return true;
394 //--------------------------- PCX ------------------------------------
395 if( !bTest || rFormatExtension.startsWith( "PCX" ) )
397 bSomethingTested=true;
398 if (sFirstBytes[0]==0x0a)
400 sal_uInt8 nVersion=sFirstBytes[1];
401 sal_uInt8 nEncoding=sFirstBytes[2];
402 if( ( nVersion==0 || nVersion==2 || nVersion==3 || nVersion==5 ) && nEncoding<=1 )
404 rFormatExtension = "PCX";
405 return true;
410 //--------------------------- TIF ------------------------------------
411 if( !bTest || rFormatExtension.startsWith( "TIF" ) )
413 bSomethingTested=true;
414 if ( nFirstLong==0x49492a00 || nFirstLong==0x4d4d002a )
416 rFormatExtension = "TIF";
417 return true;
421 //--------------------------- GIF ------------------------------------
422 if( !bTest || rFormatExtension.startsWith( "GIF" ) )
424 bSomethingTested=true;
425 if ( nFirstLong==0x47494638 && (sFirstBytes[4]==0x37 || sFirstBytes[4]==0x39) && sFirstBytes[5]==0x61 )
427 rFormatExtension = "GIF";
428 return true;
432 //--------------------------- PNG ------------------------------------
433 if( !bTest || rFormatExtension.startsWith( "PNG" ) )
435 bSomethingTested=true;
436 if (nFirstLong==0x89504e47 && nSecondLong==0x0d0a1a0a)
438 rFormatExtension = "PNG";
439 return true;
443 //--------------------------- JPG ------------------------------------
444 if( !bTest || rFormatExtension.startsWith( "JPG" ) )
446 bSomethingTested=true;
447 if ( ( nFirstLong==0xffd8ffe0 && sFirstBytes[6]==0x4a && sFirstBytes[7]==0x46 && sFirstBytes[8]==0x49 && sFirstBytes[9]==0x46 ) ||
448 ( nFirstLong==0xffd8fffe ) || ( 0xffd8ff00 == ( nFirstLong & 0xffffff00 ) ) )
450 rFormatExtension = "JPG";
451 return true;
455 //--------------------------- SVM ------------------------------------
456 if( !bTest || rFormatExtension.startsWith( "SVM" ) )
458 bSomethingTested=true;
459 if( nFirstLong==0x53564744 && sFirstBytes[4]==0x49 )
461 rFormatExtension = "SVM";
462 return true;
464 else if( sFirstBytes[0]==0x56 && sFirstBytes[1]==0x43 && sFirstBytes[2]==0x4C &&
465 sFirstBytes[3]==0x4D && sFirstBytes[4]==0x54 && sFirstBytes[5]==0x46 )
467 rFormatExtension = "SVM";
468 return true;
472 //--------------------------- PCD ------------------------------------
473 if( !bTest || rFormatExtension.startsWith( "PCD" ) )
475 bSomethingTested = true;
476 if( nStreamLen >= 2055 )
478 char sBuf[8];
479 rStream.Seek( nStreamPos + 2048 );
480 rStream.ReadBytes( sBuf, 7 );
482 if( strncmp( sBuf, "PCD_IPI", 7 ) == 0 )
484 rFormatExtension = "PCD";
485 return true;
490 //--------------------------- PSD ------------------------------------
491 if( !bTest || rFormatExtension.startsWith( "PSD" ) )
493 bSomethingTested = true;
494 if ( ( nFirstLong == 0x38425053 ) && ( (nSecondLong >> 16 ) == 1 ) )
496 rFormatExtension = "PSD";
497 return true;
501 //--------------------------- EPS ------------------------------------
502 if( !bTest || rFormatExtension.startsWith( "EPS" ) )
504 bSomethingTested = true;
505 if ( ( nFirstLong == 0xC5D0D3C6 ) || ( ImplSearchEntry( sFirstBytes, reinterpret_cast<sal_uInt8 const *>("%!PS-Adobe"), 10, 10 ) &&
506 ImplSearchEntry( &sFirstBytes[15], reinterpret_cast<sal_uInt8 const *>("EPS"), 3, 3 ) ) )
508 rFormatExtension = "EPS";
509 return true;
513 //--------------------------- DXF ------------------------------------
514 if( !bTest || rFormatExtension.startsWith( "DXF" ) )
516 // Binary DXF File Format
517 if( strncmp( reinterpret_cast<char*>(sFirstBytes), "AutoCAD Binary DXF", 18 ) == 0 )
519 rFormatExtension = "DXF";
520 return true;
523 // ASCII DXF File Format
524 int i=0;
525 while (i<256 && sFirstBytes[i]<=32)
526 ++i;
528 if (i<256 && sFirstBytes[i]=='0')
530 ++i;
532 // only now do we have sufficient data to make a judgement
533 // based on a '0' + 'SECTION' == DXF argument
534 bSomethingTested=true;
536 while( i<256 && sFirstBytes[i]<=32 )
537 ++i;
539 if (i+7<256 && (strncmp(reinterpret_cast<char*>(sFirstBytes+i),"SECTION",7)==0))
541 rFormatExtension = "DXF";
542 return true;
548 //--------------------------- PCT ------------------------------------
549 if( !bTest || rFormatExtension.startsWith( "PCT" ) )
551 bSomethingTested = true;
552 if (isPCT(rStream, nStreamPos, nStreamLen))
554 rFormatExtension = "PCT";
555 return true;
559 //------------------------- PBM + PGM + PPM ---------------------------
560 if( !bTest ||
561 rFormatExtension.startsWith( "PBM" ) ||
562 rFormatExtension.startsWith( "PGM" ) ||
563 rFormatExtension.startsWith( "PPM" ) )
565 bSomethingTested=true;
566 if ( sFirstBytes[ 0 ] == 'P' )
568 switch( sFirstBytes[ 1 ] )
570 case '1' :
571 case '4' :
572 rFormatExtension = "PBM";
573 return true;
575 case '2' :
576 case '5' :
577 rFormatExtension = "PGM";
578 return true;
580 case '3' :
581 case '6' :
582 rFormatExtension = "PPM";
583 return true;
588 //--------------------------- RAS( SUN RasterFile )------------------
589 if( !bTest || rFormatExtension.startsWith( "RAS" ) )
591 bSomethingTested=true;
592 if( nFirstLong == 0x59a66a95 )
594 rFormatExtension = "RAS";
595 return true;
599 //--------------------------- XPM ------------------------------------
600 if( !bTest )
602 bSomethingTested = true;
603 if( ImplSearchEntry( sFirstBytes, reinterpret_cast<sal_uInt8 const *>("/* XPM */"), 256, 9 ) )
605 rFormatExtension = "XPM";
606 return true;
609 else if( rFormatExtension.startsWith( "XPM" ) )
611 return true;
614 //--------------------------- XBM ------------------------------------
615 if( !bTest )
617 sal_uLong nSize = ( nStreamLen > 2048 ) ? 2048 : nStreamLen;
618 std::unique_ptr<sal_uInt8[]> pBuf(new sal_uInt8 [ nSize ]);
620 rStream.Seek( nStreamPos );
621 rStream.ReadBytes( pBuf.get(), nSize );
622 sal_uInt8* pPtr = ImplSearchEntry( pBuf.get(), reinterpret_cast<sal_uInt8 const *>("#define"), nSize, 7 );
624 if( pPtr )
626 if( ImplSearchEntry( pPtr, reinterpret_cast<sal_uInt8 const *>("_width"), pBuf.get() + nSize - pPtr, 6 ) )
628 rFormatExtension = "XBM";
629 return true;
633 else if( rFormatExtension.startsWith( "XBM" ) )
635 return true;
638 //--------------------------- SVG ------------------------------------
639 if( !bTest )
641 sal_uInt8* pCheckArray = sFirstBytes;
642 sal_uLong nCheckSize = nStreamLen < 256 ? nStreamLen : 256;
644 sal_uInt8 sExtendedOrDecompressedFirstBytes[2048];
645 sal_uLong nDecompressedSize = nCheckSize;
647 bool bIsGZip(false);
649 // check if it is gzipped -> svgz
650 if(sFirstBytes[0] == 0x1F && sFirstBytes[1] == 0x8B)
652 ZCodec aCodec;
653 rStream.Seek(nStreamPos);
654 aCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, false, true);
655 nDecompressedSize = aCodec.Read(rStream, sExtendedOrDecompressedFirstBytes, 2048);
656 nCheckSize = nDecompressedSize < 256 ? nDecompressedSize : 256;
657 aCodec.EndCompression();
658 pCheckArray = sExtendedOrDecompressedFirstBytes;
660 bIsGZip = true;
663 bool bIsSvg(false);
665 // check for Xml
666 // #119176# SVG files which have no xml header at all have shown up this is optional
667 if( ImplSearchEntry(pCheckArray, reinterpret_cast<sal_uInt8 const *>("<?xml"), nCheckSize, 5 ) // is it xml
668 && ImplSearchEntry(pCheckArray, reinterpret_cast<sal_uInt8 const *>("version"), nCheckSize, 7 )) // does it have a version (required for xml)
671 // check for DOCTYPE svg combination
672 if( ImplSearchEntry(pCheckArray, reinterpret_cast<sal_uInt8 const *>("DOCTYPE"), nCheckSize, 7 ) // 'DOCTYPE' is there
673 && ImplSearchEntry(pCheckArray, reinterpret_cast<sal_uInt8 const *>("svg"), nCheckSize, 3 )) // 'svg' is there
675 bIsSvg = true;
679 // check for svg element in 1st 256 bytes
680 if(!bIsSvg && ImplSearchEntry(pCheckArray, reinterpret_cast<sal_uInt8 const *>("<svg"), nCheckSize, 4 )) // '<svg'
682 bIsSvg = true;
685 // extended search for svg element
686 if(!bIsSvg)
688 // it's a xml, look for '<svg' in full file. Should not happen too
689 // often since the tests above will handle most cases, but can happen
690 // with Svg files containing big comment headers or Svg as the host
691 // language
693 pCheckArray = sExtendedOrDecompressedFirstBytes;
695 if (bIsGZip)
697 nCheckSize = nDecompressedSize < 2048 ? nDecompressedSize : 2048;
699 else
701 nCheckSize = nStreamLen < 2048 ? nStreamLen : 2048;
702 rStream.Seek(nStreamPos);
703 nCheckSize = rStream.ReadBytes(sExtendedOrDecompressedFirstBytes, nCheckSize);
706 if(ImplSearchEntry(pCheckArray, reinterpret_cast<sal_uInt8 const *>("<svg"), nCheckSize, 4)) // '<svg'
708 bIsSvg = true;
712 if(bIsSvg)
714 rFormatExtension = "SVG";
715 return true;
718 else if( rFormatExtension.startsWith( "SVG" ) )
720 return true;
723 //--------------------------- TGA ------------------------------------
724 if( !bTest || rFormatExtension.startsWith( "TGA" ) )
726 bSomethingTested = true;
728 // just a simple test for the extension
729 if( rFormatExtension.startsWith( "TGA" ) )
730 return true;
733 //--------------------------- SGV ------------------------------------
734 if( !bTest || rFormatExtension.startsWith( "SGV" ) )
736 bSomethingTested = true;
738 // just a simple test for the extension
739 if( rFormatExtension.startsWith( "SGV" ) )
740 return true;
743 //--------------------------- SGF ------------------------------------
744 if( !bTest || rFormatExtension.startsWith( "SGF" ) )
746 bSomethingTested=true;
747 if( sFirstBytes[ 0 ] == 'J' && sFirstBytes[ 1 ] == 'J' )
749 rFormatExtension = "SGF";
750 return true;
754 if(!bTest || rFormatExtension.startsWith( "MOV" ))
756 if ((sFirstBytes[ 4 ] == 'f' && sFirstBytes[ 5 ] == 't' && sFirstBytes[ 6 ] == 'y' &&
757 sFirstBytes[ 7 ] == 'p' && sFirstBytes[ 8 ] == 'q' && sFirstBytes[ 9 ] == 't') ||
758 (sFirstBytes[ 4 ] == 'm' && sFirstBytes[ 5 ] == 'o' && sFirstBytes[ 6 ] == 'o' &&
759 sFirstBytes[ 7 ] == 'v' && sFirstBytes[ 11 ] == 'l' && sFirstBytes[ 12 ] == 'm'))
761 rFormatExtension = "MOV";
762 return true;
766 if (!bTest || rFormatExtension.startsWith("PDF"))
768 if ((sFirstBytes[0] == '%' && sFirstBytes[1] == 'P' && sFirstBytes[2] == 'D' &&
769 sFirstBytes[3] == 'F' && sFirstBytes[4] == '-'))
771 rFormatExtension = "PDF";
772 return true;
776 return bTest && !bSomethingTested;
779 sal_uInt16 GraphicFilter::ImpTestOrFindFormat( const OUString& rPath, SvStream& rStream, sal_uInt16& rFormat )
781 // determine or check the filter/format by reading into it
782 if( rFormat == GRFILTER_FORMAT_DONTKNOW )
784 OUString aFormatExt;
785 if( ImpPeekGraphicFormat( rStream, aFormatExt, false ) )
787 rFormat = pConfig->GetImportFormatNumberForExtension( aFormatExt );
788 if( rFormat != GRFILTER_FORMAT_DONTKNOW )
789 return GRFILTER_OK;
791 // determine filter by file extension
792 if( !rPath.isEmpty() )
794 OUString aExt( ImpGetExtension( rPath ) );
795 rFormat = pConfig->GetImportFormatNumberForExtension( aExt );
796 if( rFormat != GRFILTER_FORMAT_DONTKNOW )
797 return GRFILTER_OK;
799 return GRFILTER_FORMATERROR;
801 else
803 OUString aTmpStr( pConfig->GetImportFormatExtension( rFormat ) );
804 aTmpStr = aTmpStr.toAsciiUpperCase();
805 if( !ImpPeekGraphicFormat( rStream, aTmpStr, true ) )
806 return GRFILTER_FORMATERROR;
807 if ( pConfig->GetImportFormatExtension( rFormat ).equalsIgnoreAsciiCase( "pcd" ) )
809 sal_Int32 nBase = 2; // default Base0
810 if ( pConfig->GetImportFilterType( rFormat ).equalsIgnoreAsciiCase( "pcd_Photo_CD_Base4" ) )
811 nBase = 1;
812 else if ( pConfig->GetImportFilterType( rFormat ).equalsIgnoreAsciiCase( "pcd_Photo_CD_Base16" ) )
813 nBase = 0;
814 OUString aFilterConfigPath( "Office.Common/Filter/Graphic/Import/PCD" );
815 FilterConfigItem aFilterConfigItem( aFilterConfigPath );
816 aFilterConfigItem.WriteInt32( "Resolution", nBase );
820 return GRFILTER_OK;
823 #ifndef DISABLE_EXPORT
825 static Graphic ImpGetScaledGraphic( const Graphic& rGraphic, FilterConfigItem& rConfigItem )
827 Graphic aGraphic;
829 std::unique_ptr<ResMgr> xResMgr(ResMgr::CreateResMgr( "svt", Application::GetSettings().GetUILanguageTag() ));
831 sal_Int32 nLogicalWidth = rConfigItem.ReadInt32( "LogicalWidth", 0 );
832 sal_Int32 nLogicalHeight = rConfigItem.ReadInt32( "LogicalHeight", 0 );
834 if ( rGraphic.GetType() != GraphicType::NONE )
836 sal_Int32 nMode = rConfigItem.ReadInt32( "ExportMode", -1 );
838 if ( nMode == -1 ) // the property is not there, this is possible, if the graphic filter
839 { // is called via UnoGraphicExporter and not from a graphic export Dialog
840 nMode = 0; // then we are defaulting this mode to 0
841 if ( nLogicalWidth || nLogicalHeight )
842 nMode = 2;
845 Size aOriginalSize;
846 Size aPrefSize( rGraphic.GetPrefSize() );
847 MapMode aPrefMapMode( rGraphic.GetPrefMapMode() );
848 if ( aPrefMapMode == MapUnit::MapPixel )
849 aOriginalSize = Application::GetDefaultDevice()->PixelToLogic( aPrefSize, MapUnit::Map100thMM );
850 else
851 aOriginalSize = OutputDevice::LogicToLogic( aPrefSize, aPrefMapMode, MapUnit::Map100thMM );
852 if ( !nLogicalWidth )
853 nLogicalWidth = aOriginalSize.Width();
854 if ( !nLogicalHeight )
855 nLogicalHeight = aOriginalSize.Height();
856 if( rGraphic.GetType() == GraphicType::Bitmap )
859 // Resolution is set
860 if( nMode == 1 )
862 Bitmap aBitmap( rGraphic.GetBitmap() );
863 MapMode aMap( MapUnit::Map100thInch );
865 sal_Int32 nDPI = rConfigItem.ReadInt32( "Resolution", 75 );
866 Fraction aFrac( 1, std::min( std::max( nDPI, sal_Int32( 75 ) ), sal_Int32( 600 ) ) );
868 aMap.SetScaleX( aFrac );
869 aMap.SetScaleY( aFrac );
871 Size aOldSize = aBitmap.GetSizePixel();
872 aGraphic = rGraphic;
873 aGraphic.SetPrefMapMode( aMap );
874 aGraphic.SetPrefSize( Size( aOldSize.Width() * 100,
875 aOldSize.Height() * 100 ) );
877 // Size is set
878 else if( nMode == 2 )
880 aGraphic = rGraphic;
881 aGraphic.SetPrefMapMode( MapMode( MapUnit::Map100thMM ) );
882 aGraphic.SetPrefSize( Size( nLogicalWidth, nLogicalHeight ) );
884 else
885 aGraphic = rGraphic;
887 sal_Int32 nColors = rConfigItem.ReadInt32( "Color", 0 );
888 if ( nColors ) // graphic conversion necessary ?
890 BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
891 aBmpEx.Convert( (BmpConversion)nColors ); // the entries in the xml section have the same meaning as
892 aGraphic = aBmpEx; // they have in the BmpConversion enum, so it should be
893 } // allowed to cast them
895 else
897 if( ( nMode == 1 ) || ( nMode == 2 ) )
899 GDIMetaFile aMtf( rGraphic.GetGDIMetaFile() );
900 Size aNewSize( OutputDevice::LogicToLogic( Size( nLogicalWidth, nLogicalHeight ), MapUnit::Map100thMM, aMtf.GetPrefMapMode() ) );
902 if( aNewSize.Width() && aNewSize.Height() )
904 const Size aPreferredSize( aMtf.GetPrefSize() );
905 aMtf.Scale( Fraction( aNewSize.Width(), aPreferredSize.Width() ),
906 Fraction( aNewSize.Height(), aPreferredSize.Height() ) );
908 aGraphic = Graphic( aMtf );
910 else
911 aGraphic = rGraphic;
915 else
916 aGraphic = rGraphic;
918 return aGraphic;
921 #endif
923 static OUString ImpCreateFullFilterPath( const OUString& rPath, const OUString& rFilterName )
925 OUString aPathURL;
927 ::osl::FileBase::getFileURLFromSystemPath( rPath, aPathURL );
928 aPathURL += "/";
930 OUString aSystemPath;
931 ::osl::FileBase::getSystemPathFromFileURL( aPathURL, aSystemPath );
932 aSystemPath += rFilterName;
934 return OUString( aSystemPath );
937 class ImpFilterLibCache;
939 struct ImpFilterLibCacheEntry
941 ImpFilterLibCacheEntry* mpNext;
942 #ifndef DISABLE_DYNLOADING
943 osl::Module maLibrary;
944 #endif
945 OUString maFiltername;
946 OUString maFormatName;
947 PFilterCall mpfnImport;
949 ImpFilterLibCacheEntry(const OUString& rPathname, const OUString& rFiltername, const OUString& rFormatName);
950 bool operator==( const OUString& rFiltername ) const { return maFiltername == rFiltername; }
952 PFilterCall GetImportFunction();
955 ImpFilterLibCacheEntry::ImpFilterLibCacheEntry( const OUString& rPathname, const OUString& rFiltername, const OUString& rFormatName ) :
956 mpNext ( nullptr ),
957 #ifndef DISABLE_DYNLOADING
958 maLibrary ( rPathname ),
959 #endif
960 maFiltername ( rFiltername ),
961 maFormatName ( rFormatName ),
962 mpfnImport ( nullptr )
964 #ifdef DISABLE_DYNLOADING
965 (void) rPathname;
966 #endif
969 #ifdef DISABLE_DYNLOADING
971 extern "C" bool icdGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
972 extern "C" bool idxGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
973 extern "C" bool imeGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
974 extern "C" bool ipbGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
975 extern "C" bool ipdGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
976 extern "C" bool ipsGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
977 extern "C" bool iptGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
978 extern "C" bool ipxGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
979 extern "C" bool iraGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
980 extern "C" bool itgGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
981 extern "C" bool itiGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
983 #endif
985 PFilterCall ImpFilterLibCacheEntry::GetImportFunction()
987 if( !mpfnImport )
989 #ifndef DISABLE_DYNLOADING
990 if (maFormatName == "icd")
991 mpfnImport = reinterpret_cast<PFilterCall>(maLibrary.getFunctionSymbol("icdGraphicImport"));
992 else if (maFormatName == "idx")
993 mpfnImport = reinterpret_cast<PFilterCall>(maLibrary.getFunctionSymbol("idxGraphicImport"));
994 else if (maFormatName == "ime")
995 mpfnImport = reinterpret_cast<PFilterCall>(maLibrary.getFunctionSymbol("imeGraphicImport"));
996 else if (maFormatName == "ipb")
997 mpfnImport = reinterpret_cast<PFilterCall>(maLibrary.getFunctionSymbol("ipbGraphicImport"));
998 else if (maFormatName == "ipd")
999 mpfnImport = reinterpret_cast<PFilterCall>(maLibrary.getFunctionSymbol("ipdGraphicImport"));
1000 else if (maFormatName == "ips")
1001 mpfnImport = reinterpret_cast<PFilterCall>(maLibrary.getFunctionSymbol("ipsGraphicImport"));
1002 else if (maFormatName == "ipt")
1003 mpfnImport = reinterpret_cast<PFilterCall>(maLibrary.getFunctionSymbol("iptGraphicImport"));
1004 else if (maFormatName == "ipx")
1005 mpfnImport = reinterpret_cast<PFilterCall>(maLibrary.getFunctionSymbol("ipxGraphicImport"));
1006 else if (maFormatName == "ira")
1007 mpfnImport = reinterpret_cast<PFilterCall>(maLibrary.getFunctionSymbol("iraGraphicImport"));
1008 else if (maFormatName == "itg")
1009 mpfnImport = reinterpret_cast<PFilterCall>(maLibrary.getFunctionSymbol("itgGraphicImport"));
1010 else if (maFormatName == "iti")
1011 mpfnImport = reinterpret_cast<PFilterCall>(maLibrary.getFunctionSymbol("itiGraphicImport"));
1012 #else
1013 if (maFiltername == "icd")
1014 mpfnImport = icdGraphicImport;
1015 else if (maFiltername == "idx")
1016 mpfnImport = idxGraphicImport;
1017 else if (maFiltername == "ime")
1018 mpfnImport = imeGraphicImport;
1019 else if (maFiltername == "ipb")
1020 mpfnImport = ipbGraphicImport;
1021 else if (maFiltername == "ipd")
1022 mpfnImport = ipdGraphicImport;
1023 else if (maFiltername == "ips")
1024 mpfnImport = ipsGraphicImport;
1025 else if (maFiltername == "ipt")
1026 mpfnImport = iptGraphicImport;
1027 else if (maFiltername == "ipx")
1028 mpfnImport = ipxGraphicImport;
1029 else if (maFiltername == "ira")
1030 mpfnImport = iraGraphicImport;
1031 else if (maFiltername == "itg")
1032 mpfnImport = itgGraphicImport;
1033 else if (maFiltername == "iti")
1034 mpfnImport = itiGraphicImport;
1035 #endif
1038 return mpfnImport;
1041 class ImpFilterLibCache
1043 ImpFilterLibCacheEntry* mpFirst;
1044 ImpFilterLibCacheEntry* mpLast;
1046 public:
1047 ImpFilterLibCache();
1048 ~ImpFilterLibCache();
1050 ImpFilterLibCacheEntry* GetFilter( const OUString& rFilterPath, const OUString& rFiltername, const OUString& rFormatName );
1053 ImpFilterLibCache::ImpFilterLibCache() :
1054 mpFirst ( nullptr ),
1055 mpLast ( nullptr )
1059 ImpFilterLibCache::~ImpFilterLibCache()
1061 ImpFilterLibCacheEntry* pEntry = mpFirst;
1062 while( pEntry )
1064 ImpFilterLibCacheEntry* pNext = pEntry->mpNext;
1065 delete pEntry;
1066 pEntry = pNext;
1070 ImpFilterLibCacheEntry* ImpFilterLibCache::GetFilter(const OUString& rFilterPath, const OUString& rFilterName, const OUString& rFormatName)
1072 ImpFilterLibCacheEntry* pEntry = mpFirst;
1074 while( pEntry )
1076 if( *pEntry == rFilterName && pEntry->maFormatName == rFormatName )
1077 break;
1078 else
1079 pEntry = pEntry->mpNext;
1081 if( !pEntry )
1083 OUString aPhysicalName( ImpCreateFullFilterPath( rFilterPath, rFilterName ) );
1084 pEntry = new ImpFilterLibCacheEntry(aPhysicalName, rFilterName, rFormatName );
1085 #ifndef DISABLE_DYNLOADING
1086 if ( pEntry->maLibrary.is() )
1087 #endif
1089 if( !mpFirst )
1090 mpFirst = mpLast = pEntry;
1091 else
1092 mpLast = mpLast->mpNext = pEntry;
1094 #ifndef DISABLE_DYNLOADING
1095 else
1097 delete pEntry;
1098 pEntry = nullptr;
1100 #endif
1102 return pEntry;
1105 namespace { struct Cache : public rtl::Static<ImpFilterLibCache, Cache> {}; }
1107 GraphicFilter::GraphicFilter( bool bConfig )
1108 : pErrorEx(nullptr)
1109 , bUseConfig(bConfig)
1110 , nExpGraphHint(0)
1112 ImplInit();
1115 GraphicFilter::~GraphicFilter()
1118 ::osl::MutexGuard aGuard( getListMutex() );
1119 for(
1120 FilterList_impl::iterator it = pFilterHdlList->begin();
1121 it != pFilterHdlList->end();
1122 ++it
1124 if( *it == this )
1126 pFilterHdlList->erase( it );
1127 break;
1130 if( pFilterHdlList->empty() )
1132 delete pFilterHdlList;
1133 pFilterHdlList = nullptr;
1134 delete pConfig;
1138 delete pErrorEx;
1141 void GraphicFilter::ImplInit()
1144 ::osl::MutexGuard aGuard( getListMutex() );
1146 if ( !pFilterHdlList )
1148 pFilterHdlList = new FilterList_impl;
1149 pConfig = new FilterConfigCache( bUseConfig );
1151 else
1152 pConfig = pFilterHdlList->front()->pConfig;
1154 pFilterHdlList->push_back( this );
1157 if( bUseConfig )
1159 OUString url("$BRAND_BASE_DIR/" LIBO_LIB_FOLDER);
1160 rtl::Bootstrap::expandMacros(url); //TODO: detect failure
1161 osl::FileBase::getSystemPathFromFileURL(url, aFilterPath);
1164 pErrorEx = new FilterErrorEx;
1167 sal_uLong GraphicFilter::ImplSetError( sal_uLong nError, const SvStream* pStm )
1169 pErrorEx->nFilterError = nError;
1170 pErrorEx->nStreamError = pStm ? pStm->GetError() : ERRCODE_NONE;
1171 return nError;
1174 sal_uInt16 GraphicFilter::GetImportFormatCount()
1176 return pConfig->GetImportFormatCount();
1179 sal_uInt16 GraphicFilter::GetImportFormatNumber( const OUString& rFormatName )
1181 return pConfig->GetImportFormatNumber( rFormatName );
1184 sal_uInt16 GraphicFilter::GetImportFormatNumberForShortName( const OUString& rShortName )
1186 return pConfig->GetImportFormatNumberForShortName( rShortName );
1189 sal_uInt16 GraphicFilter::GetImportFormatNumberForTypeName( const OUString& rType )
1191 return pConfig->GetImportFormatNumberForTypeName( rType );
1194 OUString GraphicFilter::GetImportFormatName( sal_uInt16 nFormat )
1196 return pConfig->GetImportFormatName( nFormat );
1199 OUString GraphicFilter::GetImportFormatTypeName( sal_uInt16 nFormat )
1201 return pConfig->GetImportFilterTypeName( nFormat );
1204 #ifdef _WIN32
1205 OUString GraphicFilter::GetImportFormatMediaType( sal_uInt16 nFormat )
1207 return pConfig->GetImportFormatMediaType( nFormat );
1209 #endif
1211 OUString GraphicFilter::GetImportFormatShortName( sal_uInt16 nFormat )
1213 return pConfig->GetImportFormatShortName( nFormat );
1216 OUString GraphicFilter::GetImportWildcard( sal_uInt16 nFormat, sal_Int32 nEntry )
1218 return pConfig->GetImportWildcard( nFormat, nEntry );
1221 sal_uInt16 GraphicFilter::GetExportFormatCount()
1223 return pConfig->GetExportFormatCount();
1226 sal_uInt16 GraphicFilter::GetExportFormatNumber( const OUString& rFormatName )
1228 return pConfig->GetExportFormatNumber( rFormatName );
1231 sal_uInt16 GraphicFilter::GetExportFormatNumberForMediaType( const OUString& rMediaType )
1233 return pConfig->GetExportFormatNumberForMediaType( rMediaType );
1236 sal_uInt16 GraphicFilter::GetExportFormatNumberForShortName( const OUString& rShortName )
1238 return pConfig->GetExportFormatNumberForShortName( rShortName );
1241 OUString GraphicFilter::GetExportInternalFilterName( sal_uInt16 nFormat )
1243 return pConfig->GetExportInternalFilterName( nFormat );
1246 sal_uInt16 GraphicFilter::GetExportFormatNumberForTypeName( const OUString& rType )
1248 return pConfig->GetExportFormatNumberForTypeName( rType );
1251 OUString GraphicFilter::GetExportFormatName( sal_uInt16 nFormat )
1253 return pConfig->GetExportFormatName( nFormat );
1256 OUString GraphicFilter::GetExportFormatMediaType( sal_uInt16 nFormat )
1258 return pConfig->GetExportFormatMediaType( nFormat );
1261 OUString GraphicFilter::GetExportFormatShortName( sal_uInt16 nFormat )
1263 return pConfig->GetExportFormatShortName( nFormat );
1266 OUString GraphicFilter::GetExportWildcard( sal_uInt16 nFormat )
1268 return pConfig->GetExportWildcard( nFormat, 0 );
1271 bool GraphicFilter::IsExportPixelFormat( sal_uInt16 nFormat )
1273 return pConfig->IsExportPixelFormat( nFormat );
1276 sal_uInt16 GraphicFilter::CanImportGraphic( const INetURLObject& rPath,
1277 sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat )
1279 sal_uInt16 nRetValue = GRFILTER_FORMATERROR;
1280 SAL_WARN_IF( rPath.GetProtocol() == INetProtocol::NotValid, "vcl", "GraphicFilter::CanImportGraphic() : ProtType == INetProtocol::NotValid" );
1282 OUString aMainUrl( rPath.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1283 std::unique_ptr<SvStream> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl, StreamMode::READ | StreamMode::SHARE_DENYNONE ));
1284 if (xStream)
1286 nRetValue = CanImportGraphic( aMainUrl, *xStream, nFormat, pDeterminedFormat );
1288 return nRetValue;
1291 sal_uInt16 GraphicFilter::CanImportGraphic( const OUString& rMainUrl, SvStream& rIStream,
1292 sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat )
1294 sal_uLong nStreamPos = rIStream.Tell();
1295 sal_uInt16 nRes = ImpTestOrFindFormat( rMainUrl, rIStream, nFormat );
1297 rIStream.Seek(nStreamPos);
1299 if( nRes==GRFILTER_OK && pDeterminedFormat!=nullptr )
1300 *pDeterminedFormat = nFormat;
1302 return (sal_uInt16) ImplSetError( nRes, &rIStream );
1305 //SJ: TODO, we need to create a GraphicImporter component
1306 sal_uInt16 GraphicFilter::ImportGraphic( Graphic& rGraphic, const INetURLObject& rPath,
1307 sal_uInt16 nFormat, sal_uInt16 * pDeterminedFormat, GraphicFilterImportFlags nImportFlags )
1309 sal_uInt16 nRetValue = GRFILTER_FORMATERROR;
1310 SAL_WARN_IF( rPath.GetProtocol() == INetProtocol::NotValid, "vcl", "GraphicFilter::ImportGraphic() : ProtType == INetProtocol::NotValid" );
1312 OUString aMainUrl( rPath.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1313 std::unique_ptr<SvStream> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl, StreamMode::READ | StreamMode::SHARE_DENYNONE ));
1314 if (xStream)
1316 nRetValue = ImportGraphic( rGraphic, aMainUrl, *xStream, nFormat, pDeterminedFormat, nImportFlags );
1318 return nRetValue;
1321 sal_uInt16 GraphicFilter::ImportGraphic( Graphic& rGraphic, const OUString& rPath, SvStream& rIStream,
1322 sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat, GraphicFilterImportFlags nImportFlags, WMF_EXTERNALHEADER *pExtHeader )
1324 return ImportGraphic( rGraphic, rPath, rIStream, nFormat, pDeterminedFormat, nImportFlags, nullptr, pExtHeader );
1327 sal_uInt16 GraphicFilter::ImportGraphic( Graphic& rGraphic, const OUString& rPath, SvStream& rIStream,
1328 sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat, GraphicFilterImportFlags nImportFlags,
1329 css::uno::Sequence< css::beans::PropertyValue >* pFilterData,
1330 WMF_EXTERNALHEADER *pExtHeader )
1332 OUString aFilterName;
1333 OUString aExternalFilterName;
1334 sal_uLong nStreamBegin;
1335 sal_uInt16 nStatus;
1336 std::shared_ptr<GraphicReader> pContext = rGraphic.GetContext();
1337 GfxLinkType eLinkType = GfxLinkType::NONE;
1338 bool bDummyContext = rGraphic.IsDummyContext();
1339 const bool bLinkSet = rGraphic.IsLink();
1340 FilterConfigItem* pFilterConfigItem = nullptr;
1342 Size aPreviewSizeHint( 0, 0 );
1343 bool bAllowPartialStreamRead = false;
1344 bool bCreateNativeLink = true;
1346 std::unique_ptr<sal_uInt8[]> pGraphicContent;
1347 sal_Int32 nGraphicContentSize = 0;
1349 ResetLastError();
1351 if ( pFilterData )
1353 sal_Int32 i;
1354 for ( i = 0; i < pFilterData->getLength(); i++ )
1356 if ( (*pFilterData)[ i ].Name == "PreviewSizeHint" )
1358 css::awt::Size aSize;
1359 if ( (*pFilterData)[ i ].Value >>= aSize )
1361 aPreviewSizeHint = Size( aSize.Width, aSize.Height );
1362 if ( aSize.Width || aSize.Height )
1363 nImportFlags |= GraphicFilterImportFlags::ForPreview;
1364 else
1365 nImportFlags &=~GraphicFilterImportFlags::ForPreview;
1368 else if ( (*pFilterData)[ i ].Name == "AllowPartialStreamRead" )
1370 (*pFilterData)[ i ].Value >>= bAllowPartialStreamRead;
1371 if ( bAllowPartialStreamRead )
1372 nImportFlags |= GraphicFilterImportFlags::AllowPartialStreamRead;
1373 else
1374 nImportFlags &=~GraphicFilterImportFlags::AllowPartialStreamRead;
1376 else if ( (*pFilterData)[ i ].Name == "CreateNativeLink" )
1378 (*pFilterData)[ i ].Value >>= bCreateNativeLink;
1383 if( !pContext || bDummyContext )
1385 if( bDummyContext )
1387 rGraphic.SetDummyContext( false );
1388 nStreamBegin = 0;
1390 else
1391 nStreamBegin = rIStream.Tell();
1393 nStatus = ImpTestOrFindFormat( rPath, rIStream, nFormat );
1394 // if pending, return GRFILTER_OK in order to request more bytes
1395 if( rIStream.GetError() == ERRCODE_IO_PENDING )
1397 rGraphic.SetDummyContext(true);
1398 rIStream.ResetError();
1399 rIStream.Seek( nStreamBegin );
1400 return (sal_uInt16) ImplSetError( GRFILTER_OK );
1403 rIStream.Seek( nStreamBegin );
1405 if( ( nStatus != GRFILTER_OK ) || rIStream.GetError() )
1406 return (sal_uInt16) ImplSetError( ( nStatus != GRFILTER_OK ) ? nStatus : GRFILTER_OPENERROR, &rIStream );
1408 if( pDeterminedFormat )
1409 *pDeterminedFormat = nFormat;
1411 aFilterName = pConfig->GetImportFilterName( nFormat );
1412 aExternalFilterName = pConfig->GetExternalFilterName(nFormat, false);
1414 else
1416 if( pContext && !bDummyContext )
1417 aFilterName = pContext->GetUpperFilterName();
1419 nStreamBegin = 0;
1420 nStatus = GRFILTER_OK;
1423 // read graphic
1424 if ( pConfig->IsImportInternalFilter( nFormat ) )
1426 if( aFilterName.equalsIgnoreAsciiCase( IMP_GIF ) )
1428 if( rGraphic.IsDummyContext())
1429 rGraphic.SetDummyContext( false );
1431 if( !ImportGIF( rIStream, rGraphic ) )
1432 nStatus = GRFILTER_FILTERERROR;
1433 else
1434 eLinkType = GfxLinkType::NativeGif;
1436 else if( aFilterName.equalsIgnoreAsciiCase( IMP_PNG ) )
1438 if( rGraphic.IsDummyContext())
1439 rGraphic.SetDummyContext( false );
1441 vcl::PNGReader aPNGReader( rIStream );
1443 // ignore animation for previews and set preview size
1444 if( aPreviewSizeHint.Width() || aPreviewSizeHint.Height() )
1446 // position the stream at the end of the image if requested
1447 if( !bAllowPartialStreamRead )
1448 aPNGReader.GetChunks();
1450 else
1452 // check if this PNG contains a GIF chunk!
1453 const std::vector<vcl::PNGReader::ChunkData>& rChunkData = aPNGReader.GetChunks();
1454 std::vector<vcl::PNGReader::ChunkData>::const_iterator aIter(rChunkData.begin());
1455 std::vector<vcl::PNGReader::ChunkData>::const_iterator aEnd(rChunkData.end());
1457 while (aIter != aEnd)
1459 // Microsoft Office is storing Animated GIFs in following chunk
1460 if (aIter->nType == PMGCHUNG_msOG)
1462 sal_uInt32 nChunkSize = aIter->aData.size();
1464 if (nChunkSize > 11)
1466 const std::vector<sal_uInt8>& rData = aIter->aData;
1467 nGraphicContentSize = nChunkSize - 11;
1468 SvMemoryStream aIStrm(const_cast<sal_uInt8*>(&rData[11]), nGraphicContentSize, StreamMode::READ);
1469 pGraphicContent = std::unique_ptr<sal_uInt8[]>(new sal_uInt8[nGraphicContentSize]);
1470 sal_uInt64 aCurrentPosition = aIStrm.Tell();
1471 aIStrm.ReadBytes(pGraphicContent.get(), nGraphicContentSize);
1472 aIStrm.Seek(aCurrentPosition);
1473 ImportGIF(aIStrm, rGraphic);
1474 eLinkType = GfxLinkType::NativeGif;
1475 break;
1478 ++aIter;
1482 if ( eLinkType == GfxLinkType::NONE )
1484 BitmapEx aBmpEx( aPNGReader.Read( aPreviewSizeHint ) );
1485 if ( aBmpEx.IsEmpty() )
1486 nStatus = GRFILTER_FILTERERROR;
1487 else
1489 rGraphic = aBmpEx;
1490 eLinkType = GfxLinkType::NativePng;
1494 else if( aFilterName.equalsIgnoreAsciiCase( IMP_JPEG ) )
1496 if( rGraphic.IsDummyContext())
1497 rGraphic.SetDummyContext( false );
1499 // set LOGSIZE flag always, if not explicitly disabled
1500 // (see #90508 and #106763)
1501 if( !( nImportFlags & GraphicFilterImportFlags::DontSetLogsizeForJpeg ) )
1502 nImportFlags |= GraphicFilterImportFlags::SetLogsizeForJpeg;
1504 if( !ImportJPEG( rIStream, rGraphic, nullptr, nImportFlags ) )
1505 nStatus = GRFILTER_FILTERERROR;
1506 else
1507 eLinkType = GfxLinkType::NativeJpg;
1509 else if( aFilterName.equalsIgnoreAsciiCase( IMP_SVG ) )
1511 if( rGraphic.IsDummyContext())
1512 rGraphic.SetDummyContext( false );
1514 const sal_uInt32 nStreamPosition(rIStream.Tell());
1515 const sal_uInt32 nStreamLength(rIStream.Seek(STREAM_SEEK_TO_END) - nStreamPosition);
1517 bool bOkay(false);
1519 if(nStreamLength > 0)
1521 std::vector<sal_uInt8> aTwoBytes(2);
1522 rIStream.Seek(nStreamPosition);
1523 rIStream.ReadBytes(&aTwoBytes[0], 2);
1524 rIStream.Seek(nStreamPosition);
1526 if(aTwoBytes[0] == 0x1F && aTwoBytes[1] == 0x8B)
1528 SvMemoryStream aMemStream;
1529 ZCodec aCodec;
1530 long nMemoryLength;
1532 aCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, false, true);
1533 nMemoryLength = aCodec.Decompress(rIStream, aMemStream);
1534 aCodec.EndCompression();
1536 if (!rIStream.GetError() && nMemoryLength >= 0)
1538 SvgDataArray aNewData(nMemoryLength);
1539 aMemStream.Seek(STREAM_SEEK_TO_BEGIN);
1540 aMemStream.ReadBytes(aNewData.begin(), nMemoryLength);
1542 // Make a uncompressed copy for GfxLink
1543 nGraphicContentSize = nMemoryLength;
1544 pGraphicContent = std::unique_ptr<sal_uInt8[]>(new sal_uInt8[nGraphicContentSize]);
1545 std::copy(aNewData.begin(), aNewData.end(), pGraphicContent.get());
1547 if(!aMemStream.GetError() )
1549 SvgDataPtr aSvgDataPtr(new SvgData(aNewData, rPath));
1550 rGraphic = Graphic(aSvgDataPtr);
1551 bOkay = true;
1555 else
1557 SvgDataArray aNewData(nStreamLength);
1558 rIStream.Seek(nStreamPosition);
1559 rIStream.ReadBytes(aNewData.begin(), nStreamLength);
1561 if(!rIStream.GetError())
1563 SvgDataPtr aSvgDataPtr(new SvgData(aNewData, rPath));
1564 rGraphic = Graphic(aSvgDataPtr);
1565 bOkay = true;
1570 if (bOkay)
1572 eLinkType = GfxLinkType::NativeSvg;
1574 else
1576 nStatus = GRFILTER_FILTERERROR;
1579 else if( aFilterName.equalsIgnoreAsciiCase( IMP_XBM ) )
1581 if( rGraphic.IsDummyContext())
1582 rGraphic.SetDummyContext( false );
1584 if( !ImportXBM( rIStream, rGraphic ) )
1585 nStatus = GRFILTER_FILTERERROR;
1587 else if( aFilterName.equalsIgnoreAsciiCase( IMP_XPM ) )
1589 if( rGraphic.IsDummyContext())
1590 rGraphic.SetDummyContext( false );
1592 if( !ImportXPM( rIStream, rGraphic ) )
1593 nStatus = GRFILTER_FILTERERROR;
1595 else if( aFilterName.equalsIgnoreAsciiCase( IMP_BMP ) ||
1596 aFilterName.equalsIgnoreAsciiCase( IMP_SVMETAFILE ) )
1598 // SV internal filters for import bitmaps and MetaFiles
1599 ReadGraphic( rIStream, rGraphic );
1600 if( rIStream.GetError() )
1602 nStatus = GRFILTER_FORMATERROR;
1604 else if (aFilterName.equalsIgnoreAsciiCase(IMP_BMP))
1606 // #i15508# added BMP type (checked, works)
1607 eLinkType = GfxLinkType::NativeBmp;
1610 else if( aFilterName.equalsIgnoreAsciiCase( IMP_MOV ) )
1612 ReadGraphic( rIStream, rGraphic );
1613 if( rIStream.GetError() )
1614 nStatus = GRFILTER_FORMATERROR;
1615 else
1617 rGraphic.SetDefaultType();
1618 rIStream.Seek( STREAM_SEEK_TO_END );
1619 eLinkType = GfxLinkType::NativeMov;
1622 else if( aFilterName.equalsIgnoreAsciiCase( IMP_WMF ) ||
1623 aFilterName.equalsIgnoreAsciiCase( IMP_EMF ) )
1625 GDIMetaFile aMtf;
1626 if( !ConvertWMFToGDIMetaFile( rIStream, aMtf, nullptr, pExtHeader ) )
1627 nStatus = GRFILTER_FORMATERROR;
1628 else
1630 rGraphic = aMtf;
1631 eLinkType = GfxLinkType::NativeWmf;
1634 else if( aFilterName.equalsIgnoreAsciiCase( IMP_SVSGF )
1635 || aFilterName.equalsIgnoreAsciiCase( IMP_SVSGV ) )
1637 sal_uInt16 nVersion;
1638 unsigned char nTyp = CheckSgfTyp( rIStream, nVersion );
1640 switch( nTyp )
1642 case SGF_BITIMAGE:
1644 SvMemoryStream aTempStream;
1645 if( aTempStream.GetError() )
1646 return GRFILTER_OPENERROR;
1648 if( !SgfBMapFilter( rIStream, aTempStream ) )
1649 nStatus = GRFILTER_FILTERERROR;
1650 else
1652 aTempStream.Seek( 0L );
1653 ReadGraphic( aTempStream, rGraphic );
1655 if( aTempStream.GetError() )
1656 nStatus = GRFILTER_FILTERERROR;
1659 break;
1661 case SGF_SIMPVECT:
1663 GDIMetaFile aMtf;
1664 if( !SgfVectFilter( rIStream, aMtf ) )
1665 nStatus = GRFILTER_FILTERERROR;
1666 else
1667 rGraphic = Graphic( aMtf );
1669 break;
1671 case SGF_STARDRAW:
1673 if( nVersion != SGV_VERSION )
1674 nStatus = GRFILTER_VERSIONERROR;
1675 else
1677 GDIMetaFile aMtf;
1678 if( !SgfSDrwFilter( rIStream, aMtf,
1679 INetURLObject(aFilterPath) ) )
1681 nStatus = GRFILTER_FILTERERROR;
1683 else
1684 rGraphic = Graphic( aMtf );
1687 break;
1689 default:
1691 nStatus = GRFILTER_FORMATERROR;
1693 break;
1696 else if (aFilterName == IMP_PDF)
1698 if (!vcl::ImportPDF(rIStream, rGraphic))
1699 nStatus = GRFILTER_FILTERERROR;
1700 else
1701 eLinkType = GfxLinkType::NativePdf;
1703 else
1704 nStatus = GRFILTER_FILTERERROR;
1706 else
1708 ImpFilterLibCacheEntry* pFilter = nullptr;
1710 // find first filter in filter paths
1711 sal_Int32 i, nTokenCount = getTokenCount(aFilterPath, ';');
1712 ImpFilterLibCache &rCache = Cache::get();
1713 for( i = 0; ( i < nTokenCount ) && ( pFilter == nullptr ); i++ )
1714 pFilter = rCache.GetFilter(aFilterPath.getToken(i, ';'), aFilterName, aExternalFilterName);
1715 if( !pFilter )
1716 nStatus = GRFILTER_FILTERERROR;
1717 else
1719 PFilterCall pFunc = pFilter->GetImportFunction();
1721 if( !pFunc )
1722 nStatus = GRFILTER_FILTERERROR;
1723 else
1725 OUString aShortName;
1726 if( nFormat != GRFILTER_FORMAT_DONTKNOW )
1728 aShortName = GetImportFormatShortName( nFormat ).toAsciiUpperCase();
1729 if ( ( pFilterConfigItem == nullptr ) && aShortName == "PCD" )
1731 OUString aFilterConfigPath( "Office.Common/Filter/Graphic/Import/PCD" );
1732 pFilterConfigItem = new FilterConfigItem( aFilterConfigPath );
1735 if( !(*pFunc)( rIStream, rGraphic, pFilterConfigItem ) )
1736 nStatus = GRFILTER_FORMATERROR;
1737 else
1739 // try to set link type if format matches
1740 if( nFormat != GRFILTER_FORMAT_DONTKNOW )
1742 if( aShortName.startsWith( TIF_SHORTNAME ) )
1743 eLinkType = GfxLinkType::NativeTif;
1744 else if( aShortName.startsWith( MET_SHORTNAME ) )
1745 eLinkType = GfxLinkType::NativeMet;
1746 else if( aShortName.startsWith( PCT_SHORTNAME ) )
1747 eLinkType = GfxLinkType::NativePct;
1754 if( nStatus == GRFILTER_OK && bCreateNativeLink && ( eLinkType != GfxLinkType::NONE ) && !rGraphic.GetContext() && !bLinkSet )
1756 if (!pGraphicContent)
1758 const sal_uLong nStreamEnd = rIStream.Tell();
1759 nGraphicContentSize = nStreamEnd - nStreamBegin;
1761 if (nGraphicContentSize > 0)
1765 pGraphicContent = std::unique_ptr<sal_uInt8[]>(new sal_uInt8[nGraphicContentSize]);
1767 catch (const std::bad_alloc&)
1769 nStatus = GRFILTER_TOOBIG;
1772 if( nStatus == GRFILTER_OK )
1774 rIStream.Seek(nStreamBegin);
1775 rIStream.ReadBytes(pGraphicContent.get(), nGraphicContentSize);
1779 if( nStatus == GRFILTER_OK )
1781 rGraphic.SetLink( GfxLink( std::move(pGraphicContent), nGraphicContentSize, eLinkType ) );
1785 // Set error code or try to set native buffer
1786 if( nStatus != GRFILTER_OK )
1788 ImplSetError( nStatus, &rIStream );
1789 rIStream.Seek( nStreamBegin );
1790 rGraphic.Clear();
1793 delete pFilterConfigItem;
1794 return nStatus;
1797 sal_uInt16 GraphicFilter::ExportGraphic( const Graphic& rGraphic, const INetURLObject& rPath,
1798 sal_uInt16 nFormat, const css::uno::Sequence< css::beans::PropertyValue >* pFilterData )
1800 #ifdef DISABLE_EXPORT
1801 (void) rGraphic;
1802 (void) rPath;
1803 (void) nFormat;
1804 (void) pFilterData;
1806 return GRFILTER_FORMATERROR;
1807 #else
1808 SAL_INFO( "vcl.filter", "GraphicFilter::ExportGraphic() (thb)" );
1809 sal_uInt16 nRetValue = GRFILTER_FORMATERROR;
1810 SAL_WARN_IF( rPath.GetProtocol() == INetProtocol::NotValid, "vcl", "GraphicFilter::ExportGraphic() : ProtType == INetProtocol::NotValid" );
1811 bool bAlreadyExists = DirEntryExists( rPath );
1813 OUString aMainUrl( rPath.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1814 std::unique_ptr<SvStream> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl, StreamMode::WRITE | StreamMode::TRUNC ));
1815 if (xStream)
1817 nRetValue = ExportGraphic( rGraphic, aMainUrl, *xStream, nFormat, pFilterData );
1818 xStream.reset();
1820 if( ( GRFILTER_OK != nRetValue ) && !bAlreadyExists )
1821 KillDirEntry( aMainUrl );
1823 return nRetValue;
1824 #endif
1827 #ifdef DISABLE_DYNLOADING
1829 #ifndef DISABLE_EXPORT
1831 extern "C" bool egiGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
1832 extern "C" bool epsGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
1833 extern "C" bool etiGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
1835 #endif
1837 #endif
1839 sal_uInt16 GraphicFilter::ExportGraphic( const Graphic& rGraphic, const OUString& rPath,
1840 SvStream& rOStm, sal_uInt16 nFormat, const css::uno::Sequence< css::beans::PropertyValue >* pFilterData )
1842 #ifdef DISABLE_EXPORT
1843 (void) rGraphic;
1844 (void) rPath;
1845 (void) rOStm;
1846 (void) nFormat;
1847 (void) pFilterData;
1849 (void) nExpGraphHint;
1851 return GRFILTER_FORMATERROR;
1852 #else
1853 SAL_INFO( "vcl.filter", "GraphicFilter::ExportGraphic() (thb)" );
1854 sal_uInt16 nFormatCount = GetExportFormatCount();
1856 ResetLastError();
1857 nExpGraphHint = 0;
1859 if( nFormat == GRFILTER_FORMAT_DONTKNOW )
1861 INetURLObject aURL( rPath );
1862 OUString aExt( aURL.GetFileExtension().toAsciiUpperCase() );
1864 for( sal_uInt16 i = 0; i < nFormatCount; i++ )
1866 if ( pConfig->GetExportFormatExtension( i ).equalsIgnoreAsciiCase( aExt ) )
1868 nFormat=i;
1869 break;
1873 if( nFormat >= nFormatCount )
1874 return (sal_uInt16) ImplSetError( GRFILTER_FORMATERROR );
1876 FilterConfigItem aConfigItem( const_cast<css::uno::Sequence< css::beans::PropertyValue >*>(pFilterData) );
1877 OUString aFilterName( pConfig->GetExportFilterName( nFormat ) );
1878 #ifndef DISABLE_DYNLOADING
1879 OUString aExternalFilterName(pConfig->GetExternalFilterName(nFormat, true));
1880 #endif
1881 sal_uInt16 nStatus = GRFILTER_OK;
1882 GraphicType eType;
1883 Graphic aGraphic( rGraphic );
1885 aGraphic = ImpGetScaledGraphic( rGraphic, aConfigItem );
1886 eType = aGraphic.GetType();
1888 if( pConfig->IsExportPixelFormat( nFormat ) )
1890 if( eType != GraphicType::Bitmap )
1892 Size aSizePixel;
1893 sal_uLong nColorCount,nBitsPerPixel,nNeededMem,nMaxMem;
1894 ScopedVclPtrInstance< VirtualDevice > aVirDev;
1896 nMaxMem = 1024;
1897 nMaxMem *= 1024; // In Bytes
1899 // Calculate how big the image would normally be:
1900 aSizePixel=aVirDev->LogicToPixel(aGraphic.GetPrefSize(),aGraphic.GetPrefMapMode());
1902 // Calculate how much memory the image will take up
1903 nColorCount=aVirDev->GetColorCount();
1904 if (nColorCount<=2) nBitsPerPixel=1;
1905 else if (nColorCount<=4) nBitsPerPixel=2;
1906 else if (nColorCount<=16) nBitsPerPixel=4;
1907 else if (nColorCount<=256) nBitsPerPixel=8;
1908 else if (nColorCount<=65536) nBitsPerPixel=16;
1909 else nBitsPerPixel=24;
1910 nNeededMem=((sal_uLong)aSizePixel.Width()*(sal_uLong)aSizePixel.Height()*nBitsPerPixel+7)/8;
1912 // is the image larger than available memory?
1913 if (nMaxMem<nNeededMem)
1915 double fFak=sqrt(((double)nMaxMem)/((double)nNeededMem));
1916 aSizePixel.Width()=(sal_uLong)(((double)aSizePixel.Width())*fFak);
1917 aSizePixel.Height()=(sal_uLong)(((double)aSizePixel.Height())*fFak);
1920 aVirDev->SetMapMode(MapMode(MapUnit::MapPixel));
1921 aVirDev->SetOutputSizePixel(aSizePixel);
1922 Graphic aGraphic2=aGraphic;
1923 aGraphic2.Draw(aVirDev.get(),Point(0,0),aSizePixel); // this changes the MapMode
1924 aVirDev->SetMapMode(MapMode(MapUnit::MapPixel));
1925 aGraphic=Graphic(aVirDev->GetBitmap(Point(0,0),aSizePixel));
1928 if( rOStm.GetError() )
1929 nStatus = GRFILTER_IOERROR;
1930 if( GRFILTER_OK == nStatus )
1932 if ( pConfig->IsExportInternalFilter( nFormat ) )
1934 if( aFilterName.equalsIgnoreAsciiCase( EXP_BMP ) )
1936 Bitmap aBmp( aGraphic.GetBitmap() );
1937 BmpConversion nColorRes = (BmpConversion) aConfigItem.ReadInt32( "Colors", 0 );
1938 if ( nColorRes != BmpConversion::NNONE && ( nColorRes <= BmpConversion::N24Bit) )
1940 if( !aBmp.Convert( nColorRes ) )
1941 aBmp = aGraphic.GetBitmap();
1943 bool bRleCoding = aConfigItem.ReadBool( "RLE_Coding", true );
1944 // save RLE encoded?
1945 WriteDIB(aBmp, rOStm, bRleCoding, true);
1947 if( rOStm.GetError() )
1948 nStatus = GRFILTER_IOERROR;
1950 else if( aFilterName.equalsIgnoreAsciiCase( EXP_SVMETAFILE ) )
1952 sal_Int32 nVersion = aConfigItem.ReadInt32( "Version", 0 ) ;
1953 if ( nVersion )
1954 rOStm.SetVersion( nVersion );
1956 // #i119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
1957 GDIMetaFile aMTF(aGraphic.GetGDIMetaFile());
1959 aMTF.Write( rOStm );
1961 if( rOStm.GetError() )
1962 nStatus = GRFILTER_IOERROR;
1964 else if ( aFilterName.equalsIgnoreAsciiCase( EXP_WMF ) )
1966 // #i119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
1967 if ( !ConvertGDIMetaFileToWMF( aGraphic.GetGDIMetaFile(), rOStm, &aConfigItem ) )
1968 nStatus = GRFILTER_FORMATERROR;
1970 if( rOStm.GetError() )
1971 nStatus = GRFILTER_IOERROR;
1973 else if ( aFilterName.equalsIgnoreAsciiCase( EXP_EMF ) )
1975 // #i119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
1976 if ( !ConvertGDIMetaFileToEMF(aGraphic.GetGDIMetaFile(), rOStm))
1977 nStatus = GRFILTER_FORMATERROR;
1979 if( rOStm.GetError() )
1980 nStatus = GRFILTER_IOERROR;
1982 else if( aFilterName.equalsIgnoreAsciiCase( EXP_JPEG ) )
1984 bool bExportedGrayJPEG = false;
1985 if( !ExportJPEG( rOStm, aGraphic, pFilterData, &bExportedGrayJPEG ) )
1986 nStatus = GRFILTER_FORMATERROR;
1987 nExpGraphHint = bExportedGrayJPEG ? GRFILTER_OUTHINT_GREY : 0;
1989 if( rOStm.GetError() )
1990 nStatus = GRFILTER_IOERROR;
1992 else if ( aFilterName.equalsIgnoreAsciiCase( EXP_PNG ) )
1994 vcl::PNGWriter aPNGWriter( aGraphic.GetBitmapEx(), pFilterData );
1995 if ( pFilterData )
1997 sal_Int32 k, j, i = 0;
1998 for ( i = 0; i < pFilterData->getLength(); i++ )
2000 if ( (*pFilterData)[ i ].Name == "AdditionalChunks" )
2002 css::uno::Sequence< css::beans::PropertyValue > aAdditionalChunkSequence;
2003 if ( (*pFilterData)[ i ].Value >>= aAdditionalChunkSequence )
2005 for ( j = 0; j < aAdditionalChunkSequence.getLength(); j++ )
2007 if ( aAdditionalChunkSequence[ j ].Name.getLength() == 4 )
2009 sal_uInt32 nChunkType = 0;
2010 for ( k = 0; k < 4; k++ )
2012 nChunkType <<= 8;
2013 nChunkType |= (sal_uInt8)aAdditionalChunkSequence[ j ].Name[ k ];
2015 css::uno::Sequence< sal_Int8 > aByteSeq;
2016 if ( aAdditionalChunkSequence[ j ].Value >>= aByteSeq )
2018 std::vector< vcl::PNGWriter::ChunkData >& rChunkData = aPNGWriter.GetChunks();
2019 if ( !rChunkData.empty() )
2021 sal_uInt32 nChunkLen = aByteSeq.getLength();
2023 vcl::PNGWriter::ChunkData aChunkData;
2024 aChunkData.nType = nChunkType;
2025 if ( nChunkLen )
2027 aChunkData.aData.resize( nChunkLen );
2028 memcpy( &aChunkData.aData[ 0 ], aByteSeq.getConstArray(), nChunkLen );
2030 std::vector< vcl::PNGWriter::ChunkData >::iterator aIter = rChunkData.end() - 1;
2031 rChunkData.insert( aIter, aChunkData );
2040 aPNGWriter.Write( rOStm );
2042 if( rOStm.GetError() )
2043 nStatus = GRFILTER_IOERROR;
2045 else if( aFilterName.equalsIgnoreAsciiCase( EXP_SVG ) )
2047 bool bDone(false);
2049 // do we have a native SVG RenderGraphic, whose data can be written directly?
2050 const SvgDataPtr& aSvgDataPtr(rGraphic.getSvgData());
2052 if (aSvgDataPtr.get() && aSvgDataPtr->getSvgDataArrayLength())
2054 rOStm.WriteBytes(aSvgDataPtr->getSvgDataArray().getConstArray(), aSvgDataPtr->getSvgDataArrayLength());
2056 if( rOStm.GetError() )
2058 nStatus = GRFILTER_IOERROR;
2060 else
2062 bDone = true;
2066 if( !bDone )
2068 // do the normal GDIMetaFile export instead
2071 css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
2073 css::uno::Reference< css::xml::sax::XDocumentHandler > xSaxWriter(
2074 css::xml::sax::Writer::create( xContext ), css::uno::UNO_QUERY_THROW);
2075 css::uno::Sequence< css::uno::Any > aArguments( 1 );
2076 aArguments[ 0 ] <<= aConfigItem.GetFilterData();
2077 css::uno::Reference< css::svg::XSVGWriter > xSVGWriter(
2078 xContext->getServiceManager()->createInstanceWithArgumentsAndContext( "com.sun.star.svg.SVGWriter", aArguments, xContext),
2079 css::uno::UNO_QUERY );
2080 if( xSaxWriter.is() && xSVGWriter.is() )
2082 css::uno::Reference< css::io::XActiveDataSource > xActiveDataSource(
2083 xSaxWriter, css::uno::UNO_QUERY );
2085 if( xActiveDataSource.is() )
2087 const css::uno::Reference< css::uno::XInterface > xStmIf(
2088 static_cast< ::cppu::OWeakObject* >( new ImpFilterOutputStream( rOStm ) ) );
2090 SvMemoryStream aMemStm( 65535, 65535 );
2092 // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
2093 ( (GDIMetaFile&) aGraphic.GetGDIMetaFile() ).Write( aMemStm );
2095 xActiveDataSource->setOutputStream( css::uno::Reference< css::io::XOutputStream >(
2096 xStmIf, css::uno::UNO_QUERY ) );
2097 css::uno::Sequence< sal_Int8 > aMtfSeq( static_cast<sal_Int8 const *>(aMemStm.GetData()), aMemStm.Tell() );
2098 xSVGWriter->write( xSaxWriter, aMtfSeq );
2102 catch(const css::uno::Exception&)
2104 nStatus = GRFILTER_IOERROR;
2108 else
2109 nStatus = GRFILTER_FILTERERROR;
2111 else
2113 sal_Int32 i, nTokenCount = getTokenCount(aFilterPath, ';');
2114 for ( i = 0; i < nTokenCount; i++ )
2116 #ifndef DISABLE_DYNLOADING
2117 OUString aPhysicalName( ImpCreateFullFilterPath( aFilterPath.getToken(i, ';'), aFilterName ) );
2118 osl::Module aLibrary( aPhysicalName );
2120 PFilterCall pFunc = nullptr;
2121 if (aExternalFilterName == "egi")
2122 pFunc = reinterpret_cast<PFilterCall>(aLibrary.getFunctionSymbol("egiGraphicExport"));
2123 else if (aExternalFilterName == "eps")
2124 pFunc = reinterpret_cast<PFilterCall>(aLibrary.getFunctionSymbol("epsGraphicExport"));
2125 else if (aExternalFilterName == "eti")
2126 pFunc = reinterpret_cast<PFilterCall>(aLibrary.getFunctionSymbol("etiGraphicExport"));
2127 // Execute dialog in DLL
2128 #else
2129 PFilterCall pFunc = NULL;
2130 if (aFilterName == "egi")
2131 pFunc = egiGraphicExport;
2132 else if (aFilterName == "eps")
2133 pFunc = epsGraphicExport;
2134 else if (aFilterName == "eti")
2135 pFunc = etiGraphicExport;
2136 #endif
2137 if( pFunc )
2139 if ( !(*pFunc)( rOStm, aGraphic, &aConfigItem ) )
2140 nStatus = GRFILTER_FORMATERROR;
2141 break;
2143 else
2144 nStatus = GRFILTER_FILTERERROR;
2148 if( nStatus != GRFILTER_OK )
2150 ImplSetError( nStatus, &rOStm );
2152 return nStatus;
2153 #endif
2157 void GraphicFilter::ResetLastError()
2159 pErrorEx->nFilterError = pErrorEx->nStreamError = 0UL;
2162 const Link<ConvertData&,bool> GraphicFilter::GetFilterCallback() const
2164 const Link<ConvertData&,bool> aLink( LINK( const_cast<GraphicFilter*>(this), GraphicFilter, FilterCallback ) );
2165 return aLink;
2168 IMPL_LINK( GraphicFilter, FilterCallback, ConvertData&, rData, bool )
2170 bool bRet = false;
2172 sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
2173 OString aShortName;
2174 switch( rData.mnFormat )
2176 case( ConvertDataFormat::BMP ): aShortName = BMP_SHORTNAME; break;
2177 case( ConvertDataFormat::GIF ): aShortName = GIF_SHORTNAME; break;
2178 case( ConvertDataFormat::JPG ): aShortName = JPG_SHORTNAME; break;
2179 case( ConvertDataFormat::MET ): aShortName = MET_SHORTNAME; break;
2180 case( ConvertDataFormat::PCT ): aShortName = PCT_SHORTNAME; break;
2181 case( ConvertDataFormat::PNG ): aShortName = PNG_SHORTNAME; break;
2182 case( ConvertDataFormat::SVM ): aShortName = SVM_SHORTNAME; break;
2183 case( ConvertDataFormat::TIF ): aShortName = TIF_SHORTNAME; break;
2184 case( ConvertDataFormat::WMF ): aShortName = WMF_SHORTNAME; break;
2185 case( ConvertDataFormat::EMF ): aShortName = EMF_SHORTNAME; break;
2186 case( ConvertDataFormat::SVG ): aShortName = SVG_SHORTNAME; break;
2188 default:
2189 break;
2191 if( GraphicType::NONE == rData.maGraphic.GetType() || rData.maGraphic.GetContext() ) // Import
2193 // Import
2194 nFormat = GetImportFormatNumberForShortName( OStringToOUString( aShortName, RTL_TEXTENCODING_UTF8) );
2195 bRet = ImportGraphic( rData.maGraphic, OUString(), rData.mrStm, nFormat ) == 0;
2197 #ifndef DISABLE_EXPORT
2198 else if( !aShortName.isEmpty() )
2200 // Export
2201 nFormat = GetExportFormatNumberForShortName( OStringToOUString(aShortName, RTL_TEXTENCODING_UTF8) );
2202 bRet = ExportGraphic( rData.maGraphic, OUString(), rData.mrStm, nFormat ) == 0;
2204 #endif
2205 return bRet;
2208 namespace
2210 class StandardGraphicFilter
2212 public:
2213 StandardGraphicFilter()
2215 m_aFilter.GetImportFormatCount();
2217 GraphicFilter m_aFilter;
2220 class theGraphicFilter : public rtl::Static<StandardGraphicFilter, theGraphicFilter> {};
2223 GraphicFilter& GraphicFilter::GetGraphicFilter()
2225 return theGraphicFilter::get().m_aFilter;
2228 int GraphicFilter::LoadGraphic( const OUString &rPath, const OUString &rFilterName,
2229 Graphic& rGraphic, GraphicFilter* pFilter,
2230 sal_uInt16* pDeterminedFormat )
2232 if ( !pFilter )
2233 pFilter = &GetGraphicFilter();
2235 const sal_uInt16 nFilter = !rFilterName.isEmpty() && pFilter->GetImportFormatCount()
2236 ? pFilter->GetImportFormatNumber( rFilterName )
2237 : GRFILTER_FORMAT_DONTKNOW;
2239 INetURLObject aURL( rPath );
2240 if ( aURL.HasError() )
2242 aURL.SetSmartProtocol( INetProtocol::File );
2243 aURL.SetSmartURL( rPath );
2246 SvStream* pStream = nullptr;
2247 if ( INetProtocol::File != aURL.GetProtocol() )
2249 pStream = ::utl::UcbStreamHelper::CreateStream( rPath, StreamMode::READ );
2252 int nRes = GRFILTER_OK;
2253 if ( !pStream )
2254 nRes = pFilter->ImportGraphic( rGraphic, aURL, nFilter, pDeterminedFormat );
2255 else
2256 nRes = pFilter->ImportGraphic( rGraphic, rPath, *pStream, nFilter, pDeterminedFormat );
2258 #ifdef DBG_UTIL
2259 OUString aReturnString;
2261 switch (nRes)
2263 case GRFILTER_OPENERROR:
2264 aReturnString="open error";
2265 break;
2266 case GRFILTER_IOERROR:
2267 aReturnString="IO error";
2268 break;
2269 case GRFILTER_FORMATERROR:
2270 aReturnString="format error";
2271 break;
2272 case GRFILTER_VERSIONERROR:
2273 aReturnString="version error";
2274 break;
2275 case GRFILTER_FILTERERROR:
2276 aReturnString="filter error";
2277 break;
2278 case GRFILTER_ABORT:
2279 aReturnString="import aborted";
2280 break;
2281 case GRFILTER_TOOBIG:
2282 aReturnString="graphic is too big";
2283 break;
2284 default:
2285 // nothing more to do
2286 break;
2289 SAL_INFO_IF( nRes, "vcl.filter", "Problem importing graphic " << rPath << ". Reason: " << aReturnString );
2290 #endif
2292 return nRes;
2295 sal_uInt16 GraphicFilter::compressAsPNG(const Graphic& rGraphic, SvStream& rOutputStream)
2297 css::uno::Sequence< css::beans::PropertyValue > aFilterData(1);
2298 aFilterData[0].Name = "Compression";
2299 aFilterData[0].Value <<= (sal_uInt32) 9;
2301 sal_uInt16 nFilterFormat = GetExportFormatNumberForShortName("PNG");
2302 return ExportGraphic(rGraphic, OUString(), rOutputStream, nFilterFormat, &aFilterData);
2305 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */