1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
>
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
98 virtual void SAL_CALL
closeOutput() throw(std::exception
) override
{}
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" );
129 SAL_WARN( "vcl.filter", "Any other exception" );
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" );
151 SAL_WARN( "vcl.filter", "Any other exception" );
155 #endif // !DISABLE_EXPORT
159 sal_uInt8
* ImplSearchEntry( sal_uInt8
* pSource
, sal_uInt8
const * pDest
, sal_uLong nComp
, sal_uLong nSize
)
161 while ( nComp
-- >= nSize
)
164 for ( i
= 0; i
< nSize
; i
++ )
166 if ( ( pSource
[i
]&~0x20 ) != ( pDest
[i
]&~0x20 ) )
176 inline OUString
ImpGetExtension( const OUString
&rPath
)
179 INetURLObject
aURL( rPath
);
180 aExt
= aURL
.GetFileExtension().toAsciiUpperCase();
184 bool isPCT(SvStream
& rStream
, sal_uLong nStreamPos
, sal_uLong nStreamLen
)
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 )
195 rStream
.Seek( nStreamPos
+ nOffset
);
196 // size of the pict in version 1 pict ( 2bytes) : ignored
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
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)
214 // normal version 1 - page A25
215 else if (sBuf
[ 0 ] == 0x11 && sBuf
[ 1 ] == 0x01 && bdBoxOk
)
221 /*************************************************************************
223 * ImpPeekGraphicFormat()
226 * This function is two-fold:
227 * 1.) Start reading file, determine the file format:
230 * rFormatExtension - content matter
233 * Return value - true if success
234 * rFormatExtension - on success: normal file extension in capitals
235 * 2.) Start reading file, verify file format
238 * rFormatExtension - normal file extension in capitals
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
);
260 SvLockBytes
* pLockBytes
= rStream
.GetLockBytes();
262 pLockBytes
->SetSynchronMode();
264 rStream
.Seek( STREAM_SEEK_TO_END
);
265 nStreamLen
= rStream
.Tell() - nStreamPos
;
266 rStream
.Seek( nStreamPos
);
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);
282 nStreamLen
= rStream
.ReadBytes(sFirstBytes
, nStreamLen
);
286 if (rStream
.GetError())
289 for (sal_uLong i
= nStreamLen
; i
< 256; ++i
)
292 // Accommodate the first 8 bytes in nFirstLong, nSecondLong
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
;
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";
338 //--------------------------- BMP ------------------------------------
339 if( !bTest
|| rFormatExtension
.startsWith( "BMP" ) )
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 )
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";
373 //--------------------------- WMF/EMF ------------------------------------
376 rFormatExtension
.startsWith( "WMF" ) ||
377 rFormatExtension
.startsWith( "EMF" ) )
379 bSomethingTested
= true;
381 if ( nFirstLong
==0xd7cdc69a || nFirstLong
==0x01000900 )
383 rFormatExtension
= "WMF";
386 else if( nFirstLong
== 0x01000000 && sFirstBytes
[ 40 ] == 0x20 && sFirstBytes
[ 41 ] == 0x45 &&
387 sFirstBytes
[ 42 ] == 0x4d && sFirstBytes
[ 43 ] == 0x46 )
389 rFormatExtension
= "EMF";
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";
410 //--------------------------- TIF ------------------------------------
411 if( !bTest
|| rFormatExtension
.startsWith( "TIF" ) )
413 bSomethingTested
=true;
414 if ( nFirstLong
==0x49492a00 || nFirstLong
==0x4d4d002a )
416 rFormatExtension
= "TIF";
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";
432 //--------------------------- PNG ------------------------------------
433 if( !bTest
|| rFormatExtension
.startsWith( "PNG" ) )
435 bSomethingTested
=true;
436 if (nFirstLong
==0x89504e47 && nSecondLong
==0x0d0a1a0a)
438 rFormatExtension
= "PNG";
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";
455 //--------------------------- SVM ------------------------------------
456 if( !bTest
|| rFormatExtension
.startsWith( "SVM" ) )
458 bSomethingTested
=true;
459 if( nFirstLong
==0x53564744 && sFirstBytes
[4]==0x49 )
461 rFormatExtension
= "SVM";
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";
472 //--------------------------- PCD ------------------------------------
473 if( !bTest
|| rFormatExtension
.startsWith( "PCD" ) )
475 bSomethingTested
= true;
476 if( nStreamLen
>= 2055 )
479 rStream
.Seek( nStreamPos
+ 2048 );
480 rStream
.ReadBytes( sBuf
, 7 );
482 if( strncmp( sBuf
, "PCD_IPI", 7 ) == 0 )
484 rFormatExtension
= "PCD";
490 //--------------------------- PSD ------------------------------------
491 if( !bTest
|| rFormatExtension
.startsWith( "PSD" ) )
493 bSomethingTested
= true;
494 if ( ( nFirstLong
== 0x38425053 ) && ( (nSecondLong
>> 16 ) == 1 ) )
496 rFormatExtension
= "PSD";
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";
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";
523 // ASCII DXF File Format
525 while (i
<256 && sFirstBytes
[i
]<=32)
528 if (i
<256 && sFirstBytes
[i
]=='0')
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 )
539 if (i
+7<256 && (strncmp(reinterpret_cast<char*>(sFirstBytes
+i
),"SECTION",7)==0))
541 rFormatExtension
= "DXF";
548 //--------------------------- PCT ------------------------------------
549 if( !bTest
|| rFormatExtension
.startsWith( "PCT" ) )
551 bSomethingTested
= true;
552 if (isPCT(rStream
, nStreamPos
, nStreamLen
))
554 rFormatExtension
= "PCT";
559 //------------------------- PBM + PGM + PPM ---------------------------
561 rFormatExtension
.startsWith( "PBM" ) ||
562 rFormatExtension
.startsWith( "PGM" ) ||
563 rFormatExtension
.startsWith( "PPM" ) )
565 bSomethingTested
=true;
566 if ( sFirstBytes
[ 0 ] == 'P' )
568 switch( sFirstBytes
[ 1 ] )
572 rFormatExtension
= "PBM";
577 rFormatExtension
= "PGM";
582 rFormatExtension
= "PPM";
588 //--------------------------- RAS( SUN RasterFile )------------------
589 if( !bTest
|| rFormatExtension
.startsWith( "RAS" ) )
591 bSomethingTested
=true;
592 if( nFirstLong
== 0x59a66a95 )
594 rFormatExtension
= "RAS";
599 //--------------------------- XPM ------------------------------------
602 bSomethingTested
= true;
603 if( ImplSearchEntry( sFirstBytes
, reinterpret_cast<sal_uInt8
const *>("/* XPM */"), 256, 9 ) )
605 rFormatExtension
= "XPM";
609 else if( rFormatExtension
.startsWith( "XPM" ) )
614 //--------------------------- XBM ------------------------------------
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 );
626 if( ImplSearchEntry( pPtr
, reinterpret_cast<sal_uInt8
const *>("_width"), pBuf
.get() + nSize
- pPtr
, 6 ) )
628 rFormatExtension
= "XBM";
633 else if( rFormatExtension
.startsWith( "XBM" ) )
638 //--------------------------- SVG ------------------------------------
641 sal_uInt8
* pCheckArray
= sFirstBytes
;
642 sal_uLong nCheckSize
= nStreamLen
< 256 ? nStreamLen
: 256;
644 sal_uInt8 sExtendedOrDecompressedFirstBytes
[2048];
645 sal_uLong nDecompressedSize
= nCheckSize
;
649 // check if it is gzipped -> svgz
650 if(sFirstBytes
[0] == 0x1F && sFirstBytes
[1] == 0x8B)
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
;
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
679 // check for svg element in 1st 256 bytes
680 if(!bIsSvg
&& ImplSearchEntry(pCheckArray
, reinterpret_cast<sal_uInt8
const *>("<svg"), nCheckSize
, 4 )) // '<svg'
685 // extended search for svg element
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
693 pCheckArray
= sExtendedOrDecompressedFirstBytes
;
697 nCheckSize
= nDecompressedSize
< 2048 ? nDecompressedSize
: 2048;
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'
714 rFormatExtension
= "SVG";
718 else if( rFormatExtension
.startsWith( "SVG" ) )
723 //--------------------------- TGA ------------------------------------
724 if( !bTest
|| rFormatExtension
.startsWith( "TGA" ) )
726 bSomethingTested
= true;
728 // just a simple test for the extension
729 if( rFormatExtension
.startsWith( "TGA" ) )
733 //--------------------------- SGV ------------------------------------
734 if( !bTest
|| rFormatExtension
.startsWith( "SGV" ) )
736 bSomethingTested
= true;
738 // just a simple test for the extension
739 if( rFormatExtension
.startsWith( "SGV" ) )
743 //--------------------------- SGF ------------------------------------
744 if( !bTest
|| rFormatExtension
.startsWith( "SGF" ) )
746 bSomethingTested
=true;
747 if( sFirstBytes
[ 0 ] == 'J' && sFirstBytes
[ 1 ] == 'J' )
749 rFormatExtension
= "SGF";
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";
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";
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
)
785 if( ImpPeekGraphicFormat( rStream
, aFormatExt
, false ) )
787 rFormat
= pConfig
->GetImportFormatNumberForExtension( aFormatExt
);
788 if( rFormat
!= GRFILTER_FORMAT_DONTKNOW
)
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
)
799 return GRFILTER_FORMATERROR
;
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" ) )
812 else if ( pConfig
->GetImportFilterType( rFormat
).equalsIgnoreAsciiCase( "pcd_Photo_CD_Base16" ) )
814 OUString
aFilterConfigPath( "Office.Common/Filter/Graphic/Import/PCD" );
815 FilterConfigItem
aFilterConfigItem( aFilterConfigPath
);
816 aFilterConfigItem
.WriteInt32( "Resolution", nBase
);
823 #ifndef DISABLE_EXPORT
825 static Graphic
ImpGetScaledGraphic( const Graphic
& rGraphic
, FilterConfigItem
& rConfigItem
)
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
)
846 Size
aPrefSize( rGraphic
.GetPrefSize() );
847 MapMode
aPrefMapMode( rGraphic
.GetPrefMapMode() );
848 if ( aPrefMapMode
== MapUnit::MapPixel
)
849 aOriginalSize
= Application::GetDefaultDevice()->PixelToLogic( aPrefSize
, MapUnit::Map100thMM
);
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
)
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();
873 aGraphic
.SetPrefMapMode( aMap
);
874 aGraphic
.SetPrefSize( Size( aOldSize
.Width() * 100,
875 aOldSize
.Height() * 100 ) );
878 else if( nMode
== 2 )
881 aGraphic
.SetPrefMapMode( MapMode( MapUnit::Map100thMM
) );
882 aGraphic
.SetPrefSize( Size( nLogicalWidth
, nLogicalHeight
) );
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
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
);
923 static OUString
ImpCreateFullFilterPath( const OUString
& rPath
, const OUString
& rFilterName
)
927 ::osl::FileBase::getFileURLFromSystemPath( rPath
, 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
;
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
) :
957 #ifndef DISABLE_DYNLOADING
958 maLibrary ( rPathname
),
960 maFiltername ( rFiltername
),
961 maFormatName ( rFormatName
),
962 mpfnImport ( nullptr )
964 #ifdef DISABLE_DYNLOADING
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
);
985 PFilterCall
ImpFilterLibCacheEntry::GetImportFunction()
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"));
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
;
1041 class ImpFilterLibCache
1043 ImpFilterLibCacheEntry
* mpFirst
;
1044 ImpFilterLibCacheEntry
* mpLast
;
1047 ImpFilterLibCache();
1048 ~ImpFilterLibCache();
1050 ImpFilterLibCacheEntry
* GetFilter( const OUString
& rFilterPath
, const OUString
& rFiltername
, const OUString
& rFormatName
);
1053 ImpFilterLibCache::ImpFilterLibCache() :
1054 mpFirst ( nullptr ),
1059 ImpFilterLibCache::~ImpFilterLibCache()
1061 ImpFilterLibCacheEntry
* pEntry
= mpFirst
;
1064 ImpFilterLibCacheEntry
* pNext
= pEntry
->mpNext
;
1070 ImpFilterLibCacheEntry
* ImpFilterLibCache::GetFilter(const OUString
& rFilterPath
, const OUString
& rFilterName
, const OUString
& rFormatName
)
1072 ImpFilterLibCacheEntry
* pEntry
= mpFirst
;
1076 if( *pEntry
== rFilterName
&& pEntry
->maFormatName
== rFormatName
)
1079 pEntry
= pEntry
->mpNext
;
1083 OUString
aPhysicalName( ImpCreateFullFilterPath( rFilterPath
, rFilterName
) );
1084 pEntry
= new ImpFilterLibCacheEntry(aPhysicalName
, rFilterName
, rFormatName
);
1085 #ifndef DISABLE_DYNLOADING
1086 if ( pEntry
->maLibrary
.is() )
1090 mpFirst
= mpLast
= pEntry
;
1092 mpLast
= mpLast
->mpNext
= pEntry
;
1094 #ifndef DISABLE_DYNLOADING
1105 namespace { struct Cache
: public rtl::Static
<ImpFilterLibCache
, Cache
> {}; }
1107 GraphicFilter::GraphicFilter( bool bConfig
)
1109 , bUseConfig(bConfig
)
1115 GraphicFilter::~GraphicFilter()
1118 ::osl::MutexGuard
aGuard( getListMutex() );
1120 FilterList_impl::iterator it
= pFilterHdlList
->begin();
1121 it
!= pFilterHdlList
->end();
1126 pFilterHdlList
->erase( it
);
1130 if( pFilterHdlList
->empty() )
1132 delete pFilterHdlList
;
1133 pFilterHdlList
= nullptr;
1141 void GraphicFilter::ImplInit()
1144 ::osl::MutexGuard
aGuard( getListMutex() );
1146 if ( !pFilterHdlList
)
1148 pFilterHdlList
= new FilterList_impl
;
1149 pConfig
= new FilterConfigCache( bUseConfig
);
1152 pConfig
= pFilterHdlList
->front()->pConfig
;
1154 pFilterHdlList
->push_back( this );
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
;
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
);
1205 OUString
GraphicFilter::GetImportFormatMediaType( sal_uInt16 nFormat
)
1207 return pConfig
->GetImportFormatMediaType( nFormat
);
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
));
1286 nRetValue
= CanImportGraphic( aMainUrl
, *xStream
, nFormat
, pDeterminedFormat
);
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
));
1316 nRetValue
= ImportGraphic( rGraphic
, aMainUrl
, *xStream
, nFormat
, pDeterminedFormat
, nImportFlags
);
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
;
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;
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
;
1365 nImportFlags
&=~GraphicFilterImportFlags::ForPreview
;
1368 else if ( (*pFilterData
)[ i
].Name
== "AllowPartialStreamRead" )
1370 (*pFilterData
)[ i
].Value
>>= bAllowPartialStreamRead
;
1371 if ( bAllowPartialStreamRead
)
1372 nImportFlags
|= GraphicFilterImportFlags::AllowPartialStreamRead
;
1374 nImportFlags
&=~GraphicFilterImportFlags::AllowPartialStreamRead
;
1376 else if ( (*pFilterData
)[ i
].Name
== "CreateNativeLink" )
1378 (*pFilterData
)[ i
].Value
>>= bCreateNativeLink
;
1383 if( !pContext
|| bDummyContext
)
1387 rGraphic
.SetDummyContext( false );
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);
1416 if( pContext
&& !bDummyContext
)
1417 aFilterName
= pContext
->GetUpperFilterName();
1420 nStatus
= GRFILTER_OK
;
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
;
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();
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
;
1482 if ( eLinkType
== GfxLinkType::NONE
)
1484 BitmapEx
aBmpEx( aPNGReader
.Read( aPreviewSizeHint
) );
1485 if ( aBmpEx
.IsEmpty() )
1486 nStatus
= GRFILTER_FILTERERROR
;
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
;
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
);
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
;
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
);
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
);
1572 eLinkType
= GfxLinkType::NativeSvg
;
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
;
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
) )
1626 if( !ConvertWMFToGDIMetaFile( rIStream
, aMtf
, nullptr, pExtHeader
) )
1627 nStatus
= GRFILTER_FORMATERROR
;
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
);
1644 SvMemoryStream aTempStream
;
1645 if( aTempStream
.GetError() )
1646 return GRFILTER_OPENERROR
;
1648 if( !SgfBMapFilter( rIStream
, aTempStream
) )
1649 nStatus
= GRFILTER_FILTERERROR
;
1652 aTempStream
.Seek( 0L );
1653 ReadGraphic( aTempStream
, rGraphic
);
1655 if( aTempStream
.GetError() )
1656 nStatus
= GRFILTER_FILTERERROR
;
1664 if( !SgfVectFilter( rIStream
, aMtf
) )
1665 nStatus
= GRFILTER_FILTERERROR
;
1667 rGraphic
= Graphic( aMtf
);
1673 if( nVersion
!= SGV_VERSION
)
1674 nStatus
= GRFILTER_VERSIONERROR
;
1678 if( !SgfSDrwFilter( rIStream
, aMtf
,
1679 INetURLObject(aFilterPath
) ) )
1681 nStatus
= GRFILTER_FILTERERROR
;
1684 rGraphic
= Graphic( aMtf
);
1691 nStatus
= GRFILTER_FORMATERROR
;
1696 else if (aFilterName
== IMP_PDF
)
1698 if (!vcl::ImportPDF(rIStream
, rGraphic
))
1699 nStatus
= GRFILTER_FILTERERROR
;
1701 eLinkType
= GfxLinkType::NativePdf
;
1704 nStatus
= GRFILTER_FILTERERROR
;
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
);
1716 nStatus
= GRFILTER_FILTERERROR
;
1719 PFilterCall pFunc
= pFilter
->GetImportFunction();
1722 nStatus
= GRFILTER_FILTERERROR
;
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
;
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
);
1793 delete pFilterConfigItem
;
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
1806 return GRFILTER_FORMATERROR
;
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
));
1817 nRetValue
= ExportGraphic( rGraphic
, aMainUrl
, *xStream
, nFormat
, pFilterData
);
1820 if( ( GRFILTER_OK
!= nRetValue
) && !bAlreadyExists
)
1821 KillDirEntry( aMainUrl
);
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
);
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
1849 (void) nExpGraphHint
;
1851 return GRFILTER_FORMATERROR
;
1853 SAL_INFO( "vcl.filter", "GraphicFilter::ExportGraphic() (thb)" );
1854 sal_uInt16 nFormatCount
= GetExportFormatCount();
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
) )
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));
1881 sal_uInt16 nStatus
= GRFILTER_OK
;
1883 Graphic
aGraphic( rGraphic
);
1885 aGraphic
= ImpGetScaledGraphic( rGraphic
, aConfigItem
);
1886 eType
= aGraphic
.GetType();
1888 if( pConfig
->IsExportPixelFormat( nFormat
) )
1890 if( eType
!= GraphicType::Bitmap
)
1893 sal_uLong nColorCount
,nBitsPerPixel
,nNeededMem
,nMaxMem
;
1894 ScopedVclPtrInstance
< VirtualDevice
> aVirDev
;
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 ) ;
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
);
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
++ )
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
;
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
) )
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
;
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
;
2109 nStatus
= GRFILTER_FILTERERROR
;
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
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
;
2139 if ( !(*pFunc
)( rOStm
, aGraphic
, &aConfigItem
) )
2140 nStatus
= GRFILTER_FORMATERROR
;
2144 nStatus
= GRFILTER_FILTERERROR
;
2148 if( nStatus
!= GRFILTER_OK
)
2150 ImplSetError( nStatus
, &rOStm
);
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
) );
2168 IMPL_LINK( GraphicFilter
, FilterCallback
, ConvertData
&, rData
, bool )
2172 sal_uInt16 nFormat
= GRFILTER_FORMAT_DONTKNOW
;
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;
2191 if( GraphicType::NONE
== rData
.maGraphic
.GetType() || rData
.maGraphic
.GetContext() ) // 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() )
2201 nFormat
= GetExportFormatNumberForShortName( OStringToOUString(aShortName
, RTL_TEXTENCODING_UTF8
) );
2202 bRet
= ExportGraphic( rData
.maGraphic
, OUString(), rData
.mrStm
, nFormat
) == 0;
2210 class StandardGraphicFilter
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
)
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
;
2254 nRes
= pFilter
->ImportGraphic( rGraphic
, aURL
, nFilter
, pDeterminedFormat
);
2256 nRes
= pFilter
->ImportGraphic( rGraphic
, rPath
, *pStream
, nFilter
, pDeterminedFormat
);
2259 OUString aReturnString
;
2263 case GRFILTER_OPENERROR
:
2264 aReturnString
="open error";
2266 case GRFILTER_IOERROR
:
2267 aReturnString
="IO error";
2269 case GRFILTER_FORMATERROR
:
2270 aReturnString
="format error";
2272 case GRFILTER_VERSIONERROR
:
2273 aReturnString
="version error";
2275 case GRFILTER_FILTERERROR
:
2276 aReturnString
="filter error";
2278 case GRFILTER_ABORT
:
2279 aReturnString
="import aborted";
2281 case GRFILTER_TOOBIG
:
2282 aReturnString
="graphic is too big";
2285 // nothing more to do
2289 SAL_INFO_IF( nRes
, "vcl.filter", "Problem importing graphic " << rPath
<< ". Reason: " << aReturnString
);
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: */