Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / source / filter / graphicfilter.cxx
blobefa848b098b6ca5cc4c6a42625984b21dd3ee1a1
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/implbase1.hxx>
27 #include <tools/urlobj.hxx>
28 #include <tools/zcodec.hxx>
29 #include <tools/fract.hxx>
30 #include <vcl/dibtools.hxx>
31 #include <vcl/salctype.hxx>
32 #include <vcl/pngread.hxx>
33 #include <vcl/pngwrite.hxx>
34 #include <vcl/svgdata.hxx>
35 #include <vcl/virdev.hxx>
36 #include <vcl/svapp.hxx>
37 #include <osl/file.hxx>
38 #include <vcl/graphicfilter.hxx>
39 #include <vcl/FilterConfigItem.hxx>
40 #include <vcl/wmf.hxx>
41 #include <vcl/settings.hxx>
42 #include "igif/gifread.hxx"
43 #include "jpeg/jpeg.hxx"
44 #include "ixbm/xbmread.hxx"
45 #include "ixpm/xpmread.hxx"
46 #include "sgffilt.hxx"
47 #include "osl/module.hxx"
48 #include <com/sun/star/uno/Reference.h>
49 #include <com/sun/star/awt/Size.hpp>
50 #include <com/sun/star/uno/XInterface.hpp>
51 #include <com/sun/star/uno/XWeak.hpp>
52 #include <com/sun/star/uno/XAggregation.hpp>
53 #include <com/sun/star/lang/XTypeProvider.hpp>
54 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
55 #include <com/sun/star/io/XActiveDataSource.hpp>
56 #include <com/sun/star/io/XOutputStream.hpp>
57 #include <com/sun/star/svg/XSVGWriter.hpp>
58 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
59 #include <com/sun/star/xml/sax/Writer.hpp>
60 #include <com/sun/star/ucb/CommandAbortedException.hpp>
61 #include <unotools/ucbstreamhelper.hxx>
62 #include <unotools/localfilehelper.hxx>
63 #include <rtl/bootstrap.hxx>
64 #include <rtl/instance.hxx>
65 #include <vcl/metaact.hxx>
66 #include <vector>
67 #include <boost/scoped_array.hpp>
68 #include <memory>
70 #include "FilterConfigCache.hxx"
71 #include "graphicfilter_internal.hxx"
73 #define PMGCHUNG_msOG 0x6d734f47 // Microsoft Office Animated GIF
75 #ifndef DISABLE_DYNLOADING
76 #define IMPORT_FUNCTION_NAME "GraphicImport"
77 #define EXPORT_FUNCTION_NAME "GraphicExport"
78 #endif
80 using namespace ::com::sun::star;
82 using comphelper::string::getTokenCount;
84 typedef ::std::vector< GraphicFilter* > FilterList_impl;
85 static FilterList_impl* pFilterHdlList = NULL;
87 static ::osl::Mutex& getListMutex()
89 static ::osl::Mutex s_aListProtection;
90 return s_aListProtection;
93 class ImpFilterOutputStream : public ::cppu::WeakImplHelper1< css::io::XOutputStream >
95 protected:
97 SvStream& mrStm;
99 virtual void SAL_CALL writeBytes( const css::uno::Sequence< sal_Int8 >& rData )
100 throw (css::io::NotConnectedException, css::io::BufferSizeExceededException, css::io::IOException, css::uno::RuntimeException, std::exception) SAL_OVERRIDE
101 { mrStm.Write( rData.getConstArray(), rData.getLength() ); }
102 virtual void SAL_CALL flush()
103 throw (css::io::NotConnectedException, css::io::BufferSizeExceededException, css::io::IOException, css::uno::RuntimeException, std::exception) SAL_OVERRIDE
104 { mrStm.Flush(); }
105 virtual void SAL_CALL closeOutput() throw(std::exception) SAL_OVERRIDE {}
107 public:
109 ImpFilterOutputStream( SvStream& rStm ) : mrStm( rStm ) {}
110 virtual ~ImpFilterOutputStream() {}
113 #ifndef DISABLE_EXPORT
115 static bool DirEntryExists( const INetURLObject& rObj )
117 bool bExists = false;
121 ::ucbhelper::Content aCnt( rObj.GetMainURL( INetURLObject::NO_DECODE ),
122 css::uno::Reference< css::ucb::XCommandEnvironment >(),
123 comphelper::getProcessComponentContext() );
125 bExists = aCnt.isDocument();
127 catch(const css::ucb::CommandAbortedException&)
129 SAL_WARN( "vcl.filter", "CommandAbortedException" );
131 catch(const css::ucb::ContentCreationException&)
133 SAL_WARN( "vcl.filter", "ContentCreationException" );
135 catch( ... )
137 SAL_WARN( "vcl.filter", "Any other exception" );
139 return bExists;
142 static void KillDirEntry( const OUString& rMainUrl )
146 ::ucbhelper::Content aCnt( rMainUrl,
147 css::uno::Reference< css::ucb::XCommandEnvironment >(),
148 comphelper::getProcessComponentContext() );
150 aCnt.executeCommand( "delete",
151 css::uno::makeAny( true ) );
153 catch(const css::ucb::CommandAbortedException&)
155 SAL_WARN( "vcl.filter", "CommandAbortedException" );
157 catch( ... )
159 SAL_WARN( "vcl.filter", "Any other exception" );
163 #endif // !DISABLE_EXPORT
165 // Helper functions
167 sal_uInt8* ImplSearchEntry( sal_uInt8* pSource, sal_uInt8 const * pDest, sal_uLong nComp, sal_uLong nSize )
169 while ( nComp-- >= nSize )
171 sal_uLong i;
172 for ( i = 0; i < nSize; i++ )
174 if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
175 break;
177 if ( i == nSize )
178 return pSource;
179 pSource++;
181 return NULL;
184 inline OUString ImpGetExtension( const OUString &rPath )
186 OUString aExt;
187 INetURLObject aURL( rPath );
188 aExt = aURL.GetFileExtension().toAsciiUpperCase();
189 return aExt;
192 bool isPCT(SvStream& rStream, sal_uLong nStreamPos, sal_uLong nStreamLen)
194 sal_uInt8 sBuf[3];
195 // store number format
196 SvStreamEndian oldNumberFormat = rStream.GetEndian();
197 sal_uInt32 nOffset; // in MS documents the pict format is used without the first 512 bytes
198 for ( nOffset = 0; ( nOffset <= 512 ) && ( ( nStreamPos + nOffset + 14 ) <= nStreamLen ); nOffset += 512 )
200 short y1,x1,y2,x2;
201 bool bdBoxOk = true;
203 rStream.Seek( nStreamPos + nOffset);
204 // size of the pict in version 1 pict ( 2bytes) : ignored
205 rStream.SeekRel(2);
206 // bounding box (bytes 2 -> 9)
207 rStream.SetEndian(SvStreamEndian::BIG);
208 rStream.ReadInt16( y1 ).ReadInt16( x1 ).ReadInt16( y2 ).ReadInt16( x2 );
209 rStream.SetEndian(oldNumberFormat); // reset format
211 if (x1 > x2 || y1 > y2 || // bad bdbox
212 (x1 == x2 && y1 == y2) || // 1 pixel picture
213 x2-x1 > 2048 || y2-y1 > 2048 ) // picture anormaly big
214 bdBoxOk = false;
216 // read version op
217 rStream.Read( sBuf,3 );
218 // see http://developer.apple.com/legacy/mac/library/documentation/mac/pdf/Imaging_With_QuickDraw/Appendix_A.pdf
219 // normal version 2 - page A23 and A24
220 if ( sBuf[ 0 ] == 0x00 && sBuf[ 1 ] == 0x11 && sBuf[ 2 ] == 0x02)
221 return true;
222 // normal version 1 - page A25
223 else if (sBuf[ 0 ] == 0x11 && sBuf[ 1 ] == 0x01 && bdBoxOk)
224 return true;
226 return false;
229 /*************************************************************************
231 * ImpPeekGraphicFormat()
233 * Description:
234 * This function is two-fold:
235 * 1.) Start reading file, determine the file format:
236 * Input parameters:
237 * rPath - file path
238 * rFormatExtension - content matter
239 * bTest - set false
240 * Output parameters:
241 * Return value - true if success
242 * rFormatExtension - on success: normal file extension in capitals
243 * 2.) Start reading file, verify file format
244 * Input parameters:
245 * rPath - file path
246 * rFormatExtension - normal file extension in capitals
247 * bTest - set true
248 * Output parameters:
249 * Return value - false, if cannot verify the file type
250 * passed to the function
251 * true, when the format is PROBABLY verified or
252 * WHEN THE FORMAT IS NOT KNOWN!
254 *************************************************************************/
256 static bool ImpPeekGraphicFormat( SvStream& rStream, OUString& rFormatExtension, bool bTest )
258 sal_uInt8 sFirstBytes[ 256 ];
259 sal_uLong nFirstLong(0), nSecondLong(0);
260 sal_uLong nStreamPos = rStream.Tell();
262 rStream.Seek( STREAM_SEEK_TO_END );
263 sal_uLong nStreamLen = rStream.Tell() - nStreamPos;
264 rStream.Seek( nStreamPos );
266 if ( !nStreamLen )
268 SvLockBytes* pLockBytes = rStream.GetLockBytes();
269 if ( pLockBytes )
270 pLockBytes->SetSynchronMode( true );
272 rStream.Seek( STREAM_SEEK_TO_END );
273 nStreamLen = rStream.Tell() - nStreamPos;
274 rStream.Seek( nStreamPos );
277 if (!nStreamLen)
279 return false; // this prevents at least a STL assertion
281 else if (nStreamLen >= 256)
283 // load first 256 bytes into a buffer
284 sal_uLong nRead = rStream.Read(sFirstBytes, 256);
285 if (nRead < 256)
286 nStreamLen = nRead;
288 else
290 nStreamLen = rStream.Read(sFirstBytes, nStreamLen);
294 if (rStream.GetError())
295 return false;
297 for (sal_uLong i = nStreamLen; i < 256; ++i)
298 sFirstBytes[i] = 0;
300 // Accommodate the first 8 bytes in nFirstLong, nSecondLong
301 // Big-Endian:
302 for (int i = 0; i < 4; ++i)
304 nFirstLong=(nFirstLong<<8)|(sal_uLong)sFirstBytes[i];
305 nSecondLong=(nSecondLong<<8)|(sal_uLong)sFirstBytes[i+4];
308 // The following variable is used when bTest == true. It remains false
309 // if the format (rFormatExtension) has not yet been set.
310 bool bSomethingTested = false;
312 // Now the different formats are checked. The order *does* matter. e.g. a MET file
313 // could also go through the BMP test, however, a BMP file can hardly go through the MET test.
314 // So MET should be tested prior to BMP. However, theoretically a BMP file could conceivably
315 // go through the MET test. These problems are of course not only in MET and BMP.
316 // Therefore, in the case of a format check (bTest == true) we only test *exactly* this
317 // format. Everything else could have fatal consequences, for example if the user says it is
318 // a BMP file (and it is a BMP) file, and the file would go through the MET test ...
319 //--------------------------- MET ------------------------------------
320 if( !bTest || rFormatExtension.startsWith( "MET" ) )
322 bSomethingTested=true;
323 if( sFirstBytes[2] == 0xd3 )
325 rStream.SetEndian( SvStreamEndian::BIG );
326 rStream.Seek( nStreamPos );
327 sal_uInt16 nFieldSize;
328 sal_uInt8 nMagic;
329 bool bOK=true;
330 rStream.ReadUInt16( nFieldSize ).ReadUChar( nMagic );
331 for (int i=0; i<3; i++) {
332 if (nFieldSize<6) { bOK=false; break; }
333 if (nStreamLen < rStream.Tell() + nFieldSize ) { bOK=false; break; }
334 rStream.SeekRel(nFieldSize-3);
335 rStream.ReadUInt16( nFieldSize ).ReadUChar( nMagic );
336 if (nMagic!=0xd3) { bOK=false; break; }
338 rStream.SetEndian( SvStreamEndian::LITTLE );
339 if (bOK && !rStream.GetError()) {
340 rFormatExtension = "MET";
341 return true;
346 //--------------------------- BMP ------------------------------------
347 if( !bTest || rFormatExtension.startsWith( "BMP" ) )
349 sal_uInt8 nOffs;
351 bSomethingTested=true;
353 // We're possibly also able to read an OS/2 bitmap array
354 // ('BA'), therefore we must adjust the offset to discover the
355 // first bitmap in the array
356 if ( sFirstBytes[0] == 0x42 && sFirstBytes[1] == 0x41 )
357 nOffs = 14;
358 else
359 nOffs = 0;
361 // Now we initially test on 'BM'
362 if ( sFirstBytes[0+nOffs]==0x42 && sFirstBytes[1+nOffs]==0x4d )
365 // OS/2 can set the Reserved flags to a value other than 0
366 // (which they really should not do...);
367 // In this case we test the size of the BmpInfoHeaders
368 if ( ( sFirstBytes[6+nOffs]==0x00 &&
369 sFirstBytes[7+nOffs]==0x00 &&
370 sFirstBytes[8+nOffs]==0x00 &&
371 sFirstBytes[9+nOffs]==0x00 ) ||
372 sFirstBytes[14+nOffs] == 0x28 ||
373 sFirstBytes[14+nOffs] == 0x0c )
375 rFormatExtension = "BMP";
376 return true;
381 //--------------------------- WMF/EMF ------------------------------------
383 if( !bTest ||
384 rFormatExtension.startsWith( "WMF" ) ||
385 rFormatExtension.startsWith( "EMF" ) )
387 bSomethingTested = true;
389 if ( nFirstLong==0xd7cdc69a || nFirstLong==0x01000900 )
391 rFormatExtension = "WMF";
392 return true;
394 else if( nFirstLong == 0x01000000 && sFirstBytes[ 40 ] == 0x20 && sFirstBytes[ 41 ] == 0x45 &&
395 sFirstBytes[ 42 ] == 0x4d && sFirstBytes[ 43 ] == 0x46 )
397 rFormatExtension = "EMF";
398 return true;
402 //--------------------------- PCX ------------------------------------
403 if( !bTest || rFormatExtension.startsWith( "PCX" ) )
405 bSomethingTested=true;
406 if (sFirstBytes[0]==0x0a)
408 sal_uInt8 nVersion=sFirstBytes[1];
409 sal_uInt8 nEncoding=sFirstBytes[2];
410 if( ( nVersion==0 || nVersion==2 || nVersion==3 || nVersion==5 ) && nEncoding<=1 )
412 rFormatExtension = "PCX";
413 return true;
418 //--------------------------- TIF ------------------------------------
419 if( !bTest || rFormatExtension.startsWith( "TIF" ) )
421 bSomethingTested=true;
422 if ( nFirstLong==0x49492a00 || nFirstLong==0x4d4d002a )
424 rFormatExtension = "TIF";
425 return true;
429 //--------------------------- GIF ------------------------------------
430 if( !bTest || rFormatExtension.startsWith( "GIF" ) )
432 bSomethingTested=true;
433 if ( nFirstLong==0x47494638 && (sFirstBytes[4]==0x37 || sFirstBytes[4]==0x39) && sFirstBytes[5]==0x61 )
435 rFormatExtension = "GIF";
436 return true;
440 //--------------------------- PNG ------------------------------------
441 if( !bTest || rFormatExtension.startsWith( "PNG" ) )
443 bSomethingTested=true;
444 if (nFirstLong==0x89504e47 && nSecondLong==0x0d0a1a0a)
446 rFormatExtension = "PNG";
447 return true;
451 //--------------------------- JPG ------------------------------------
452 if( !bTest || rFormatExtension.startsWith( "JPG" ) )
454 bSomethingTested=true;
455 if ( ( nFirstLong==0xffd8ffe0 && sFirstBytes[6]==0x4a && sFirstBytes[7]==0x46 && sFirstBytes[8]==0x49 && sFirstBytes[9]==0x46 ) ||
456 ( nFirstLong==0xffd8fffe ) || ( 0xffd8ff00 == ( nFirstLong & 0xffffff00 ) ) )
458 rFormatExtension = "JPG";
459 return true;
463 //--------------------------- SVM ------------------------------------
464 if( !bTest || rFormatExtension.startsWith( "SVM" ) )
466 bSomethingTested=true;
467 if( nFirstLong==0x53564744 && sFirstBytes[4]==0x49 )
469 rFormatExtension = "SVM";
470 return true;
472 else if( sFirstBytes[0]==0x56 && sFirstBytes[1]==0x43 && sFirstBytes[2]==0x4C &&
473 sFirstBytes[3]==0x4D && sFirstBytes[4]==0x54 && sFirstBytes[5]==0x46 )
475 rFormatExtension = "SVM";
476 return true;
480 //--------------------------- PCD ------------------------------------
481 if( !bTest || rFormatExtension.startsWith( "PCD" ) )
483 bSomethingTested = true;
484 if( nStreamLen >= 2055 )
486 char sBuf[8];
487 rStream.Seek( nStreamPos + 2048 );
488 rStream.Read( sBuf, 7 );
490 if( strncmp( sBuf, "PCD_IPI", 7 ) == 0 )
492 rFormatExtension = "PCD";
493 return true;
498 //--------------------------- PSD ------------------------------------
499 if( !bTest || rFormatExtension.startsWith( "PSD" ) )
501 bSomethingTested = true;
502 if ( ( nFirstLong == 0x38425053 ) && ( (nSecondLong >> 16 ) == 1 ) )
504 rFormatExtension = "PSD";
505 return true;
509 //--------------------------- EPS ------------------------------------
510 if( !bTest || rFormatExtension.startsWith( "EPS" ) )
512 bSomethingTested = true;
513 if ( ( nFirstLong == 0xC5D0D3C6 ) || ( ImplSearchEntry( sFirstBytes, reinterpret_cast<sal_uInt8 const *>("%!PS-Adobe"), 10, 10 ) &&
514 ImplSearchEntry( &sFirstBytes[15], reinterpret_cast<sal_uInt8 const *>("EPS"), 3, 3 ) ) )
516 rFormatExtension = "EPS";
517 return true;
521 //--------------------------- DXF ------------------------------------
522 if( !bTest || rFormatExtension.startsWith( "DXF" ) )
524 // Binary DXF File Format
525 if( strncmp( reinterpret_cast<char*>(sFirstBytes), "AutoCAD Binary DXF", 18 ) == 0 )
527 rFormatExtension = "DXF";
528 return true;
531 // ASCII DXF File Format
532 int i=0;
533 while (i<256 && sFirstBytes[i]<=32)
534 ++i;
536 if (i<256 && sFirstBytes[i]=='0')
538 ++i;
540 // only now do we have sufficient data to make a judgement
541 // based on a '0' + 'SECTION' == DXF argument
542 bSomethingTested=true;
544 while( i<256 && sFirstBytes[i]<=32 )
545 ++i;
547 if (i+7<256 && (strncmp(reinterpret_cast<char*>(sFirstBytes+i),"SECTION",7)==0))
549 rFormatExtension = "DXF";
550 return true;
556 //--------------------------- PCT ------------------------------------
557 if( !bTest || rFormatExtension.startsWith( "PCT" ) )
559 bSomethingTested = true;
560 if (isPCT(rStream, nStreamPos, nStreamLen))
562 rFormatExtension = "PCT";
563 return true;
567 //------------------------- PBM + PGM + PPM ---------------------------
568 if( !bTest ||
569 rFormatExtension.startsWith( "PBM" ) ||
570 rFormatExtension.startsWith( "PGM" ) ||
571 rFormatExtension.startsWith( "PPM" ) )
573 bSomethingTested=true;
574 if ( sFirstBytes[ 0 ] == 'P' )
576 switch( sFirstBytes[ 1 ] )
578 case '1' :
579 case '4' :
580 rFormatExtension = "PBM";
581 return true;
583 case '2' :
584 case '5' :
585 rFormatExtension = "PGM";
586 return true;
588 case '3' :
589 case '6' :
590 rFormatExtension = "PPM";
591 return true;
596 //--------------------------- RAS( SUN RasterFile )------------------
597 if( !bTest || rFormatExtension.startsWith( "RAS" ) )
599 bSomethingTested=true;
600 if( nFirstLong == 0x59a66a95 )
602 rFormatExtension = "RAS";
603 return true;
607 //--------------------------- XPM ------------------------------------
608 if( !bTest )
610 bSomethingTested = true;
611 if( ImplSearchEntry( sFirstBytes, reinterpret_cast<sal_uInt8 const *>("/* XPM */"), 256, 9 ) )
613 rFormatExtension = "XPM";
614 return true;
617 else if( rFormatExtension.startsWith( "XPM" ) )
619 bSomethingTested = true;
620 return true;
623 //--------------------------- XBM ------------------------------------
624 if( !bTest )
626 sal_uLong nSize = ( nStreamLen > 2048 ) ? 2048 : nStreamLen;
627 boost::scoped_array<sal_uInt8> pBuf(new sal_uInt8 [ nSize ]);
629 rStream.Seek( nStreamPos );
630 rStream.Read( pBuf.get(), nSize );
631 sal_uInt8* pPtr = ImplSearchEntry( pBuf.get(), reinterpret_cast<sal_uInt8 const *>("#define"), nSize, 7 );
633 if( pPtr )
635 if( ImplSearchEntry( pPtr, reinterpret_cast<sal_uInt8 const *>("_width"), pBuf.get() + nSize - pPtr, 6 ) )
637 rFormatExtension = "XBM";
638 return true;
642 else if( rFormatExtension.startsWith( "XBM" ) )
644 bSomethingTested = true;
645 return true;
648 //--------------------------- SVG ------------------------------------
649 if( !bTest )
651 sal_uInt8* pCheckArray = sFirstBytes;
652 sal_uLong nCheckSize = nStreamLen < 256 ? nStreamLen : 256;
654 sal_uInt8 sExtendedOrDecompressedFirstBytes[2048];
655 sal_uLong nDecompressedSize = nCheckSize;
657 bool bIsGZip(false);
659 // check if it is gzipped -> svgz
660 if(sFirstBytes[0] == 0x1F && sFirstBytes[1] == 0x8B)
662 ZCodec aCodec;
663 rStream.Seek(nStreamPos);
664 aCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, false, true);
665 nDecompressedSize = aCodec.Read(rStream, sExtendedOrDecompressedFirstBytes, 2048);
666 nCheckSize = nDecompressedSize < 256 ? nDecompressedSize : 256;
667 aCodec.EndCompression();
668 pCheckArray = sExtendedOrDecompressedFirstBytes;
670 bIsGZip = true;
673 bool bIsSvg(false);
675 // check for Xml
676 // #119176# SVG files which have no xml header at all have shown up this is optional
677 if( ImplSearchEntry(pCheckArray, reinterpret_cast<sal_uInt8 const *>("<?xml"), nCheckSize, 5 ) // is it xml
678 && ImplSearchEntry(pCheckArray, reinterpret_cast<sal_uInt8 const *>("version"), nCheckSize, 7 )) // does it have a version (required for xml)
681 // check for DOCTYPE svg combination
682 if( ImplSearchEntry(pCheckArray, reinterpret_cast<sal_uInt8 const *>("DOCTYPE"), nCheckSize, 7 ) // 'DOCTYPE' is there
683 && ImplSearchEntry(pCheckArray, reinterpret_cast<sal_uInt8 const *>("svg"), nCheckSize, 3 )) // 'svg' is there
685 bIsSvg = true;
689 // check for svg element in 1st 256 bytes
690 if(!bIsSvg && ImplSearchEntry(pCheckArray, reinterpret_cast<sal_uInt8 const *>("<svg"), nCheckSize, 4 )) // '<svg'
692 bIsSvg = true;
695 // extended search for svg element
696 if(!bIsSvg)
698 // it's a xml, look for '<svg' in full file. Should not happen too
699 // often since the tests above will handle most cases, but can happen
700 // with Svg files containing big comment headers or Svg as the host
701 // language
703 pCheckArray = sExtendedOrDecompressedFirstBytes;
705 if (bIsGZip)
707 nCheckSize = nDecompressedSize < 2048 ? nDecompressedSize : 2048;
709 else
711 nCheckSize = nStreamLen < 2048 ? nStreamLen : 2048;
712 rStream.Seek(nStreamPos);
713 nCheckSize = rStream.Read(sExtendedOrDecompressedFirstBytes, nCheckSize);
716 if(ImplSearchEntry(pCheckArray, reinterpret_cast<sal_uInt8 const *>("<svg"), nCheckSize, 4)) // '<svg'
718 bIsSvg = true;
722 if(bIsSvg)
724 rFormatExtension = "SVG";
725 return true;
728 else if( rFormatExtension.startsWith( "SVG" ) )
730 bSomethingTested = true;
731 return true;
734 //--------------------------- TGA ------------------------------------
735 if( !bTest || rFormatExtension.startsWith( "TGA" ) )
737 bSomethingTested = true;
739 // just a simple test for the extension
740 if( rFormatExtension.startsWith( "TGA" ) )
741 return true;
744 //--------------------------- SGV ------------------------------------
745 if( !bTest || rFormatExtension.startsWith( "SGV" ) )
747 bSomethingTested = true;
749 // just a simple test for the extension
750 if( rFormatExtension.startsWith( "SGV" ) )
751 return true;
754 //--------------------------- SGF ------------------------------------
755 if( !bTest || rFormatExtension.startsWith( "SGF" ) )
757 bSomethingTested=true;
758 if( sFirstBytes[ 0 ] == 'J' && sFirstBytes[ 1 ] == 'J' )
760 rFormatExtension = "SGF";
761 return true;
765 if(!bTest || rFormatExtension.startsWith( "MOV" ))
767 if ((sFirstBytes[ 4 ] == 'f' && sFirstBytes[ 5 ] == 't' && sFirstBytes[ 6 ] == 'y' &&
768 sFirstBytes[ 7 ] == 'p' && sFirstBytes[ 8 ] == 'q' && sFirstBytes[ 9 ] == 't') ||
769 (sFirstBytes[ 4 ] == 'm' && sFirstBytes[ 5 ] == 'o' && sFirstBytes[ 6 ] == 'o' &&
770 sFirstBytes[ 7 ] == 'v' && sFirstBytes[ 11 ] == 'l' && sFirstBytes[ 12 ] == 'm'))
772 bSomethingTested=true;
773 rFormatExtension = "MOV";
774 return true;
778 return bTest && !bSomethingTested;
781 sal_uInt16 GraphicFilter::ImpTestOrFindFormat( const OUString& rPath, SvStream& rStream, sal_uInt16& rFormat )
783 // determine or check the filter/format by reading into it
784 if( rFormat == GRFILTER_FORMAT_DONTKNOW )
786 OUString aFormatExt;
787 if( ImpPeekGraphicFormat( rStream, aFormatExt, false ) )
789 rFormat = pConfig->GetImportFormatNumberForExtension( aFormatExt );
790 if( rFormat != GRFILTER_FORMAT_DONTKNOW )
791 return GRFILTER_OK;
793 // determine filter by file extension
794 if( !rPath.isEmpty() )
796 OUString aExt( ImpGetExtension( rPath ) );
797 rFormat = pConfig->GetImportFormatNumberForExtension( aExt );
798 if( rFormat != GRFILTER_FORMAT_DONTKNOW )
799 return GRFILTER_OK;
801 return GRFILTER_FORMATERROR;
803 else
805 OUString aTmpStr( pConfig->GetImportFormatExtension( rFormat ) );
806 aTmpStr = aTmpStr.toAsciiUpperCase();
807 if( !ImpPeekGraphicFormat( rStream, aTmpStr, true ) )
808 return GRFILTER_FORMATERROR;
809 if ( pConfig->GetImportFormatExtension( rFormat ).equalsIgnoreAsciiCase( "pcd" ) )
811 sal_Int32 nBase = 2; // default Base0
812 if ( pConfig->GetImportFilterType( rFormat ).equalsIgnoreAsciiCase( "pcd_Photo_CD_Base4" ) )
813 nBase = 1;
814 else if ( pConfig->GetImportFilterType( rFormat ).equalsIgnoreAsciiCase( "pcd_Photo_CD_Base16" ) )
815 nBase = 0;
816 OUString aFilterConfigPath( "Office.Common/Filter/Graphic/Import/PCD" );
817 FilterConfigItem aFilterConfigItem( aFilterConfigPath );
818 aFilterConfigItem.WriteInt32( "Resolution", nBase );
822 return GRFILTER_OK;
825 #ifndef DISABLE_EXPORT
827 static Graphic ImpGetScaledGraphic( const Graphic& rGraphic, FilterConfigItem& rConfigItem )
829 Graphic aGraphic;
831 std::unique_ptr<ResMgr> xResMgr(ResMgr::CreateResMgr( "svt", Application::GetSettings().GetUILanguageTag() ));
833 sal_Int32 nLogicalWidth = rConfigItem.ReadInt32( "LogicalWidth", 0 );
834 sal_Int32 nLogicalHeight = rConfigItem.ReadInt32( "LogicalHeight", 0 );
836 if ( rGraphic.GetType() != GRAPHIC_NONE )
838 sal_Int32 nMode = rConfigItem.ReadInt32( "ExportMode", -1 );
840 if ( nMode == -1 ) // the property is not there, this is possible, if the graphic filter
841 { // is called via UnoGraphicExporter and not from a graphic export Dialog
842 nMode = 0; // then we are defaulting this mode to 0
843 if ( nLogicalWidth || nLogicalHeight )
844 nMode = 2;
847 Size aOriginalSize;
848 Size aPrefSize( rGraphic.GetPrefSize() );
849 MapMode aPrefMapMode( rGraphic.GetPrefMapMode() );
850 if ( aPrefMapMode == MAP_PIXEL )
851 aOriginalSize = Application::GetDefaultDevice()->PixelToLogic( aPrefSize, MAP_100TH_MM );
852 else
853 aOriginalSize = OutputDevice::LogicToLogic( aPrefSize, aPrefMapMode, MAP_100TH_MM );
854 if ( !nLogicalWidth )
855 nLogicalWidth = aOriginalSize.Width();
856 if ( !nLogicalHeight )
857 nLogicalHeight = aOriginalSize.Height();
858 if( rGraphic.GetType() == GRAPHIC_BITMAP )
861 // Resolution is set
862 if( nMode == 1 )
864 Bitmap aBitmap( rGraphic.GetBitmap() );
865 MapMode aMap( MAP_100TH_INCH );
867 sal_Int32 nDPI = rConfigItem.ReadInt32( "Resolution", 75 );
868 Fraction aFrac( 1, std::min( std::max( nDPI, sal_Int32( 75 ) ), sal_Int32( 600 ) ) );
870 aMap.SetScaleX( aFrac );
871 aMap.SetScaleY( aFrac );
873 Size aOldSize = aBitmap.GetSizePixel();
874 aGraphic = rGraphic;
875 aGraphic.SetPrefMapMode( aMap );
876 aGraphic.SetPrefSize( Size( aOldSize.Width() * 100,
877 aOldSize.Height() * 100 ) );
879 // Size is set
880 else if( nMode == 2 )
882 aGraphic = rGraphic;
883 aGraphic.SetPrefMapMode( MapMode( MAP_100TH_MM ) );
884 aGraphic.SetPrefSize( Size( nLogicalWidth, nLogicalHeight ) );
886 else
887 aGraphic = rGraphic;
889 sal_Int32 nColors = rConfigItem.ReadInt32( "Color", 0 ); // #92767#
890 if ( nColors ) // graphic conversion necessary ?
892 BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
893 aBmpEx.Convert( (BmpConversion)nColors ); // the entries in the xml section have the same meaning as
894 aGraphic = aBmpEx; // they have in the BmpConversion enum, so it should be
895 } // allowed to cast them
897 else
899 if( ( nMode == 1 ) || ( nMode == 2 ) )
901 GDIMetaFile aMtf( rGraphic.GetGDIMetaFile() );
902 css::awt::Size aDefaultSize( 10000, 10000 );
903 Size aNewSize( OutputDevice::LogicToLogic( Size( nLogicalWidth, nLogicalHeight ), MAP_100TH_MM, aMtf.GetPrefMapMode() ) );
905 if( aNewSize.Width() && aNewSize.Height() )
907 const Size aPreferredSize( aMtf.GetPrefSize() );
908 aMtf.Scale( Fraction( aNewSize.Width(), aPreferredSize.Width() ),
909 Fraction( aNewSize.Height(), aPreferredSize.Height() ) );
911 aGraphic = Graphic( aMtf );
913 else
914 aGraphic = rGraphic;
918 else
919 aGraphic = rGraphic;
921 return aGraphic;
924 #endif
926 static OUString ImpCreateFullFilterPath( const OUString& rPath, const OUString& rFilterName )
928 OUString aPathURL;
930 ::osl::FileBase::getFileURLFromSystemPath( rPath, aPathURL );
931 aPathURL += "/";
933 OUString aSystemPath;
934 ::osl::FileBase::getSystemPathFromFileURL( aPathURL, aSystemPath );
935 aSystemPath += rFilterName;
937 return OUString( aSystemPath );
940 class ImpFilterLibCache;
942 struct ImpFilterLibCacheEntry
944 ImpFilterLibCacheEntry* mpNext;
945 #ifndef DISABLE_DYNLOADING
946 osl::Module maLibrary;
947 #endif
948 OUString maFiltername;
949 PFilterCall mpfnImport;
951 ImpFilterLibCacheEntry( const OUString& rPathname, const OUString& rFiltername );
952 bool operator==( const OUString& rFiltername ) const { return maFiltername == rFiltername; }
954 PFilterCall GetImportFunction();
957 ImpFilterLibCacheEntry::ImpFilterLibCacheEntry( const OUString& rPathname, const OUString& rFiltername ) :
958 mpNext ( NULL ),
959 #ifndef DISABLE_DYNLOADING
960 maLibrary ( rPathname ),
961 #endif
962 maFiltername ( rFiltername ),
963 mpfnImport ( NULL )
965 #ifdef DISABLE_DYNLOADING
966 (void) rPathname;
967 #endif
970 #ifdef DISABLE_DYNLOADING
972 extern "C" bool icdGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
973 extern "C" bool idxGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
974 extern "C" bool imeGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
975 extern "C" bool ipbGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
976 extern "C" bool ipdGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
977 extern "C" bool ipsGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
978 extern "C" bool iptGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
979 extern "C" bool ipxGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
980 extern "C" bool iraGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
981 extern "C" bool itgGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
982 extern "C" bool itiGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
984 #endif
986 PFilterCall ImpFilterLibCacheEntry::GetImportFunction()
988 if( !mpfnImport )
990 #ifndef DISABLE_DYNLOADING
991 mpfnImport = reinterpret_cast<PFilterCall>(maLibrary.getFunctionSymbol(OUString(IMPORT_FUNCTION_NAME)));
992 #else
993 if( maFiltername.equalsAscii( "icd" ) )
994 mpfnImport = icdGraphicImport;
995 else if( maFiltername.equalsAscii( "idx" ) )
996 mpfnImport = idxGraphicImport;
997 else if( maFiltername.equalsAscii( "ime" ) )
998 mpfnImport = imeGraphicImport;
999 else if( maFiltername.equalsAscii( "ipb" ) )
1000 mpfnImport = ipbGraphicImport;
1001 else if( maFiltername.equalsAscii( "ipd" ) )
1002 mpfnImport = ipdGraphicImport;
1003 else if( maFiltername.equalsAscii( "ips" ) )
1004 mpfnImport = ipsGraphicImport;
1005 else if( maFiltername.equalsAscii( "ipt" ) )
1006 mpfnImport = iptGraphicImport;
1007 else if( maFiltername.equalsAscii( "ipx" ) )
1008 mpfnImport = ipxGraphicImport;
1009 else if( maFiltername.equalsAscii( "ira" ) )
1010 mpfnImport = iraGraphicImport;
1011 else if( maFiltername.equalsAscii( "itg" ) )
1012 mpfnImport = itgGraphicImport;
1013 else if( maFiltername.equalsAscii( "iti" ) )
1014 mpfnImport = itiGraphicImport;
1015 #endif
1018 return mpfnImport;
1021 class ImpFilterLibCache
1023 ImpFilterLibCacheEntry* mpFirst;
1024 ImpFilterLibCacheEntry* mpLast;
1026 public:
1027 ImpFilterLibCache();
1028 ~ImpFilterLibCache();
1030 ImpFilterLibCacheEntry* GetFilter( const OUString& rFilterPath, const OUString& rFiltername );
1033 ImpFilterLibCache::ImpFilterLibCache() :
1034 mpFirst ( NULL ),
1035 mpLast ( NULL )
1039 ImpFilterLibCache::~ImpFilterLibCache()
1041 ImpFilterLibCacheEntry* pEntry = mpFirst;
1042 while( pEntry )
1044 ImpFilterLibCacheEntry* pNext = pEntry->mpNext;
1045 delete pEntry;
1046 pEntry = pNext;
1050 ImpFilterLibCacheEntry* ImpFilterLibCache::GetFilter( const OUString& rFilterPath, const OUString& rFilterName )
1052 ImpFilterLibCacheEntry* pEntry = mpFirst;
1054 while( pEntry )
1056 if( *pEntry == rFilterName )
1057 break;
1058 else
1059 pEntry = pEntry->mpNext;
1061 if( !pEntry )
1063 OUString aPhysicalName( ImpCreateFullFilterPath( rFilterPath, rFilterName ) );
1064 pEntry = new ImpFilterLibCacheEntry( aPhysicalName, rFilterName );
1065 #ifndef DISABLE_DYNLOADING
1066 if ( pEntry->maLibrary.is() )
1067 #endif
1069 if( !mpFirst )
1070 mpFirst = mpLast = pEntry;
1071 else
1072 mpLast = mpLast->mpNext = pEntry;
1074 #ifndef DISABLE_DYNLOADING
1075 else
1077 delete pEntry;
1078 pEntry = NULL;
1080 #endif
1082 return pEntry;
1085 namespace { struct Cache : public rtl::Static<ImpFilterLibCache, Cache> {}; }
1087 GraphicFilter::GraphicFilter( bool bConfig )
1088 : pErrorEx(NULL)
1089 , bUseConfig(bConfig)
1090 , nExpGraphHint(0)
1092 ImplInit();
1095 GraphicFilter::~GraphicFilter()
1098 ::osl::MutexGuard aGuard( getListMutex() );
1099 for(
1100 FilterList_impl::iterator it = pFilterHdlList->begin();
1101 it != pFilterHdlList->end();
1102 ++it
1104 if( *it == this )
1106 pFilterHdlList->erase( it );
1107 break;
1110 if( pFilterHdlList->empty() )
1112 delete pFilterHdlList, pFilterHdlList = NULL;
1113 delete pConfig;
1117 delete pErrorEx;
1120 void GraphicFilter::ImplInit()
1123 ::osl::MutexGuard aGuard( getListMutex() );
1125 if ( !pFilterHdlList )
1127 pFilterHdlList = new FilterList_impl;
1128 pConfig = new FilterConfigCache( bUseConfig );
1130 else
1131 pConfig = pFilterHdlList->front()->pConfig;
1133 pFilterHdlList->push_back( this );
1136 if( bUseConfig )
1138 OUString url("$BRAND_BASE_DIR/" LIBO_LIB_FOLDER);
1139 rtl::Bootstrap::expandMacros(url); //TODO: detect failure
1140 utl::LocalFileHelper::ConvertURLToPhysicalName(url, aFilterPath);
1143 pErrorEx = new FilterErrorEx;
1144 bAbort = false;
1147 sal_uLong GraphicFilter::ImplSetError( sal_uLong nError, const SvStream* pStm )
1149 pErrorEx->nFilterError = nError;
1150 pErrorEx->nStreamError = pStm ? pStm->GetError() : ERRCODE_NONE;
1151 return nError;
1154 sal_uInt16 GraphicFilter::GetImportFormatCount()
1156 return pConfig->GetImportFormatCount();
1159 sal_uInt16 GraphicFilter::GetImportFormatNumber( const OUString& rFormatName )
1161 return pConfig->GetImportFormatNumber( rFormatName );
1164 sal_uInt16 GraphicFilter::GetImportFormatNumberForMediaType( const OUString& rMediaType )
1166 return pConfig->GetImportFormatNumberForMediaType( rMediaType );
1169 sal_uInt16 GraphicFilter::GetImportFormatNumberForShortName( const OUString& rShortName )
1171 return pConfig->GetImportFormatNumberForShortName( rShortName );
1174 sal_uInt16 GraphicFilter::GetImportFormatNumberForTypeName( const OUString& rType )
1176 return pConfig->GetImportFormatNumberForTypeName( rType );
1179 OUString GraphicFilter::GetImportFormatName( sal_uInt16 nFormat )
1181 return pConfig->GetImportFormatName( nFormat );
1184 OUString GraphicFilter::GetImportFormatTypeName( sal_uInt16 nFormat )
1186 return pConfig->GetImportFilterTypeName( nFormat );
1189 OUString GraphicFilter::GetImportFormatMediaType( sal_uInt16 nFormat )
1191 return pConfig->GetImportFormatMediaType( nFormat );
1194 OUString GraphicFilter::GetImportFormatShortName( sal_uInt16 nFormat )
1196 return pConfig->GetImportFormatShortName( nFormat );
1199 OUString GraphicFilter::GetImportOSFileType( sal_uInt16 )
1201 OUString aOSFileType;
1202 return aOSFileType;
1205 OUString GraphicFilter::GetImportWildcard( sal_uInt16 nFormat, sal_Int32 nEntry )
1207 return pConfig->GetImportWildcard( nFormat, nEntry );
1210 bool GraphicFilter::IsImportPixelFormat( sal_uInt16 nFormat )
1212 return pConfig->IsImportPixelFormat( nFormat );
1215 sal_uInt16 GraphicFilter::GetExportFormatCount()
1217 return pConfig->GetExportFormatCount();
1220 sal_uInt16 GraphicFilter::GetExportFormatNumber( const OUString& rFormatName )
1222 return pConfig->GetExportFormatNumber( rFormatName );
1225 sal_uInt16 GraphicFilter::GetExportFormatNumberForMediaType( const OUString& rMediaType )
1227 return pConfig->GetExportFormatNumberForMediaType( rMediaType );
1230 sal_uInt16 GraphicFilter::GetExportFormatNumberForShortName( const OUString& rShortName )
1232 return pConfig->GetExportFormatNumberForShortName( rShortName );
1235 OUString GraphicFilter::GetExportInternalFilterName( sal_uInt16 nFormat )
1237 return pConfig->GetExportInternalFilterName( nFormat );
1240 sal_uInt16 GraphicFilter::GetExportFormatNumberForTypeName( const OUString& rType )
1242 return pConfig->GetExportFormatNumberForTypeName( rType );
1245 OUString GraphicFilter::GetExportFormatName( sal_uInt16 nFormat )
1247 return pConfig->GetExportFormatName( nFormat );
1250 OUString GraphicFilter::GetExportFormatTypeName( sal_uInt16 nFormat )
1252 return pConfig->GetExportFilterTypeName( nFormat );
1255 OUString GraphicFilter::GetExportFormatMediaType( sal_uInt16 nFormat )
1257 return pConfig->GetExportFormatMediaType( nFormat );
1260 OUString GraphicFilter::GetExportFormatShortName( sal_uInt16 nFormat )
1262 return pConfig->GetExportFormatShortName( nFormat );
1265 OUString GraphicFilter::GetExportOSFileType( sal_uInt16 )
1267 OUString aOSFileType;
1268 return aOSFileType;
1271 OUString GraphicFilter::GetExportWildcard( sal_uInt16 nFormat, sal_Int32 nEntry )
1273 return pConfig->GetExportWildcard( nFormat, nEntry );
1276 bool GraphicFilter::IsExportPixelFormat( sal_uInt16 nFormat )
1278 return pConfig->IsExportPixelFormat( nFormat );
1281 sal_uInt16 GraphicFilter::CanImportGraphic( const INetURLObject& rPath,
1282 sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat )
1284 sal_uInt16 nRetValue = GRFILTER_FORMATERROR;
1285 DBG_ASSERT( rPath.GetProtocol() != INetProtocol::NotValid, "GraphicFilter::CanImportGraphic() : ProtType == INetProtocol::NotValid" );
1287 OUString aMainUrl( rPath.GetMainURL( INetURLObject::NO_DECODE ) );
1288 std::unique_ptr<SvStream> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl, StreamMode::READ | StreamMode::SHARE_DENYNONE ));
1289 if (xStream)
1291 nRetValue = CanImportGraphic( aMainUrl, *xStream, nFormat, pDeterminedFormat );
1293 return nRetValue;
1296 sal_uInt16 GraphicFilter::CanImportGraphic( const OUString& rMainUrl, SvStream& rIStream,
1297 sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat )
1299 sal_uLong nStreamPos = rIStream.Tell();
1300 sal_uInt16 nRes = ImpTestOrFindFormat( rMainUrl, rIStream, nFormat );
1302 rIStream.Seek(nStreamPos);
1304 if( nRes==GRFILTER_OK && pDeterminedFormat!=NULL )
1305 *pDeterminedFormat = nFormat;
1307 return (sal_uInt16) ImplSetError( nRes, &rIStream );
1310 //SJ: TODO, we need to create a GraphicImporter component
1311 sal_uInt16 GraphicFilter::ImportGraphic( Graphic& rGraphic, const INetURLObject& rPath,
1312 sal_uInt16 nFormat, sal_uInt16 * pDeterminedFormat, GraphicFilterImportFlags nImportFlags )
1314 sal_uInt16 nRetValue = GRFILTER_FORMATERROR;
1315 DBG_ASSERT( rPath.GetProtocol() != INetProtocol::NotValid, "GraphicFilter::ImportGraphic() : ProtType == INetProtocol::NotValid" );
1317 OUString aMainUrl( rPath.GetMainURL( INetURLObject::NO_DECODE ) );
1318 std::unique_ptr<SvStream> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl, StreamMode::READ | StreamMode::SHARE_DENYNONE ));
1319 if (xStream)
1321 nRetValue = ImportGraphic( rGraphic, aMainUrl, *xStream, nFormat, pDeterminedFormat, nImportFlags );
1323 return nRetValue;
1326 sal_uInt16 GraphicFilter::ImportGraphic( Graphic& rGraphic, const OUString& rPath, SvStream& rIStream,
1327 sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat, GraphicFilterImportFlags nImportFlags, WMF_EXTERNALHEADER *pExtHeader )
1329 return ImportGraphic( rGraphic, rPath, rIStream, nFormat, pDeterminedFormat, nImportFlags, NULL, pExtHeader );
1332 sal_uInt16 GraphicFilter::ImportGraphic( Graphic& rGraphic, const OUString& rPath, SvStream& rIStream,
1333 sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat, GraphicFilterImportFlags nImportFlags,
1334 com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >* pFilterData,
1335 WMF_EXTERNALHEADER *pExtHeader )
1337 OUString aFilterName;
1338 sal_uLong nStreamBegin;
1339 sal_uInt16 nStatus;
1340 GraphicReader* pContext = rGraphic.GetContext();
1341 GfxLinkType eLinkType = GFX_LINK_TYPE_NONE;
1342 bool bDummyContext = ( pContext == reinterpret_cast<GraphicReader*>(1) );
1343 const bool bLinkSet = rGraphic.IsLink();
1344 FilterConfigItem* pFilterConfigItem = NULL;
1346 Size aPreviewSizeHint( 0, 0 );
1347 bool bAllowPartialStreamRead = false;
1348 bool bCreateNativeLink = true;
1350 sal_uInt8* pGraphicContent = NULL;
1351 bool bGraphicContentOwned = true;
1352 sal_Int32 nGraphicContentSize = 0;
1354 ResetLastError();
1356 if ( pFilterData )
1358 sal_Int32 i;
1359 for ( i = 0; i < pFilterData->getLength(); i++ )
1361 if ( (*pFilterData)[ i ].Name == "PreviewSizeHint" )
1363 awt::Size aSize;
1364 if ( (*pFilterData)[ i ].Value >>= aSize )
1366 aPreviewSizeHint = Size( aSize.Width, aSize.Height );
1367 if ( aSize.Width || aSize.Height )
1368 nImportFlags |= GraphicFilterImportFlags::ForPreview;
1369 else
1370 nImportFlags &=~GraphicFilterImportFlags::ForPreview;
1373 else if ( (*pFilterData)[ i ].Name == "AllowPartialStreamRead" )
1375 (*pFilterData)[ i ].Value >>= bAllowPartialStreamRead;
1376 if ( bAllowPartialStreamRead )
1377 nImportFlags |= GraphicFilterImportFlags::AllowPartialStreamRead;
1378 else
1379 nImportFlags &=~GraphicFilterImportFlags::AllowPartialStreamRead;
1381 else if ( (*pFilterData)[ i ].Name == "CreateNativeLink" )
1383 (*pFilterData)[ i ].Value >>= bCreateNativeLink;
1388 if( !pContext || bDummyContext )
1390 if( bDummyContext )
1392 rGraphic.SetContext( NULL );
1393 nStreamBegin = 0;
1395 else
1396 nStreamBegin = rIStream.Tell();
1398 bAbort = false;
1399 nStatus = ImpTestOrFindFormat( rPath, rIStream, nFormat );
1400 // if pending, return GRFILTER_OK in order to request more bytes
1401 if( rIStream.GetError() == ERRCODE_IO_PENDING )
1403 rGraphic.SetContext( reinterpret_cast<GraphicReader*>(1) );
1404 rIStream.ResetError();
1405 rIStream.Seek( nStreamBegin );
1406 return (sal_uInt16) ImplSetError( GRFILTER_OK );
1409 rIStream.Seek( nStreamBegin );
1411 if( ( nStatus != GRFILTER_OK ) || rIStream.GetError() )
1412 return (sal_uInt16) ImplSetError( ( nStatus != GRFILTER_OK ) ? nStatus : GRFILTER_OPENERROR, &rIStream );
1414 if( pDeterminedFormat )
1415 *pDeterminedFormat = nFormat;
1417 aFilterName = pConfig->GetImportFilterName( nFormat );
1419 else
1421 if( pContext && !bDummyContext )
1422 aFilterName = pContext->GetUpperFilterName();
1424 nStreamBegin = 0;
1425 nStatus = GRFILTER_OK;
1428 // read graphic
1429 if ( pConfig->IsImportInternalFilter( nFormat ) )
1431 if( aFilterName.equalsIgnoreAsciiCase( IMP_GIF ) )
1433 if( rGraphic.GetContext() == reinterpret_cast<GraphicReader*>(1) )
1434 rGraphic.SetContext( NULL );
1436 if( !ImportGIF( rIStream, rGraphic ) )
1437 nStatus = GRFILTER_FILTERERROR;
1438 else
1439 eLinkType = GFX_LINK_TYPE_NATIVE_GIF;
1441 else if( aFilterName.equalsIgnoreAsciiCase( IMP_PNG ) )
1443 if ( rGraphic.GetContext() == reinterpret_cast<GraphicReader*>(1) )
1444 rGraphic.SetContext( NULL );
1446 vcl::PNGReader aPNGReader( rIStream );
1448 // ignore animation for previews and set preview size
1449 if( aPreviewSizeHint.Width() || aPreviewSizeHint.Height() )
1451 // position the stream at the end of the image if requested
1452 if( !bAllowPartialStreamRead )
1453 aPNGReader.GetChunks();
1455 else
1457 // check if this PNG contains a GIF chunk!
1458 const std::vector< vcl::PNGReader::ChunkData >& rChunkData = aPNGReader.GetChunks();
1459 std::vector< vcl::PNGReader::ChunkData >::const_iterator aIter( rChunkData.begin() );
1460 std::vector< vcl::PNGReader::ChunkData >::const_iterator aEnd ( rChunkData.end() );
1461 while( aIter != aEnd )
1463 // Microsoft Office is storing Animated GIFs in following chunk
1464 if ( aIter->nType == PMGCHUNG_msOG )
1466 sal_uInt32 nChunkSize = aIter->aData.size();
1467 if ( nChunkSize > 11 )
1469 const std::vector< sal_uInt8 >& rData = aIter->aData;
1470 SvMemoryStream aIStrm( (void*)&rData[ 11 ], nChunkSize - 11, StreamMode::READ );
1471 ImportGIF( aIStrm, rGraphic );
1472 eLinkType = GFX_LINK_TYPE_NATIVE_PNG;
1473 break;
1476 ++aIter;
1480 if ( eLinkType == GFX_LINK_TYPE_NONE )
1482 BitmapEx aBmpEx( aPNGReader.Read( aPreviewSizeHint ) );
1483 if ( aBmpEx.IsEmpty() )
1484 nStatus = GRFILTER_FILTERERROR;
1485 else
1487 rGraphic = aBmpEx;
1488 eLinkType = GFX_LINK_TYPE_NATIVE_PNG;
1492 else if( aFilterName.equalsIgnoreAsciiCase( IMP_JPEG ) )
1494 if( rGraphic.GetContext() == reinterpret_cast<GraphicReader*>(1) )
1495 rGraphic.SetContext( NULL );
1497 // set LOGSIZE flag always, if not explicitly disabled
1498 // (see #90508 and #106763)
1499 if( !( nImportFlags & GraphicFilterImportFlags::DontSetLogsizeForJpeg ) )
1500 nImportFlags |= GraphicFilterImportFlags::SetLogsizeForJpeg;
1502 if( !ImportJPEG( rIStream, rGraphic, NULL, nImportFlags ) )
1503 nStatus = GRFILTER_FILTERERROR;
1504 else
1505 eLinkType = GFX_LINK_TYPE_NATIVE_JPG;
1507 else if( aFilterName.equalsIgnoreAsciiCase( IMP_SVG ) )
1509 if( rGraphic.GetContext() == reinterpret_cast<GraphicReader*>(1) )
1510 rGraphic.SetContext( NULL );
1512 const sal_uInt32 nStreamPosition(rIStream.Tell());
1513 const sal_uInt32 nStreamLength(rIStream.Seek(STREAM_SEEK_TO_END) - nStreamPosition);
1515 bool bOkay(false);
1517 if(nStreamLength > 0)
1519 std::vector<sal_uInt8> aTwoBytes(2);
1520 rIStream.Seek(nStreamPosition);
1521 rIStream.Read(&aTwoBytes[0], 2);
1522 rIStream.Seek(nStreamPosition);
1523 if(aTwoBytes[0] == 0x1F && aTwoBytes[1] == 0x8B)
1525 SvMemoryStream aMemStream;
1526 ZCodec aCodec;
1527 long nMemoryLength;
1529 aCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, false, true);
1530 nMemoryLength = aCodec.Decompress(rIStream, aMemStream);
1531 aCodec.EndCompression();
1533 if (!rIStream.GetError() && nMemoryLength >= 0)
1535 SvgDataArray aNewData(new sal_uInt8[nMemoryLength]);
1536 aMemStream.Seek(STREAM_SEEK_TO_BEGIN);
1537 aMemStream.Read(aNewData.get(), nMemoryLength);
1539 // Make a uncompressed copy for GfxLink
1540 nGraphicContentSize = nMemoryLength;
1541 pGraphicContent = new sal_uInt8[nGraphicContentSize];
1542 std::copy(aNewData.get(), aNewData.get() + nMemoryLength, pGraphicContent);
1544 if(!aMemStream.GetError() )
1546 SvgDataPtr aSvgDataPtr(new SvgData(aNewData, nMemoryLength, rPath));
1547 rGraphic = Graphic(aSvgDataPtr);
1548 bOkay = true;
1552 else
1554 SvgDataArray aNewData(new sal_uInt8[nStreamLength]);
1555 rIStream.Seek(nStreamPosition);
1556 rIStream.Read(aNewData.get(), nStreamLength);
1558 if(!rIStream.GetError())
1560 SvgDataPtr aSvgDataPtr(new SvgData(aNewData, nStreamLength, rPath));
1561 rGraphic = Graphic(aSvgDataPtr);
1562 bOkay = true;
1567 if(bOkay)
1569 eLinkType = GFX_LINK_TYPE_NATIVE_SVG;
1571 else
1573 nStatus = GRFILTER_FILTERERROR;
1576 else if( aFilterName.equalsIgnoreAsciiCase( IMP_XBM ) )
1578 if( rGraphic.GetContext() == reinterpret_cast<GraphicReader*>(1) )
1579 rGraphic.SetContext( NULL );
1581 if( !ImportXBM( rIStream, rGraphic ) )
1582 nStatus = GRFILTER_FILTERERROR;
1584 else if( aFilterName.equalsIgnoreAsciiCase( IMP_XPM ) )
1586 if( rGraphic.GetContext() == reinterpret_cast<GraphicReader*>(1) )
1587 rGraphic.SetContext( NULL );
1589 if( !ImportXPM( rIStream, rGraphic ) )
1590 nStatus = GRFILTER_FILTERERROR;
1592 else if( aFilterName.equalsIgnoreAsciiCase( IMP_BMP ) ||
1593 aFilterName.equalsIgnoreAsciiCase( IMP_SVMETAFILE ) )
1595 // SV internal filters for import bitmaps and MetaFiles
1596 ReadGraphic( rIStream, rGraphic );
1597 if( rIStream.GetError() )
1599 nStatus = GRFILTER_FORMATERROR;
1601 else if (aFilterName.equalsIgnoreAsciiCase(IMP_BMP))
1603 // #i15508# added BMP type (checked, works)
1604 eLinkType = GFX_LINK_TYPE_NATIVE_BMP;
1607 else if( aFilterName.equalsIgnoreAsciiCase( IMP_MOV ) )
1609 ReadGraphic( rIStream, rGraphic );
1610 if( rIStream.GetError() )
1611 nStatus = GRFILTER_FORMATERROR;
1612 else
1614 rGraphic.SetDefaultType();
1615 rIStream.Seek( STREAM_SEEK_TO_END );
1616 eLinkType = GFX_LINK_TYPE_NATIVE_MOV;
1619 else if( aFilterName.equalsIgnoreAsciiCase( IMP_WMF ) ||
1620 aFilterName.equalsIgnoreAsciiCase( IMP_EMF ) )
1622 GDIMetaFile aMtf;
1623 if( !ConvertWMFToGDIMetaFile( rIStream, aMtf, NULL, pExtHeader ) )
1624 nStatus = GRFILTER_FORMATERROR;
1625 else
1627 rGraphic = aMtf;
1628 eLinkType = GFX_LINK_TYPE_NATIVE_WMF;
1631 else if( aFilterName.equalsIgnoreAsciiCase( IMP_SVSGF )
1632 || aFilterName.equalsIgnoreAsciiCase( IMP_SVSGV ) )
1634 sal_uInt16 nVersion;
1635 unsigned char nTyp = CheckSgfTyp( rIStream, nVersion );
1637 switch( nTyp )
1639 case SGF_BITIMAGE:
1641 SvMemoryStream aTempStream;
1642 if( aTempStream.GetError() )
1643 return GRFILTER_OPENERROR;
1645 if( !SgfBMapFilter( rIStream, aTempStream ) )
1646 nStatus = GRFILTER_FILTERERROR;
1647 else
1649 aTempStream.Seek( 0L );
1650 ReadGraphic( aTempStream, rGraphic );
1652 if( aTempStream.GetError() )
1653 nStatus = GRFILTER_FILTERERROR;
1656 break;
1658 case SGF_SIMPVECT:
1660 GDIMetaFile aMtf;
1661 if( !SgfVectFilter( rIStream, aMtf ) )
1662 nStatus = GRFILTER_FILTERERROR;
1663 else
1664 rGraphic = Graphic( aMtf );
1666 break;
1668 case SGF_STARDRAW:
1670 if( nVersion != SGV_VERSION )
1671 nStatus = GRFILTER_VERSIONERROR;
1672 else
1674 GDIMetaFile aMtf;
1675 if( !SgfSDrwFilter( rIStream, aMtf,
1676 INetURLObject(aFilterPath) ) )
1678 nStatus = GRFILTER_FILTERERROR;
1680 else
1681 rGraphic = Graphic( aMtf );
1684 break;
1686 default:
1688 nStatus = GRFILTER_FORMATERROR;
1690 break;
1693 else
1694 nStatus = GRFILTER_FILTERERROR;
1696 else
1698 ImpFilterLibCacheEntry* pFilter = NULL;
1700 // find first filter in filter paths
1701 sal_Int32 i, nTokenCount = getTokenCount(aFilterPath, ';');
1702 ImpFilterLibCache &rCache = Cache::get();
1703 for( i = 0; ( i < nTokenCount ) && ( pFilter == NULL ); i++ )
1704 pFilter = rCache.GetFilter( aFilterPath.getToken(i, ';'), aFilterName );
1705 if( !pFilter )
1706 nStatus = GRFILTER_FILTERERROR;
1707 else
1709 PFilterCall pFunc = pFilter->GetImportFunction();
1711 if( !pFunc )
1712 nStatus = GRFILTER_FILTERERROR;
1713 else
1715 OUString aShortName;
1716 if( nFormat != GRFILTER_FORMAT_DONTKNOW )
1718 aShortName = GetImportFormatShortName( nFormat ).toAsciiUpperCase();
1719 if ( ( pFilterConfigItem == NULL ) && aShortName == "PCD" )
1721 OUString aFilterConfigPath( "Office.Common/Filter/Graphic/Import/PCD" );
1722 pFilterConfigItem = new FilterConfigItem( aFilterConfigPath );
1725 if( !(*pFunc)( rIStream, rGraphic, pFilterConfigItem ) )
1726 nStatus = GRFILTER_FORMATERROR;
1727 else
1729 // try to set link type if format matches
1730 if( nFormat != GRFILTER_FORMAT_DONTKNOW )
1732 if( aShortName.startsWith( TIF_SHORTNAME ) )
1733 eLinkType = GFX_LINK_TYPE_NATIVE_TIF;
1734 else if( aShortName.startsWith( MET_SHORTNAME ) )
1735 eLinkType = GFX_LINK_TYPE_NATIVE_MET;
1736 else if( aShortName.startsWith( PCT_SHORTNAME ) )
1737 eLinkType = GFX_LINK_TYPE_NATIVE_PCT;
1744 if( nStatus == GRFILTER_OK && bCreateNativeLink && ( eLinkType != GFX_LINK_TYPE_NONE ) && !rGraphic.GetContext() && !bLinkSet )
1746 if (pGraphicContent == NULL)
1748 const sal_uLong nStreamEnd = rIStream.Tell();
1749 nGraphicContentSize = nStreamEnd - nStreamBegin;
1751 if (nGraphicContentSize > 0)
1755 pGraphicContent = new sal_uInt8[nGraphicContentSize];
1757 catch (const std::bad_alloc&)
1759 nStatus = GRFILTER_TOOBIG;
1762 if( nStatus == GRFILTER_OK )
1764 rIStream.Seek(nStreamBegin);
1765 rIStream.Read(pGraphicContent, nGraphicContentSize);
1769 if( nStatus == GRFILTER_OK )
1771 rGraphic.SetLink( GfxLink( pGraphicContent, nGraphicContentSize, eLinkType, true ) );
1772 bGraphicContentOwned = false; //ownership passed to the GfxLink
1776 if (bGraphicContentOwned)
1777 delete[] pGraphicContent;
1779 // Set error code or try to set native buffer
1780 if( nStatus != GRFILTER_OK )
1782 if( bAbort )
1783 nStatus = GRFILTER_ABORT;
1785 ImplSetError( nStatus, &rIStream );
1786 rIStream.Seek( nStreamBegin );
1787 rGraphic.Clear();
1790 delete pFilterConfigItem;
1791 return nStatus;
1794 sal_uInt16 GraphicFilter::ExportGraphic( const Graphic& rGraphic, const INetURLObject& rPath,
1795 sal_uInt16 nFormat, const uno::Sequence< beans::PropertyValue >* pFilterData )
1797 #ifdef DISABLE_EXPORT
1798 (void) rGraphic;
1799 (void) rPath;
1800 (void) nFormat;
1801 (void) pFilterData;
1803 return GRFILTER_FORMATERROR;
1804 #else
1805 SAL_INFO( "vcl.filter", "GraphicFilter::ExportGraphic() (thb)" );
1806 sal_uInt16 nRetValue = GRFILTER_FORMATERROR;
1807 DBG_ASSERT( rPath.GetProtocol() != INetProtocol::NotValid, "GraphicFilter::ExportGraphic() : ProtType == INetProtocol::NotValid" );
1808 bool bAlreadyExists = DirEntryExists( rPath );
1810 OUString aMainUrl( rPath.GetMainURL( INetURLObject::NO_DECODE ) );
1811 std::unique_ptr<SvStream> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl, StreamMode::WRITE | StreamMode::TRUNC ));
1812 if (xStream)
1814 nRetValue = ExportGraphic( rGraphic, aMainUrl, *xStream, nFormat, pFilterData );
1815 xStream.reset();
1817 if( ( GRFILTER_OK != nRetValue ) && !bAlreadyExists )
1818 KillDirEntry( aMainUrl );
1820 return nRetValue;
1821 #endif
1824 #ifdef DISABLE_DYNLOADING
1826 #ifndef DISABLE_EXPORT
1828 extern "C" bool egiGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
1829 extern "C" bool emeGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
1830 extern "C" bool epbGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
1831 extern "C" bool epgGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
1832 extern "C" bool eppGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
1833 extern "C" bool epsGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
1834 extern "C" bool eptGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
1835 extern "C" bool eraGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
1836 extern "C" bool etiGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
1837 extern "C" bool expGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem );
1839 #endif
1841 #endif
1843 sal_uInt16 GraphicFilter::ExportGraphic( const Graphic& rGraphic, const OUString& rPath,
1844 SvStream& rOStm, sal_uInt16 nFormat, const uno::Sequence< beans::PropertyValue >* pFilterData )
1846 #ifdef DISABLE_EXPORT
1847 (void) rGraphic;
1848 (void) rPath;
1849 (void) rOStm;
1850 (void) nFormat;
1851 (void) pFilterData;
1853 return GRFILTER_FORMATERROR;
1854 #else
1855 SAL_INFO( "vcl.filter", "GraphicFilter::ExportGraphic() (thb)" );
1856 sal_uInt16 nFormatCount = GetExportFormatCount();
1858 ResetLastError();
1859 nExpGraphHint = 0;
1861 if( nFormat == GRFILTER_FORMAT_DONTKNOW )
1863 INetURLObject aURL( rPath );
1864 OUString aExt( aURL.GetFileExtension().toAsciiUpperCase() );
1866 for( sal_uInt16 i = 0; i < nFormatCount; i++ )
1868 if ( pConfig->GetExportFormatExtension( i ).equalsIgnoreAsciiCase( aExt ) )
1870 nFormat=i;
1871 break;
1875 if( nFormat >= nFormatCount )
1876 return (sal_uInt16) ImplSetError( GRFILTER_FORMATERROR );
1878 FilterConfigItem aConfigItem( const_cast<uno::Sequence< beans::PropertyValue >*>(pFilterData) );
1879 OUString aFilterName( pConfig->GetExportFilterName( nFormat ) );
1881 bAbort = false;
1882 sal_uInt16 nStatus = GRFILTER_OK;
1883 GraphicType eType;
1884 Graphic aGraphic( rGraphic );
1886 aGraphic = ImpGetScaledGraphic( rGraphic, aConfigItem );
1887 eType = aGraphic.GetType();
1889 if( pConfig->IsExportPixelFormat( nFormat ) )
1891 if( eType != GRAPHIC_BITMAP )
1893 Size aSizePixel;
1894 sal_uLong nColorCount,nBitsPerPixel,nNeededMem,nMaxMem;
1895 ScopedVclPtrInstance< VirtualDevice > aVirDev;
1897 nMaxMem = 1024;
1898 nMaxMem *= 1024; // In Bytes
1900 // Calculate how big the image would normally be:
1901 aSizePixel=aVirDev->LogicToPixel(aGraphic.GetPrefSize(),aGraphic.GetPrefMapMode());
1903 // Calculate how much memory the image will take up
1904 nColorCount=aVirDev->GetColorCount();
1905 if (nColorCount<=2) nBitsPerPixel=1;
1906 else if (nColorCount<=4) nBitsPerPixel=2;
1907 else if (nColorCount<=16) nBitsPerPixel=4;
1908 else if (nColorCount<=256) nBitsPerPixel=8;
1909 else if (nColorCount<=65536) nBitsPerPixel=16;
1910 else nBitsPerPixel=24;
1911 nNeededMem=((sal_uLong)aSizePixel.Width()*(sal_uLong)aSizePixel.Height()*nBitsPerPixel+7)/8;
1913 // is the image larger than available memory?
1914 if (nMaxMem<nNeededMem)
1916 double fFak=sqrt(((double)nMaxMem)/((double)nNeededMem));
1917 aSizePixel.Width()=(sal_uLong)(((double)aSizePixel.Width())*fFak);
1918 aSizePixel.Height()=(sal_uLong)(((double)aSizePixel.Height())*fFak);
1921 aVirDev->SetMapMode(MapMode(MAP_PIXEL));
1922 aVirDev->SetOutputSizePixel(aSizePixel);
1923 Graphic aGraphic2=aGraphic;
1924 aGraphic2.Draw(aVirDev.get(),Point(0,0),aSizePixel); // this changes the MapMode
1925 aVirDev->SetMapMode(MapMode(MAP_PIXEL));
1926 aGraphic=Graphic(aVirDev->GetBitmap(Point(0,0),aSizePixel));
1929 if( rOStm.GetError() )
1930 nStatus = GRFILTER_IOERROR;
1931 if( GRFILTER_OK == nStatus )
1933 if ( pConfig->IsExportInternalFilter( nFormat ) )
1935 if( aFilterName.equalsIgnoreAsciiCase( EXP_BMP ) )
1937 Bitmap aBmp( aGraphic.GetBitmap() );
1938 sal_Int32 nColorRes = aConfigItem.ReadInt32( "Colors", 0 );
1939 if ( nColorRes && ( nColorRes <= (sal_uInt16)BMP_CONVERSION_24BIT) )
1941 if( !aBmp.Convert( (BmpConversion) nColorRes ) )
1942 aBmp = aGraphic.GetBitmap();
1944 bool bRleCoding = aConfigItem.ReadBool( "RLE_Coding", true );
1945 // save RLE encoded?
1946 WriteDIB(aBmp, rOStm, bRleCoding, true);
1948 if( rOStm.GetError() )
1949 nStatus = GRFILTER_IOERROR;
1951 else if( aFilterName.equalsIgnoreAsciiCase( EXP_SVMETAFILE ) )
1953 sal_Int32 nVersion = aConfigItem.ReadInt32( "Version", 0 ) ;
1954 if ( nVersion )
1955 rOStm.SetVersion( nVersion );
1957 // #i119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
1958 GDIMetaFile aMTF(aGraphic.GetGDIMetaFile());
1960 aMTF.Write( rOStm );
1962 if( rOStm.GetError() )
1963 nStatus = GRFILTER_IOERROR;
1965 else if ( aFilterName.equalsIgnoreAsciiCase( EXP_WMF ) )
1967 // #i119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
1968 if ( !ConvertGDIMetaFileToWMF( aGraphic.GetGDIMetaFile(), rOStm, &aConfigItem ) )
1969 nStatus = GRFILTER_FORMATERROR;
1971 if( rOStm.GetError() )
1972 nStatus = GRFILTER_IOERROR;
1974 else if ( aFilterName.equalsIgnoreAsciiCase( EXP_EMF ) )
1976 // #i119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
1977 if ( !ConvertGDIMetaFileToEMF(aGraphic.GetGDIMetaFile(), rOStm))
1978 nStatus = GRFILTER_FORMATERROR;
1980 if( rOStm.GetError() )
1981 nStatus = GRFILTER_IOERROR;
1983 else if( aFilterName.equalsIgnoreAsciiCase( EXP_JPEG ) )
1985 bool bExportedGrayJPEG = false;
1986 if( !ExportJPEG( rOStm, aGraphic, pFilterData, &bExportedGrayJPEG ) )
1987 nStatus = GRFILTER_FORMATERROR;
1988 nExpGraphHint = bExportedGrayJPEG ? GRFILTER_OUTHINT_GREY : 0;
1990 if( rOStm.GetError() )
1991 nStatus = GRFILTER_IOERROR;
1993 else if ( aFilterName.equalsIgnoreAsciiCase( EXP_PNG ) )
1995 vcl::PNGWriter aPNGWriter( aGraphic.GetBitmapEx(), pFilterData );
1996 if ( pFilterData )
1998 sal_Int32 k, j, i = 0;
1999 for ( i = 0; i < pFilterData->getLength(); i++ )
2001 if ( (*pFilterData)[ i ].Name == "AdditionalChunks" )
2003 com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > aAdditionalChunkSequence;
2004 if ( (*pFilterData)[ i ].Value >>= aAdditionalChunkSequence )
2006 for ( j = 0; j < aAdditionalChunkSequence.getLength(); j++ )
2008 if ( aAdditionalChunkSequence[ j ].Name.getLength() == 4 )
2010 sal_uInt32 nChunkType = 0;
2011 for ( k = 0; k < 4; k++ )
2013 nChunkType <<= 8;
2014 nChunkType |= (sal_uInt8)aAdditionalChunkSequence[ j ].Name[ k ];
2016 com::sun::star::uno::Sequence< sal_Int8 > aByteSeq;
2017 if ( aAdditionalChunkSequence[ j ].Value >>= aByteSeq )
2019 std::vector< vcl::PNGWriter::ChunkData >& rChunkData = aPNGWriter.GetChunks();
2020 if ( !rChunkData.empty() )
2022 sal_uInt32 nChunkLen = aByteSeq.getLength();
2024 vcl::PNGWriter::ChunkData aChunkData;
2025 aChunkData.nType = nChunkType;
2026 if ( nChunkLen )
2028 aChunkData.aData.resize( nChunkLen );
2029 memcpy( &aChunkData.aData[ 0 ], aByteSeq.getConstArray(), nChunkLen );
2031 std::vector< vcl::PNGWriter::ChunkData >::iterator aIter = rChunkData.end() - 1;
2032 rChunkData.insert( aIter, aChunkData );
2041 aPNGWriter.Write( rOStm );
2043 if( rOStm.GetError() )
2044 nStatus = GRFILTER_IOERROR;
2046 else if( aFilterName.equalsIgnoreAsciiCase( EXP_SVG ) )
2048 bool bDone(false);
2050 // do we have a native SVG RenderGraphic, whose data can be written directly?
2051 const SvgDataPtr aSvgDataPtr(rGraphic.getSvgData());
2053 if(aSvgDataPtr.get() && aSvgDataPtr->getSvgDataArrayLength())
2055 rOStm.Write(aSvgDataPtr->getSvgDataArray().get(), aSvgDataPtr->getSvgDataArrayLength());
2057 if( rOStm.GetError() )
2059 nStatus = GRFILTER_IOERROR;
2061 else
2063 bDone = true;
2067 if( !bDone )
2069 // do the normal GDIMetaFile export instead
2072 css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
2074 css::uno::Reference< css::xml::sax::XDocumentHandler > xSaxWriter(
2075 xml::sax::Writer::create( xContext ), uno::UNO_QUERY_THROW);
2076 css::uno::Sequence< css::uno::Any > aArguments( 1 );
2077 aArguments[ 0 ] <<= aConfigItem.GetFilterData();
2078 css::uno::Reference< css::svg::XSVGWriter > xSVGWriter(
2079 xContext->getServiceManager()->createInstanceWithArgumentsAndContext( "com.sun.star.svg.SVGWriter", aArguments, xContext),
2080 css::uno::UNO_QUERY );
2081 if( xSaxWriter.is() && xSVGWriter.is() )
2083 css::uno::Reference< css::io::XActiveDataSource > xActiveDataSource(
2084 xSaxWriter, css::uno::UNO_QUERY );
2086 if( xActiveDataSource.is() )
2088 const css::uno::Reference< css::uno::XInterface > xStmIf(
2089 static_cast< ::cppu::OWeakObject* >( new ImpFilterOutputStream( rOStm ) ) );
2091 SvMemoryStream aMemStm( 65535, 65535 );
2093 // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
2094 ( (GDIMetaFile&) aGraphic.GetGDIMetaFile() ).Write( aMemStm );
2096 xActiveDataSource->setOutputStream( css::uno::Reference< css::io::XOutputStream >(
2097 xStmIf, css::uno::UNO_QUERY ) );
2098 css::uno::Sequence< sal_Int8 > aMtfSeq( static_cast<sal_Int8 const *>(aMemStm.GetData()), aMemStm.Tell() );
2099 xSVGWriter->write( xSaxWriter, aMtfSeq );
2103 catch(const css::uno::Exception&)
2105 nStatus = GRFILTER_IOERROR;
2109 else
2110 nStatus = GRFILTER_FILTERERROR;
2112 else
2114 sal_Int32 i, nTokenCount = getTokenCount(aFilterPath, ';');
2115 for ( i = 0; i < nTokenCount; i++ )
2117 #ifndef DISABLE_DYNLOADING
2118 OUString aPhysicalName( ImpCreateFullFilterPath( aFilterPath.getToken(i, ';'), aFilterName ) );
2119 osl::Module aLibrary( aPhysicalName );
2121 PFilterCall pFunc = reinterpret_cast<PFilterCall>(aLibrary.getFunctionSymbol(OUString(EXPORT_FUNCTION_NAME)));
2122 // Execute dialog in DLL
2123 #else
2124 PFilterCall pFunc = NULL;
2125 if( aFilterName.equalsAscii( "egi" ) )
2126 pFunc = egiGraphicExport;
2127 else if( aFilterName.equalsAscii( "eme" ) )
2128 pFunc = emeGraphicExport;
2129 else if( aFilterName.equalsAscii( "epb" ) )
2130 pFunc = epbGraphicExport;
2131 else if( aFilterName.equalsAscii( "epg" ) )
2132 pFunc = epgGraphicExport;
2133 else if( aFilterName.equalsAscii( "epp" ) )
2134 pFunc = eppGraphicExport;
2135 else if( aFilterName.equalsAscii( "eps" ) )
2136 pFunc = epsGraphicExport;
2137 else if( aFilterName.equalsAscii( "ept" ) )
2138 pFunc = eptGraphicExport;
2139 else if( aFilterName.equalsAscii( "era" ) )
2140 pFunc = eraGraphicExport;
2141 else if( aFilterName.equalsAscii( "eti" ) )
2142 pFunc = etiGraphicExport;
2143 else if( aFilterName.equalsAscii( "exp" ) )
2144 pFunc = expGraphicExport;
2145 #endif
2146 if( pFunc )
2148 if ( !(*pFunc)( rOStm, aGraphic, &aConfigItem ) )
2149 nStatus = GRFILTER_FORMATERROR;
2150 break;
2152 else
2153 nStatus = GRFILTER_FILTERERROR;
2157 if( nStatus != GRFILTER_OK )
2159 if( bAbort )
2160 nStatus = GRFILTER_ABORT;
2162 ImplSetError( nStatus, &rOStm );
2164 return nStatus;
2165 #endif
2169 void GraphicFilter::ResetLastError()
2171 pErrorEx->nFilterError = pErrorEx->nStreamError = 0UL;
2174 const Link<> GraphicFilter::GetFilterCallback() const
2176 const Link<> aLink( LINK( const_cast<GraphicFilter*>(this), GraphicFilter, FilterCallback ) );
2177 return aLink;
2180 IMPL_LINK( GraphicFilter, FilterCallback, ConvertData*, pData )
2182 bool nRet = false;
2184 if( pData )
2186 sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
2187 OString aShortName;
2188 switch( pData->mnFormat )
2190 case( CVT_BMP ): aShortName = BMP_SHORTNAME; break;
2191 case( CVT_GIF ): aShortName = GIF_SHORTNAME; break;
2192 case( CVT_JPG ): aShortName = JPG_SHORTNAME; break;
2193 case( CVT_MET ): aShortName = MET_SHORTNAME; break;
2194 case( CVT_PCT ): aShortName = PCT_SHORTNAME; break;
2195 case( CVT_PNG ): aShortName = PNG_SHORTNAME; break;
2196 case( CVT_SVM ): aShortName = SVM_SHORTNAME; break;
2197 case( CVT_TIF ): aShortName = TIF_SHORTNAME; break;
2198 case( CVT_WMF ): aShortName = WMF_SHORTNAME; break;
2199 case( CVT_EMF ): aShortName = EMF_SHORTNAME; break;
2200 case( CVT_SVG ): aShortName = SVG_SHORTNAME; break;
2202 default:
2203 break;
2205 if( GRAPHIC_NONE == pData->maGraphic.GetType() || pData->maGraphic.GetContext() ) // Import
2207 // Import
2208 nFormat = GetImportFormatNumberForShortName( OStringToOUString( aShortName, RTL_TEXTENCODING_UTF8) );
2209 nRet = ImportGraphic( pData->maGraphic, OUString(), pData->mrStm, nFormat ) == 0;
2211 #ifndef DISABLE_EXPORT
2212 else if( !aShortName.isEmpty() )
2214 // Export
2215 nFormat = GetExportFormatNumberForShortName( OStringToOUString(aShortName, RTL_TEXTENCODING_UTF8) );
2216 nRet = ExportGraphic( pData->maGraphic, OUString(), pData->mrStm, nFormat ) == 0;
2218 #endif
2220 return long(nRet);
2223 namespace
2225 class StandardGraphicFilter
2227 public:
2228 StandardGraphicFilter()
2230 m_aFilter.GetImportFormatCount();
2232 GraphicFilter m_aFilter;
2235 class theGraphicFilter : public rtl::Static<StandardGraphicFilter, theGraphicFilter> {};
2238 GraphicFilter& GraphicFilter::GetGraphicFilter()
2240 return theGraphicFilter::get().m_aFilter;
2243 int GraphicFilter::LoadGraphic( const OUString &rPath, const OUString &rFilterName,
2244 Graphic& rGraphic, GraphicFilter* pFilter,
2245 sal_uInt16* pDeterminedFormat )
2247 if ( !pFilter )
2248 pFilter = &GetGraphicFilter();
2250 const sal_uInt16 nFilter = !rFilterName.isEmpty() && pFilter->GetImportFormatCount()
2251 ? pFilter->GetImportFormatNumber( rFilterName )
2252 : GRFILTER_FORMAT_DONTKNOW;
2254 INetURLObject aURL( rPath );
2255 if ( aURL.HasError() )
2257 aURL.SetSmartProtocol( INetProtocol::File );
2258 aURL.SetSmartURL( rPath );
2261 SvStream* pStream = NULL;
2262 if ( INetProtocol::File != aURL.GetProtocol() )
2264 pStream = ::utl::UcbStreamHelper::CreateStream( rPath, StreamMode::READ );
2267 int nRes = GRFILTER_OK;
2268 if ( !pStream )
2269 nRes = pFilter->ImportGraphic( rGraphic, aURL, nFilter, pDeterminedFormat );
2270 else
2271 nRes = pFilter->ImportGraphic( rGraphic, rPath, *pStream, nFilter, pDeterminedFormat );
2273 #ifdef DBG_UTIL
2274 OUString aReturnString;
2276 switch (nRes)
2278 case GRFILTER_OPENERROR:
2279 aReturnString="open error";
2280 break;
2281 case GRFILTER_IOERROR:
2282 aReturnString="IO error";
2283 break;
2284 case GRFILTER_FORMATERROR:
2285 aReturnString="format error";
2286 break;
2287 case GRFILTER_VERSIONERROR:
2288 aReturnString="version error";
2289 break;
2290 case GRFILTER_FILTERERROR:
2291 aReturnString="filter error";
2292 break;
2293 case GRFILTER_ABORT:
2294 aReturnString="import aborted";
2295 break;
2296 case GRFILTER_TOOBIG:
2297 aReturnString="graphic is too big";
2298 break;
2299 default:
2300 // nothing more to do
2301 break;
2304 SAL_INFO_IF( nRes, "vcl.filter", "Problem importing graphic " << rPath << ". Reason: " << aReturnString );
2305 #endif
2307 return nRes;
2310 sal_uInt16 GraphicFilter::compressAsPNG(const Graphic& rGraphic, SvStream& rOutputStream, sal_uInt32 nCompression)
2312 nCompression = MinMax(nCompression, 0, 100);
2314 uno::Sequence<beans::PropertyValue> aFilterData(1);
2315 aFilterData[0].Name = "Compression";
2316 aFilterData[0].Value <<= nCompression;
2318 sal_uInt16 nFilterFormat = GetExportFormatNumberForShortName("PNG");
2319 return ExportGraphic(rGraphic, OUString(), rOutputStream, nFilterFormat, &aFilterData);
2322 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */