bump product version to 7.2.5.1
[LibreOffice.git] / vcl / source / filter / graphicfilter.cxx
blob18e8757adfa776505ae598d75c2df7d3e6bc3a29
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_folders.h>
22 #include <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>
81 #include <vector>
82 #include <memory>
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;
101 namespace {
103 class ImpFilterOutputStream : public ::cppu::WeakImplHelper< css::io::XOutputStream >
105 SvStream& mrStm;
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
110 { mrStm.Flush(); }
111 virtual void SAL_CALL closeOutput() override {}
113 public:
115 explicit ImpFilterOutputStream( SvStream& rStm ) : mrStm( rStm ) {}
120 // Helper functions
122 sal_uInt8* ImplSearchEntry( sal_uInt8* pSource, sal_uInt8 const * pDest, sal_uLong nComp, sal_uLong nSize )
124 while ( nComp-- >= nSize )
126 sal_uLong i;
127 for ( i = 0; i < nSize; i++ )
129 if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
130 break;
132 if ( i == nSize )
133 return pSource;
134 pSource++;
136 return nullptr;
139 static OUString ImpGetExtension( const OUString &rPath )
141 OUString aExt;
142 INetURLObject aURL( rPath );
143 aExt = aURL.GetFileExtension().toAsciiUpperCase();
144 return aExt;
147 bool isPCT(SvStream& rStream, sal_uLong nStreamPos, sal_uLong nStreamLen)
149 sal_uInt8 sBuf[3];
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 )
155 short y1,x1,y2,x2;
156 bool bdBoxOk = true;
158 rStream.Seek( nStreamPos + nOffset);
159 // size of the pict in version 1 pict ( 2bytes) : ignored
160 rStream.SeekRel(2);
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
169 bdBoxOk = false;
171 // read version op
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)
176 return true;
177 // normal version 1 - page A25
178 else if (sBuf[ 0 ] == 0x11 && sBuf[ 1 ] == 0x01 && bdBoxOk)
179 return true;
181 return false;
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 )
189 OUString aFormatExt;
190 if (vcl::peekGraphicFormat(rStream, aFormatExt, false))
192 rFormat = pConfig->GetImportFormatNumberForExtension( aFormatExt );
193 if( rFormat != GRFILTER_FORMAT_DONTKNOW )
194 return ERRCODE_NONE;
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 )
202 return ERRCODE_NONE;
204 return ERRCODE_GRFILTER_FORMATERROR;
206 else
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" ) )
216 nBase = 1;
217 else if ( pConfig->GetImportFilterType( rFormat ).equalsIgnoreAsciiCase( "pcd_Photo_CD_Base16" ) )
218 nBase = 0;
219 FilterConfigItem aFilterConfigItem( u"Office.Common/Filter/Graphic/Import/PCD" );
220 aFilterConfigItem.WriteInt32( "Resolution", nBase );
224 return ERRCODE_NONE;
227 static Graphic ImpGetScaledGraphic( const Graphic& rGraphic, FilterConfigItem& rConfigItem )
229 Graphic aGraphic;
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 )
242 nMode = 2;
245 Size aOriginalSize;
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));
250 else
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 )
259 // Resolution is set
260 if( nMode == 1 )
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();
272 aGraphic = rGraphic;
273 aGraphic.SetPrefMapMode( aMap );
274 aGraphic.SetPrefSize( Size( aOldSize.Width() * 100,
275 aOldSize.Height() * 100 ) );
277 // Size is set
278 else if( nMode == 2 )
280 aGraphic = rGraphic;
281 aGraphic.SetPrefMapMode( MapMode( MapUnit::Map100thMM ) );
282 aGraphic.SetPrefSize( Size( nLogicalWidth, nLogicalHeight ) );
284 else
285 aGraphic = rGraphic;
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
295 else
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 );
310 else
311 aGraphic = rGraphic;
315 else
316 aGraphic = rGraphic;
318 return aGraphic;
321 GraphicFilter::GraphicFilter( bool bConfig )
322 : bUseConfig(bConfig)
324 ImplInit();
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;
339 delete pConfig;
343 pErrorEx.reset();
346 void GraphicFilter::ImplInit()
349 ::osl::MutexGuard aGuard( getListMutex() );
351 if ( !pFilterHdlList )
353 pFilterHdlList = new FilterList_impl;
354 pConfig = new FilterConfigCache( bUseConfig );
356 else
357 pConfig = pFilterHdlList->front()->pConfig;
359 pFilterHdlList->push_back( this );
362 if( bUseConfig )
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;
375 return nError;
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 );
408 #ifdef _WIN32
409 OUString GraphicFilter::GetImportFormatMediaType( sal_uInt16 nFormat )
411 return pConfig->GetImportFormatMediaType( nFormat );
413 #endif
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 ));
488 if (xStream)
490 nRetValue = CanImportGraphic( aMainUrl, *xStream, nFormat, pDeterminedFormat );
492 return nRetValue;
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 ));
518 if (xStream)
520 nRetValue = ImportGraphic( rGraphic, aMainUrl, *xStream, nFormat, pDeterminedFormat, nImportFlags );
522 return nRetValue;
525 ErrCode GraphicFilter::ImportGraphic(
526 Graphic& rGraphic,
527 const OUString& rPath,
528 SvStream& rIStream,
529 sal_uInt16 nFormat,
530 sal_uInt16* pDeterminedFormat,
531 GraphicFilterImportFlags nImportFlags,
532 WmfExternal const *pExtHeader)
534 return ImportGraphic( rGraphic, rPath, rIStream, nFormat, pDeterminedFormat, nImportFlags, nullptr, pExtHeader );
537 namespace {
539 /// Contains a stream and other associated data to import pixels into a
540 /// Graphic.
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;
566 public:
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),
577 m_rContext(rContext)
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();
617 if (pStream)
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.
624 ResetLastError();
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);
645 if (bThreads)
646 rSharedPool.pushTask(std::make_unique<GraphicImportTask>(pTag, rContext));
647 else
648 GraphicImportTask::doImport(rContext);
650 else
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);
675 if (bThreads)
676 rSharedPool.pushTask(std::make_unique<GraphicImportTask>(pTag, rContext));
677 else
678 GraphicImportTask::doImport(rContext);
680 else
681 rContext.m_nStatus = ERRCODE_GRFILTER_FILTERERROR;
683 else
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 );
755 if( toLoad.empty())
756 return;
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)
776 Graphic aGraphic;
777 sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
778 GfxLinkType eLinkType = GfxLinkType::NONE;
780 ResetLastError();
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;
798 // read graphic
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;
810 else
811 eLinkType = GfxLinkType::NativePng;
813 else if (aFilterName.equalsIgnoreAsciiCase(IMP_JPEG))
815 eLinkType = GfxLinkType::NativeJpg;
817 else if (aFilterName.equalsIgnoreAsciiCase(IMP_SVG))
819 bool bOkay(false);
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;
830 ZCodec aCodec;
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);
845 bOkay = true;
848 else
850 nGraphicContentSize = nStreamLength;
851 pGraphicContent.reset(new sal_uInt8[nGraphicContentSize]);
852 rIStream.ReadBytes(pGraphicContent.get(), nStreamLength);
854 bOkay = true;
858 if (bOkay)
860 eLinkType = GfxLinkType::NativeSvg;
862 else
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;
888 else
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;
909 else
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;
943 Size aLogicSize;
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);
964 return aGraphic;
967 ErrCode GraphicFilter::readGIF(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
969 if (ImportGIF(rStream, rGraphic))
971 rLinkType = GfxLinkType::NativeGif;
972 return ERRCODE_NONE;
974 else
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;
990 return aReturnCode;
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;
1001 else
1002 aReturnCode = ERRCODE_GRFILTER_FILTERERROR;
1004 return aReturnCode;
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;
1021 else
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;
1028 else
1029 rLinkType = GfxLinkType::NativeJpg;
1032 return aReturnCode;
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());
1043 bool bOkay(false);
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;
1054 ZCodec aCodec;
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);
1077 bOkay = true;
1081 else
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);
1091 bOkay = true;
1096 if (bOkay)
1098 rLinkType = GfxLinkType::NativeSvg;
1100 else
1102 aReturnCode = ERRCODE_GRFILTER_FILTERERROR;
1105 return aReturnCode;
1108 ErrCode GraphicFilter::readXBM(SvStream & rStream, Graphic & rGraphic)
1110 if (ImportXBM(rStream, rGraphic))
1111 return ERRCODE_NONE;
1112 else
1113 return ERRCODE_GRFILTER_FILTERERROR;
1116 ErrCode GraphicFilter::readXPM(SvStream & rStream, Graphic & rGraphic)
1118 if (ImportXPM(rStream, rGraphic))
1119 return ERRCODE_NONE;
1120 else
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);
1145 if (pExtHeader)
1147 aVectorGraphicDataPtr->setWmfExternalHeader(*pExtHeader);
1150 rGraphic = Graphic(aVectorGraphicDataPtr);
1151 rLinkType = GfxLinkType::NativeWmf;
1152 aReturnCode = ERRCODE_NONE;
1155 return aReturnCode;
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;
1175 else
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;
1186 else
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;
1208 return aReturnCode;
1211 ErrCode GraphicFilter::readBMP(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
1213 if (BmpReader(rStream, rGraphic))
1215 rLinkType = GfxLinkType::NativeBmp;
1216 return ERRCODE_NONE;
1218 else
1219 return ERRCODE_GRFILTER_FILTERERROR;
1222 ErrCode GraphicFilter::readTGA(SvStream & rStream, Graphic & rGraphic)
1224 if (ImportTgaGraphic(rStream, rGraphic))
1225 return ERRCODE_NONE;
1226 else
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;
1237 else
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;
1248 else
1249 return ERRCODE_GRFILTER_FILTERERROR;
1252 ErrCode GraphicFilter::readRAS(SvStream & rStream, Graphic & rGraphic)
1254 if (ImportRasGraphic(rStream, rGraphic))
1255 return ERRCODE_NONE;
1256 else
1257 return ERRCODE_GRFILTER_FILTERERROR;
1260 ErrCode GraphicFilter::readPCX(SvStream & rStream, Graphic & rGraphic)
1262 if (ImportPcxGraphic(rStream, rGraphic))
1263 return ERRCODE_NONE;
1264 else
1265 return ERRCODE_GRFILTER_FILTERERROR;
1268 ErrCode GraphicFilter::readEPS(SvStream & rStream, Graphic & rGraphic)
1270 if (ImportEpsGraphic(rStream, rGraphic))
1271 return ERRCODE_NONE;
1272 else
1273 return ERRCODE_GRFILTER_FILTERERROR;
1276 ErrCode GraphicFilter::readPSD(SvStream & rStream, Graphic & rGraphic)
1278 if (ImportPsdGraphic(rStream, rGraphic))
1279 return ERRCODE_NONE;
1280 else
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;
1295 else
1296 return ERRCODE_GRFILTER_FILTERERROR;
1299 ErrCode GraphicFilter::readPBM(SvStream & rStream, Graphic & rGraphic)
1301 if (ImportPbmGraphic(rStream, rGraphic))
1302 return ERRCODE_NONE;
1303 else
1304 return ERRCODE_GRFILTER_FILTERERROR;
1307 ErrCode GraphicFilter::readDXF(SvStream & rStream, Graphic & rGraphic)
1309 if (ImportDxfGraphic(rStream, rGraphic))
1310 return ERRCODE_NONE;
1311 else
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;
1322 ErrCode nStatus;
1323 GfxLinkType eLinkType = GfxLinkType::NONE;
1324 const bool bLinkSet = rGraphic.IsGfxLink();
1326 std::unique_ptr<sal_uInt8[]> pGraphicContent;
1327 sal_Int32 nGraphicContentSize = 0;
1329 ResetLastError();
1331 std::shared_ptr<GraphicReader> pContext = rGraphic.GetReaderContext();
1332 bool bDummyContext = rGraphic.IsDummyContext();
1333 if( !pContext || bDummyContext )
1335 if( bDummyContext )
1337 rGraphic.SetDummyContext( false );
1338 nStreamBegin = 0;
1340 else
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 );
1363 else
1365 aFilterName = pContext->GetUpperFilterName();
1367 nStreamBegin = 0;
1368 nStatus = ERRCODE_NONE;
1371 // read graphic
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);
1465 else
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 );
1505 rGraphic.Clear();
1508 return nStatus;
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 ));
1522 if (xStream)
1524 nRetValue = ExportGraphic( rGraphic, aMainUrl, *xStream, nFormat, pFilterData );
1525 xStream.reset();
1527 if( ( ERRCODE_NONE != nRetValue ) && !bAlreadyExists )
1528 utl::UCBContentHelper::Kill(aMainUrl);
1530 return nRetValue;
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();
1539 ResetLastError();
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 ) )
1550 nFormat=i;
1551 break;
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;
1561 GraphicType eType;
1562 Graphic aGraphic = ImpGetScaledGraphic( rGraphic, aConfigItem );
1563 eType = aGraphic.GetType();
1565 if( pConfig->IsExportPixelFormat( nFormat ) )
1567 if( eType != GraphicType::Bitmap )
1569 Size aSizePixel;
1570 sal_uLong nBitsPerPixel,nNeededMem,nMaxMem;
1571 ScopedVclPtrInstance< VirtualDevice > aVirDev;
1573 nMaxMem = 1024;
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 ) ;
1629 if ( nVersion )
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 ) )
1642 bool bDone(false);
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
1650 // only.
1651 if (rVectorGraphicDataPtr
1652 && rVectorGraphicDataPtr->getType() == VectorGraphicDataType::Wmf
1653 && !rVectorGraphicDataPtr->getBinaryDataContainer().isEmpty()
1654 && !bIsEMF)
1656 auto & aDataContainer = rVectorGraphicDataPtr->getBinaryDataContainer();
1657 rOStm.WriteBytes(aDataContainer.getData(), aDataContainer.getSize());
1659 if (rOStm.GetError())
1661 nStatus = ERRCODE_GRFILTER_IOERROR;
1663 else
1665 bDone = true;
1669 if (!bDone)
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 ) )
1681 bool bDone(false);
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;
1697 else
1699 bDone = true;
1703 if (!bDone)
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 );
1733 if ( 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++ )
1749 nChunkType <<= 8;
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;
1762 if ( nChunkLen )
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 ) )
1784 bool bDone(false);
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;
1800 else
1802 bDone = true;
1806 if( !bDone )
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;
1848 else
1849 nStatus = ERRCODE_GRFILTER_FILTERERROR;
1851 if( nStatus != ERRCODE_NONE )
1853 ImplSetError( nStatus, &rOStm );
1855 return nStatus;
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 ) );
1867 return aLink;
1870 IMPL_LINK( GraphicFilter, FilterCallback, ConvertData&, rData, bool )
1872 bool bRet = false;
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;
1891 default:
1892 break;
1894 if( GraphicType::NONE == rData.maGraphic.GetType() || rData.maGraphic.GetReaderContext() ) // Import
1896 // Import
1897 nFormat = GetImportFormatNumberForShortName( aShortName );
1898 bRet = ImportGraphic( rData.maGraphic, OUString(), rData.mrStm, nFormat ) == ERRCODE_NONE;
1900 else if( !aShortName.isEmpty() )
1902 // Export
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);
1911 #endif
1912 nFormat = GetExportFormatNumberForShortName( aShortName );
1913 bRet = ExportGraphic( rData.maGraphic, OUString(), rData.mrStm, nFormat, &aFilterData ) == ERRCODE_NONE;
1916 return bRet;
1919 namespace
1921 class StandardGraphicFilter
1923 public:
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 )
1943 if ( !pFilter )
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;
1962 if ( !pStream )
1963 nRes = pFilter->ImportGraphic( rGraphic, aURL, nFilter, pDeterminedFormat );
1964 else
1965 nRes = pFilter->ImportGraphic( rGraphic, rPath, *pStream, nFilter, pDeterminedFormat );
1967 #ifdef DBG_UTIL
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 );
1984 #endif
1986 return nRes;
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: */