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 <sal/log.hxx>
23 #include <osl/mutex.hxx>
24 #include <comphelper/processfactory.hxx>
25 #include <comphelper/threadpool.hxx>
26 #include <ucbhelper/content.hxx>
27 #include <cppuhelper/implbase.hxx>
28 #include <tools/fract.hxx>
29 #include <unotools/configmgr.hxx>
30 #include <tools/stream.hxx>
31 #include <tools/urlobj.hxx>
32 #include <tools/zcodec.hxx>
33 #include <vcl/dibtools.hxx>
34 #include <vcl/fltcall.hxx>
35 #include <vcl/salctype.hxx>
36 #include <vcl/pngread.hxx>
37 #include <vcl/pngwrite.hxx>
38 #include <vcl/vectorgraphicdata.hxx>
39 #include <vcl/virdev.hxx>
40 #include <impgraph.hxx>
41 #include <vcl/svapp.hxx>
42 #include <osl/file.hxx>
43 #include <vcl/graphicfilter.hxx>
44 #include <vcl/FilterConfigItem.hxx>
45 #include <vcl/wmf.hxx>
46 #include "igif/gifread.hxx"
47 #include <vcl/pdfread.hxx>
48 #include "jpeg/jpeg.hxx"
49 #include "ixbm/xbmread.hxx"
50 #include "ixpm/xpmread.hxx"
51 #include <osl/module.hxx>
52 #include <com/sun/star/uno/Reference.h>
53 #include <com/sun/star/awt/Size.hpp>
54 #include <com/sun/star/uno/XInterface.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 <com/sun/star/ucb/ContentCreationException.hpp>
62 #include <unotools/ucbstreamhelper.hxx>
63 #include <rtl/bootstrap.hxx>
64 #include <rtl/instance.hxx>
65 #include <tools/svlibrary.h>
66 #include <comphelper/string.hxx>
70 #include "FilterConfigCache.hxx"
71 #include "graphicfilter_internal.hxx"
73 #include <graphic/GraphicFormatDetector.hxx>
75 #define PMGCHUNG_msOG 0x6d734f47 // Microsoft Office Animated GIF
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
>
90 virtual void SAL_CALL
writeBytes( const css::uno::Sequence
< sal_Int8
>& rData
) override
91 { mrStm
.WriteBytes(rData
.getConstArray(), rData
.getLength()); }
92 virtual void SAL_CALL
flush() override
94 virtual void SAL_CALL
closeOutput() override
{}
98 explicit ImpFilterOutputStream( SvStream
& rStm
) : mrStm( rStm
) {}
101 static bool DirEntryExists( const INetURLObject
& rObj
)
103 bool bExists
= false;
107 ::ucbhelper::Content
aCnt( rObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
),
108 css::uno::Reference
< css::ucb::XCommandEnvironment
>(),
109 comphelper::getProcessComponentContext() );
111 bExists
= aCnt
.isDocument();
113 catch(const css::ucb::CommandAbortedException
&)
115 SAL_WARN( "vcl.filter", "CommandAbortedException" );
117 catch(const css::ucb::ContentCreationException
&)
119 SAL_WARN( "vcl.filter", "ContentCreationException" );
123 SAL_WARN( "vcl.filter", "Any other exception" );
128 static void KillDirEntry( const OUString
& rMainUrl
)
132 ::ucbhelper::Content
aCnt( rMainUrl
,
133 css::uno::Reference
< css::ucb::XCommandEnvironment
>(),
134 comphelper::getProcessComponentContext() );
136 aCnt
.executeCommand( "delete",
137 css::uno::makeAny( true ) );
139 catch(const css::ucb::CommandAbortedException
&)
141 SAL_WARN( "vcl.filter", "CommandAbortedException" );
145 SAL_WARN( "vcl.filter", "Any other exception" );
151 sal_uInt8
* ImplSearchEntry( sal_uInt8
* pSource
, sal_uInt8
const * pDest
, sal_uLong nComp
, sal_uLong nSize
)
153 while ( nComp
-- >= nSize
)
156 for ( i
= 0; i
< nSize
; i
++ )
158 if ( ( pSource
[i
]&~0x20 ) != ( pDest
[i
]&~0x20 ) )
168 static OUString
ImpGetExtension( const OUString
&rPath
)
171 INetURLObject
aURL( rPath
);
172 aExt
= aURL
.GetFileExtension().toAsciiUpperCase();
176 bool isPCT(SvStream
& rStream
, sal_uLong nStreamPos
, sal_uLong nStreamLen
)
179 // store number format
180 SvStreamEndian oldNumberFormat
= rStream
.GetEndian();
181 sal_uInt32 nOffset
; // in MS documents the pict format is used without the first 512 bytes
182 for ( nOffset
= 0; ( nOffset
<= 512 ) && ( ( nStreamPos
+ nOffset
+ 14 ) <= nStreamLen
); nOffset
+= 512 )
187 rStream
.Seek( nStreamPos
+ nOffset
);
188 // size of the pict in version 1 pict ( 2bytes) : ignored
190 // bounding box (bytes 2 -> 9)
191 rStream
.SetEndian(SvStreamEndian::BIG
);
192 rStream
.ReadInt16( y1
).ReadInt16( x1
).ReadInt16( y2
).ReadInt16( x2
);
193 rStream
.SetEndian(oldNumberFormat
); // reset format
195 if (x1
> x2
|| y1
> y2
|| // bad bdbox
196 (x1
== x2
&& y1
== y2
) || // 1 pixel picture
197 x2
-x1
> 2048 || y2
-y1
> 2048 ) // picture abnormally big
201 rStream
.ReadBytes(sBuf
, 3);
202 // see http://developer.apple.com/legacy/mac/library/documentation/mac/pdf/Imaging_With_QuickDraw/Appendix_A.pdf
203 // normal version 2 - page A23 and A24
204 if ( sBuf
[ 0 ] == 0x00 && sBuf
[ 1 ] == 0x11 && sBuf
[ 2 ] == 0x02)
206 // normal version 1 - page A25
207 else if (sBuf
[ 0 ] == 0x11 && sBuf
[ 1 ] == 0x01 && bdBoxOk
)
213 /*************************************************************************
215 * ImpPeekGraphicFormat()
218 * This function is two-fold:
219 * 1.) Start reading file, determine the file format:
222 * rFormatExtension - content matter
225 * Return value - true if success
226 * rFormatExtension - on success: normal file extension in capitals
227 * 2.) Start reading file, verify file format
230 * rFormatExtension - normal file extension in capitals
233 * Return value - false, if cannot verify the file type
234 * passed to the function
235 * true, when the format is PROBABLY verified or
236 * WHEN THE FORMAT IS NOT KNOWN!
238 *************************************************************************/
240 bool ImpPeekGraphicFormat( SvStream
& rStream
, OUString
& rFormatExtension
, bool bTest
)
242 vcl::GraphicFormatDetector
aDetector(rStream
, rFormatExtension
);
243 if (!aDetector
.detect())
246 // The following variable is used when bTest == true. It remains false
247 // if the format (rFormatExtension) has not yet been set.
248 bool bSomethingTested
= false;
250 // Now the different formats are checked. The order *does* matter. e.g. a MET file
251 // could also go through the BMP test, however, a BMP file can hardly go through the MET test.
252 // So MET should be tested prior to BMP. However, theoretically a BMP file could conceivably
253 // go through the MET test. These problems are of course not only in MET and BMP.
254 // Therefore, in the case of a format check (bTest == true) we only test *exactly* this
255 // format. Everything else could have fatal consequences, for example if the user says it is
256 // a BMP file (and it is a BMP) file, and the file would go through the MET test ...
258 if (!bTest
|| rFormatExtension
.startsWith("MET"))
260 bSomethingTested
= true;
261 if (aDetector
.checkMET())
263 rFormatExtension
= aDetector
.msDetectedFormat
;
268 if (!bTest
|| rFormatExtension
.startsWith("BMP"))
270 bSomethingTested
= true;
271 if (aDetector
.checkBMP())
273 rFormatExtension
= aDetector
.msDetectedFormat
;
279 rFormatExtension
.startsWith("WMF") ||
280 rFormatExtension
.startsWith("EMF"))
282 bSomethingTested
= true;
283 if (aDetector
.checkWMForEMF())
285 rFormatExtension
= aDetector
.msDetectedFormat
;
290 if (!bTest
|| rFormatExtension
.startsWith("PCX"))
292 bSomethingTested
= true;
293 if (aDetector
.checkPCX())
295 rFormatExtension
= aDetector
.msDetectedFormat
;
300 if (!bTest
|| rFormatExtension
.startsWith("TIF"))
302 bSomethingTested
= true;
303 if (aDetector
.checkTIF())
305 rFormatExtension
= aDetector
.msDetectedFormat
;
310 if (!bTest
|| rFormatExtension
.startsWith("GIF"))
312 bSomethingTested
= true;
313 if (aDetector
.checkGIF())
315 rFormatExtension
= aDetector
.msDetectedFormat
;
320 if (!bTest
|| rFormatExtension
.startsWith("PNG"))
322 bSomethingTested
= true;
323 if (aDetector
.checkPNG())
325 rFormatExtension
= aDetector
.msDetectedFormat
;
330 if (!bTest
|| rFormatExtension
.startsWith("JPG"))
332 bSomethingTested
= true;
333 if (aDetector
.checkJPG())
335 rFormatExtension
= aDetector
.msDetectedFormat
;
340 if (!bTest
|| rFormatExtension
.startsWith("SVM"))
342 bSomethingTested
= true;
343 if (aDetector
.checkSVM())
345 rFormatExtension
= aDetector
.msDetectedFormat
;
350 if (!bTest
|| rFormatExtension
.startsWith("PCD"))
352 bSomethingTested
= true;
353 if (aDetector
.checkPCD())
355 rFormatExtension
= aDetector
.msDetectedFormat
;
360 if (!bTest
|| rFormatExtension
.startsWith("PSD"))
362 bSomethingTested
= true;
363 if (aDetector
.checkPSD())
365 rFormatExtension
= aDetector
.msDetectedFormat
;
370 if (!bTest
|| rFormatExtension
.startsWith("EPS"))
372 bSomethingTested
= true;
373 if (aDetector
.checkEPS())
375 rFormatExtension
= aDetector
.msDetectedFormat
;
380 if (!bTest
|| rFormatExtension
.startsWith("DXF"))
382 if (aDetector
.checkDXF())
384 rFormatExtension
= aDetector
.msDetectedFormat
;
389 if (!bTest
|| rFormatExtension
.startsWith("PCT"))
391 bSomethingTested
= true;
392 if (aDetector
.checkPCT())
394 rFormatExtension
= aDetector
.msDetectedFormat
;
400 rFormatExtension
.startsWith("PBM") ||
401 rFormatExtension
.startsWith("PGM") ||
402 rFormatExtension
.startsWith("PPM"))
404 bSomethingTested
= true;
405 if (aDetector
.checkPBMorPGMorPPM())
407 rFormatExtension
= aDetector
.msDetectedFormat
;
412 if (!bTest
|| rFormatExtension
.startsWith("RAS"))
414 bSomethingTested
= true;
415 if (aDetector
.checkRAS())
417 rFormatExtension
= aDetector
.msDetectedFormat
;
424 bSomethingTested
= true;
425 if (aDetector
.checkXPM())
427 rFormatExtension
= aDetector
.msDetectedFormat
;
432 else if (rFormatExtension
.startsWith("XPM"))
439 if (aDetector
.checkXBM())
441 rFormatExtension
= aDetector
.msDetectedFormat
;
445 else if (rFormatExtension
.startsWith("XBM"))
452 if (aDetector
.checkSVG())
454 rFormatExtension
= aDetector
.msDetectedFormat
;
458 else if (rFormatExtension
.startsWith("SVG"))
463 if (!bTest
|| rFormatExtension
.startsWith("TGA"))
465 bSomethingTested
= true;
466 if (aDetector
.checkTGA())
468 rFormatExtension
= aDetector
.msDetectedFormat
;
473 if (!bTest
|| rFormatExtension
.startsWith("MOV"))
475 if (aDetector
.checkMOV())
477 rFormatExtension
= aDetector
.msDetectedFormat
;
482 if (!bTest
|| rFormatExtension
.startsWith("PDF"))
484 if (aDetector
.checkPDF())
486 rFormatExtension
= aDetector
.msDetectedFormat
;
491 return bTest
&& !bSomethingTested
;
494 ErrCode
GraphicFilter::ImpTestOrFindFormat( const OUString
& rPath
, SvStream
& rStream
, sal_uInt16
& rFormat
)
496 // determine or check the filter/format by reading into it
497 if( rFormat
== GRFILTER_FORMAT_DONTKNOW
)
500 if( ImpPeekGraphicFormat( rStream
, aFormatExt
, false ) )
502 rFormat
= pConfig
->GetImportFormatNumberForExtension( aFormatExt
);
503 if( rFormat
!= GRFILTER_FORMAT_DONTKNOW
)
506 // determine filter by file extension
507 if( !rPath
.isEmpty() )
509 OUString
aExt( ImpGetExtension( rPath
) );
510 rFormat
= pConfig
->GetImportFormatNumberForExtension( aExt
);
511 if( rFormat
!= GRFILTER_FORMAT_DONTKNOW
)
514 return ERRCODE_GRFILTER_FORMATERROR
;
518 OUString
aTmpStr( pConfig
->GetImportFormatExtension( rFormat
) );
519 aTmpStr
= aTmpStr
.toAsciiUpperCase();
520 if( !ImpPeekGraphicFormat( rStream
, aTmpStr
, true ) )
521 return ERRCODE_GRFILTER_FORMATERROR
;
522 if ( pConfig
->GetImportFormatExtension( rFormat
).equalsIgnoreAsciiCase( "pcd" ) )
524 sal_Int32 nBase
= 2; // default Base0
525 if ( pConfig
->GetImportFilterType( rFormat
).equalsIgnoreAsciiCase( "pcd_Photo_CD_Base4" ) )
527 else if ( pConfig
->GetImportFilterType( rFormat
).equalsIgnoreAsciiCase( "pcd_Photo_CD_Base16" ) )
529 FilterConfigItem
aFilterConfigItem( "Office.Common/Filter/Graphic/Import/PCD" );
530 aFilterConfigItem
.WriteInt32( "Resolution", nBase
);
537 static Graphic
ImpGetScaledGraphic( const Graphic
& rGraphic
, FilterConfigItem
& rConfigItem
)
541 sal_Int32 nLogicalWidth
= rConfigItem
.ReadInt32( "LogicalWidth", 0 );
542 sal_Int32 nLogicalHeight
= rConfigItem
.ReadInt32( "LogicalHeight", 0 );
544 if ( rGraphic
.GetType() != GraphicType::NONE
)
546 sal_Int32 nMode
= rConfigItem
.ReadInt32( "ExportMode", -1 );
548 if ( nMode
== -1 ) // the property is not there, this is possible, if the graphic filter
549 { // is called via UnoGraphicExporter and not from a graphic export Dialog
550 nMode
= 0; // then we are defaulting this mode to 0
551 if ( nLogicalWidth
|| nLogicalHeight
)
556 Size
aPrefSize( rGraphic
.GetPrefSize() );
557 MapMode
aPrefMapMode( rGraphic
.GetPrefMapMode() );
558 if (aPrefMapMode
.GetMapUnit() == MapUnit::MapPixel
)
559 aOriginalSize
= Application::GetDefaultDevice()->PixelToLogic(aPrefSize
, MapMode(MapUnit::Map100thMM
));
561 aOriginalSize
= OutputDevice::LogicToLogic(aPrefSize
, aPrefMapMode
, MapMode(MapUnit::Map100thMM
));
562 if ( !nLogicalWidth
)
563 nLogicalWidth
= aOriginalSize
.Width();
564 if ( !nLogicalHeight
)
565 nLogicalHeight
= aOriginalSize
.Height();
566 if( rGraphic
.GetType() == GraphicType::Bitmap
)
572 BitmapEx
aBitmap( rGraphic
.GetBitmapEx() );
573 MapMode
aMap( MapUnit::Map100thInch
);
575 sal_Int32 nDPI
= rConfigItem
.ReadInt32( "Resolution", 75 );
576 Fraction
aFrac( 1, std::min( std::max( nDPI
, sal_Int32( 75 ) ), sal_Int32( 600 ) ) );
578 aMap
.SetScaleX( aFrac
);
579 aMap
.SetScaleY( aFrac
);
581 Size aOldSize
= aBitmap
.GetSizePixel();
583 aGraphic
.SetPrefMapMode( aMap
);
584 aGraphic
.SetPrefSize( Size( aOldSize
.Width() * 100,
585 aOldSize
.Height() * 100 ) );
588 else if( nMode
== 2 )
591 aGraphic
.SetPrefMapMode( MapMode( MapUnit::Map100thMM
) );
592 aGraphic
.SetPrefSize( Size( nLogicalWidth
, nLogicalHeight
) );
597 sal_Int32 nColors
= rConfigItem
.ReadInt32( "Color", 0 );
598 if ( nColors
) // graphic conversion necessary ?
600 BitmapEx
aBmpEx( aGraphic
.GetBitmapEx() );
601 aBmpEx
.Convert( static_cast<BmpConversion
>(nColors
) ); // the entries in the xml section have the same meaning as
602 aGraphic
= aBmpEx
; // they have in the BmpConversion enum, so it should be
603 } // allowed to cast them
607 if( ( nMode
== 1 ) || ( nMode
== 2 ) )
609 GDIMetaFile
aMtf( rGraphic
.GetGDIMetaFile() );
610 Size
aNewSize( OutputDevice::LogicToLogic(Size(nLogicalWidth
, nLogicalHeight
), MapMode(MapUnit::Map100thMM
), aMtf
.GetPrefMapMode()) );
612 if( aNewSize
.Width() && aNewSize
.Height() )
614 const Size
aPreferredSize( aMtf
.GetPrefSize() );
615 aMtf
.Scale( Fraction( aNewSize
.Width(), aPreferredSize
.Width() ),
616 Fraction( aNewSize
.Height(), aPreferredSize
.Height() ) );
618 aGraphic
= Graphic( aMtf
);
631 static OUString
ImpCreateFullFilterPath( const OUString
& rPath
, const OUString
& rFilterName
)
635 ::osl::FileBase::getFileURLFromSystemPath( rPath
, aPathURL
);
638 OUString aSystemPath
;
639 ::osl::FileBase::getSystemPathFromFileURL( aPathURL
, aSystemPath
);
640 aSystemPath
+= rFilterName
;
645 class ImpFilterLibCache
;
647 struct ImpFilterLibCacheEntry
649 ImpFilterLibCacheEntry
* mpNext
;
650 #ifndef DISABLE_DYNLOADING
651 osl::Module maLibrary
;
653 OUString
const maFiltername
;
654 OUString
const maFormatName
;
655 PFilterCall mpfnImport
;
657 ImpFilterLibCacheEntry(const OUString
& rPathname
, const OUString
& rFiltername
, const OUString
& rFormatName
);
658 bool operator==( const OUString
& rFiltername
) const { return maFiltername
== rFiltername
; }
660 PFilterCall
GetImportFunction();
663 ImpFilterLibCacheEntry::ImpFilterLibCacheEntry( const OUString
& rPathname
, const OUString
& rFiltername
, const OUString
& rFormatName
) :
665 #ifndef DISABLE_DYNLOADING
666 maLibrary ( rPathname
),
668 maFiltername ( rFiltername
),
669 maFormatName ( rFormatName
),
670 mpfnImport ( nullptr )
672 #ifdef DISABLE_DYNLOADING
677 #ifdef DISABLE_DYNLOADING
679 extern "C" bool icdGraphicImport( SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
* pConfigItem
);
680 extern "C" bool idxGraphicImport( SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
* pConfigItem
);
681 extern "C" bool imeGraphicImport( SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
* pConfigItem
);
682 extern "C" bool ipbGraphicImport( SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
* pConfigItem
);
683 extern "C" bool ipdGraphicImport( SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
* pConfigItem
);
684 extern "C" bool ipsGraphicImport( SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
* pConfigItem
);
685 extern "C" bool iptGraphicImport( SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
* pConfigItem
);
686 extern "C" bool ipxGraphicImport( SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
* pConfigItem
);
687 extern "C" bool iraGraphicImport( SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
* pConfigItem
);
688 extern "C" bool itgGraphicImport( SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
* pConfigItem
);
689 extern "C" bool itiGraphicImport( SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
* pConfigItem
);
693 PFilterCall
ImpFilterLibCacheEntry::GetImportFunction()
697 #ifndef DISABLE_DYNLOADING
698 if (maFormatName
== "icd")
699 mpfnImport
= reinterpret_cast<PFilterCall
>(maLibrary
.getFunctionSymbol("icdGraphicImport"));
700 else if (maFormatName
== "idx")
701 mpfnImport
= reinterpret_cast<PFilterCall
>(maLibrary
.getFunctionSymbol("idxGraphicImport"));
702 else if (maFormatName
== "ime")
703 mpfnImport
= reinterpret_cast<PFilterCall
>(maLibrary
.getFunctionSymbol("imeGraphicImport"));
704 else if (maFormatName
== "ipb")
705 mpfnImport
= reinterpret_cast<PFilterCall
>(maLibrary
.getFunctionSymbol("ipbGraphicImport"));
706 else if (maFormatName
== "ipd")
707 mpfnImport
= reinterpret_cast<PFilterCall
>(maLibrary
.getFunctionSymbol("ipdGraphicImport"));
708 else if (maFormatName
== "ips")
709 mpfnImport
= reinterpret_cast<PFilterCall
>(maLibrary
.getFunctionSymbol("ipsGraphicImport"));
710 else if (maFormatName
== "ipt")
711 mpfnImport
= reinterpret_cast<PFilterCall
>(maLibrary
.getFunctionSymbol("iptGraphicImport"));
712 else if (maFormatName
== "ipx")
713 mpfnImport
= reinterpret_cast<PFilterCall
>(maLibrary
.getFunctionSymbol("ipxGraphicImport"));
714 else if (maFormatName
== "ira")
715 mpfnImport
= reinterpret_cast<PFilterCall
>(maLibrary
.getFunctionSymbol("iraGraphicImport"));
716 else if (maFormatName
== "itg")
717 mpfnImport
= reinterpret_cast<PFilterCall
>(maLibrary
.getFunctionSymbol("itgGraphicImport"));
718 else if (maFormatName
== "iti")
719 mpfnImport
= reinterpret_cast<PFilterCall
>(maLibrary
.getFunctionSymbol("itiGraphicImport"));
721 if (maFormatName
== "icd")
722 mpfnImport
= icdGraphicImport
;
723 else if (maFormatName
== "idx")
724 mpfnImport
= idxGraphicImport
;
725 else if (maFormatName
== "ime")
726 mpfnImport
= imeGraphicImport
;
727 else if (maFormatName
== "ipb")
728 mpfnImport
= ipbGraphicImport
;
729 else if (maFormatName
== "ipd")
730 mpfnImport
= ipdGraphicImport
;
731 else if (maFormatName
== "ips")
732 mpfnImport
= ipsGraphicImport
;
733 else if (maFormatName
== "ipt")
734 mpfnImport
= iptGraphicImport
;
735 else if (maFormatName
== "ipx")
736 mpfnImport
= ipxGraphicImport
;
737 else if (maFormatName
== "ira")
738 mpfnImport
= iraGraphicImport
;
739 else if (maFormatName
== "itg")
740 mpfnImport
= itgGraphicImport
;
741 else if (maFormatName
== "iti")
742 mpfnImport
= itiGraphicImport
;
749 class ImpFilterLibCache
751 ImpFilterLibCacheEntry
* mpFirst
;
752 ImpFilterLibCacheEntry
* mpLast
;
756 ~ImpFilterLibCache();
758 ImpFilterLibCacheEntry
* GetFilter( const OUString
& rFilterPath
, const OUString
& rFiltername
, const OUString
& rFormatName
);
761 ImpFilterLibCache::ImpFilterLibCache() :
767 ImpFilterLibCache::~ImpFilterLibCache()
769 ImpFilterLibCacheEntry
* pEntry
= mpFirst
;
772 ImpFilterLibCacheEntry
* pNext
= pEntry
->mpNext
;
778 ImpFilterLibCacheEntry
* ImpFilterLibCache::GetFilter(const OUString
& rFilterPath
, const OUString
& rFilterName
, const OUString
& rFormatName
)
780 ImpFilterLibCacheEntry
* pEntry
= mpFirst
;
784 if( *pEntry
== rFilterName
&& pEntry
->maFormatName
== rFormatName
)
787 pEntry
= pEntry
->mpNext
;
791 OUString
aPhysicalName( ImpCreateFullFilterPath( rFilterPath
, rFilterName
) );
792 pEntry
= new ImpFilterLibCacheEntry(aPhysicalName
, rFilterName
, rFormatName
);
793 #ifndef DISABLE_DYNLOADING
794 if ( pEntry
->maLibrary
.is() )
798 mpFirst
= mpLast
= pEntry
;
800 mpLast
= mpLast
->mpNext
= pEntry
;
802 #ifndef DISABLE_DYNLOADING
813 namespace { struct Cache
: public rtl::Static
<ImpFilterLibCache
, Cache
> {}; }
815 GraphicFilter::GraphicFilter( bool bConfig
)
816 : bUseConfig(bConfig
)
821 GraphicFilter::~GraphicFilter()
824 ::osl::MutexGuard
aGuard( getListMutex() );
825 auto it
= std::find(pFilterHdlList
->begin(), pFilterHdlList
->end(), this);
826 if( it
!= pFilterHdlList
->end() )
827 pFilterHdlList
->erase( it
);
829 if( pFilterHdlList
->empty() )
831 delete pFilterHdlList
;
832 pFilterHdlList
= nullptr;
840 void GraphicFilter::ImplInit()
843 ::osl::MutexGuard
aGuard( getListMutex() );
845 if ( !pFilterHdlList
)
847 pFilterHdlList
= new FilterList_impl
;
848 pConfig
= new FilterConfigCache( bUseConfig
);
851 pConfig
= pFilterHdlList
->front()->pConfig
;
853 pFilterHdlList
->push_back( this );
858 OUString
url("$BRAND_BASE_DIR/" LIBO_LIB_FOLDER
);
859 rtl::Bootstrap::expandMacros(url
); //TODO: detect failure
860 osl::FileBase::getSystemPathFromFileURL(url
, aFilterPath
);
863 pErrorEx
.reset( new FilterErrorEx
);
866 ErrCode
GraphicFilter::ImplSetError( ErrCode nError
, const SvStream
* pStm
)
868 pErrorEx
->nStreamError
= pStm
? pStm
->GetError() : ERRCODE_NONE
;
872 sal_uInt16
GraphicFilter::GetImportFormatCount()
874 return pConfig
->GetImportFormatCount();
877 sal_uInt16
GraphicFilter::GetImportFormatNumber( const OUString
& rFormatName
)
879 return pConfig
->GetImportFormatNumber( rFormatName
);
882 sal_uInt16
GraphicFilter::GetImportFormatNumberForShortName( const OUString
& rShortName
)
884 return pConfig
->GetImportFormatNumberForShortName( rShortName
);
887 sal_uInt16
GraphicFilter::GetImportFormatNumberForTypeName( const OUString
& rType
)
889 return pConfig
->GetImportFormatNumberForTypeName( rType
);
892 OUString
GraphicFilter::GetImportFormatName( sal_uInt16 nFormat
)
894 return pConfig
->GetImportFormatName( nFormat
);
897 OUString
GraphicFilter::GetImportFormatTypeName( sal_uInt16 nFormat
)
899 return pConfig
->GetImportFilterTypeName( nFormat
);
903 OUString
GraphicFilter::GetImportFormatMediaType( sal_uInt16 nFormat
)
905 return pConfig
->GetImportFormatMediaType( nFormat
);
909 OUString
GraphicFilter::GetImportFormatShortName( sal_uInt16 nFormat
)
911 return pConfig
->GetImportFormatShortName( nFormat
);
914 OUString
GraphicFilter::GetImportWildcard( sal_uInt16 nFormat
, sal_Int32 nEntry
)
916 return pConfig
->GetImportWildcard( nFormat
, nEntry
);
919 sal_uInt16
GraphicFilter::GetExportFormatCount()
921 return pConfig
->GetExportFormatCount();
924 sal_uInt16
GraphicFilter::GetExportFormatNumber( const OUString
& rFormatName
)
926 return pConfig
->GetExportFormatNumber( rFormatName
);
929 sal_uInt16
GraphicFilter::GetExportFormatNumberForMediaType( const OUString
& rMediaType
)
931 return pConfig
->GetExportFormatNumberForMediaType( rMediaType
);
934 sal_uInt16
GraphicFilter::GetExportFormatNumberForShortName( const OUString
& rShortName
)
936 return pConfig
->GetExportFormatNumberForShortName( rShortName
);
939 OUString
GraphicFilter::GetExportInternalFilterName( sal_uInt16 nFormat
)
941 return pConfig
->GetExportInternalFilterName( nFormat
);
944 sal_uInt16
GraphicFilter::GetExportFormatNumberForTypeName( const OUString
& rType
)
946 return pConfig
->GetExportFormatNumberForTypeName( rType
);
949 OUString
GraphicFilter::GetExportFormatName( sal_uInt16 nFormat
)
951 return pConfig
->GetExportFormatName( nFormat
);
954 OUString
GraphicFilter::GetExportFormatMediaType( sal_uInt16 nFormat
)
956 return pConfig
->GetExportFormatMediaType( nFormat
);
959 OUString
GraphicFilter::GetExportFormatShortName( sal_uInt16 nFormat
)
961 return pConfig
->GetExportFormatShortName( nFormat
);
964 OUString
GraphicFilter::GetExportWildcard( sal_uInt16 nFormat
)
966 return pConfig
->GetExportWildcard( nFormat
, 0 );
969 bool GraphicFilter::IsExportPixelFormat( sal_uInt16 nFormat
)
971 return pConfig
->IsExportPixelFormat( nFormat
);
974 ErrCode
GraphicFilter::CanImportGraphic( const INetURLObject
& rPath
,
975 sal_uInt16 nFormat
, sal_uInt16
* pDeterminedFormat
)
977 ErrCode nRetValue
= ERRCODE_GRFILTER_FORMATERROR
;
978 SAL_WARN_IF( rPath
.GetProtocol() == INetProtocol::NotValid
, "vcl.filter", "GraphicFilter::CanImportGraphic() : ProtType == INetProtocol::NotValid" );
980 OUString
aMainUrl( rPath
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
981 std::unique_ptr
<SvStream
> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl
, StreamMode::READ
| StreamMode::SHARE_DENYNONE
));
984 nRetValue
= CanImportGraphic( aMainUrl
, *xStream
, nFormat
, pDeterminedFormat
);
989 ErrCode
GraphicFilter::CanImportGraphic( const OUString
& rMainUrl
, SvStream
& rIStream
,
990 sal_uInt16 nFormat
, sal_uInt16
* pDeterminedFormat
)
992 sal_uLong nStreamPos
= rIStream
.Tell();
993 ErrCode nRes
= ImpTestOrFindFormat( rMainUrl
, rIStream
, nFormat
);
995 rIStream
.Seek(nStreamPos
);
997 if( nRes
==ERRCODE_NONE
&& pDeterminedFormat
!=nullptr )
998 *pDeterminedFormat
= nFormat
;
1000 return ImplSetError( nRes
, &rIStream
);
1003 //SJ: TODO, we need to create a GraphicImporter component
1004 ErrCode
GraphicFilter::ImportGraphic( Graphic
& rGraphic
, const INetURLObject
& rPath
,
1005 sal_uInt16 nFormat
, sal_uInt16
* pDeterminedFormat
, GraphicFilterImportFlags nImportFlags
)
1007 ErrCode nRetValue
= ERRCODE_GRFILTER_FORMATERROR
;
1008 SAL_WARN_IF( rPath
.GetProtocol() == INetProtocol::NotValid
, "vcl.filter", "GraphicFilter::ImportGraphic() : ProtType == INetProtocol::NotValid" );
1010 OUString
aMainUrl( rPath
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1011 std::unique_ptr
<SvStream
> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl
, StreamMode::READ
| StreamMode::SHARE_DENYNONE
));
1014 nRetValue
= ImportGraphic( rGraphic
, aMainUrl
, *xStream
, nFormat
, pDeterminedFormat
, nImportFlags
);
1019 ErrCode
GraphicFilter::ImportGraphic(
1021 const OUString
& rPath
,
1024 sal_uInt16
* pDeterminedFormat
,
1025 GraphicFilterImportFlags nImportFlags
,
1026 WmfExternal
const *pExtHeader
)
1028 return ImportGraphic( rGraphic
, rPath
, rIStream
, nFormat
, pDeterminedFormat
, nImportFlags
, nullptr, pExtHeader
);
1031 /// Contains a stream and other associated data to import pixels into a
1033 struct GraphicImportContext
1035 /// Pixel data is read from this stream.
1036 std::unique_ptr
<SvStream
> m_pStream
;
1037 /// The Graphic the import filter gets.
1038 std::shared_ptr
<Graphic
> m_pGraphic
;
1039 /// Write pixel data using this access.
1040 std::unique_ptr
<BitmapScopedWriteAccess
> m_pAccess
;
1041 /// Signals if import finished correctly.
1042 ErrCode m_nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1043 /// Original graphic format.
1044 GfxLinkType m_eLinkType
= GfxLinkType::NONE
;
1045 /// Position of the stream before reading the data.
1046 sal_uInt64 m_nStreamBegin
= 0;
1047 /// Flags for the import filter.
1048 GraphicFilterImportFlags m_nImportFlags
= GraphicFilterImportFlags::NONE
;
1051 /// Graphic import worker that gets executed on a thread.
1052 class GraphicImportTask
: public comphelper::ThreadTask
1054 GraphicImportContext
& m_rContext
;
1056 GraphicImportTask(const std::shared_ptr
<comphelper::ThreadTaskTag
>& pTag
, GraphicImportContext
& rContext
);
1057 void doWork() override
;
1058 /// Shared code between threaded and non-threaded version.
1059 static void doImport(GraphicImportContext
& rContext
);
1062 GraphicImportTask::GraphicImportTask(const std::shared_ptr
<comphelper::ThreadTaskTag
>& pTag
, GraphicImportContext
& rContext
)
1063 : comphelper::ThreadTask(pTag
),
1064 m_rContext(rContext
)
1068 void GraphicImportTask::doWork()
1070 GraphicImportTask::doImport(m_rContext
);
1073 void GraphicImportTask::doImport(GraphicImportContext
& rContext
)
1075 if (!ImportJPEG(*rContext
.m_pStream
, *rContext
.m_pGraphic
, rContext
.m_nImportFlags
| GraphicFilterImportFlags::UseExistingBitmap
, rContext
.m_pAccess
.get()))
1076 rContext
.m_nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1078 rContext
.m_eLinkType
= GfxLinkType::NativeJpg
;
1081 void GraphicFilter::ImportGraphics(std::vector
< std::shared_ptr
<Graphic
> >& rGraphics
, std::vector
< std::unique_ptr
<SvStream
> > vStreams
)
1083 static bool bThreads
= !getenv("VCL_NO_THREAD_IMPORT");
1084 std::vector
<GraphicImportContext
> aContexts
;
1085 aContexts
.reserve(vStreams
.size());
1086 comphelper::ThreadPool
& rSharedPool
= comphelper::ThreadPool::getSharedOptimalPool();
1087 std::shared_ptr
<comphelper::ThreadTaskTag
> pTag
= comphelper::ThreadPool::createThreadTaskTag();
1089 for (auto& pStream
: vStreams
)
1091 aContexts
.emplace_back();
1092 GraphicImportContext
& rContext
= aContexts
.back();
1096 rContext
.m_pStream
= std::move(pStream
);
1097 rContext
.m_pGraphic
= std::make_shared
<Graphic
>();
1098 rContext
.m_nStatus
= ERRCODE_NONE
;
1100 // Detect the format.
1102 rContext
.m_nStreamBegin
= rContext
.m_pStream
->Tell();
1103 sal_uInt16 nFormat
= GRFILTER_FORMAT_DONTKNOW
;
1104 rContext
.m_nStatus
= ImpTestOrFindFormat(OUString(), *rContext
.m_pStream
, nFormat
);
1105 rContext
.m_pStream
->Seek(rContext
.m_nStreamBegin
);
1107 // Import the graphic.
1108 if (rContext
.m_nStatus
== ERRCODE_NONE
&& !rContext
.m_pStream
->GetError())
1110 OUString aFilterName
= pConfig
->GetImportFilterName(nFormat
);
1112 if (aFilterName
.equalsIgnoreAsciiCase(IMP_JPEG
))
1114 rContext
.m_nImportFlags
= GraphicFilterImportFlags::SetLogsizeForJpeg
;
1116 if (!ImportJPEG( *rContext
.m_pStream
, *rContext
.m_pGraphic
, rContext
.m_nImportFlags
| GraphicFilterImportFlags::OnlyCreateBitmap
, nullptr))
1117 rContext
.m_nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1120 Bitmap
& rBitmap
= const_cast<Bitmap
&>(rContext
.m_pGraphic
->GetBitmapExRef().GetBitmapRef());
1121 rContext
.m_pAccess
= std::make_unique
<BitmapScopedWriteAccess
>(rBitmap
);
1122 rContext
.m_pStream
->Seek(rContext
.m_nStreamBegin
);
1124 rSharedPool
.pushTask(std::make_unique
<GraphicImportTask
>(pTag
, rContext
));
1126 GraphicImportTask::doImport(rContext
);
1130 rContext
.m_nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1135 rSharedPool
.waitUntilDone(pTag
);
1137 // Process data after import.
1138 for (auto& rContext
: aContexts
)
1140 rContext
.m_pAccess
.reset();
1142 if (rContext
.m_nStatus
== ERRCODE_NONE
&& (rContext
.m_eLinkType
!= GfxLinkType::NONE
) && !rContext
.m_pGraphic
->GetContext())
1144 std::unique_ptr
<sal_uInt8
[]> pGraphicContent
;
1146 const sal_uInt64 nStreamEnd
= rContext
.m_pStream
->Tell();
1147 sal_Int32 nGraphicContentSize
= nStreamEnd
- rContext
.m_nStreamBegin
;
1149 if (nGraphicContentSize
> 0)
1153 pGraphicContent
.reset(new sal_uInt8
[nGraphicContentSize
]);
1155 catch (const std::bad_alloc
&)
1157 rContext
.m_nStatus
= ERRCODE_GRFILTER_TOOBIG
;
1160 if (rContext
.m_nStatus
== ERRCODE_NONE
)
1162 rContext
.m_pStream
->Seek(rContext
.m_nStreamBegin
);
1163 rContext
.m_pStream
->ReadBytes(pGraphicContent
.get(), nGraphicContentSize
);
1167 if (rContext
.m_nStatus
== ERRCODE_NONE
)
1168 rContext
.m_pGraphic
->SetGfxLink(std::make_shared
<GfxLink
>(std::move(pGraphicContent
), nGraphicContentSize
, rContext
.m_eLinkType
));
1171 if (rContext
.m_nStatus
!= ERRCODE_NONE
)
1172 rContext
.m_pGraphic
= nullptr;
1174 rGraphics
.push_back(rContext
.m_pGraphic
);
1178 Graphic
GraphicFilter::ImportUnloadedGraphic(SvStream
& rIStream
, sal_uInt64 sizeLimit
,
1182 sal_uInt16 nFormat
= GRFILTER_FORMAT_DONTKNOW
;
1183 GfxLinkType eLinkType
= GfxLinkType::NONE
;
1187 const sal_uLong nStreamBegin
= rIStream
.Tell();
1189 rIStream
.Seek(nStreamBegin
);
1191 ErrCode nStatus
= ImpTestOrFindFormat("", rIStream
, nFormat
);
1193 rIStream
.Seek(nStreamBegin
);
1194 sal_uInt32
nStreamLength(rIStream
.remainingSize());
1195 if (sizeLimit
&& sizeLimit
< nStreamLength
)
1196 nStreamLength
= sizeLimit
;
1198 OUString aFilterName
= pConfig
->GetImportFilterName(nFormat
);
1199 OUString aExternalFilterName
= pConfig
->GetExternalFilterName(nFormat
, false);
1201 std::unique_ptr
<sal_uInt8
[]> pGraphicContent
;
1202 sal_Int32 nGraphicContentSize
= 0;
1205 if (pConfig
->IsImportInternalFilter(nFormat
))
1207 if (aFilterName
.equalsIgnoreAsciiCase(IMP_GIF
))
1209 eLinkType
= GfxLinkType::NativeGif
;
1211 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_PNG
))
1213 vcl::PNGReader
aPNGReader(rIStream
);
1215 // check if this PNG contains a GIF chunk!
1216 const std::vector
<vcl::PNGReader::ChunkData
>& rChunkData
= aPNGReader
.GetChunks();
1217 for (auto const& chunk
: rChunkData
)
1219 // Microsoft Office is storing Animated GIFs in following chunk
1220 if (chunk
.nType
== PMGCHUNG_msOG
)
1222 sal_uInt32 nChunkSize
= chunk
.aData
.size();
1224 if (nChunkSize
> 11)
1226 const std::vector
<sal_uInt8
>& rData
= chunk
.aData
;
1227 nGraphicContentSize
= nChunkSize
- 11;
1228 SvMemoryStream
aIStrm(const_cast<sal_uInt8
*>(&rData
[11]), nGraphicContentSize
, StreamMode::READ
);
1229 pGraphicContent
.reset(new sal_uInt8
[nGraphicContentSize
]);
1230 sal_uInt64 aCurrentPosition
= aIStrm
.Tell();
1231 aIStrm
.ReadBytes(pGraphicContent
.get(), nGraphicContentSize
);
1232 aIStrm
.Seek(aCurrentPosition
);
1233 eLinkType
= GfxLinkType::NativeGif
;
1238 if (eLinkType
== GfxLinkType::NONE
)
1240 eLinkType
= GfxLinkType::NativePng
;
1243 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_JPEG
))
1245 eLinkType
= GfxLinkType::NativeJpg
;
1247 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_SVG
))
1251 if (nStreamLength
> 0)
1253 std::vector
<sal_uInt8
> aTwoBytes(2);
1254 rIStream
.ReadBytes(aTwoBytes
.data(), 2);
1255 rIStream
.Seek(nStreamBegin
);
1257 if (aTwoBytes
[0] == 0x1F && aTwoBytes
[1] == 0x8B)
1259 SvMemoryStream aMemStream
;
1263 aCodec
.BeginCompression(ZCODEC_DEFAULT_COMPRESSION
, false, true);
1264 nMemoryLength
= aCodec
.Decompress(rIStream
, aMemStream
);
1265 aCodec
.EndCompression();
1267 if (!rIStream
.GetError() && nMemoryLength
>= 0)
1269 nGraphicContentSize
= nMemoryLength
;
1270 pGraphicContent
.reset(new sal_uInt8
[nGraphicContentSize
]);
1272 aMemStream
.Seek(STREAM_SEEK_TO_BEGIN
);
1273 aMemStream
.ReadBytes(pGraphicContent
.get(), nGraphicContentSize
);
1280 nGraphicContentSize
= nStreamLength
;
1281 pGraphicContent
.reset(new sal_uInt8
[nGraphicContentSize
]);
1282 rIStream
.ReadBytes(pGraphicContent
.get(), nStreamLength
);
1290 eLinkType
= GfxLinkType::NativeSvg
;
1294 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1297 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_BMP
))
1299 eLinkType
= GfxLinkType::NativeBmp
;
1301 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_MOV
))
1303 eLinkType
= GfxLinkType::NativeMov
;
1305 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_WMF
) ||
1306 aFilterName
.equalsIgnoreAsciiCase(IMP_EMF
))
1308 nGraphicContentSize
= nStreamLength
;
1309 pGraphicContent
.reset(new sal_uInt8
[nGraphicContentSize
]);
1311 rIStream
.Seek(nStreamBegin
);
1312 rIStream
.ReadBytes(pGraphicContent
.get(), nStreamLength
);
1314 if (!rIStream
.GetError())
1316 eLinkType
= GfxLinkType::NativeWmf
;
1320 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1323 else if (aFilterName
== IMP_PDF
)
1325 eLinkType
= GfxLinkType::NativePdf
;
1329 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1334 ImpFilterLibCacheEntry
* pFilter
= nullptr;
1336 if (!aFilterPath
.isEmpty())
1338 // find first filter in filter paths
1339 ImpFilterLibCache
&rCache
= Cache::get();
1342 pFilter
= rCache
.GetFilter(aFilterPath
.getToken(0, ';', nIdx
), aFilterName
, aExternalFilterName
);
1343 } while (nIdx
>=0 && pFilter
==nullptr);
1347 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1350 PFilterCall pFunc
= pFilter
->GetImportFunction();
1353 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1356 OUString aShortName
;
1357 if (nFormat
!= GRFILTER_FORMAT_DONTKNOW
)
1358 aShortName
= GetImportFormatShortName(nFormat
).toAsciiUpperCase();
1360 if (aShortName
.startsWith(TIF_SHORTNAME
))
1361 eLinkType
= GfxLinkType::NativeTif
;
1362 else if( aShortName
.startsWith(MET_SHORTNAME
))
1363 eLinkType
= GfxLinkType::NativeMet
;
1364 else if( aShortName
.startsWith(PCT_SHORTNAME
))
1365 eLinkType
= GfxLinkType::NativePct
;
1370 if (nStatus
== ERRCODE_NONE
&& eLinkType
!= GfxLinkType::NONE
)
1372 if (!pGraphicContent
)
1374 nGraphicContentSize
= nStreamLength
;
1376 if (nGraphicContentSize
> 0)
1380 pGraphicContent
.reset(new sal_uInt8
[nGraphicContentSize
]);
1382 catch (const std::bad_alloc
&)
1384 nStatus
= ERRCODE_GRFILTER_TOOBIG
;
1387 if (nStatus
== ERRCODE_NONE
)
1389 rIStream
.Seek(nStreamBegin
);
1390 rIStream
.ReadBytes(pGraphicContent
.get(), nGraphicContentSize
);
1395 if( nStatus
== ERRCODE_NONE
)
1397 bool bAnimated
= false;
1398 if (eLinkType
== GfxLinkType::NativeGif
)
1400 SvMemoryStream
aMemoryStream(pGraphicContent
.get(), nGraphicContentSize
, StreamMode::READ
);
1401 bAnimated
= IsGIFAnimated(aMemoryStream
);
1403 aGraphic
.SetGfxLink(std::make_shared
<GfxLink
>(std::move(pGraphicContent
), nGraphicContentSize
, eLinkType
));
1404 aGraphic
.ImplGetImpGraphic()->ImplSetPrepared(bAnimated
, pSizeHint
);
1408 // Set error code or try to set native buffer
1409 if (nStatus
!= ERRCODE_NONE
)
1410 ImplSetError(nStatus
, &rIStream
);
1411 if (nStatus
!= ERRCODE_NONE
|| eLinkType
== GfxLinkType::NONE
)
1412 rIStream
.Seek(nStreamBegin
);
1417 void GraphicFilter::preload()
1419 sal_Int32 nTokenCount
= comphelper::string::getTokenCount(aFilterPath
, ';');
1420 ImpFilterLibCache
& rCache
= Cache::get();
1421 static const std::initializer_list
<OUStringLiteral
> aFilterNames
= {
1422 "icd", "idx", "ime", "ipb", "ipd", "ips", "ipt", "ipx", "ira", "itg", "iti",
1425 // Load library for each filter.
1426 for (const auto& rFilterName
: aFilterNames
)
1428 ImpFilterLibCacheEntry
* pFilter
= nullptr;
1429 // Look at the library in each element inside the filter path.
1430 for (sal_Int32 i
= 0; i
< nTokenCount
; ++i
)
1432 pFilter
= rCache
.GetFilter(aFilterPath
.getToken(i
, ';'), SVLIBRARY("gie"), rFilterName
);
1441 ErrCode
GraphicFilter::ImportGraphic( Graphic
& rGraphic
, const OUString
& rPath
, SvStream
& rIStream
,
1442 sal_uInt16 nFormat
, sal_uInt16
* pDeterminedFormat
, GraphicFilterImportFlags nImportFlags
,
1443 const css::uno::Sequence
< css::beans::PropertyValue
>* pFilterData
,
1444 WmfExternal
const *pExtHeader
)
1446 OUString aFilterName
;
1447 OUString aExternalFilterName
;
1448 sal_uLong nStreamBegin
;
1450 GfxLinkType eLinkType
= GfxLinkType::NONE
;
1451 const bool bLinkSet
= rGraphic
.IsGfxLink();
1453 Size
aPreviewSizeHint( 0, 0 );
1454 bool bAllowPartialStreamRead
= false;
1455 bool bCreateNativeLink
= true;
1457 std::unique_ptr
<sal_uInt8
[]> pGraphicContent
;
1458 sal_Int32 nGraphicContentSize
= 0;
1464 for ( const auto& rPropVal
: *pFilterData
)
1466 if ( rPropVal
.Name
== "PreviewSizeHint" )
1468 css::awt::Size aSize
;
1469 if ( rPropVal
.Value
>>= aSize
)
1471 aPreviewSizeHint
= Size( aSize
.Width
, aSize
.Height
);
1472 if ( aSize
.Width
|| aSize
.Height
)
1473 nImportFlags
|= GraphicFilterImportFlags::ForPreview
;
1475 nImportFlags
&=~GraphicFilterImportFlags::ForPreview
;
1478 else if ( rPropVal
.Name
== "AllowPartialStreamRead" )
1480 rPropVal
.Value
>>= bAllowPartialStreamRead
;
1482 else if ( rPropVal
.Name
== "CreateNativeLink" )
1484 rPropVal
.Value
>>= bCreateNativeLink
;
1489 std::shared_ptr
<GraphicReader
> pContext
= rGraphic
.GetContext();
1490 bool bDummyContext
= rGraphic
.IsDummyContext();
1491 if( !pContext
|| bDummyContext
)
1495 rGraphic
.SetDummyContext( false );
1499 nStreamBegin
= rIStream
.Tell();
1501 nStatus
= ImpTestOrFindFormat( rPath
, rIStream
, nFormat
);
1502 // if pending, return ERRCODE_NONE in order to request more bytes
1503 if( rIStream
.GetError() == ERRCODE_IO_PENDING
)
1505 rGraphic
.SetDummyContext(true);
1506 rIStream
.ResetError();
1507 rIStream
.Seek( nStreamBegin
);
1508 return ImplSetError( ERRCODE_NONE
);
1511 rIStream
.Seek( nStreamBegin
);
1513 if( ( nStatus
!= ERRCODE_NONE
) || rIStream
.GetError() )
1514 return ImplSetError( ( nStatus
!= ERRCODE_NONE
) ? nStatus
: ERRCODE_GRFILTER_OPENERROR
, &rIStream
);
1516 if( pDeterminedFormat
)
1517 *pDeterminedFormat
= nFormat
;
1519 aFilterName
= pConfig
->GetImportFilterName( nFormat
);
1520 aExternalFilterName
= pConfig
->GetExternalFilterName(nFormat
, false);
1524 aFilterName
= pContext
->GetUpperFilterName();
1527 nStatus
= ERRCODE_NONE
;
1531 if ( pConfig
->IsImportInternalFilter( nFormat
) )
1533 if( aFilterName
.equalsIgnoreAsciiCase( IMP_GIF
) )
1535 if( !ImportGIF( rIStream
, rGraphic
) )
1536 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1538 eLinkType
= GfxLinkType::NativeGif
;
1540 else if( aFilterName
.equalsIgnoreAsciiCase( IMP_PNG
) )
1542 vcl::PNGReader
aPNGReader( rIStream
);
1544 // ignore animation for previews and set preview size
1545 if( aPreviewSizeHint
.Width() || aPreviewSizeHint
.Height() )
1547 // position the stream at the end of the image if requested
1548 if( !bAllowPartialStreamRead
)
1549 aPNGReader
.GetChunks();
1553 // check if this PNG contains a GIF chunk!
1554 const std::vector
<vcl::PNGReader::ChunkData
>& rChunkData
= aPNGReader
.GetChunks();
1555 for (auto const& chunk
: rChunkData
)
1557 // Microsoft Office is storing Animated GIFs in following chunk
1558 if (chunk
.nType
== PMGCHUNG_msOG
)
1560 sal_uInt32 nChunkSize
= chunk
.aData
.size();
1562 if (nChunkSize
> 11)
1564 const std::vector
<sal_uInt8
>& rData
= chunk
.aData
;
1565 nGraphicContentSize
= nChunkSize
- 11;
1566 SvMemoryStream
aIStrm(const_cast<sal_uInt8
*>(&rData
[11]), nGraphicContentSize
, StreamMode::READ
);
1567 pGraphicContent
.reset(new sal_uInt8
[nGraphicContentSize
]);
1568 sal_uInt64 aCurrentPosition
= aIStrm
.Tell();
1569 aIStrm
.ReadBytes(pGraphicContent
.get(), nGraphicContentSize
);
1570 aIStrm
.Seek(aCurrentPosition
);
1571 ImportGIF(aIStrm
, rGraphic
);
1572 eLinkType
= GfxLinkType::NativeGif
;
1579 if ( eLinkType
== GfxLinkType::NONE
)
1581 BitmapEx
aBmpEx( aPNGReader
.Read( aPreviewSizeHint
) );
1582 if ( aBmpEx
.IsEmpty() )
1583 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1587 eLinkType
= GfxLinkType::NativePng
;
1591 else if( aFilterName
.equalsIgnoreAsciiCase( IMP_JPEG
) )
1593 // set LOGSIZE flag always, if not explicitly disabled
1594 // (see #90508 and #106763)
1595 if( !( nImportFlags
& GraphicFilterImportFlags::DontSetLogsizeForJpeg
) )
1596 nImportFlags
|= GraphicFilterImportFlags::SetLogsizeForJpeg
;
1598 sal_uInt64 nPosition
= rIStream
.Tell();
1599 if( !ImportJPEG( rIStream
, rGraphic
, nImportFlags
| GraphicFilterImportFlags::OnlyCreateBitmap
, nullptr ) )
1600 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1603 Bitmap
& rBitmap
= const_cast<Bitmap
&>(rGraphic
.GetBitmapExRef().GetBitmapRef());
1604 BitmapScopedWriteAccess
pWriteAccess(rBitmap
);
1605 rIStream
.Seek(nPosition
);
1606 if( !ImportJPEG( rIStream
, rGraphic
, nImportFlags
| GraphicFilterImportFlags::UseExistingBitmap
, &pWriteAccess
) )
1607 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1609 eLinkType
= GfxLinkType::NativeJpg
;
1612 else if( aFilterName
.equalsIgnoreAsciiCase( IMP_SVG
) )
1614 const sal_uInt32
nStreamPosition(rIStream
.Tell());
1615 const sal_uInt32
nStreamLength(rIStream
.remainingSize());
1619 if(nStreamLength
> 0)
1621 std::vector
<sal_uInt8
> aTwoBytes(2);
1622 rIStream
.ReadBytes(aTwoBytes
.data(), 2);
1623 rIStream
.Seek(nStreamPosition
);
1625 if(aTwoBytes
[0] == 0x1F && aTwoBytes
[1] == 0x8B)
1627 SvMemoryStream aMemStream
;
1631 aCodec
.BeginCompression(ZCODEC_DEFAULT_COMPRESSION
, false, true);
1632 nMemoryLength
= aCodec
.Decompress(rIStream
, aMemStream
);
1633 aCodec
.EndCompression();
1635 if (!rIStream
.GetError() && nMemoryLength
>= 0)
1637 VectorGraphicDataArray
aNewData(nMemoryLength
);
1638 aMemStream
.Seek(STREAM_SEEK_TO_BEGIN
);
1639 aMemStream
.ReadBytes(aNewData
.begin(), nMemoryLength
);
1641 // Make a uncompressed copy for GfxLink
1642 nGraphicContentSize
= nMemoryLength
;
1643 pGraphicContent
.reset(new sal_uInt8
[nGraphicContentSize
]);
1644 std::copy(aNewData
.begin(), aNewData
.end(), pGraphicContent
.get());
1646 if(!aMemStream
.GetError() )
1648 VectorGraphicDataPtr
aVectorGraphicDataPtr(new VectorGraphicData(aNewData
, rPath
, VectorGraphicDataType::Svg
));
1649 rGraphic
= Graphic(aVectorGraphicDataPtr
);
1656 VectorGraphicDataArray
aNewData(nStreamLength
);
1657 rIStream
.ReadBytes(aNewData
.begin(), nStreamLength
);
1659 if(!rIStream
.GetError())
1661 VectorGraphicDataPtr
aVectorGraphicDataPtr(new VectorGraphicData(aNewData
, rPath
, VectorGraphicDataType::Svg
));
1662 rGraphic
= Graphic(aVectorGraphicDataPtr
);
1670 eLinkType
= GfxLinkType::NativeSvg
;
1674 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1677 else if( aFilterName
.equalsIgnoreAsciiCase( IMP_XBM
) )
1679 if( !ImportXBM( rIStream
, rGraphic
) )
1680 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1682 else if( aFilterName
.equalsIgnoreAsciiCase( IMP_XPM
) )
1684 if( !ImportXPM( rIStream
, rGraphic
) )
1685 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1687 else if( aFilterName
.equalsIgnoreAsciiCase( IMP_BMP
) ||
1688 aFilterName
.equalsIgnoreAsciiCase( IMP_SVMETAFILE
) )
1690 // SV internal filters for import bitmaps and MetaFiles
1691 ReadGraphic( rIStream
, rGraphic
);
1692 if( rIStream
.GetError() )
1694 nStatus
= ERRCODE_GRFILTER_FORMATERROR
;
1696 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_BMP
))
1698 // #i15508# added BMP type (checked, works)
1699 eLinkType
= GfxLinkType::NativeBmp
;
1702 else if( aFilterName
.equalsIgnoreAsciiCase( IMP_MOV
) )
1704 ReadGraphic( rIStream
, rGraphic
);
1705 if( rIStream
.GetError() )
1706 nStatus
= ERRCODE_GRFILTER_FORMATERROR
;
1709 rGraphic
.SetDefaultType();
1710 rIStream
.Seek( STREAM_SEEK_TO_END
);
1711 eLinkType
= GfxLinkType::NativeMov
;
1714 else if( aFilterName
.equalsIgnoreAsciiCase( IMP_WMF
) ||
1715 aFilterName
.equalsIgnoreAsciiCase( IMP_EMF
) )
1717 // use new UNO API service, do not directly import but create a
1718 // Graphic that contains the original data and decomposes to
1719 // primitives on demand
1721 const sal_uInt32
nStreamLength(rIStream
.remainingSize());
1722 VectorGraphicDataArray
aNewData(nStreamLength
);
1725 rIStream
.ReadBytes(aNewData
.begin(), nStreamLength
);
1727 if (!rIStream
.GetError())
1729 const bool bIsWmf(aFilterName
.equalsIgnoreAsciiCase(IMP_WMF
));
1730 const VectorGraphicDataType
aDataType(bIsWmf
? VectorGraphicDataType::Wmf
: VectorGraphicDataType::Emf
);
1731 VectorGraphicDataPtr
aVectorGraphicDataPtr(
1732 new VectorGraphicData(
1739 aVectorGraphicDataPtr
->setWmfExternalHeader(*pExtHeader
);
1742 rGraphic
= Graphic(aVectorGraphicDataPtr
);
1748 eLinkType
= GfxLinkType::NativeWmf
;
1752 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1755 else if (aFilterName
== IMP_PDF
)
1757 if (!vcl::ImportPDF(rIStream
, rGraphic
))
1758 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1760 eLinkType
= GfxLinkType::NativePdf
;
1763 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1767 ImpFilterLibCacheEntry
* pFilter
= nullptr;
1769 if (!aFilterPath
.isEmpty())
1771 // find first filter in filter paths
1772 ImpFilterLibCache
&rCache
= Cache::get();
1775 pFilter
= rCache
.GetFilter(aFilterPath
.getToken(0, ';', nIdx
), aFilterName
, aExternalFilterName
);
1776 } while (nIdx
>=0 && pFilter
==nullptr);
1780 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1783 PFilterCall pFunc
= pFilter
->GetImportFunction();
1786 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1789 std::unique_ptr
<FilterConfigItem
> pFilterConfigItem
;
1790 OUString aShortName
;
1791 if( nFormat
!= GRFILTER_FORMAT_DONTKNOW
)
1793 aShortName
= GetImportFormatShortName( nFormat
).toAsciiUpperCase();
1794 if (aShortName
== "PCD" && !utl::ConfigManager::IsFuzzing())
1796 OUString
aFilterConfigPath( "Office.Common/Filter/Graphic/Import/PCD" );
1797 pFilterConfigItem
= std::make_unique
<FilterConfigItem
>( aFilterConfigPath
);
1800 if( !(*pFunc
)( rIStream
, rGraphic
, pFilterConfigItem
.get() ) )
1801 nStatus
= ERRCODE_GRFILTER_FORMATERROR
;
1804 // try to set link type if format matches
1805 if( nFormat
!= GRFILTER_FORMAT_DONTKNOW
)
1807 if( aShortName
.startsWith( TIF_SHORTNAME
) )
1808 eLinkType
= GfxLinkType::NativeTif
;
1809 else if( aShortName
.startsWith( MET_SHORTNAME
) )
1810 eLinkType
= GfxLinkType::NativeMet
;
1811 else if( aShortName
.startsWith( PCT_SHORTNAME
) )
1812 eLinkType
= GfxLinkType::NativePct
;
1819 if( nStatus
== ERRCODE_NONE
&& bCreateNativeLink
&& ( eLinkType
!= GfxLinkType::NONE
) && !rGraphic
.GetContext() && !bLinkSet
)
1821 if (!pGraphicContent
)
1823 const sal_uLong nStreamEnd
= rIStream
.Tell();
1824 nGraphicContentSize
= nStreamEnd
- nStreamBegin
;
1826 if (nGraphicContentSize
> 0)
1830 pGraphicContent
.reset(new sal_uInt8
[nGraphicContentSize
]);
1832 catch (const std::bad_alloc
&)
1834 nStatus
= ERRCODE_GRFILTER_TOOBIG
;
1837 if( nStatus
== ERRCODE_NONE
)
1839 rIStream
.Seek(nStreamBegin
);
1840 rIStream
.ReadBytes(pGraphicContent
.get(), nGraphicContentSize
);
1844 if( nStatus
== ERRCODE_NONE
)
1846 rGraphic
.SetGfxLink(std::make_shared
<GfxLink
>(std::move(pGraphicContent
), nGraphicContentSize
, eLinkType
));
1850 // Set error code or try to set native buffer
1851 if( nStatus
!= ERRCODE_NONE
)
1853 ImplSetError( nStatus
, &rIStream
);
1854 rIStream
.Seek( nStreamBegin
);
1861 ErrCode
GraphicFilter::ExportGraphic( const Graphic
& rGraphic
, const INetURLObject
& rPath
,
1862 sal_uInt16 nFormat
, const css::uno::Sequence
< css::beans::PropertyValue
>* pFilterData
)
1864 SAL_INFO( "vcl.filter", "GraphicFilter::ExportGraphic() (thb)" );
1865 ErrCode nRetValue
= ERRCODE_GRFILTER_FORMATERROR
;
1866 SAL_WARN_IF( rPath
.GetProtocol() == INetProtocol::NotValid
, "vcl.filter", "GraphicFilter::ExportGraphic() : ProtType == INetProtocol::NotValid" );
1867 bool bAlreadyExists
= DirEntryExists( rPath
);
1869 OUString
aMainUrl( rPath
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1870 std::unique_ptr
<SvStream
> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl
, StreamMode::WRITE
| StreamMode::TRUNC
));
1873 nRetValue
= ExportGraphic( rGraphic
, aMainUrl
, *xStream
, nFormat
, pFilterData
);
1876 if( ( ERRCODE_NONE
!= nRetValue
) && !bAlreadyExists
)
1877 KillDirEntry( aMainUrl
);
1882 #ifdef DISABLE_DYNLOADING
1884 extern "C" bool egiGraphicExport( SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
* pConfigItem
);
1885 extern "C" bool epsGraphicExport( SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
* pConfigItem
);
1886 extern "C" bool etiGraphicExport( SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
* pConfigItem
);
1890 ErrCode
GraphicFilter::ExportGraphic( const Graphic
& rGraphic
, const OUString
& rPath
,
1891 SvStream
& rOStm
, sal_uInt16 nFormat
, const css::uno::Sequence
< css::beans::PropertyValue
>* pFilterData
)
1893 SAL_INFO( "vcl.filter", "GraphicFilter::ExportGraphic() (thb)" );
1894 sal_uInt16 nFormatCount
= GetExportFormatCount();
1898 if( nFormat
== GRFILTER_FORMAT_DONTKNOW
)
1900 INetURLObject
aURL( rPath
);
1901 OUString
aExt( aURL
.GetFileExtension().toAsciiUpperCase() );
1903 for( sal_uInt16 i
= 0; i
< nFormatCount
; i
++ )
1905 if ( pConfig
->GetExportFormatExtension( i
).equalsIgnoreAsciiCase( aExt
) )
1912 if( nFormat
>= nFormatCount
)
1913 return ImplSetError( ERRCODE_GRFILTER_FORMATERROR
);
1915 FilterConfigItem
aConfigItem( pFilterData
);
1916 OUString
aFilterName( pConfig
->GetExportFilterName( nFormat
) );
1917 OUString
aExternalFilterName(pConfig
->GetExternalFilterName(nFormat
, true));
1918 ErrCode nStatus
= ERRCODE_NONE
;
1920 Graphic aGraphic
= ImpGetScaledGraphic( rGraphic
, aConfigItem
);
1921 eType
= aGraphic
.GetType();
1923 if( pConfig
->IsExportPixelFormat( nFormat
) )
1925 if( eType
!= GraphicType::Bitmap
)
1928 sal_uLong nBitsPerPixel
,nNeededMem
,nMaxMem
;
1929 ScopedVclPtrInstance
< VirtualDevice
> aVirDev
;
1932 nMaxMem
*= 1024; // In Bytes
1934 // Calculate how big the image would normally be:
1935 aSizePixel
=aVirDev
->LogicToPixel(aGraphic
.GetPrefSize(),aGraphic
.GetPrefMapMode());
1937 // Calculate how much memory the image will take up
1938 nBitsPerPixel
=aVirDev
->GetBitCount();
1939 nNeededMem
=(static_cast<sal_uLong
>(aSizePixel
.Width())*static_cast<sal_uLong
>(aSizePixel
.Height())*nBitsPerPixel
+7)/8;
1941 // is the image larger than available memory?
1942 if (nMaxMem
<nNeededMem
)
1944 double fFak
=sqrt(static_cast<double>(nMaxMem
)/static_cast<double>(nNeededMem
));
1945 aSizePixel
.setWidth(static_cast<sal_uLong
>(static_cast<double>(aSizePixel
.Width())*fFak
) );
1946 aSizePixel
.setHeight(static_cast<sal_uLong
>(static_cast<double>(aSizePixel
.Height())*fFak
) );
1949 aVirDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
1950 aVirDev
->SetOutputSizePixel(aSizePixel
);
1951 Graphic aGraphic2
=aGraphic
;
1952 aGraphic2
.Draw(aVirDev
.get(),Point(0,0),aSizePixel
); // this changes the MapMode
1953 aVirDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
1954 aGraphic
=Graphic(aVirDev
->GetBitmapEx(Point(0,0),aSizePixel
));
1957 if( rOStm
.GetError() )
1958 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1959 if( ERRCODE_NONE
== nStatus
)
1961 if ( pConfig
->IsExportInternalFilter( nFormat
) )
1963 if( aFilterName
.equalsIgnoreAsciiCase( EXP_BMP
) )
1965 BitmapEx
aBmp( aGraphic
.GetBitmapEx() );
1966 BmpConversion nColorRes
= static_cast<BmpConversion
>(aConfigItem
.ReadInt32( "Colors", 0 ));
1967 if ( nColorRes
!= BmpConversion::NNONE
&& ( nColorRes
<= BmpConversion::N24Bit
) )
1969 if( !aBmp
.Convert( nColorRes
) )
1970 aBmp
= aGraphic
.GetBitmapEx();
1972 bool bRleCoding
= aConfigItem
.ReadBool( "RLE_Coding", true );
1973 // save RLE encoded?
1974 WriteDIB(aBmp
, rOStm
, bRleCoding
);
1976 if( rOStm
.GetError() )
1977 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1979 else if( aFilterName
.equalsIgnoreAsciiCase( EXP_SVMETAFILE
) )
1981 sal_Int32 nVersion
= aConfigItem
.ReadInt32( "Version", 0 ) ;
1983 rOStm
.SetVersion( nVersion
);
1985 // #i119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
1986 GDIMetaFile
aMTF(aGraphic
.GetGDIMetaFile());
1988 aMTF
.Write( rOStm
);
1990 if( rOStm
.GetError() )
1991 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1993 else if ( aFilterName
.equalsIgnoreAsciiCase( EXP_WMF
) )
1997 // do we have a native Vector Graphic Data RenderGraphic, whose data can be written directly?
1998 const VectorGraphicDataPtr
& aVectorGraphicDataPtr(rGraphic
.getVectorGraphicData());
2000 if (aVectorGraphicDataPtr
.get()
2001 && aVectorGraphicDataPtr
->getVectorGraphicDataArrayLength()
2002 && VectorGraphicDataType::Wmf
== aVectorGraphicDataPtr
->getVectorGraphicDataType())
2004 rOStm
.WriteBytes(aVectorGraphicDataPtr
->getVectorGraphicDataArray().getConstArray(), aVectorGraphicDataPtr
->getVectorGraphicDataArrayLength());
2006 if (rOStm
.GetError())
2008 nStatus
= ERRCODE_GRFILTER_IOERROR
;
2018 // #i119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
2019 if (!ConvertGDIMetaFileToWMF(aGraphic
.GetGDIMetaFile(), rOStm
, &aConfigItem
))
2020 nStatus
= ERRCODE_GRFILTER_FORMATERROR
;
2022 if (rOStm
.GetError())
2023 nStatus
= ERRCODE_GRFILTER_IOERROR
;
2026 else if ( aFilterName
.equalsIgnoreAsciiCase( EXP_EMF
) )
2030 // do we have a native Vector Graphic Data RenderGraphic, whose data can be written directly?
2031 const VectorGraphicDataPtr
& aVectorGraphicDataPtr(rGraphic
.getVectorGraphicData());
2033 if (aVectorGraphicDataPtr
.get()
2034 && aVectorGraphicDataPtr
->getVectorGraphicDataArrayLength()
2035 && VectorGraphicDataType::Emf
== aVectorGraphicDataPtr
->getVectorGraphicDataType())
2037 rOStm
.WriteBytes(aVectorGraphicDataPtr
->getVectorGraphicDataArray().getConstArray(), aVectorGraphicDataPtr
->getVectorGraphicDataArrayLength());
2039 if (rOStm
.GetError())
2041 nStatus
= ERRCODE_GRFILTER_IOERROR
;
2051 // #i119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
2052 if (!ConvertGDIMetaFileToEMF(aGraphic
.GetGDIMetaFile(), rOStm
))
2053 nStatus
= ERRCODE_GRFILTER_FORMATERROR
;
2055 if (rOStm
.GetError())
2056 nStatus
= ERRCODE_GRFILTER_IOERROR
;
2059 else if( aFilterName
.equalsIgnoreAsciiCase( EXP_JPEG
) )
2061 bool bExportedGrayJPEG
= false;
2062 if( !ExportJPEG( rOStm
, aGraphic
, pFilterData
, &bExportedGrayJPEG
) )
2063 nStatus
= ERRCODE_GRFILTER_FORMATERROR
;
2065 if( rOStm
.GetError() )
2066 nStatus
= ERRCODE_GRFILTER_IOERROR
;
2068 else if ( aFilterName
.equalsIgnoreAsciiCase( EXP_PNG
) )
2070 vcl::PNGWriter
aPNGWriter( aGraphic
.GetBitmapEx(), pFilterData
);
2073 for ( const auto& rPropVal
: *pFilterData
)
2075 if ( rPropVal
.Name
== "AdditionalChunks" )
2077 css::uno::Sequence
< css::beans::PropertyValue
> aAdditionalChunkSequence
;
2078 if ( rPropVal
.Value
>>= aAdditionalChunkSequence
)
2080 for ( const auto& rAdditionalChunk
: std::as_const(aAdditionalChunkSequence
) )
2082 if ( rAdditionalChunk
.Name
.getLength() == 4 )
2084 sal_uInt32 nChunkType
= 0;
2085 for ( sal_Int32 k
= 0; k
< 4; k
++ )
2088 nChunkType
|= static_cast<sal_uInt8
>(rAdditionalChunk
.Name
[ k
]);
2090 css::uno::Sequence
< sal_Int8
> aByteSeq
;
2091 if ( rAdditionalChunk
.Value
>>= aByteSeq
)
2093 std::vector
< vcl::PNGWriter::ChunkData
>& rChunkData
= aPNGWriter
.GetChunks();
2094 if ( !rChunkData
.empty() )
2096 sal_uInt32 nChunkLen
= aByteSeq
.getLength();
2098 vcl::PNGWriter::ChunkData aChunkData
;
2099 aChunkData
.nType
= nChunkType
;
2102 aChunkData
.aData
.resize( nChunkLen
);
2103 memcpy( aChunkData
.aData
.data(), aByteSeq
.getConstArray(), nChunkLen
);
2105 std::vector
< vcl::PNGWriter::ChunkData
>::iterator aIter
= rChunkData
.end() - 1;
2106 rChunkData
.insert( aIter
, aChunkData
);
2115 aPNGWriter
.Write( rOStm
);
2117 if( rOStm
.GetError() )
2118 nStatus
= ERRCODE_GRFILTER_IOERROR
;
2120 else if( aFilterName
.equalsIgnoreAsciiCase( EXP_SVG
) )
2124 // do we have a native Vector Graphic Data RenderGraphic, whose data can be written directly?
2125 const VectorGraphicDataPtr
& aVectorGraphicDataPtr(rGraphic
.getVectorGraphicData());
2127 if (aVectorGraphicDataPtr
.get()
2128 && aVectorGraphicDataPtr
->getVectorGraphicDataArrayLength()
2129 && VectorGraphicDataType::Svg
== aVectorGraphicDataPtr
->getVectorGraphicDataType())
2131 rOStm
.WriteBytes(aVectorGraphicDataPtr
->getVectorGraphicDataArray().getConstArray(), aVectorGraphicDataPtr
->getVectorGraphicDataArrayLength());
2133 if( rOStm
.GetError() )
2135 nStatus
= ERRCODE_GRFILTER_IOERROR
;
2145 // do the normal GDIMetaFile export instead
2148 css::uno::Reference
< css::uno::XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
2150 css::uno::Reference
< css::xml::sax::XDocumentHandler
> xSaxWriter(
2151 css::xml::sax::Writer::create( xContext
), css::uno::UNO_QUERY_THROW
);
2152 css::uno::Sequence
< css::uno::Any
> aArguments( 1 );
2153 aArguments
[ 0 ] <<= aConfigItem
.GetFilterData();
2154 css::uno::Reference
< css::svg::XSVGWriter
> xSVGWriter(
2155 xContext
->getServiceManager()->createInstanceWithArgumentsAndContext( "com.sun.star.svg.SVGWriter", aArguments
, xContext
),
2156 css::uno::UNO_QUERY
);
2157 if( xSaxWriter
.is() && xSVGWriter
.is() )
2159 css::uno::Reference
< css::io::XActiveDataSource
> xActiveDataSource(
2160 xSaxWriter
, css::uno::UNO_QUERY
);
2162 if( xActiveDataSource
.is() )
2164 const css::uno::Reference
< css::uno::XInterface
> xStmIf(
2165 static_cast< ::cppu::OWeakObject
* >( new ImpFilterOutputStream( rOStm
) ) );
2167 SvMemoryStream
aMemStm( 65535, 65535 );
2169 // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
2170 const_cast<GDIMetaFile
&>( aGraphic
.GetGDIMetaFile() ).Write( aMemStm
);
2172 xActiveDataSource
->setOutputStream( css::uno::Reference
< css::io::XOutputStream
>(
2173 xStmIf
, css::uno::UNO_QUERY
) );
2174 css::uno::Sequence
< sal_Int8
> aMtfSeq( static_cast<sal_Int8
const *>(aMemStm
.GetData()), aMemStm
.Tell() );
2175 xSVGWriter
->write( xSaxWriter
, aMtfSeq
);
2179 catch(const css::uno::Exception
&)
2181 nStatus
= ERRCODE_GRFILTER_IOERROR
;
2186 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
2190 sal_Int32 nIdx
{aFilterPath
.isEmpty() ? -1 : 0};
2193 #ifndef DISABLE_DYNLOADING
2194 OUString
aPhysicalName( ImpCreateFullFilterPath( aFilterPath
.getToken(0, ';', nIdx
), aFilterName
) );
2195 osl::Module
aLibrary( aPhysicalName
);
2197 PFilterCall pFunc
= nullptr;
2198 if (aExternalFilterName
== "egi")
2199 pFunc
= reinterpret_cast<PFilterCall
>(aLibrary
.getFunctionSymbol("egiGraphicExport"));
2200 else if (aExternalFilterName
== "eps")
2201 pFunc
= reinterpret_cast<PFilterCall
>(aLibrary
.getFunctionSymbol("epsGraphicExport"));
2202 else if (aExternalFilterName
== "eti")
2203 pFunc
= reinterpret_cast<PFilterCall
>(aLibrary
.getFunctionSymbol("etiGraphicExport"));
2204 // Execute dialog in DLL
2206 --nIdx
; // Just one iteration
2207 PFilterCall pFunc
= NULL
;
2208 if (aExternalFilterName
== "egi")
2209 pFunc
= egiGraphicExport
;
2210 else if (aExternalFilterName
== "eps")
2211 pFunc
= epsGraphicExport
;
2212 else if (aExternalFilterName
== "eti")
2213 pFunc
= etiGraphicExport
;
2217 if ( !(*pFunc
)( rOStm
, aGraphic
, &aConfigItem
) )
2218 nStatus
= ERRCODE_GRFILTER_FORMATERROR
;
2222 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
2226 if( nStatus
!= ERRCODE_NONE
)
2228 ImplSetError( nStatus
, &rOStm
);
2234 void GraphicFilter::ResetLastError()
2236 pErrorEx
->nStreamError
= ERRCODE_NONE
;
2239 const Link
<ConvertData
&,bool> GraphicFilter::GetFilterCallback() const
2241 const Link
<ConvertData
&,bool> aLink( LINK( const_cast<GraphicFilter
*>(this), GraphicFilter
, FilterCallback
) );
2245 IMPL_LINK( GraphicFilter
, FilterCallback
, ConvertData
&, rData
, bool )
2249 sal_uInt16 nFormat
= GRFILTER_FORMAT_DONTKNOW
;
2251 css::uno::Sequence
< css::beans::PropertyValue
> aFilterData
;
2252 switch( rData
.mnFormat
)
2254 case ConvertDataFormat::BMP
: aShortName
= BMP_SHORTNAME
; break;
2255 case ConvertDataFormat::GIF
: aShortName
= GIF_SHORTNAME
; break;
2256 case ConvertDataFormat::JPG
: aShortName
= JPG_SHORTNAME
; break;
2257 case ConvertDataFormat::MET
: aShortName
= MET_SHORTNAME
; break;
2258 case ConvertDataFormat::PCT
: aShortName
= PCT_SHORTNAME
; break;
2259 case ConvertDataFormat::PNG
: aShortName
= PNG_SHORTNAME
; break;
2260 case ConvertDataFormat::SVM
: aShortName
= SVM_SHORTNAME
; break;
2261 case ConvertDataFormat::TIF
: aShortName
= TIF_SHORTNAME
; break;
2262 case ConvertDataFormat::WMF
: aShortName
= WMF_SHORTNAME
; break;
2263 case ConvertDataFormat::EMF
: aShortName
= EMF_SHORTNAME
; break;
2264 case ConvertDataFormat::SVG
: aShortName
= SVG_SHORTNAME
; break;
2269 if( GraphicType::NONE
== rData
.maGraphic
.GetType() || rData
.maGraphic
.GetContext() ) // Import
2272 nFormat
= GetImportFormatNumberForShortName( OStringToOUString( aShortName
, RTL_TEXTENCODING_UTF8
) );
2273 bRet
= ImportGraphic( rData
.maGraphic
, OUString(), rData
.mrStm
, nFormat
) == ERRCODE_NONE
;
2275 else if( !aShortName
.isEmpty() )
2279 if (aShortName
== PNG_SHORTNAME
)
2281 aFilterData
.realloc(aFilterData
.getLength() + 1);
2282 aFilterData
[aFilterData
.getLength() - 1].Name
= "Compression";
2283 // We "know" that this gets passed to zlib's deflateInit2_(). 1 means best speed.
2284 aFilterData
[aFilterData
.getLength() - 1].Value
<<= 1;
2287 nFormat
= GetExportFormatNumberForShortName( OStringToOUString(aShortName
, RTL_TEXTENCODING_UTF8
) );
2288 bRet
= ExportGraphic( rData
.maGraphic
, OUString(), rData
.mrStm
, nFormat
, &aFilterData
) == ERRCODE_NONE
;
2296 class StandardGraphicFilter
2299 StandardGraphicFilter()
2301 m_aFilter
.GetImportFormatCount();
2303 GraphicFilter m_aFilter
;
2306 class theGraphicFilter
: public rtl::Static
<StandardGraphicFilter
, theGraphicFilter
> {};
2309 GraphicFilter
& GraphicFilter::GetGraphicFilter()
2311 return theGraphicFilter::get().m_aFilter
;
2314 ErrCode
GraphicFilter::LoadGraphic( const OUString
&rPath
, const OUString
&rFilterName
,
2315 Graphic
& rGraphic
, GraphicFilter
* pFilter
,
2316 sal_uInt16
* pDeterminedFormat
)
2319 pFilter
= &GetGraphicFilter();
2321 const sal_uInt16 nFilter
= !rFilterName
.isEmpty() && pFilter
->GetImportFormatCount()
2322 ? pFilter
->GetImportFormatNumber( rFilterName
)
2323 : GRFILTER_FORMAT_DONTKNOW
;
2325 INetURLObject
aURL( rPath
);
2326 if ( aURL
.HasError() )
2328 aURL
.SetSmartProtocol( INetProtocol::File
);
2329 aURL
.SetSmartURL( rPath
);
2332 std::unique_ptr
<SvStream
> pStream
;
2333 if ( INetProtocol::File
!= aURL
.GetProtocol() )
2334 pStream
= ::utl::UcbStreamHelper::CreateStream( rPath
, StreamMode::READ
);
2336 ErrCode nRes
= ERRCODE_NONE
;
2338 nRes
= pFilter
->ImportGraphic( rGraphic
, aURL
, nFilter
, pDeterminedFormat
);
2340 nRes
= pFilter
->ImportGraphic( rGraphic
, rPath
, *pStream
, nFilter
, pDeterminedFormat
);
2343 OUString aReturnString
;
2345 if (nRes
== ERRCODE_GRFILTER_OPENERROR
)
2346 aReturnString
="open error";
2347 else if (nRes
== ERRCODE_GRFILTER_IOERROR
)
2348 aReturnString
="IO error";
2349 else if (nRes
== ERRCODE_GRFILTER_FORMATERROR
)
2350 aReturnString
="format error";
2351 else if (nRes
== ERRCODE_GRFILTER_VERSIONERROR
)
2352 aReturnString
="version error";
2353 else if (nRes
== ERRCODE_GRFILTER_FILTERERROR
)
2354 aReturnString
="filter error";
2355 else if (nRes
== ERRCODE_GRFILTER_TOOBIG
)
2356 aReturnString
="graphic is too big";
2358 SAL_INFO_IF( nRes
, "vcl.filter", "Problem importing graphic " << rPath
<< ". Reason: " << aReturnString
);
2364 ErrCode
GraphicFilter::compressAsPNG(const Graphic
& rGraphic
, SvStream
& rOutputStream
)
2366 css::uno::Sequence
< css::beans::PropertyValue
> aFilterData(1);
2367 aFilterData
[0].Name
= "Compression";
2368 aFilterData
[0].Value
<<= sal_uInt32(9);
2370 sal_uInt16 nFilterFormat
= GetExportFormatNumberForShortName("PNG");
2371 return ExportGraphic(rGraphic
, OUString(), rOutputStream
, nFilterFormat
, &aFilterData
);
2374 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */