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 <cppuhelper/implbase.hxx>
27 #include <tools/fract.hxx>
28 #include <unotools/configmgr.hxx>
29 #include <tools/stream.hxx>
30 #include <tools/urlobj.hxx>
31 #include <tools/zcodec.hxx>
32 #include <fltcall.hxx>
33 #include <vcl/salctype.hxx>
34 #include <vcl/filter/PngImageReader.hxx>
35 #include <vcl/pngwrite.hxx>
36 #include <vcl/vectorgraphicdata.hxx>
37 #include <vcl/virdev.hxx>
38 #include <impgraph.hxx>
39 #include <vcl/svapp.hxx>
40 #include <osl/file.hxx>
41 #include <vcl/graphicfilter.hxx>
42 #include <vcl/FilterConfigItem.hxx>
43 #include <vcl/wmf.hxx>
44 #include "igif/gifread.hxx"
45 #include <vcl/pdfread.hxx>
46 #include "jpeg/jpeg.hxx"
47 #include "png/png.hxx"
48 #include "ixbm/xbmread.hxx"
49 #include <filter/XpmReader.hxx>
50 #include <filter/TiffReader.hxx>
51 #include <filter/TiffWriter.hxx>
52 #include <filter/TgaReader.hxx>
53 #include <filter/PictReader.hxx>
54 #include <filter/MetReader.hxx>
55 #include <filter/RasReader.hxx>
56 #include <filter/PcxReader.hxx>
57 #include <filter/EpsReader.hxx>
58 #include <filter/EpsWriter.hxx>
59 #include <filter/PsdReader.hxx>
60 #include <filter/PcdReader.hxx>
61 #include <filter/PbmReader.hxx>
62 #include <filter/DxfReader.hxx>
63 #include <filter/GifWriter.hxx>
64 #include <filter/BmpReader.hxx>
65 #include <filter/BmpWriter.hxx>
66 #include <osl/module.hxx>
67 #include <com/sun/star/uno/Reference.h>
68 #include <com/sun/star/awt/Size.hpp>
69 #include <com/sun/star/uno/XInterface.hpp>
70 #include <com/sun/star/io/XActiveDataSource.hpp>
71 #include <com/sun/star/io/XOutputStream.hpp>
72 #include <com/sun/star/svg/XSVGWriter.hpp>
73 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
74 #include <com/sun/star/xml/sax/Writer.hpp>
75 #include <unotools/ucbstreamhelper.hxx>
76 #include <rtl/bootstrap.hxx>
77 #include <rtl/instance.hxx>
78 #include <tools/svlibrary.h>
79 #include <comphelper/string.hxx>
80 #include <unotools/ucbhelper.hxx>
83 #include <string_view>
84 #include <vcl/TypeSerializer.hxx>
86 #include "FilterConfigCache.hxx"
87 #include "graphicfilter_internal.hxx"
89 #include <graphic/GraphicFormatDetector.hxx>
90 #include <graphic/GraphicReader.hxx>
92 typedef ::std::vector
< GraphicFilter
* > FilterList_impl
;
93 static FilterList_impl
* pFilterHdlList
= nullptr;
95 static ::osl::Mutex
& getListMutex()
97 static ::osl::Mutex s_aListProtection
;
98 return s_aListProtection
;
103 class ImpFilterOutputStream
: public ::cppu::WeakImplHelper
< css::io::XOutputStream
>
107 virtual void SAL_CALL
writeBytes( const css::uno::Sequence
< sal_Int8
>& rData
) override
108 { mrStm
.WriteBytes(rData
.getConstArray(), rData
.getLength()); }
109 virtual void SAL_CALL
flush() override
111 virtual void SAL_CALL
closeOutput() override
{}
115 explicit ImpFilterOutputStream( SvStream
& rStm
) : mrStm( rStm
) {}
122 sal_uInt8
* ImplSearchEntry( sal_uInt8
* pSource
, sal_uInt8
const * pDest
, sal_uLong nComp
, sal_uLong nSize
)
124 while ( nComp
-- >= nSize
)
127 for ( i
= 0; i
< nSize
; i
++ )
129 if ( ( pSource
[i
]&~0x20 ) != ( pDest
[i
]&~0x20 ) )
139 static OUString
ImpGetExtension( const OUString
&rPath
)
142 INetURLObject
aURL( rPath
);
143 aExt
= aURL
.GetFileExtension().toAsciiUpperCase();
147 bool isPCT(SvStream
& rStream
, sal_uLong nStreamPos
, sal_uLong nStreamLen
)
150 // store number format
151 SvStreamEndian oldNumberFormat
= rStream
.GetEndian();
152 sal_uInt32 nOffset
; // in MS documents the pict format is used without the first 512 bytes
153 for ( nOffset
= 0; ( nOffset
<= 512 ) && ( ( nStreamPos
+ nOffset
+ 14 ) <= nStreamLen
); nOffset
+= 512 )
158 rStream
.Seek( nStreamPos
+ nOffset
);
159 // size of the pict in version 1 pict ( 2bytes) : ignored
161 // bounding box (bytes 2 -> 9)
162 rStream
.SetEndian(SvStreamEndian::BIG
);
163 rStream
.ReadInt16( y1
).ReadInt16( x1
).ReadInt16( y2
).ReadInt16( x2
);
164 rStream
.SetEndian(oldNumberFormat
); // reset format
166 if (x1
> x2
|| y1
> y2
|| // bad bdbox
167 (x1
== x2
&& y1
== y2
) || // 1 pixel picture
168 x2
-x1
> 2048 || y2
-y1
> 2048 ) // picture abnormally big
172 rStream
.ReadBytes(sBuf
, 3);
173 // see http://developer.apple.com/legacy/mac/library/documentation/mac/pdf/Imaging_With_QuickDraw/Appendix_A.pdf
174 // normal version 2 - page A23 and A24
175 if ( sBuf
[ 0 ] == 0x00 && sBuf
[ 1 ] == 0x11 && sBuf
[ 2 ] == 0x02)
177 // normal version 1 - page A25
178 else if (sBuf
[ 0 ] == 0x11 && sBuf
[ 1 ] == 0x01 && bdBoxOk
)
184 ErrCode
GraphicFilter::ImpTestOrFindFormat( const OUString
& rPath
, SvStream
& rStream
, sal_uInt16
& rFormat
)
186 // determine or check the filter/format by reading into it
187 if( rFormat
== GRFILTER_FORMAT_DONTKNOW
)
190 if (vcl::peekGraphicFormat(rStream
, aFormatExt
, false))
192 rFormat
= pConfig
->GetImportFormatNumberForExtension( aFormatExt
);
193 if( rFormat
!= GRFILTER_FORMAT_DONTKNOW
)
196 // determine filter by file extension
197 if( !rPath
.isEmpty() )
199 OUString
aExt( ImpGetExtension( rPath
) );
200 rFormat
= pConfig
->GetImportFormatNumberForExtension( aExt
);
201 if( rFormat
!= GRFILTER_FORMAT_DONTKNOW
)
204 return ERRCODE_GRFILTER_FORMATERROR
;
208 OUString
aTmpStr( pConfig
->GetImportFormatExtension( rFormat
) );
209 aTmpStr
= aTmpStr
.toAsciiUpperCase();
210 if (!vcl::peekGraphicFormat(rStream
, aTmpStr
, true))
211 return ERRCODE_GRFILTER_FORMATERROR
;
212 if ( pConfig
->GetImportFormatExtension( rFormat
).equalsIgnoreAsciiCase( "pcd" ) )
214 sal_Int32 nBase
= 2; // default Base0
215 if ( pConfig
->GetImportFilterType( rFormat
).equalsIgnoreAsciiCase( "pcd_Photo_CD_Base4" ) )
217 else if ( pConfig
->GetImportFilterType( rFormat
).equalsIgnoreAsciiCase( "pcd_Photo_CD_Base16" ) )
219 FilterConfigItem
aFilterConfigItem( u
"Office.Common/Filter/Graphic/Import/PCD" );
220 aFilterConfigItem
.WriteInt32( "Resolution", nBase
);
227 static Graphic
ImpGetScaledGraphic( const Graphic
& rGraphic
, FilterConfigItem
& rConfigItem
)
231 sal_Int32 nLogicalWidth
= rConfigItem
.ReadInt32( "LogicalWidth", 0 );
232 sal_Int32 nLogicalHeight
= rConfigItem
.ReadInt32( "LogicalHeight", 0 );
234 if ( rGraphic
.GetType() != GraphicType::NONE
)
236 sal_Int32 nMode
= rConfigItem
.ReadInt32( "ExportMode", -1 );
238 if ( nMode
== -1 ) // the property is not there, this is possible, if the graphic filter
239 { // is called via UnoGraphicExporter and not from a graphic export Dialog
240 nMode
= 0; // then we are defaulting this mode to 0
241 if ( nLogicalWidth
|| nLogicalHeight
)
246 Size
aPrefSize( rGraphic
.GetPrefSize() );
247 MapMode
aPrefMapMode( rGraphic
.GetPrefMapMode() );
248 if (aPrefMapMode
.GetMapUnit() == MapUnit::MapPixel
)
249 aOriginalSize
= Application::GetDefaultDevice()->PixelToLogic(aPrefSize
, MapMode(MapUnit::Map100thMM
));
251 aOriginalSize
= OutputDevice::LogicToLogic(aPrefSize
, aPrefMapMode
, MapMode(MapUnit::Map100thMM
));
252 if ( !nLogicalWidth
)
253 nLogicalWidth
= aOriginalSize
.Width();
254 if ( !nLogicalHeight
)
255 nLogicalHeight
= aOriginalSize
.Height();
256 if( rGraphic
.GetType() == GraphicType::Bitmap
)
262 BitmapEx
aBitmap( rGraphic
.GetBitmapEx() );
263 MapMode
aMap( MapUnit::Map100thInch
);
265 sal_Int32 nDPI
= rConfigItem
.ReadInt32( "Resolution", 75 );
266 Fraction
aFrac( 1, std::clamp( nDPI
, sal_Int32(75), sal_Int32(600) ) );
268 aMap
.SetScaleX( aFrac
);
269 aMap
.SetScaleY( aFrac
);
271 Size aOldSize
= aBitmap
.GetSizePixel();
273 aGraphic
.SetPrefMapMode( aMap
);
274 aGraphic
.SetPrefSize( Size( aOldSize
.Width() * 100,
275 aOldSize
.Height() * 100 ) );
278 else if( nMode
== 2 )
281 aGraphic
.SetPrefMapMode( MapMode( MapUnit::Map100thMM
) );
282 aGraphic
.SetPrefSize( Size( nLogicalWidth
, nLogicalHeight
) );
287 sal_Int32 nColors
= rConfigItem
.ReadInt32( "Color", 0 );
288 if ( nColors
) // graphic conversion necessary ?
290 BitmapEx
aBmpEx( aGraphic
.GetBitmapEx() );
291 aBmpEx
.Convert( static_cast<BmpConversion
>(nColors
) ); // the entries in the xml section have the same meaning as
292 aGraphic
= aBmpEx
; // they have in the BmpConversion enum, so it should be
293 } // allowed to cast them
297 if( ( nMode
== 1 ) || ( nMode
== 2 ) )
299 GDIMetaFile
aMtf( rGraphic
.GetGDIMetaFile() );
300 Size
aNewSize( OutputDevice::LogicToLogic(Size(nLogicalWidth
, nLogicalHeight
), MapMode(MapUnit::Map100thMM
), aMtf
.GetPrefMapMode()) );
302 if( aNewSize
.Width() && aNewSize
.Height() )
304 const Size
aPreferredSize( aMtf
.GetPrefSize() );
305 aMtf
.Scale( Fraction( aNewSize
.Width(), aPreferredSize
.Width() ),
306 Fraction( aNewSize
.Height(), aPreferredSize
.Height() ) );
308 aGraphic
= Graphic( aMtf
);
321 GraphicFilter::GraphicFilter( bool bConfig
)
322 : bUseConfig(bConfig
)
327 GraphicFilter::~GraphicFilter()
330 ::osl::MutexGuard
aGuard( getListMutex() );
331 auto it
= std::find(pFilterHdlList
->begin(), pFilterHdlList
->end(), this);
332 if( it
!= pFilterHdlList
->end() )
333 pFilterHdlList
->erase( it
);
335 if( pFilterHdlList
->empty() )
337 delete pFilterHdlList
;
338 pFilterHdlList
= nullptr;
346 void GraphicFilter::ImplInit()
349 ::osl::MutexGuard
aGuard( getListMutex() );
351 if ( !pFilterHdlList
)
353 pFilterHdlList
= new FilterList_impl
;
354 pConfig
= new FilterConfigCache( bUseConfig
);
357 pConfig
= pFilterHdlList
->front()->pConfig
;
359 pFilterHdlList
->push_back( this );
364 OUString
url("$BRAND_BASE_DIR/" LIBO_LIB_FOLDER
);
365 rtl::Bootstrap::expandMacros(url
); //TODO: detect failure
366 osl::FileBase::getSystemPathFromFileURL(url
, aFilterPath
);
369 pErrorEx
.reset( new FilterErrorEx
);
372 ErrCode
GraphicFilter::ImplSetError( ErrCode nError
, const SvStream
* pStm
)
374 pErrorEx
->nStreamError
= pStm
? pStm
->GetError() : ERRCODE_NONE
;
378 sal_uInt16
GraphicFilter::GetImportFormatCount() const
380 return pConfig
->GetImportFormatCount();
383 sal_uInt16
GraphicFilter::GetImportFormatNumber( std::u16string_view rFormatName
)
385 return pConfig
->GetImportFormatNumber( rFormatName
);
388 sal_uInt16
GraphicFilter::GetImportFormatNumberForShortName( std::u16string_view rShortName
)
390 return pConfig
->GetImportFormatNumberForShortName( rShortName
);
393 sal_uInt16
GraphicFilter::GetImportFormatNumberForTypeName( std::u16string_view rType
)
395 return pConfig
->GetImportFormatNumberForTypeName( rType
);
398 OUString
GraphicFilter::GetImportFormatName( sal_uInt16 nFormat
)
400 return pConfig
->GetImportFormatName( nFormat
);
403 OUString
GraphicFilter::GetImportFormatTypeName( sal_uInt16 nFormat
)
405 return pConfig
->GetImportFilterTypeName( nFormat
);
409 OUString
GraphicFilter::GetImportFormatMediaType( sal_uInt16 nFormat
)
411 return pConfig
->GetImportFormatMediaType( nFormat
);
415 OUString
GraphicFilter::GetImportFormatShortName( sal_uInt16 nFormat
)
417 return pConfig
->GetImportFormatShortName( nFormat
);
420 OUString
GraphicFilter::GetImportWildcard( sal_uInt16 nFormat
, sal_Int32 nEntry
)
422 return pConfig
->GetImportWildcard( nFormat
, nEntry
);
425 sal_uInt16
GraphicFilter::GetExportFormatCount() const
427 return pConfig
->GetExportFormatCount();
430 sal_uInt16
GraphicFilter::GetExportFormatNumber( std::u16string_view rFormatName
)
432 return pConfig
->GetExportFormatNumber( rFormatName
);
435 sal_uInt16
GraphicFilter::GetExportFormatNumberForMediaType( std::u16string_view rMediaType
)
437 return pConfig
->GetExportFormatNumberForMediaType( rMediaType
);
440 sal_uInt16
GraphicFilter::GetExportFormatNumberForShortName( std::u16string_view rShortName
)
442 return pConfig
->GetExportFormatNumberForShortName( rShortName
);
445 OUString
GraphicFilter::GetExportInternalFilterName( sal_uInt16 nFormat
)
447 return pConfig
->GetExportInternalFilterName( nFormat
);
450 sal_uInt16
GraphicFilter::GetExportFormatNumberForTypeName( std::u16string_view rType
)
452 return pConfig
->GetExportFormatNumberForTypeName( rType
);
455 OUString
GraphicFilter::GetExportFormatName( sal_uInt16 nFormat
)
457 return pConfig
->GetExportFormatName( nFormat
);
460 OUString
GraphicFilter::GetExportFormatMediaType( sal_uInt16 nFormat
)
462 return pConfig
->GetExportFormatMediaType( nFormat
);
465 OUString
GraphicFilter::GetExportFormatShortName( sal_uInt16 nFormat
)
467 return pConfig
->GetExportFormatShortName( nFormat
);
470 OUString
GraphicFilter::GetExportWildcard( sal_uInt16 nFormat
)
472 return pConfig
->GetExportWildcard( nFormat
, 0 );
475 bool GraphicFilter::IsExportPixelFormat( sal_uInt16 nFormat
)
477 return pConfig
->IsExportPixelFormat( nFormat
);
480 ErrCode
GraphicFilter::CanImportGraphic( const INetURLObject
& rPath
,
481 sal_uInt16 nFormat
, sal_uInt16
* pDeterminedFormat
)
483 ErrCode nRetValue
= ERRCODE_GRFILTER_FORMATERROR
;
484 SAL_WARN_IF( rPath
.GetProtocol() == INetProtocol::NotValid
, "vcl.filter", "GraphicFilter::CanImportGraphic() : ProtType == INetProtocol::NotValid" );
486 OUString
aMainUrl( rPath
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
487 std::unique_ptr
<SvStream
> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl
, StreamMode::READ
| StreamMode::SHARE_DENYNONE
));
490 nRetValue
= CanImportGraphic( aMainUrl
, *xStream
, nFormat
, pDeterminedFormat
);
495 ErrCode
GraphicFilter::CanImportGraphic( const OUString
& rMainUrl
, SvStream
& rIStream
,
496 sal_uInt16 nFormat
, sal_uInt16
* pDeterminedFormat
)
498 sal_uLong nStreamPos
= rIStream
.Tell();
499 ErrCode nRes
= ImpTestOrFindFormat( rMainUrl
, rIStream
, nFormat
);
501 rIStream
.Seek(nStreamPos
);
503 if( nRes
==ERRCODE_NONE
&& pDeterminedFormat
!=nullptr )
504 *pDeterminedFormat
= nFormat
;
506 return ImplSetError( nRes
, &rIStream
);
509 //SJ: TODO, we need to create a GraphicImporter component
510 ErrCode
GraphicFilter::ImportGraphic( Graphic
& rGraphic
, const INetURLObject
& rPath
,
511 sal_uInt16 nFormat
, sal_uInt16
* pDeterminedFormat
, GraphicFilterImportFlags nImportFlags
)
513 ErrCode nRetValue
= ERRCODE_GRFILTER_FORMATERROR
;
514 SAL_WARN_IF( rPath
.GetProtocol() == INetProtocol::NotValid
, "vcl.filter", "GraphicFilter::ImportGraphic() : ProtType == INetProtocol::NotValid" );
516 OUString
aMainUrl( rPath
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
517 std::unique_ptr
<SvStream
> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl
, StreamMode::READ
| StreamMode::SHARE_DENYNONE
));
520 nRetValue
= ImportGraphic( rGraphic
, aMainUrl
, *xStream
, nFormat
, pDeterminedFormat
, nImportFlags
);
525 ErrCode
GraphicFilter::ImportGraphic(
527 const OUString
& rPath
,
530 sal_uInt16
* pDeterminedFormat
,
531 GraphicFilterImportFlags nImportFlags
,
532 WmfExternal
const *pExtHeader
)
534 return ImportGraphic( rGraphic
, rPath
, rIStream
, nFormat
, pDeterminedFormat
, nImportFlags
, nullptr, pExtHeader
);
539 /// Contains a stream and other associated data to import pixels into a
541 struct GraphicImportContext
543 /// Pixel data is read from this stream.
544 std::unique_ptr
<SvStream
> m_pStream
;
545 /// The Graphic the import filter gets.
546 std::shared_ptr
<Graphic
> m_pGraphic
;
547 /// Write pixel data using this access.
548 std::unique_ptr
<BitmapScopedWriteAccess
> m_pAccess
;
549 std::unique_ptr
<AlphaScopedWriteAccess
> m_pAlphaAccess
;
550 // Need to have an AlphaMask instance to keep its lifetime.
551 AlphaMask mAlphaMask
;
552 /// Signals if import finished correctly.
553 ErrCode m_nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
554 /// Original graphic format.
555 GfxLinkType m_eLinkType
= GfxLinkType::NONE
;
556 /// Position of the stream before reading the data.
557 sal_uInt64 m_nStreamBegin
= 0;
558 /// Flags for the import filter.
559 GraphicFilterImportFlags m_nImportFlags
= GraphicFilterImportFlags::NONE
;
562 /// Graphic import worker that gets executed on a thread.
563 class GraphicImportTask
: public comphelper::ThreadTask
565 GraphicImportContext
& m_rContext
;
567 GraphicImportTask(const std::shared_ptr
<comphelper::ThreadTaskTag
>& pTag
, GraphicImportContext
& rContext
);
568 void doWork() override
;
569 /// Shared code between threaded and non-threaded version.
570 static void doImport(GraphicImportContext
& rContext
);
575 GraphicImportTask::GraphicImportTask(const std::shared_ptr
<comphelper::ThreadTaskTag
>& pTag
, GraphicImportContext
& rContext
)
576 : comphelper::ThreadTask(pTag
),
581 void GraphicImportTask::doWork()
583 GraphicImportTask::doImport(m_rContext
);
586 void GraphicImportTask::doImport(GraphicImportContext
& rContext
)
588 if(rContext
.m_eLinkType
== GfxLinkType::NativeJpg
)
590 if (!ImportJPEG(*rContext
.m_pStream
, *rContext
.m_pGraphic
, rContext
.m_nImportFlags
| GraphicFilterImportFlags::UseExistingBitmap
, rContext
.m_pAccess
.get()))
591 rContext
.m_nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
593 else if(rContext
.m_eLinkType
== GfxLinkType::NativePng
)
595 if (!vcl::ImportPNG(*rContext
.m_pStream
, *rContext
.m_pGraphic
,
596 rContext
.m_nImportFlags
| GraphicFilterImportFlags::UseExistingBitmap
,
597 rContext
.m_pAccess
.get(), rContext
.m_pAlphaAccess
.get()))
599 rContext
.m_nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
604 void GraphicFilter::ImportGraphics(std::vector
< std::shared_ptr
<Graphic
> >& rGraphics
, std::vector
< std::unique_ptr
<SvStream
> > vStreams
)
606 static bool bThreads
= !getenv("VCL_NO_THREAD_IMPORT");
607 std::vector
<GraphicImportContext
> aContexts
;
608 aContexts
.reserve(vStreams
.size());
609 comphelper::ThreadPool
& rSharedPool
= comphelper::ThreadPool::getSharedOptimalPool();
610 std::shared_ptr
<comphelper::ThreadTaskTag
> pTag
= comphelper::ThreadPool::createThreadTaskTag();
612 for (auto& pStream
: vStreams
)
614 aContexts
.emplace_back();
615 GraphicImportContext
& rContext
= aContexts
.back();
619 rContext
.m_pStream
= std::move(pStream
);
620 rContext
.m_pGraphic
= std::make_shared
<Graphic
>();
621 rContext
.m_nStatus
= ERRCODE_NONE
;
623 // Detect the format.
625 rContext
.m_nStreamBegin
= rContext
.m_pStream
->Tell();
626 sal_uInt16 nFormat
= GRFILTER_FORMAT_DONTKNOW
;
627 rContext
.m_nStatus
= ImpTestOrFindFormat(OUString(), *rContext
.m_pStream
, nFormat
);
628 rContext
.m_pStream
->Seek(rContext
.m_nStreamBegin
);
630 // Import the graphic.
631 if (rContext
.m_nStatus
== ERRCODE_NONE
&& !rContext
.m_pStream
->GetError())
633 OUString aFilterName
= pConfig
->GetImportFilterName(nFormat
);
635 if (aFilterName
.equalsIgnoreAsciiCase(IMP_JPEG
))
637 rContext
.m_eLinkType
= GfxLinkType::NativeJpg
;
638 rContext
.m_nImportFlags
= GraphicFilterImportFlags::SetLogsizeForJpeg
;
640 if (ImportJPEG( *rContext
.m_pStream
, *rContext
.m_pGraphic
, rContext
.m_nImportFlags
| GraphicFilterImportFlags::OnlyCreateBitmap
, nullptr))
642 Bitmap
& rBitmap
= const_cast<Bitmap
&>(rContext
.m_pGraphic
->GetBitmapExRef().GetBitmap());
643 rContext
.m_pAccess
= std::make_unique
<BitmapScopedWriteAccess
>(rBitmap
);
644 rContext
.m_pStream
->Seek(rContext
.m_nStreamBegin
);
646 rSharedPool
.pushTask(std::make_unique
<GraphicImportTask
>(pTag
, rContext
));
648 GraphicImportTask::doImport(rContext
);
651 rContext
.m_nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
653 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_PNG
))
655 rContext
.m_eLinkType
= GfxLinkType::NativePng
;
657 if (vcl::ImportPNG( *rContext
.m_pStream
, *rContext
.m_pGraphic
, rContext
.m_nImportFlags
| GraphicFilterImportFlags::OnlyCreateBitmap
, nullptr, nullptr))
659 const BitmapEx
& rBitmapEx
= rContext
.m_pGraphic
->GetBitmapExRef();
660 Bitmap
& rBitmap
= const_cast<Bitmap
&>(rBitmapEx
.GetBitmap());
661 rContext
.m_pAccess
= std::make_unique
<BitmapScopedWriteAccess
>(rBitmap
);
662 if(rBitmapEx
.IsAlpha())
664 // The separate alpha bitmap causes a number of complications. Not only
665 // we need to have an extra bitmap access for it, but we also need
666 // to keep an AlphaMask instance in the context. This is because
667 // BitmapEx internally keeps Bitmap and not AlphaMask (because the Bitmap
668 // may be also a mask, not alpha). So BitmapEx::GetAlpha() returns
669 // a temporary, and direct access to the Bitmap wouldn't work
670 // with AlphaScopedBitmapAccess. *sigh*
671 rContext
.mAlphaMask
= rBitmapEx
.GetAlpha();
672 rContext
.m_pAlphaAccess
= std::make_unique
<AlphaScopedWriteAccess
>(rContext
.mAlphaMask
);
674 rContext
.m_pStream
->Seek(rContext
.m_nStreamBegin
);
676 rSharedPool
.pushTask(std::make_unique
<GraphicImportTask
>(pTag
, rContext
));
678 GraphicImportTask::doImport(rContext
);
681 rContext
.m_nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
684 rContext
.m_nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
689 rSharedPool
.waitUntilDone(pTag
);
691 // Process data after import.
692 for (auto& rContext
: aContexts
)
694 if(rContext
.m_pAlphaAccess
) // Need to move the AlphaMask back to the BitmapEx.
695 *rContext
.m_pGraphic
= BitmapEx( rContext
.m_pGraphic
->GetBitmapExRef().GetBitmap(), rContext
.mAlphaMask
);
696 rContext
.m_pAccess
.reset();
697 rContext
.m_pAlphaAccess
.reset();
699 if (rContext
.m_nStatus
== ERRCODE_NONE
&& (rContext
.m_eLinkType
!= GfxLinkType::NONE
) && !rContext
.m_pGraphic
->GetReaderContext())
701 std::unique_ptr
<sal_uInt8
[]> pGraphicContent
;
703 const sal_uInt64 nStreamEnd
= rContext
.m_pStream
->Tell();
704 sal_Int32 nGraphicContentSize
= nStreamEnd
- rContext
.m_nStreamBegin
;
706 if (nGraphicContentSize
> 0)
710 pGraphicContent
.reset(new sal_uInt8
[nGraphicContentSize
]);
712 catch (const std::bad_alloc
&)
714 rContext
.m_nStatus
= ERRCODE_GRFILTER_TOOBIG
;
717 if (rContext
.m_nStatus
== ERRCODE_NONE
)
719 rContext
.m_pStream
->Seek(rContext
.m_nStreamBegin
);
720 rContext
.m_pStream
->ReadBytes(pGraphicContent
.get(), nGraphicContentSize
);
724 if (rContext
.m_nStatus
== ERRCODE_NONE
)
725 rContext
.m_pGraphic
->SetGfxLink(std::make_shared
<GfxLink
>(std::move(pGraphicContent
), nGraphicContentSize
, rContext
.m_eLinkType
));
728 if (rContext
.m_nStatus
!= ERRCODE_NONE
)
729 rContext
.m_pGraphic
= nullptr;
731 rGraphics
.push_back(rContext
.m_pGraphic
);
735 void GraphicFilter::MakeGraphicsAvailableThreaded(std::vector
<Graphic
*>& graphics
)
737 // Graphic::makeAvailable() is not thread-safe. Only the jpeg and png loaders are, so here
738 // we process only jpeg and png images that also have their stream data, load new Graphic's
739 // from them and then update the passed objects using them.
740 std::vector
< Graphic
* > toLoad
;
741 for(auto graphic
: graphics
)
743 // Need to use GetSharedGfxLink, to access the pointer without copying.
744 if(!graphic
->isAvailable() && graphic
->IsGfxLink()
745 && graphic
->GetSharedGfxLink()->GetDataSize() != 0
746 && (graphic
->GetSharedGfxLink()->GetType() == GfxLinkType::NativeJpg
747 || graphic
->GetSharedGfxLink()->GetType() == GfxLinkType::NativePng
))
749 // Graphic objects share internal ImpGraphic, do not process any of those twice.
750 const auto predicate
= [graphic
](Graphic
* item
) { return item
->ImplGetImpGraphic() == graphic
->ImplGetImpGraphic(); };
751 if( std::find_if(toLoad
.begin(), toLoad
.end(), predicate
) == toLoad
.end())
752 toLoad
.push_back( graphic
);
757 std::vector
< std::unique_ptr
<SvStream
>> streams
;
758 for( auto graphic
: toLoad
)
760 streams
.push_back( std::make_unique
<SvMemoryStream
>( const_cast<sal_uInt8
*>(graphic
->GetSharedGfxLink()->GetData()),
761 graphic
->GetSharedGfxLink()->GetDataSize(), StreamMode::READ
| StreamMode::WRITE
));
763 std::vector
< std::shared_ptr
<Graphic
>> loadedGraphics
;
764 ImportGraphics(loadedGraphics
, std::move(streams
));
765 assert(loadedGraphics
.size() == toLoad
.size());
766 for( size_t i
= 0; i
< toLoad
.size(); ++i
)
768 if(loadedGraphics
[ i
] != nullptr)
769 toLoad
[ i
]->ImplGetImpGraphic()->updateFromLoadedGraphic(loadedGraphics
[ i
]->ImplGetImpGraphic());
773 Graphic
GraphicFilter::ImportUnloadedGraphic(SvStream
& rIStream
, sal_uInt64 sizeLimit
,
774 const Size
* pSizeHint
)
777 sal_uInt16 nFormat
= GRFILTER_FORMAT_DONTKNOW
;
778 GfxLinkType eLinkType
= GfxLinkType::NONE
;
782 const sal_uLong nStreamBegin
= rIStream
.Tell();
784 rIStream
.Seek(nStreamBegin
);
786 ErrCode nStatus
= ImpTestOrFindFormat("", rIStream
, nFormat
);
788 rIStream
.Seek(nStreamBegin
);
789 sal_uInt32
nStreamLength(rIStream
.remainingSize());
790 if (sizeLimit
&& sizeLimit
< nStreamLength
)
791 nStreamLength
= sizeLimit
;
793 OUString aFilterName
= pConfig
->GetImportFilterName(nFormat
);
795 std::unique_ptr
<sal_uInt8
[]> pGraphicContent
;
796 sal_Int32 nGraphicContentSize
= 0;
800 if (aFilterName
.equalsIgnoreAsciiCase(IMP_GIF
))
802 eLinkType
= GfxLinkType::NativeGif
;
804 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_PNG
))
806 // check if this PNG contains a GIF chunk!
807 pGraphicContent
= vcl::PngImageReader::getMicrosoftGifChunk(rIStream
, &nGraphicContentSize
);
808 if( pGraphicContent
)
809 eLinkType
= GfxLinkType::NativeGif
;
811 eLinkType
= GfxLinkType::NativePng
;
813 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_JPEG
))
815 eLinkType
= GfxLinkType::NativeJpg
;
817 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_SVG
))
821 if (nStreamLength
> 0)
823 std::vector
<sal_uInt8
> aTwoBytes(2);
824 rIStream
.ReadBytes(aTwoBytes
.data(), 2);
825 rIStream
.Seek(nStreamBegin
);
827 if (aTwoBytes
[0] == 0x1F && aTwoBytes
[1] == 0x8B)
829 SvMemoryStream aMemStream
;
831 tools::Long nMemoryLength
;
833 aCodec
.BeginCompression(ZCODEC_DEFAULT_COMPRESSION
, /*gzLib*/true);
834 nMemoryLength
= aCodec
.Decompress(rIStream
, aMemStream
);
835 aCodec
.EndCompression();
837 if (!rIStream
.GetError() && nMemoryLength
>= 0)
839 nGraphicContentSize
= nMemoryLength
;
840 pGraphicContent
.reset(new sal_uInt8
[nGraphicContentSize
]);
842 aMemStream
.Seek(STREAM_SEEK_TO_BEGIN
);
843 aMemStream
.ReadBytes(pGraphicContent
.get(), nGraphicContentSize
);
850 nGraphicContentSize
= nStreamLength
;
851 pGraphicContent
.reset(new sal_uInt8
[nGraphicContentSize
]);
852 rIStream
.ReadBytes(pGraphicContent
.get(), nStreamLength
);
860 eLinkType
= GfxLinkType::NativeSvg
;
864 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
867 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_BMP
))
869 eLinkType
= GfxLinkType::NativeBmp
;
871 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_MOV
))
873 eLinkType
= GfxLinkType::NativeMov
;
875 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_WMF
) ||
876 aFilterName
.equalsIgnoreAsciiCase(IMP_EMF
))
878 nGraphicContentSize
= nStreamLength
;
879 pGraphicContent
.reset(new sal_uInt8
[nGraphicContentSize
]);
881 rIStream
.Seek(nStreamBegin
);
882 rIStream
.ReadBytes(pGraphicContent
.get(), nStreamLength
);
884 if (!rIStream
.GetError())
886 eLinkType
= GfxLinkType::NativeWmf
;
890 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
893 else if (aFilterName
== IMP_PDF
)
895 eLinkType
= GfxLinkType::NativePdf
;
897 else if (aFilterName
== IMP_TIFF
)
899 eLinkType
= GfxLinkType::NativeTif
;
901 else if (aFilterName
== IMP_PICT
)
903 eLinkType
= GfxLinkType::NativePct
;
905 else if (aFilterName
== IMP_MET
)
907 eLinkType
= GfxLinkType::NativeMet
;
911 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
915 if (nStatus
== ERRCODE_NONE
&& eLinkType
!= GfxLinkType::NONE
)
917 if (!pGraphicContent
)
919 nGraphicContentSize
= nStreamLength
;
921 if (nGraphicContentSize
> 0)
925 pGraphicContent
.reset(new sal_uInt8
[nGraphicContentSize
]);
927 catch (const std::bad_alloc
&)
929 nStatus
= ERRCODE_GRFILTER_TOOBIG
;
932 if (nStatus
== ERRCODE_NONE
)
934 rIStream
.Seek(nStreamBegin
);
935 rIStream
.ReadBytes(pGraphicContent
.get(), nGraphicContentSize
);
940 if( nStatus
== ERRCODE_NONE
)
942 bool bAnimated
= false;
944 if (eLinkType
== GfxLinkType::NativeGif
)
946 SvMemoryStream
aMemoryStream(pGraphicContent
.get(), nGraphicContentSize
, StreamMode::READ
);
947 bAnimated
= IsGIFAnimated(aMemoryStream
, aLogicSize
);
948 if (!pSizeHint
&& aLogicSize
.getWidth() && aLogicSize
.getHeight())
950 pSizeHint
= &aLogicSize
;
953 aGraphic
.SetGfxLink(std::make_shared
<GfxLink
>(std::move(pGraphicContent
), nGraphicContentSize
, eLinkType
));
954 aGraphic
.ImplGetImpGraphic()->setPrepared(bAnimated
, pSizeHint
);
958 // Set error code or try to set native buffer
959 if (nStatus
!= ERRCODE_NONE
)
960 ImplSetError(nStatus
, &rIStream
);
961 if (nStatus
!= ERRCODE_NONE
|| eLinkType
== GfxLinkType::NONE
)
962 rIStream
.Seek(nStreamBegin
);
967 ErrCode
GraphicFilter::readGIF(SvStream
& rStream
, Graphic
& rGraphic
, GfxLinkType
& rLinkType
)
969 if (ImportGIF(rStream
, rGraphic
))
971 rLinkType
= GfxLinkType::NativeGif
;
975 return ERRCODE_GRFILTER_FILTERERROR
;
978 ErrCode
GraphicFilter::readPNG(SvStream
& rStream
, Graphic
& rGraphic
, GfxLinkType
& rLinkType
, std::unique_ptr
<sal_uInt8
[]> & rpGraphicContent
,
979 sal_Int32
& rGraphicContentSize
)
981 ErrCode aReturnCode
= ERRCODE_NONE
;
983 // check if this PNG contains a GIF chunk!
984 rpGraphicContent
= vcl::PngImageReader::getMicrosoftGifChunk(rStream
, &rGraphicContentSize
);
985 if( rpGraphicContent
)
987 SvMemoryStream
aIStrm(rpGraphicContent
.get(), rGraphicContentSize
, StreamMode::READ
);
988 ImportGIF(aIStrm
, rGraphic
);
989 rLinkType
= GfxLinkType::NativeGif
;
993 // PNG has no GIF chunk
994 vcl::PngImageReader
aPNGReader(rStream
);
995 BitmapEx
aBitmapEx(aPNGReader
.read());
996 if (!aBitmapEx
.IsEmpty())
998 rGraphic
= aBitmapEx
;
999 rLinkType
= GfxLinkType::NativePng
;
1002 aReturnCode
= ERRCODE_GRFILTER_FILTERERROR
;
1007 ErrCode
GraphicFilter::readJPEG(SvStream
& rStream
, Graphic
& rGraphic
, GfxLinkType
& rLinkType
, GraphicFilterImportFlags nImportFlags
)
1009 ErrCode aReturnCode
= ERRCODE_NONE
;
1011 // set LOGSIZE flag always, if not explicitly disabled
1012 // (see #90508 and #106763)
1013 if (!(nImportFlags
& GraphicFilterImportFlags::DontSetLogsizeForJpeg
))
1015 nImportFlags
|= GraphicFilterImportFlags::SetLogsizeForJpeg
;
1018 sal_uInt64 nPosition
= rStream
.Tell();
1019 if (!ImportJPEG(rStream
, rGraphic
, nImportFlags
| GraphicFilterImportFlags::OnlyCreateBitmap
, nullptr))
1020 aReturnCode
= ERRCODE_GRFILTER_FILTERERROR
;
1023 Bitmap
& rBitmap
= const_cast<Bitmap
&>(rGraphic
.GetBitmapExRef().GetBitmap());
1024 BitmapScopedWriteAccess
pWriteAccess(rBitmap
);
1025 rStream
.Seek(nPosition
);
1026 if (!ImportJPEG(rStream
, rGraphic
, nImportFlags
| GraphicFilterImportFlags::UseExistingBitmap
, &pWriteAccess
))
1027 aReturnCode
= ERRCODE_GRFILTER_FILTERERROR
;
1029 rLinkType
= GfxLinkType::NativeJpg
;
1035 ErrCode
GraphicFilter::readSVG(SvStream
& rStream
, Graphic
& rGraphic
, GfxLinkType
& rLinkType
, std::unique_ptr
<sal_uInt8
[]> & rpGraphicContent
,
1036 sal_Int32
& rGraphicContentSize
)
1038 ErrCode aReturnCode
= ERRCODE_NONE
;
1040 const sal_uInt32
nStreamPosition(rStream
.Tell());
1041 const sal_uInt32
nStreamLength(rStream
.remainingSize());
1045 if (nStreamLength
> 0)
1047 std::vector
<sal_uInt8
> aTwoBytes(2);
1048 rStream
.ReadBytes(aTwoBytes
.data(), 2);
1049 rStream
.Seek(nStreamPosition
);
1051 if (aTwoBytes
[0] == 0x1F && aTwoBytes
[1] == 0x8B)
1053 SvMemoryStream aMemStream
;
1055 tools::Long nMemoryLength
;
1057 aCodec
.BeginCompression(ZCODEC_DEFAULT_COMPRESSION
, /*gzLib*/true);
1058 nMemoryLength
= aCodec
.Decompress(rStream
, aMemStream
);
1059 aCodec
.EndCompression();
1061 if (!rStream
.GetError() && nMemoryLength
>= 0)
1063 VectorGraphicDataArray
aNewData(nMemoryLength
);
1064 aMemStream
.Seek(STREAM_SEEK_TO_BEGIN
);
1065 aMemStream
.ReadBytes(aNewData
.begin(), nMemoryLength
);
1067 // Make a uncompressed copy for GfxLink
1068 rGraphicContentSize
= nMemoryLength
;
1069 rpGraphicContent
.reset(new sal_uInt8
[rGraphicContentSize
]);
1070 std::copy(aNewData
.begin(), aNewData
.end(), rpGraphicContent
.get());
1072 if (!aMemStream
.GetError())
1074 BinaryDataContainer
aDataContainer(reinterpret_cast<const sal_uInt8
*>(aNewData
.getConstArray()), aNewData
.getLength());
1075 auto aVectorGraphicDataPtr
= std::make_shared
<VectorGraphicData
>(aDataContainer
, VectorGraphicDataType::Svg
);
1076 rGraphic
= Graphic(aVectorGraphicDataPtr
);
1083 VectorGraphicDataArray
aNewData(nStreamLength
);
1084 rStream
.ReadBytes(aNewData
.begin(), nStreamLength
);
1086 if (!rStream
.GetError())
1088 BinaryDataContainer
aDataContainer(reinterpret_cast<const sal_uInt8
*>(aNewData
.getConstArray()), aNewData
.getLength());
1089 auto aVectorGraphicDataPtr
= std::make_shared
<VectorGraphicData
>(aDataContainer
, VectorGraphicDataType::Svg
);
1090 rGraphic
= Graphic(aVectorGraphicDataPtr
);
1098 rLinkType
= GfxLinkType::NativeSvg
;
1102 aReturnCode
= ERRCODE_GRFILTER_FILTERERROR
;
1108 ErrCode
GraphicFilter::readXBM(SvStream
& rStream
, Graphic
& rGraphic
)
1110 if (ImportXBM(rStream
, rGraphic
))
1111 return ERRCODE_NONE
;
1113 return ERRCODE_GRFILTER_FILTERERROR
;
1116 ErrCode
GraphicFilter::readXPM(SvStream
& rStream
, Graphic
& rGraphic
)
1118 if (ImportXPM(rStream
, rGraphic
))
1119 return ERRCODE_NONE
;
1121 return ERRCODE_GRFILTER_FILTERERROR
;
1124 ErrCode
GraphicFilter::readWMF_EMF(SvStream
& rStream
, Graphic
& rGraphic
, GfxLinkType
& rLinkType
,
1125 WmfExternal
const *pExtHeader
, VectorGraphicDataType eType
)
1127 // use new UNO API service, do not directly import but create a
1128 // Graphic that contains the original data and decomposes to
1129 // primitives on demand
1131 ErrCode aReturnCode
= ERRCODE_GRFILTER_FILTERERROR
;
1133 const sal_uInt32
nStreamLength(rStream
.remainingSize());
1134 VectorGraphicDataArray
aNewData(nStreamLength
);
1136 rStream
.ReadBytes(aNewData
.begin(), nStreamLength
);
1138 if (!rStream
.GetError())
1140 const VectorGraphicDataType
aDataType(eType
);
1141 BinaryDataContainer
aDataContainer(reinterpret_cast<const sal_uInt8
*>(aNewData
.getConstArray()), aNewData
.getLength());
1143 auto aVectorGraphicDataPtr
= std::make_shared
<VectorGraphicData
>(aDataContainer
, aDataType
);
1147 aVectorGraphicDataPtr
->setWmfExternalHeader(*pExtHeader
);
1150 rGraphic
= Graphic(aVectorGraphicDataPtr
);
1151 rLinkType
= GfxLinkType::NativeWmf
;
1152 aReturnCode
= ERRCODE_NONE
;
1158 ErrCode
GraphicFilter::readWMF(SvStream
& rStream
, Graphic
& rGraphic
, GfxLinkType
& rLinkType
, WmfExternal
const* pExtHeader
)
1160 return readWMF_EMF(rStream
, rGraphic
, rLinkType
, pExtHeader
, VectorGraphicDataType::Wmf
);
1163 ErrCode
GraphicFilter::readEMF(SvStream
& rStream
, Graphic
& rGraphic
, GfxLinkType
& rLinkType
, WmfExternal
const* pExtHeader
)
1165 return readWMF_EMF(rStream
, rGraphic
, rLinkType
, pExtHeader
, VectorGraphicDataType::Emf
);
1168 ErrCode
GraphicFilter::readPDF(SvStream
& rStream
, Graphic
& rGraphic
, GfxLinkType
& rLinkType
)
1170 if (vcl::ImportPDF(rStream
, rGraphic
))
1172 rLinkType
= GfxLinkType::NativePdf
;
1173 return ERRCODE_NONE
;
1176 return ERRCODE_GRFILTER_FILTERERROR
;
1179 ErrCode
GraphicFilter::readTIFF(SvStream
& rStream
, Graphic
& rGraphic
, GfxLinkType
& rLinkType
)
1181 if (ImportTiffGraphicImport(rStream
, rGraphic
))
1183 rLinkType
= GfxLinkType::NativeTif
;
1184 return ERRCODE_NONE
;
1187 return ERRCODE_GRFILTER_FILTERERROR
;
1190 ErrCode
GraphicFilter::readWithTypeSerializer(SvStream
& rStream
, Graphic
& rGraphic
, GfxLinkType
& rLinkType
, OUString aFilterName
)
1192 ErrCode aReturnCode
= ERRCODE_GRFILTER_FILTERERROR
;
1194 // SV internal filters for import bitmaps and MetaFiles
1195 TypeSerializer
aSerializer(rStream
);
1196 aSerializer
.readGraphic(rGraphic
);
1198 if (!rStream
.GetError())
1200 if (aFilterName
.equalsIgnoreAsciiCase(IMP_MOV
))
1202 rGraphic
.SetDefaultType();
1203 rStream
.Seek(STREAM_SEEK_TO_END
);
1204 rLinkType
= GfxLinkType::NativeMov
;
1206 aReturnCode
= ERRCODE_NONE
;
1211 ErrCode
GraphicFilter::readBMP(SvStream
& rStream
, Graphic
& rGraphic
, GfxLinkType
& rLinkType
)
1213 if (BmpReader(rStream
, rGraphic
))
1215 rLinkType
= GfxLinkType::NativeBmp
;
1216 return ERRCODE_NONE
;
1219 return ERRCODE_GRFILTER_FILTERERROR
;
1222 ErrCode
GraphicFilter::readTGA(SvStream
& rStream
, Graphic
& rGraphic
)
1224 if (ImportTgaGraphic(rStream
, rGraphic
))
1225 return ERRCODE_NONE
;
1227 return ERRCODE_GRFILTER_FILTERERROR
;
1230 ErrCode
GraphicFilter::readPICT(SvStream
& rStream
, Graphic
& rGraphic
, GfxLinkType
& rLinkType
)
1232 if (ImportPictGraphic(rStream
, rGraphic
))
1234 rLinkType
= GfxLinkType::NativePct
;
1235 return ERRCODE_NONE
;
1238 return ERRCODE_GRFILTER_FILTERERROR
;
1241 ErrCode
GraphicFilter::readMET(SvStream
& rStream
, Graphic
& rGraphic
, GfxLinkType
& rLinkType
)
1243 if (ImportMetGraphic(rStream
, rGraphic
))
1245 rLinkType
= GfxLinkType::NativeMet
;
1246 return ERRCODE_NONE
;
1249 return ERRCODE_GRFILTER_FILTERERROR
;
1252 ErrCode
GraphicFilter::readRAS(SvStream
& rStream
, Graphic
& rGraphic
)
1254 if (ImportRasGraphic(rStream
, rGraphic
))
1255 return ERRCODE_NONE
;
1257 return ERRCODE_GRFILTER_FILTERERROR
;
1260 ErrCode
GraphicFilter::readPCX(SvStream
& rStream
, Graphic
& rGraphic
)
1262 if (ImportPcxGraphic(rStream
, rGraphic
))
1263 return ERRCODE_NONE
;
1265 return ERRCODE_GRFILTER_FILTERERROR
;
1268 ErrCode
GraphicFilter::readEPS(SvStream
& rStream
, Graphic
& rGraphic
)
1270 if (ImportEpsGraphic(rStream
, rGraphic
))
1271 return ERRCODE_NONE
;
1273 return ERRCODE_GRFILTER_FILTERERROR
;
1276 ErrCode
GraphicFilter::readPSD(SvStream
& rStream
, Graphic
& rGraphic
)
1278 if (ImportPsdGraphic(rStream
, rGraphic
))
1279 return ERRCODE_NONE
;
1281 return ERRCODE_GRFILTER_FILTERERROR
;
1284 ErrCode
GraphicFilter::readPCD(SvStream
& rStream
, Graphic
& rGraphic
)
1286 std::unique_ptr
<FilterConfigItem
> pFilterConfigItem
;
1287 if (!utl::ConfigManager::IsFuzzing())
1289 OUString
aFilterConfigPath( "Office.Common/Filter/Graphic/Import/PCD" );
1290 pFilterConfigItem
= std::make_unique
<FilterConfigItem
>(aFilterConfigPath
);
1293 if (ImportPcdGraphic(rStream
, rGraphic
, pFilterConfigItem
.get()))
1294 return ERRCODE_NONE
;
1296 return ERRCODE_GRFILTER_FILTERERROR
;
1299 ErrCode
GraphicFilter::readPBM(SvStream
& rStream
, Graphic
& rGraphic
)
1301 if (ImportPbmGraphic(rStream
, rGraphic
))
1302 return ERRCODE_NONE
;
1304 return ERRCODE_GRFILTER_FILTERERROR
;
1307 ErrCode
GraphicFilter::readDXF(SvStream
& rStream
, Graphic
& rGraphic
)
1309 if (ImportDxfGraphic(rStream
, rGraphic
))
1310 return ERRCODE_NONE
;
1312 return ERRCODE_GRFILTER_FILTERERROR
;
1315 ErrCode
GraphicFilter::ImportGraphic( Graphic
& rGraphic
, const OUString
& rPath
, SvStream
& rIStream
,
1316 sal_uInt16 nFormat
, sal_uInt16
* pDeterminedFormat
, GraphicFilterImportFlags nImportFlags
,
1317 const css::uno::Sequence
< css::beans::PropertyValue
>* /*pFilterData*/,
1318 WmfExternal
const *pExtHeader
)
1320 OUString aFilterName
;
1321 sal_uLong nStreamBegin
;
1323 GfxLinkType eLinkType
= GfxLinkType::NONE
;
1324 const bool bLinkSet
= rGraphic
.IsGfxLink();
1326 std::unique_ptr
<sal_uInt8
[]> pGraphicContent
;
1327 sal_Int32 nGraphicContentSize
= 0;
1331 std::shared_ptr
<GraphicReader
> pContext
= rGraphic
.GetReaderContext();
1332 bool bDummyContext
= rGraphic
.IsDummyContext();
1333 if( !pContext
|| bDummyContext
)
1337 rGraphic
.SetDummyContext( false );
1341 nStreamBegin
= rIStream
.Tell();
1343 nStatus
= ImpTestOrFindFormat( rPath
, rIStream
, nFormat
);
1344 // if pending, return ERRCODE_NONE in order to request more bytes
1345 if( rIStream
.GetError() == ERRCODE_IO_PENDING
)
1347 rGraphic
.SetDummyContext(true);
1348 rIStream
.ResetError();
1349 rIStream
.Seek( nStreamBegin
);
1350 return ImplSetError( ERRCODE_NONE
);
1353 rIStream
.Seek( nStreamBegin
);
1355 if( ( nStatus
!= ERRCODE_NONE
) || rIStream
.GetError() )
1356 return ImplSetError( ( nStatus
!= ERRCODE_NONE
) ? nStatus
: ERRCODE_GRFILTER_OPENERROR
, &rIStream
);
1358 if( pDeterminedFormat
)
1359 *pDeterminedFormat
= nFormat
;
1361 aFilterName
= pConfig
->GetImportFilterName( nFormat
);
1365 aFilterName
= pContext
->GetUpperFilterName();
1368 nStatus
= ERRCODE_NONE
;
1373 if (aFilterName
.equalsIgnoreAsciiCase(IMP_GIF
))
1375 nStatus
= readGIF(rIStream
, rGraphic
, eLinkType
);
1377 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_PNG
))
1379 nStatus
= readPNG(rIStream
, rGraphic
, eLinkType
, pGraphicContent
, nGraphicContentSize
);
1381 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_JPEG
))
1383 nStatus
= readJPEG(rIStream
, rGraphic
, eLinkType
, nImportFlags
);
1385 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_SVG
))
1387 nStatus
= readSVG(rIStream
, rGraphic
, eLinkType
, pGraphicContent
, nGraphicContentSize
);
1389 else if( aFilterName
.equalsIgnoreAsciiCase( IMP_XBM
) )
1391 nStatus
= readXBM(rIStream
, rGraphic
);
1393 else if( aFilterName
.equalsIgnoreAsciiCase( IMP_XPM
) )
1395 nStatus
= readXPM(rIStream
, rGraphic
);
1397 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_BMP
))
1399 nStatus
= readBMP(rIStream
, rGraphic
, eLinkType
);
1401 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_SVMETAFILE
))
1403 nStatus
= readWithTypeSerializer(rIStream
, rGraphic
, eLinkType
, aFilterName
);
1405 else if( aFilterName
.equalsIgnoreAsciiCase(IMP_MOV
))
1407 nStatus
= readWithTypeSerializer(rIStream
, rGraphic
, eLinkType
, aFilterName
);
1409 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_WMF
))
1411 nStatus
= readWMF(rIStream
, rGraphic
, eLinkType
, pExtHeader
);
1413 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_EMF
))
1415 nStatus
= readEMF(rIStream
, rGraphic
, eLinkType
, pExtHeader
);
1417 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_PDF
))
1419 nStatus
= readPDF(rIStream
, rGraphic
, eLinkType
);
1421 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_TIFF
) )
1423 nStatus
= readTIFF(rIStream
, rGraphic
, eLinkType
);
1425 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_TGA
) )
1427 nStatus
= readTGA(rIStream
, rGraphic
);
1429 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_PICT
))
1431 nStatus
= readPICT(rIStream
, rGraphic
, eLinkType
);
1433 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_MET
))
1435 nStatus
= readMET(rIStream
, rGraphic
, eLinkType
);
1437 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_RAS
))
1439 nStatus
= readRAS(rIStream
, rGraphic
);
1441 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_PCX
))
1443 nStatus
= readPCX(rIStream
, rGraphic
);
1445 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_EPS
))
1447 nStatus
= readEPS(rIStream
, rGraphic
);
1449 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_PSD
))
1451 nStatus
= readPSD(rIStream
, rGraphic
);
1453 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_PCD
))
1455 nStatus
= readPCD(rIStream
, rGraphic
);
1457 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_PBM
))
1459 nStatus
= readPBM(rIStream
, rGraphic
);
1461 else if (aFilterName
.equalsIgnoreAsciiCase(IMP_DXF
))
1463 nStatus
= readDXF(rIStream
, rGraphic
);
1466 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1469 if( nStatus
== ERRCODE_NONE
&& ( eLinkType
!= GfxLinkType::NONE
) && !rGraphic
.GetReaderContext() && !bLinkSet
)
1471 if (!pGraphicContent
)
1473 const sal_uLong nStreamEnd
= rIStream
.Tell();
1474 nGraphicContentSize
= nStreamEnd
- nStreamBegin
;
1476 if (nGraphicContentSize
> 0)
1480 pGraphicContent
.reset(new sal_uInt8
[nGraphicContentSize
]);
1482 catch (const std::bad_alloc
&)
1484 nStatus
= ERRCODE_GRFILTER_TOOBIG
;
1487 if( nStatus
== ERRCODE_NONE
)
1489 rIStream
.Seek(nStreamBegin
);
1490 rIStream
.ReadBytes(pGraphicContent
.get(), nGraphicContentSize
);
1494 if( nStatus
== ERRCODE_NONE
)
1496 rGraphic
.SetGfxLink(std::make_shared
<GfxLink
>(std::move(pGraphicContent
), nGraphicContentSize
, eLinkType
));
1500 // Set error code or try to set native buffer
1501 if( nStatus
!= ERRCODE_NONE
)
1503 ImplSetError( nStatus
, &rIStream
);
1504 rIStream
.Seek( nStreamBegin
);
1511 ErrCode
GraphicFilter::ExportGraphic( const Graphic
& rGraphic
, const INetURLObject
& rPath
,
1512 sal_uInt16 nFormat
, const css::uno::Sequence
< css::beans::PropertyValue
>* pFilterData
)
1514 SAL_INFO( "vcl.filter", "GraphicFilter::ExportGraphic() (thb)" );
1515 ErrCode nRetValue
= ERRCODE_GRFILTER_FORMATERROR
;
1516 SAL_WARN_IF( rPath
.GetProtocol() == INetProtocol::NotValid
, "vcl.filter", "GraphicFilter::ExportGraphic() : ProtType == INetProtocol::NotValid" );
1518 OUString
aMainUrl(rPath
.GetMainURL(INetURLObject::DecodeMechanism::NONE
));
1519 bool bAlreadyExists
= utl::UCBContentHelper::IsDocument(aMainUrl
);
1521 std::unique_ptr
<SvStream
> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl
, StreamMode::WRITE
| StreamMode::TRUNC
));
1524 nRetValue
= ExportGraphic( rGraphic
, aMainUrl
, *xStream
, nFormat
, pFilterData
);
1527 if( ( ERRCODE_NONE
!= nRetValue
) && !bAlreadyExists
)
1528 utl::UCBContentHelper::Kill(aMainUrl
);
1533 ErrCode
GraphicFilter::ExportGraphic( const Graphic
& rGraphic
, const OUString
& rPath
,
1534 SvStream
& rOStm
, sal_uInt16 nFormat
, const css::uno::Sequence
< css::beans::PropertyValue
>* pFilterData
)
1536 SAL_INFO( "vcl.filter", "GraphicFilter::ExportGraphic() (thb)" );
1537 sal_uInt16 nFormatCount
= GetExportFormatCount();
1541 if( nFormat
== GRFILTER_FORMAT_DONTKNOW
)
1543 INetURLObject
aURL( rPath
);
1544 OUString
aExt( aURL
.GetFileExtension().toAsciiUpperCase() );
1546 for( sal_uInt16 i
= 0; i
< nFormatCount
; i
++ )
1548 if ( pConfig
->GetExportFormatExtension( i
).equalsIgnoreAsciiCase( aExt
) )
1555 if( nFormat
>= nFormatCount
)
1556 return ImplSetError( ERRCODE_GRFILTER_FORMATERROR
);
1558 FilterConfigItem
aConfigItem( pFilterData
);
1559 OUString
aFilterName( pConfig
->GetExportFilterName( nFormat
) );
1560 ErrCode nStatus
= ERRCODE_NONE
;
1562 Graphic aGraphic
= ImpGetScaledGraphic( rGraphic
, aConfigItem
);
1563 eType
= aGraphic
.GetType();
1565 if( pConfig
->IsExportPixelFormat( nFormat
) )
1567 if( eType
!= GraphicType::Bitmap
)
1570 sal_uLong nBitsPerPixel
,nNeededMem
,nMaxMem
;
1571 ScopedVclPtrInstance
< VirtualDevice
> aVirDev
;
1574 nMaxMem
*= 1024; // In Bytes
1576 // Calculate how big the image would normally be:
1577 aSizePixel
=aVirDev
->LogicToPixel(aGraphic
.GetPrefSize(),aGraphic
.GetPrefMapMode());
1579 // Calculate how much memory the image will take up
1580 nBitsPerPixel
=aVirDev
->GetBitCount();
1581 nNeededMem
=(static_cast<sal_uLong
>(aSizePixel
.Width())*static_cast<sal_uLong
>(aSizePixel
.Height())*nBitsPerPixel
+7)/8;
1583 // is the image larger than available memory?
1584 if (nMaxMem
<nNeededMem
)
1586 double fFak
=sqrt(static_cast<double>(nMaxMem
)/static_cast<double>(nNeededMem
));
1587 aSizePixel
.setWidth(static_cast<sal_uLong
>(static_cast<double>(aSizePixel
.Width())*fFak
) );
1588 aSizePixel
.setHeight(static_cast<sal_uLong
>(static_cast<double>(aSizePixel
.Height())*fFak
) );
1591 aVirDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
1592 aVirDev
->SetOutputSizePixel(aSizePixel
);
1593 Graphic aGraphic2
=aGraphic
;
1594 aGraphic2
.Draw(*aVirDev
, Point(0, 0), aSizePixel
); // this changes the MapMode
1595 aVirDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
1596 aGraphic
=Graphic(aVirDev
->GetBitmapEx(Point(0,0),aSizePixel
));
1599 if( rOStm
.GetError() )
1600 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1601 if( ERRCODE_NONE
== nStatus
)
1603 if( aFilterName
.equalsIgnoreAsciiCase( EXP_BMP
) )
1605 if (!BmpWriter(rOStm
, aGraphic
, &aConfigItem
))
1606 nStatus
= ERRCODE_GRFILTER_FORMATERROR
;
1607 if (rOStm
.GetError())
1608 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1610 else if (aFilterName
.equalsIgnoreAsciiCase(EXP_TIFF
))
1612 if (!ExportTiffGraphicImport(rOStm
, aGraphic
, &aConfigItem
))
1613 nStatus
= ERRCODE_GRFILTER_FORMATERROR
;
1615 if( rOStm
.GetError() )
1616 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1618 else if (aFilterName
.equalsIgnoreAsciiCase(EXP_GIF
))
1620 if (!ExportGifGraphic(rOStm
, aGraphic
, &aConfigItem
))
1621 nStatus
= ERRCODE_GRFILTER_FORMATERROR
;
1623 if( rOStm
.GetError() )
1624 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1626 else if( aFilterName
.equalsIgnoreAsciiCase( EXP_SVMETAFILE
) )
1628 sal_Int32 nVersion
= aConfigItem
.ReadInt32( "Version", 0 ) ;
1630 rOStm
.SetVersion( nVersion
);
1632 // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
1633 GDIMetaFile
aMTF(aGraphic
.GetGDIMetaFile());
1635 aMTF
.Write( rOStm
);
1637 if( rOStm
.GetError() )
1638 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1640 else if ( aFilterName
.equalsIgnoreAsciiCase( EXP_WMF
) )
1644 // do we have a native Vector Graphic Data RenderGraphic, whose data can be written directly?
1645 auto const & rVectorGraphicDataPtr(rGraphic
.getVectorGraphicData());
1647 bool bIsEMF
= rGraphic
.GetGfxLink().IsEMF();
1649 // VectorGraphicDataType::Wmf means WMF or EMF, allow direct write in the WMF case
1651 if (rVectorGraphicDataPtr
1652 && rVectorGraphicDataPtr
->getType() == VectorGraphicDataType::Wmf
1653 && !rVectorGraphicDataPtr
->getBinaryDataContainer().isEmpty()
1656 auto & aDataContainer
= rVectorGraphicDataPtr
->getBinaryDataContainer();
1657 rOStm
.WriteBytes(aDataContainer
.getData(), aDataContainer
.getSize());
1659 if (rOStm
.GetError())
1661 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1671 // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
1672 if (!ConvertGraphicToWMF(aGraphic
, rOStm
, &aConfigItem
))
1673 nStatus
= ERRCODE_GRFILTER_FORMATERROR
;
1675 if (rOStm
.GetError())
1676 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1679 else if ( aFilterName
.equalsIgnoreAsciiCase( EXP_EMF
) )
1683 // do we have a native Vector Graphic Data RenderGraphic, whose data can be written directly?
1684 auto const & rVectorGraphicDataPtr(rGraphic
.getVectorGraphicData());
1686 if (rVectorGraphicDataPtr
1687 && rVectorGraphicDataPtr
->getType() == VectorGraphicDataType::Emf
1688 && !rVectorGraphicDataPtr
->getBinaryDataContainer().isEmpty())
1690 auto & aDataContainer
= rVectorGraphicDataPtr
->getBinaryDataContainer();
1691 rOStm
.WriteBytes(aDataContainer
.getData(), aDataContainer
.getSize());
1693 if (rOStm
.GetError())
1695 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1705 // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
1706 if (!ConvertGDIMetaFileToEMF(aGraphic
.GetGDIMetaFile(), rOStm
))
1707 nStatus
= ERRCODE_GRFILTER_FORMATERROR
;
1709 if (rOStm
.GetError())
1710 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1713 else if( aFilterName
.equalsIgnoreAsciiCase( EXP_JPEG
) )
1715 bool bExportedGrayJPEG
= false;
1716 if( !ExportJPEG( rOStm
, aGraphic
, pFilterData
, &bExportedGrayJPEG
) )
1717 nStatus
= ERRCODE_GRFILTER_FORMATERROR
;
1719 if( rOStm
.GetError() )
1720 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1722 else if (aFilterName
.equalsIgnoreAsciiCase(EXP_EPS
))
1724 if (!ExportEpsGraphic(rOStm
, aGraphic
, &aConfigItem
))
1725 nStatus
= ERRCODE_GRFILTER_FORMATERROR
;
1727 if (rOStm
.GetError())
1728 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1730 else if ( aFilterName
.equalsIgnoreAsciiCase( EXP_PNG
) )
1732 vcl::PNGWriter
aPNGWriter( aGraphic
.GetBitmapEx(), pFilterData
);
1735 for ( const auto& rPropVal
: *pFilterData
)
1737 if ( rPropVal
.Name
== "AdditionalChunks" )
1739 css::uno::Sequence
< css::beans::PropertyValue
> aAdditionalChunkSequence
;
1740 if ( rPropVal
.Value
>>= aAdditionalChunkSequence
)
1742 for ( const auto& rAdditionalChunk
: std::as_const(aAdditionalChunkSequence
) )
1744 if ( rAdditionalChunk
.Name
.getLength() == 4 )
1746 sal_uInt32 nChunkType
= 0;
1747 for ( sal_Int32 k
= 0; k
< 4; k
++ )
1750 nChunkType
|= static_cast<sal_uInt8
>(rAdditionalChunk
.Name
[ k
]);
1752 css::uno::Sequence
< sal_Int8
> aByteSeq
;
1753 if ( rAdditionalChunk
.Value
>>= aByteSeq
)
1755 std::vector
< vcl::PNGWriter::ChunkData
>& rChunkData
= aPNGWriter
.GetChunks();
1756 if ( !rChunkData
.empty() )
1758 sal_uInt32 nChunkLen
= aByteSeq
.getLength();
1760 vcl::PNGWriter::ChunkData aChunkData
;
1761 aChunkData
.nType
= nChunkType
;
1764 aChunkData
.aData
.resize( nChunkLen
);
1765 memcpy( aChunkData
.aData
.data(), aByteSeq
.getConstArray(), nChunkLen
);
1767 std::vector
< vcl::PNGWriter::ChunkData
>::iterator aIter
= rChunkData
.end() - 1;
1768 rChunkData
.insert( aIter
, aChunkData
);
1777 aPNGWriter
.Write( rOStm
);
1779 if( rOStm
.GetError() )
1780 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1782 else if( aFilterName
.equalsIgnoreAsciiCase( EXP_SVG
) )
1786 // do we have a native Vector Graphic Data RenderGraphic, whose data can be written directly?
1787 auto const & rVectorGraphicDataPtr(rGraphic
.getVectorGraphicData());
1789 if (rVectorGraphicDataPtr
1790 && rVectorGraphicDataPtr
->getType() == VectorGraphicDataType::Svg
1791 && !rVectorGraphicDataPtr
->getBinaryDataContainer().isEmpty())
1793 auto & aDataContainer
= rVectorGraphicDataPtr
->getBinaryDataContainer();
1794 rOStm
.WriteBytes(aDataContainer
.getData(), aDataContainer
.getSize());
1796 if( rOStm
.GetError() )
1798 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1808 // do the normal GDIMetaFile export instead
1811 css::uno::Reference
< css::uno::XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
1813 css::uno::Reference
< css::xml::sax::XDocumentHandler
> xSaxWriter(
1814 css::xml::sax::Writer::create( xContext
), css::uno::UNO_QUERY_THROW
);
1815 css::uno::Sequence
< css::uno::Any
> aArguments( 1 );
1816 aArguments
[ 0 ] <<= aConfigItem
.GetFilterData();
1817 css::uno::Reference
< css::svg::XSVGWriter
> xSVGWriter(
1818 xContext
->getServiceManager()->createInstanceWithArgumentsAndContext( "com.sun.star.svg.SVGWriter", aArguments
, xContext
),
1819 css::uno::UNO_QUERY
);
1820 if( xSaxWriter
.is() && xSVGWriter
.is() )
1822 css::uno::Reference
< css::io::XActiveDataSource
> xActiveDataSource(
1823 xSaxWriter
, css::uno::UNO_QUERY
);
1825 if( xActiveDataSource
.is() )
1827 const css::uno::Reference
< css::uno::XInterface
> xStmIf(
1828 static_cast< ::cppu::OWeakObject
* >( new ImpFilterOutputStream( rOStm
) ) );
1830 SvMemoryStream
aMemStm( 65535, 65535 );
1832 // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
1833 const_cast<GDIMetaFile
&>( aGraphic
.GetGDIMetaFile() ).Write( aMemStm
);
1835 xActiveDataSource
->setOutputStream( css::uno::Reference
< css::io::XOutputStream
>(
1836 xStmIf
, css::uno::UNO_QUERY
) );
1837 css::uno::Sequence
< sal_Int8
> aMtfSeq( static_cast<sal_Int8
const *>(aMemStm
.GetData()), aMemStm
.Tell() );
1838 xSVGWriter
->write( xSaxWriter
, aMtfSeq
);
1842 catch(const css::uno::Exception
&)
1844 nStatus
= ERRCODE_GRFILTER_IOERROR
;
1849 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1851 if( nStatus
!= ERRCODE_NONE
)
1853 ImplSetError( nStatus
, &rOStm
);
1859 void GraphicFilter::ResetLastError()
1861 pErrorEx
->nStreamError
= ERRCODE_NONE
;
1864 Link
<ConvertData
&,bool> GraphicFilter::GetFilterCallback() const
1866 Link
<ConvertData
&,bool> aLink( LINK( const_cast<GraphicFilter
*>(this), GraphicFilter
, FilterCallback
) );
1870 IMPL_LINK( GraphicFilter
, FilterCallback
, ConvertData
&, rData
, bool )
1874 sal_uInt16 nFormat
= GRFILTER_FORMAT_DONTKNOW
;
1875 OUString aShortName
;
1876 css::uno::Sequence
< css::beans::PropertyValue
> aFilterData
;
1877 switch( rData
.mnFormat
)
1879 case ConvertDataFormat::BMP
: aShortName
= BMP_SHORTNAME
; break;
1880 case ConvertDataFormat::GIF
: aShortName
= GIF_SHORTNAME
; break;
1881 case ConvertDataFormat::JPG
: aShortName
= JPG_SHORTNAME
; break;
1882 case ConvertDataFormat::MET
: aShortName
= MET_SHORTNAME
; break;
1883 case ConvertDataFormat::PCT
: aShortName
= PCT_SHORTNAME
; break;
1884 case ConvertDataFormat::PNG
: aShortName
= PNG_SHORTNAME
; break;
1885 case ConvertDataFormat::SVM
: aShortName
= SVM_SHORTNAME
; break;
1886 case ConvertDataFormat::TIF
: aShortName
= TIF_SHORTNAME
; break;
1887 case ConvertDataFormat::WMF
: aShortName
= WMF_SHORTNAME
; break;
1888 case ConvertDataFormat::EMF
: aShortName
= EMF_SHORTNAME
; break;
1889 case ConvertDataFormat::SVG
: aShortName
= SVG_SHORTNAME
; break;
1894 if( GraphicType::NONE
== rData
.maGraphic
.GetType() || rData
.maGraphic
.GetReaderContext() ) // Import
1897 nFormat
= GetImportFormatNumberForShortName( aShortName
);
1898 bRet
= ImportGraphic( rData
.maGraphic
, OUString(), rData
.mrStm
, nFormat
) == ERRCODE_NONE
;
1900 else if( !aShortName
.isEmpty() )
1903 #if defined(IOS) || defined(ANDROID)
1904 if (aShortName
== PNG_SHORTNAME
)
1906 aFilterData
.realloc(aFilterData
.getLength() + 1);
1907 aFilterData
[aFilterData
.getLength() - 1].Name
= "Compression";
1908 // We "know" that this gets passed to zlib's deflateInit2_(). 1 means best speed.
1909 aFilterData
[aFilterData
.getLength() - 1].Value
<<= static_cast<sal_Int32
>(1);
1912 nFormat
= GetExportFormatNumberForShortName( aShortName
);
1913 bRet
= ExportGraphic( rData
.maGraphic
, OUString(), rData
.mrStm
, nFormat
, &aFilterData
) == ERRCODE_NONE
;
1921 class StandardGraphicFilter
1924 StandardGraphicFilter()
1926 m_aFilter
.GetImportFormatCount();
1928 GraphicFilter m_aFilter
;
1931 class theGraphicFilter
: public rtl::Static
<StandardGraphicFilter
, theGraphicFilter
> {};
1934 GraphicFilter
& GraphicFilter::GetGraphicFilter()
1936 return theGraphicFilter::get().m_aFilter
;
1939 ErrCode
GraphicFilter::LoadGraphic( const OUString
&rPath
, const OUString
&rFilterName
,
1940 Graphic
& rGraphic
, GraphicFilter
* pFilter
,
1941 sal_uInt16
* pDeterminedFormat
)
1944 pFilter
= &GetGraphicFilter();
1946 const sal_uInt16 nFilter
= !rFilterName
.isEmpty() && pFilter
->GetImportFormatCount()
1947 ? pFilter
->GetImportFormatNumber( rFilterName
)
1948 : GRFILTER_FORMAT_DONTKNOW
;
1950 INetURLObject
aURL( rPath
);
1951 if ( aURL
.HasError() )
1953 aURL
.SetSmartProtocol( INetProtocol::File
);
1954 aURL
.SetSmartURL( rPath
);
1957 std::unique_ptr
<SvStream
> pStream
;
1958 if ( INetProtocol::File
!= aURL
.GetProtocol() )
1959 pStream
= ::utl::UcbStreamHelper::CreateStream( rPath
, StreamMode::READ
);
1961 ErrCode nRes
= ERRCODE_NONE
;
1963 nRes
= pFilter
->ImportGraphic( rGraphic
, aURL
, nFilter
, pDeterminedFormat
);
1965 nRes
= pFilter
->ImportGraphic( rGraphic
, rPath
, *pStream
, nFilter
, pDeterminedFormat
);
1968 OUString aReturnString
;
1970 if (nRes
== ERRCODE_GRFILTER_OPENERROR
)
1971 aReturnString
="open error";
1972 else if (nRes
== ERRCODE_GRFILTER_IOERROR
)
1973 aReturnString
="IO error";
1974 else if (nRes
== ERRCODE_GRFILTER_FORMATERROR
)
1975 aReturnString
="format error";
1976 else if (nRes
== ERRCODE_GRFILTER_VERSIONERROR
)
1977 aReturnString
="version error";
1978 else if (nRes
== ERRCODE_GRFILTER_FILTERERROR
)
1979 aReturnString
="filter error";
1980 else if (nRes
== ERRCODE_GRFILTER_TOOBIG
)
1981 aReturnString
="graphic is too big";
1983 SAL_INFO_IF( nRes
, "vcl.filter", "Problem importing graphic " << rPath
<< ". Reason: " << aReturnString
);
1989 ErrCode
GraphicFilter::compressAsPNG(const Graphic
& rGraphic
, SvStream
& rOutputStream
)
1991 css::uno::Sequence
< css::beans::PropertyValue
> aFilterData(1);
1992 aFilterData
[0].Name
= "Compression";
1993 aFilterData
[0].Value
<<= sal_uInt32(9);
1995 sal_uInt16 nFilterFormat
= GetExportFormatNumberForShortName(u
"PNG");
1996 return ExportGraphic(rGraphic
, OUString(), rOutputStream
, nFilterFormat
, &aFilterData
);
1999 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */