tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / vcl / source / filter / graphicfilter.cxx
blobaf9b2b774b4ba8ee0bbc5245e3b75423feb31928
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 <comphelper/processfactory.hxx>
24 #include <comphelper/propertyvalue.hxx>
25 #include <comphelper/threadpool.hxx>
26 #include <cppuhelper/implbase.hxx>
27 #include <tools/fract.hxx>
28 #include <comphelper/configuration.hxx>
29 #include <tools/stream.hxx>
30 #include <tools/urlobj.hxx>
31 #include <tools/zcodec.hxx>
32 #include <rtl/crc.h>
33 #include <fltcall.hxx>
34 #include <vcl/salctype.hxx>
35 #include <vcl/filter/PngImageReader.hxx>
36 #include <vcl/filter/SvmWriter.hxx>
37 #include <vcl/filter/PngImageWriter.hxx>
38 #include <vcl/vectorgraphicdata.hxx>
39 #include <vcl/virdev.hxx>
40 #include <impgraph.hxx>
41 #include <vcl/svapp.hxx>
42 #include <osl/file.hxx>
43 #include <vcl/graphicfilter.hxx>
44 #include <vcl/FilterConfigItem.hxx>
45 #include <vcl/wmf.hxx>
46 #include "igif/gifread.hxx"
47 #include <vcl/pdfread.hxx>
48 #include "jpeg/jpeg.hxx"
49 #include "png/png.hxx"
50 #include "ixbm/xbmread.hxx"
51 #include <filter/XpmReader.hxx>
52 #include <filter/TiffReader.hxx>
53 #include <filter/TiffWriter.hxx>
54 #include <filter/TgaReader.hxx>
55 #include <filter/PictReader.hxx>
56 #include <filter/MetReader.hxx>
57 #include <filter/RasReader.hxx>
58 #include <filter/PcxReader.hxx>
59 #include <filter/EpsReader.hxx>
60 #include <filter/EpsWriter.hxx>
61 #include <filter/PsdReader.hxx>
62 #include <filter/PcdReader.hxx>
63 #include <filter/PbmReader.hxx>
64 #include <filter/DxfReader.hxx>
65 #include <filter/GifWriter.hxx>
66 #include <filter/BmpReader.hxx>
67 #include <filter/BmpWriter.hxx>
68 #include <filter/WebpReader.hxx>
69 #include <filter/WebpWriter.hxx>
70 #include <osl/module.hxx>
71 #include <com/sun/star/uno/Reference.h>
72 #include <com/sun/star/awt/Size.hpp>
73 #include <com/sun/star/uno/XInterface.hpp>
74 #include <com/sun/star/io/XActiveDataSource.hpp>
75 #include <com/sun/star/io/XOutputStream.hpp>
76 #include <com/sun/star/svg/XSVGWriter.hpp>
77 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
78 #include <com/sun/star/xml/sax/Writer.hpp>
79 #include <unotools/ucbstreamhelper.hxx>
80 #include <rtl/bootstrap.hxx>
81 #include <tools/svlibrary.h>
82 #include <comphelper/string.hxx>
83 #include <unotools/ucbhelper.hxx>
84 #include <vector>
85 #include <memory>
86 #include <mutex>
87 #include <string_view>
88 #include <o3tl/string_view.hxx>
89 #include <o3tl/test_info.hxx>
90 #include <vcl/TypeSerializer.hxx>
92 #include "FilterConfigCache.hxx"
94 #include <graphic/GraphicFormatDetector.hxx>
96 // Support for GfxLinkType::NativeWebp is so far disabled,
97 // as enabling it would write .webp images e.g. to .odt documents,
98 // making those images unreadable for older readers. So for now
99 // disable the support so that .webp images will be written out as .png,
100 // and somewhen later enable the support unconditionally.
101 static bool supportNativeWebp()
103 // Enable support only for unittests
104 return o3tl::IsRunningUnitTest();
107 static std::vector< GraphicFilter* > gaFilterHdlList;
109 static std::mutex& getListMutex()
111 static std::mutex s_aListProtection;
112 return s_aListProtection;
115 namespace {
117 class ImpFilterOutputStream : public ::cppu::WeakImplHelper< css::io::XOutputStream >
119 SvStream& mrStm;
121 virtual void SAL_CALL writeBytes( const css::uno::Sequence< sal_Int8 >& rData ) override
122 { mrStm.WriteBytes(rData.getConstArray(), rData.getLength()); }
123 virtual void SAL_CALL flush() override
124 { mrStm.FlushBuffer(); }
125 virtual void SAL_CALL closeOutput() override {}
127 public:
129 explicit ImpFilterOutputStream( SvStream& rStm ) : mrStm( rStm ) {}
134 // Helper functions
136 static OUString ImpGetExtension( std::u16string_view rPath )
138 OUString aExt;
139 INetURLObject aURL( rPath );
140 aExt = aURL.GetFileExtension().toAsciiUpperCase();
141 return aExt;
144 ErrCode GraphicFilter::ImpTestOrFindFormat( std::u16string_view rPath, SvStream& rStream, sal_uInt16& rFormat )
146 // determine or check the filter/format by reading into it
147 if( rFormat == GRFILTER_FORMAT_DONTKNOW )
149 OUString aFormatExt;
150 if (vcl::peekGraphicFormat(rStream, aFormatExt, false))
152 rFormat = pConfig->GetImportFormatNumberForExtension( aFormatExt );
153 if( rFormat != GRFILTER_FORMAT_DONTKNOW )
154 return ERRCODE_NONE;
156 // determine filter by file extension
157 if( !rPath.empty() )
159 OUString aExt( ImpGetExtension( rPath ) );
160 rFormat = pConfig->GetImportFormatNumberForExtension( aExt );
161 if( rFormat != GRFILTER_FORMAT_DONTKNOW )
162 return ERRCODE_NONE;
164 return ERRCODE_GRFILTER_FORMATERROR;
166 else
168 OUString aTmpStr( pConfig->GetImportFormatExtension( rFormat ) );
169 aTmpStr = aTmpStr.toAsciiUpperCase();
170 if (!vcl::peekGraphicFormat(rStream, aTmpStr, true))
171 return ERRCODE_GRFILTER_FORMATERROR;
172 if ( pConfig->GetImportFormatExtension( rFormat ).equalsIgnoreAsciiCase( "pcd" ) )
174 sal_Int32 nBase = 2; // default Base0
175 if ( pConfig->GetImportFilterType( rFormat ).equalsIgnoreAsciiCase( "pcd_Photo_CD_Base4" ) )
176 nBase = 1;
177 else if ( pConfig->GetImportFilterType( rFormat ).equalsIgnoreAsciiCase( "pcd_Photo_CD_Base16" ) )
178 nBase = 0;
179 FilterConfigItem aFilterConfigItem( u"Office.Common/Filter/Graphic/Import/PCD" );
180 aFilterConfigItem.WriteInt32( u"Resolution"_ustr, nBase );
184 return ERRCODE_NONE;
187 static Graphic ImpGetScaledGraphic( const Graphic& rGraphic, FilterConfigItem& rConfigItem )
189 if ( rGraphic.GetType() == GraphicType::NONE )
190 return rGraphic;
192 sal_Int32 nLogicalWidth = rConfigItem.ReadInt32( u"LogicalWidth"_ustr, 0 );
193 sal_Int32 nLogicalHeight = rConfigItem.ReadInt32( u"LogicalHeight"_ustr, 0 );
194 sal_Int32 nMode = rConfigItem.ReadInt32( u"ExportMode"_ustr, -1 );
195 if ( nMode == -1 ) // the property is not there, this is possible, if the graphic filter
196 { // is called via UnoGraphicExporter and not from a graphic export Dialog
197 nMode = 0; // then we are defaulting this mode to 0
198 if ( nLogicalWidth || nLogicalHeight )
199 nMode = 2;
202 Graphic aGraphic;
203 Size aPrefSize( rGraphic.GetPrefSize() );
204 Size aOriginalSize;
205 MapMode aPrefMapMode( rGraphic.GetPrefMapMode() );
206 if (aPrefMapMode.GetMapUnit() == MapUnit::MapPixel)
207 aOriginalSize = Application::GetDefaultDevice()->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM));
208 else
209 aOriginalSize = OutputDevice::LogicToLogic(aPrefSize, aPrefMapMode, MapMode(MapUnit::Map100thMM));
210 if ( !nLogicalWidth )
211 nLogicalWidth = aOriginalSize.Width();
212 if ( !nLogicalHeight )
213 nLogicalHeight = aOriginalSize.Height();
215 if( rGraphic.GetType() == GraphicType::Bitmap )
218 // Resolution is set
219 if( nMode == 1 )
221 BitmapEx aBitmap( rGraphic.GetBitmapEx() );
222 MapMode aMap( MapUnit::Map100thInch );
224 sal_Int32 nDPI = rConfigItem.ReadInt32( u"Resolution"_ustr, 75 );
225 Fraction aFrac( 1, std::clamp( nDPI, sal_Int32(75), sal_Int32(600) ) );
227 aMap.SetScaleX( aFrac );
228 aMap.SetScaleY( aFrac );
230 Size aOldSize = aBitmap.GetSizePixel();
231 aGraphic = rGraphic;
232 aGraphic.SetPrefMapMode( aMap );
233 aGraphic.SetPrefSize( Size( aOldSize.Width() * 100,
234 aOldSize.Height() * 100 ) );
236 // Size is set
237 else if( nMode == 2 )
239 aGraphic = rGraphic;
240 aGraphic.SetPrefMapMode( MapMode( MapUnit::Map100thMM ) );
241 aGraphic.SetPrefSize( Size( nLogicalWidth, nLogicalHeight ) );
243 else
244 aGraphic = rGraphic;
246 sal_Int32 nColors = rConfigItem.ReadInt32( u"Color"_ustr, 0 );
247 if ( nColors ) // graphic conversion necessary ?
249 BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
250 aBmpEx.Convert( static_cast<BmpConversion>(nColors) ); // the entries in the xml section have the same meaning as
251 aGraphic = aBmpEx; // they have in the BmpConversion enum, so it should be
252 } // allowed to cast them
254 else
256 if( ( nMode == 1 ) || ( nMode == 2 ) )
258 GDIMetaFile aMtf( rGraphic.GetGDIMetaFile() );
259 Size aNewSize( OutputDevice::LogicToLogic(Size(nLogicalWidth, nLogicalHeight), MapMode(MapUnit::Map100thMM), aMtf.GetPrefMapMode()) );
261 if( aNewSize.Width() && aNewSize.Height() )
263 const Size aPreferredSize( aMtf.GetPrefSize() );
264 aMtf.Scale( Fraction( aNewSize.Width(), aPreferredSize.Width() ),
265 Fraction( aNewSize.Height(), aPreferredSize.Height() ) );
267 aGraphic = Graphic( aMtf );
269 else
270 aGraphic = rGraphic;
274 return aGraphic;
277 GraphicFilter::GraphicFilter()
280 std::scoped_lock aGuard( getListMutex() );
282 if ( gaFilterHdlList.empty() )
283 pConfig = new FilterConfigCache;
284 else
285 pConfig = gaFilterHdlList.front()->pConfig;
287 gaFilterHdlList.push_back( this );
290 mxErrorEx = ERRCODE_NONE;
293 GraphicFilter::~GraphicFilter()
296 std::scoped_lock aGuard( getListMutex() );
297 auto it = std::find(gaFilterHdlList.begin(), gaFilterHdlList.end(), this);
298 if( it != gaFilterHdlList.end() )
299 gaFilterHdlList.erase( it );
301 if( gaFilterHdlList.empty() )
302 delete pConfig;
305 mxErrorEx.reset();
308 ErrCode GraphicFilter::ImplSetError( ErrCode nError, const SvStream* pStm )
310 mxErrorEx = pStm ? pStm->GetError() : ERRCODE_NONE;
311 return nError;
314 sal_uInt16 GraphicFilter::GetImportFormatCount() const
316 return pConfig->GetImportFormatCount();
319 sal_uInt16 GraphicFilter::GetImportFormatNumber( std::u16string_view rFormatName )
321 return pConfig->GetImportFormatNumber( rFormatName );
324 sal_uInt16 GraphicFilter::GetImportFormatNumberForShortName( std::u16string_view rShortName )
326 return pConfig->GetImportFormatNumberForShortName( rShortName );
329 sal_uInt16 GraphicFilter::GetImportFormatNumberForTypeName( std::u16string_view rType )
331 return pConfig->GetImportFormatNumberForTypeName( rType );
334 const OUString & GraphicFilter::GetImportFormatName( sal_uInt16 nFormat )
336 return pConfig->GetImportFormatName( nFormat );
339 const OUString & GraphicFilter::GetImportFormatTypeName( sal_uInt16 nFormat )
341 return pConfig->GetImportFilterTypeName( nFormat );
344 #ifdef _WIN32
345 OUString GraphicFilter::GetImportFormatMediaType( sal_uInt16 nFormat )
347 return pConfig->GetImportFormatMediaType( nFormat );
349 #endif
351 OUString GraphicFilter::GetImportFormatShortName( sal_uInt16 nFormat )
353 return pConfig->GetImportFormatShortName( nFormat );
356 OUString GraphicFilter::GetImportWildcard( sal_uInt16 nFormat, sal_Int32 nEntry )
358 return pConfig->GetImportWildcard( nFormat, nEntry );
361 sal_uInt16 GraphicFilter::GetExportFormatCount() const
363 return pConfig->GetExportFormatCount();
366 sal_uInt16 GraphicFilter::GetExportFormatNumber( std::u16string_view rFormatName )
368 return pConfig->GetExportFormatNumber( rFormatName );
371 sal_uInt16 GraphicFilter::GetExportFormatNumberForMediaType( std::u16string_view rMediaType )
373 return pConfig->GetExportFormatNumberForMediaType( rMediaType );
376 sal_uInt16 GraphicFilter::GetExportFormatNumberForShortName( std::u16string_view rShortName )
378 return pConfig->GetExportFormatNumberForShortName( rShortName );
381 const OUString & GraphicFilter::GetExportInternalFilterName( sal_uInt16 nFormat )
383 return pConfig->GetExportInternalFilterName( nFormat );
386 sal_uInt16 GraphicFilter::GetExportFormatNumberForTypeName( std::u16string_view rType )
388 return pConfig->GetExportFormatNumberForTypeName( rType );
391 const OUString & GraphicFilter::GetExportFormatName( sal_uInt16 nFormat )
393 return pConfig->GetExportFormatName( nFormat );
396 const OUString & GraphicFilter::GetExportFormatMediaType( sal_uInt16 nFormat )
398 return pConfig->GetExportFormatMediaType( nFormat );
401 OUString GraphicFilter::GetExportFormatShortName( sal_uInt16 nFormat )
403 return pConfig->GetExportFormatShortName( nFormat );
406 OUString GraphicFilter::GetExportWildcard( sal_uInt16 nFormat )
408 return pConfig->GetExportWildcard( nFormat, 0 );
411 bool GraphicFilter::IsExportPixelFormat( sal_uInt16 nFormat )
413 return pConfig->IsExportPixelFormat( nFormat );
416 ErrCode GraphicFilter::CanImportGraphic( const INetURLObject& rPath,
417 sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat )
419 ErrCode nRetValue = ERRCODE_GRFILTER_FORMATERROR;
420 SAL_WARN_IF( rPath.GetProtocol() == INetProtocol::NotValid, "vcl.filter", "GraphicFilter::CanImportGraphic() : ProtType == INetProtocol::NotValid" );
422 OUString aMainUrl( rPath.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
423 std::unique_ptr<SvStream> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl, StreamMode::READ | StreamMode::SHARE_DENYNONE ));
424 if (xStream)
426 nRetValue = CanImportGraphic( aMainUrl, *xStream, nFormat, pDeterminedFormat );
428 return nRetValue;
431 ErrCode GraphicFilter::CanImportGraphic( std::u16string_view rMainUrl, SvStream& rIStream,
432 sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat )
434 sal_uInt64 nStreamPos = rIStream.Tell();
435 ErrCode nRes = ImpTestOrFindFormat( rMainUrl, rIStream, nFormat );
437 rIStream.Seek(nStreamPos);
439 if( nRes==ERRCODE_NONE && pDeterminedFormat!=nullptr )
440 *pDeterminedFormat = nFormat;
442 return ImplSetError( nRes, &rIStream );
445 //SJ: TODO, we need to create a GraphicImporter component
446 ErrCode GraphicFilter::ImportGraphic( Graphic& rGraphic, const INetURLObject& rPath,
447 sal_uInt16 nFormat, sal_uInt16 * pDeterminedFormat, GraphicFilterImportFlags nImportFlags )
449 SAL_WARN_IF( rPath.GetProtocol() == INetProtocol::NotValid, "vcl.filter", "GraphicFilter::ImportGraphic() : ProtType == INetProtocol::NotValid" );
451 OUString aMainUrl( rPath.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
452 if (rPath.IsExoticProtocol())
454 SAL_WARN("vcl.filter", "GraphicFilter::ImportGraphic(), ignore exotic protocol: " << aMainUrl);
455 return ERRCODE_GRFILTER_FORMATERROR;
458 ErrCode nRetValue = ERRCODE_GRFILTER_FORMATERROR;
459 std::unique_ptr<SvStream> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl, StreamMode::READ | StreamMode::SHARE_DENYNONE ));
460 if (xStream)
462 nRetValue = ImportGraphic( rGraphic, aMainUrl, *xStream, nFormat, pDeterminedFormat, nImportFlags );
464 return nRetValue;
467 namespace {
469 /// Contains a stream and other associated data to import pixels into a
470 /// Graphic.
471 struct GraphicImportContext
473 /// Pixel data is read from this stream.
474 std::unique_ptr<SvStream> m_pStream;
475 /// The Graphic the import filter gets.
476 std::shared_ptr<Graphic> m_pGraphic;
477 /// Write pixel data using this access.
478 std::unique_ptr<BitmapScopedWriteAccess> m_pAccess;
479 std::unique_ptr<BitmapScopedWriteAccess> m_pAlphaAccess;
480 // Need to have an AlphaMask instance to keep its lifetime.
481 AlphaMask mAlphaMask;
482 /// Signals if import finished correctly.
483 ErrCode m_nStatus = ERRCODE_GRFILTER_FILTERERROR;
484 /// Original graphic format.
485 GfxLinkType m_eLinkType = GfxLinkType::NONE;
486 /// Position of the stream before reading the data.
487 sal_uInt64 m_nStreamBegin = 0;
488 /// Flags for the import filter.
489 GraphicFilterImportFlags m_nImportFlags = GraphicFilterImportFlags::NONE;
492 /// Graphic import worker that gets executed on a thread.
493 class GraphicImportTask : public comphelper::ThreadTask
495 GraphicImportContext& m_rContext;
496 public:
497 GraphicImportTask(const std::shared_ptr<comphelper::ThreadTaskTag>& pTag, GraphicImportContext& rContext);
498 void doWork() override;
499 /// Shared code between threaded and non-threaded version.
500 static void doImport(GraphicImportContext& rContext);
505 GraphicImportTask::GraphicImportTask(const std::shared_ptr<comphelper::ThreadTaskTag>& pTag, GraphicImportContext& rContext)
506 : comphelper::ThreadTask(pTag),
507 m_rContext(rContext)
511 void GraphicImportTask::doWork()
513 GraphicImportTask::doImport(m_rContext);
516 void GraphicImportTask::doImport(GraphicImportContext& rContext)
518 if(rContext.m_eLinkType == GfxLinkType::NativeJpg)
520 if (!ImportJPEG(*rContext.m_pStream, *rContext.m_pGraphic, rContext.m_nImportFlags | GraphicFilterImportFlags::UseExistingBitmap, rContext.m_pAccess.get()))
521 rContext.m_nStatus = ERRCODE_GRFILTER_FILTERERROR;
523 else if(rContext.m_eLinkType == GfxLinkType::NativePng)
525 if (!vcl::ImportPNG(*rContext.m_pStream, *rContext.m_pGraphic,
526 rContext.m_nImportFlags | GraphicFilterImportFlags::UseExistingBitmap,
527 rContext.m_pAccess.get(), rContext.m_pAlphaAccess.get()))
529 rContext.m_nStatus = ERRCODE_GRFILTER_FILTERERROR;
534 void GraphicFilter::ImportGraphics(std::vector< std::shared_ptr<Graphic> >& rGraphics, std::vector< std::unique_ptr<SvStream> > vStreams)
536 static bool bThreads = !getenv("VCL_NO_THREAD_IMPORT");
537 std::vector<GraphicImportContext> aContexts;
538 aContexts.reserve(vStreams.size());
539 comphelper::ThreadPool& rSharedPool = comphelper::ThreadPool::getSharedOptimalPool();
540 std::shared_ptr<comphelper::ThreadTaskTag> pTag = comphelper::ThreadPool::createThreadTaskTag();
542 for (auto& pStream : vStreams)
544 aContexts.emplace_back();
545 GraphicImportContext& rContext = aContexts.back();
547 if (pStream)
549 rContext.m_pStream = std::move(pStream);
550 rContext.m_pGraphic = std::make_shared<Graphic>();
551 rContext.m_nStatus = ERRCODE_NONE;
553 // Detect the format.
554 ResetLastError();
555 rContext.m_nStreamBegin = rContext.m_pStream->Tell();
556 sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
557 rContext.m_nStatus = ImpTestOrFindFormat(u"", *rContext.m_pStream, nFormat);
558 rContext.m_pStream->Seek(rContext.m_nStreamBegin);
560 // Import the graphic.
561 if (rContext.m_nStatus == ERRCODE_NONE && !rContext.m_pStream->GetError())
563 OUString aFilterName = pConfig->GetImportFilterName(nFormat);
565 if (aFilterName.equalsIgnoreAsciiCase(IMP_JPEG))
567 rContext.m_eLinkType = GfxLinkType::NativeJpg;
568 rContext.m_nImportFlags = GraphicFilterImportFlags::SetLogsizeForJpeg;
570 if (ImportJPEG( *rContext.m_pStream, *rContext.m_pGraphic, rContext.m_nImportFlags | GraphicFilterImportFlags::OnlyCreateBitmap, nullptr))
572 Bitmap& rBitmap = const_cast<Bitmap&>(rContext.m_pGraphic->GetBitmapExRef().GetBitmap());
573 rContext.m_pAccess = std::make_unique<BitmapScopedWriteAccess>(rBitmap);
574 rContext.m_pStream->Seek(rContext.m_nStreamBegin);
575 if (bThreads)
576 rSharedPool.pushTask(std::make_unique<GraphicImportTask>(pTag, rContext));
577 else
578 GraphicImportTask::doImport(rContext);
580 else
581 rContext.m_nStatus = ERRCODE_GRFILTER_FILTERERROR;
583 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PNG))
585 rContext.m_eLinkType = GfxLinkType::NativePng;
587 if (vcl::ImportPNG( *rContext.m_pStream, *rContext.m_pGraphic, rContext.m_nImportFlags | GraphicFilterImportFlags::OnlyCreateBitmap, nullptr, nullptr))
589 const BitmapEx& rBitmapEx = rContext.m_pGraphic->GetBitmapExRef();
590 Bitmap& rBitmap = const_cast<Bitmap&>(rBitmapEx.GetBitmap());
591 rContext.m_pAccess = std::make_unique<BitmapScopedWriteAccess>(rBitmap);
592 if(rBitmapEx.IsAlpha())
594 // The separate alpha bitmap causes a number of complications. Not only
595 // we need to have an extra bitmap access for it, but we also need
596 // to keep an AlphaMask instance in the context. This is because
597 // BitmapEx internally keeps Bitmap and not AlphaMask (because the Bitmap
598 // may be also a mask, not alpha). So BitmapEx::GetAlpha() returns
599 // a temporary, and direct access to the Bitmap wouldn't work
600 // with AlphaScopedBitmapAccess. *sigh*
601 rContext.mAlphaMask = rBitmapEx.GetAlphaMask();
602 rContext.m_pAlphaAccess = std::make_unique<BitmapScopedWriteAccess>(rContext.mAlphaMask);
604 rContext.m_pStream->Seek(rContext.m_nStreamBegin);
605 if (bThreads)
606 rSharedPool.pushTask(std::make_unique<GraphicImportTask>(pTag, rContext));
607 else
608 GraphicImportTask::doImport(rContext);
610 else
611 rContext.m_nStatus = ERRCODE_GRFILTER_FILTERERROR;
613 else
614 rContext.m_nStatus = ERRCODE_GRFILTER_FILTERERROR;
619 rSharedPool.waitUntilDone(pTag);
621 // Process data after import.
622 for (auto& rContext : aContexts)
624 rContext.m_pAccess.reset();
625 rContext.m_pAlphaAccess.reset();
626 if (!rContext.mAlphaMask.IsEmpty()) // Need to move the AlphaMask back to the BitmapEx.
627 *rContext.m_pGraphic = BitmapEx( rContext.m_pGraphic->GetBitmapExRef().GetBitmap(), rContext.mAlphaMask );
629 if (rContext.m_nStatus == ERRCODE_NONE && rContext.m_eLinkType != GfxLinkType::NONE)
631 BinaryDataContainer aGraphicContent;
633 const sal_uInt64 nStreamEnd = rContext.m_pStream->Tell();
634 sal_Int32 nGraphicContentSize = nStreamEnd - rContext.m_nStreamBegin;
636 if (nGraphicContentSize > 0)
640 rContext.m_pStream->Seek(rContext.m_nStreamBegin);
641 aGraphicContent = BinaryDataContainer(*rContext.m_pStream, nGraphicContentSize);
643 catch (const std::bad_alloc&)
645 rContext.m_nStatus = ERRCODE_GRFILTER_TOOBIG;
649 if (rContext.m_nStatus == ERRCODE_NONE)
650 rContext.m_pGraphic->SetGfxLink(std::make_shared<GfxLink>(aGraphicContent, rContext.m_eLinkType));
653 if (rContext.m_nStatus != ERRCODE_NONE)
654 rContext.m_pGraphic = nullptr;
656 rGraphics.push_back(rContext.m_pGraphic);
660 void GraphicFilter::MakeGraphicsAvailableThreaded(std::vector<Graphic*>& graphics)
662 // Graphic::makeAvailable() is not thread-safe. Only the jpeg and png loaders are, so here
663 // we process only jpeg and png images that also have their stream data, load new Graphic's
664 // from them and then update the passed objects using them.
665 std::vector< Graphic* > toLoad;
666 for(auto graphic : graphics)
668 // Need to use GetSharedGfxLink, to access the pointer without copying.
669 if(!graphic->isAvailable() && graphic->IsGfxLink()
670 && graphic->GetSharedGfxLink()->GetDataSize() != 0
671 && (graphic->GetSharedGfxLink()->GetType() == GfxLinkType::NativeJpg
672 || graphic->GetSharedGfxLink()->GetType() == GfxLinkType::NativePng))
674 // Graphic objects share internal ImpGraphic, do not process any of those twice.
675 const auto predicate = [graphic](Graphic* item) { return item->ImplGetImpGraphic() == graphic->ImplGetImpGraphic(); };
676 if( std::none_of(toLoad.begin(), toLoad.end(), predicate ))
677 toLoad.push_back( graphic );
680 if( toLoad.empty())
681 return;
682 std::vector< std::unique_ptr<SvStream>> streams;
683 streams.reserve(toLoad.size());
684 for( auto graphic : toLoad )
686 streams.push_back( std::make_unique<SvMemoryStream>( const_cast<sal_uInt8*>(graphic->GetSharedGfxLink()->GetData()),
687 graphic->GetSharedGfxLink()->GetDataSize(), StreamMode::READ | StreamMode::WRITE));
689 std::vector< std::shared_ptr<Graphic>> loadedGraphics;
690 loadedGraphics.reserve(streams.size());
691 ImportGraphics(loadedGraphics, std::move(streams));
692 assert(loadedGraphics.size() == toLoad.size());
693 for( size_t i = 0; i < toLoad.size(); ++i )
695 if(loadedGraphics[ i ] != nullptr)
696 toLoad[ i ]->ImplGetImpGraphic()->updateFromLoadedGraphic(loadedGraphics[ i ]->ImplGetImpGraphic());
700 namespace
703 BinaryDataContainer insertContentOrDecompressFromZ(SvStream& rStream, sal_uInt32 nStreamLength)
705 BinaryDataContainer aGraphicContent;
707 if (ZCodec::IsZCompressed(rStream))
709 ZCodec aCodec;
710 SvMemoryStream aMemStream;
711 tools::Long nMemoryLength;
712 aCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, /*gzLib*/true);
713 nMemoryLength = aCodec.Decompress(rStream, aMemStream);
714 aCodec.EndCompression();
716 if (rStream.good() && nMemoryLength >= 0)
718 aMemStream.Seek(STREAM_SEEK_TO_BEGIN);
719 aGraphicContent = BinaryDataContainer(aMemStream, nMemoryLength);
722 else
724 aGraphicContent = BinaryDataContainer(rStream, nStreamLength);
726 return aGraphicContent;
730 ErrCode prepareImageTypeAndData(SvStream& rStream, sal_uInt32 nStreamLength, BinaryDataContainer& rGraphicContent, std::u16string_view rFilterName, GfxLinkType& rLinkType)
732 const sal_uInt64 nStreamBegin = rStream.Tell();
733 ErrCode nStatus = ERRCODE_GRFILTER_FILTERERROR;
735 if (o3tl::equalsIgnoreAsciiCase(rFilterName, IMP_GIF))
737 rLinkType = GfxLinkType::NativeGif;
738 nStatus = ERRCODE_NONE;
740 else if (o3tl::equalsIgnoreAsciiCase(rFilterName, IMP_PNG))
742 // check if this PNG contains a GIF chunk!
743 rGraphicContent = vcl::PngImageReader::getMicrosoftGifChunk(rStream);
744 if (!rGraphicContent.isEmpty())
745 rLinkType = GfxLinkType::NativeGif;
746 else
747 rLinkType = GfxLinkType::NativePng;
748 nStatus = ERRCODE_NONE;
750 else if (o3tl::equalsIgnoreAsciiCase(rFilterName, IMP_JPEG))
752 rLinkType = GfxLinkType::NativeJpg;
753 nStatus = ERRCODE_NONE;
755 else if (o3tl::equalsIgnoreAsciiCase(rFilterName, IMP_SVG))
757 rStream.Seek(nStreamBegin);
758 rGraphicContent = insertContentOrDecompressFromZ(rStream, nStreamLength);
759 if (rStream.good())
761 rLinkType = GfxLinkType::NativeSvg;
762 nStatus = ERRCODE_NONE;
765 else if (o3tl::equalsIgnoreAsciiCase(rFilterName, IMP_BMP))
767 rLinkType = GfxLinkType::NativeBmp;
768 nStatus = ERRCODE_NONE;
770 else if (o3tl::equalsIgnoreAsciiCase(rFilterName, IMP_MOV))
772 rLinkType = GfxLinkType::NativeMov;
773 nStatus = ERRCODE_NONE;
775 else if (o3tl::equalsIgnoreAsciiCase(rFilterName, IMP_WMF) ||
776 o3tl::equalsIgnoreAsciiCase(rFilterName, IMP_EMF) ||
777 o3tl::equalsIgnoreAsciiCase(rFilterName, IMP_WMZ) ||
778 o3tl::equalsIgnoreAsciiCase(rFilterName, IMP_EMZ))
780 rStream.Seek(nStreamBegin);
781 rGraphicContent = insertContentOrDecompressFromZ(rStream, nStreamLength);
782 if (rStream.good())
784 rLinkType = GfxLinkType::NativeWmf;
785 nStatus = ERRCODE_NONE;
788 else if (o3tl::equalsIgnoreAsciiCase(rFilterName, IMP_PDF))
790 rLinkType = GfxLinkType::NativePdf;
791 nStatus = ERRCODE_NONE;
793 else if (o3tl::equalsIgnoreAsciiCase(rFilterName, IMP_TIFF))
795 rLinkType = GfxLinkType::NativeTif;
796 nStatus = ERRCODE_NONE;
798 else if (o3tl::equalsIgnoreAsciiCase(rFilterName, IMP_PICT))
800 rLinkType = GfxLinkType::NativePct;
801 nStatus = ERRCODE_NONE;
803 else if (o3tl::equalsIgnoreAsciiCase(rFilterName, IMP_MET))
805 rLinkType = GfxLinkType::NativeMet;
806 nStatus = ERRCODE_NONE;
808 else if (o3tl::equalsIgnoreAsciiCase(rFilterName, IMP_WEBP))
810 if (supportNativeWebp())
812 rLinkType = GfxLinkType::NativeWebp;
813 nStatus = ERRCODE_NONE;
817 return nStatus;
820 } // end anonymous namespace
822 Graphic GraphicFilter::ImportUnloadedGraphic(SvStream& rIStream, sal_uInt64 sizeLimit,
823 const Size* pSizeHint)
825 Graphic aGraphic;
826 sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
828 ResetLastError();
830 const sal_uInt64 nStreamBegin = rIStream.Tell();
832 // Get the image format
833 rIStream.Seek(nStreamBegin);
834 ErrCode nStatus = ImpTestOrFindFormat(u"", rIStream, nFormat);
835 if (nStatus != ERRCODE_NONE)
836 return aGraphic;
838 rIStream.Seek(nStreamBegin);
839 sal_uInt32 nStreamLength(rIStream.remainingSize());
840 if (sizeLimit && sizeLimit < nStreamLength)
841 nStreamLength = sizeLimit;
843 OUString aFilterName = pConfig->GetImportFilterName(nFormat);
845 BinaryDataContainer aBinaryDataContainer;
847 GfxLinkType eLinkType = GfxLinkType::NONE;
848 rIStream.Seek(nStreamBegin);
849 nStatus = prepareImageTypeAndData(rIStream, nStreamLength, aBinaryDataContainer, aFilterName, eLinkType);
851 if (nStatus == ERRCODE_NONE && eLinkType != GfxLinkType::NONE)
853 if (aBinaryDataContainer.isEmpty() && nStreamLength > 0)
857 rIStream.Seek(nStreamBegin);
858 aBinaryDataContainer = BinaryDataContainer(rIStream, nStreamLength);
860 catch (const std::bad_alloc&)
862 nStatus = ERRCODE_GRFILTER_TOOBIG;
866 if (nStatus == ERRCODE_NONE)
868 bool bAnimated = false;
869 Size aLogicSize;
871 if (eLinkType == GfxLinkType::NativeGif && !aBinaryDataContainer.isEmpty())
873 std::shared_ptr<SvStream> pMemoryStream = aBinaryDataContainer.getAsStream();
874 bAnimated = IsGIFAnimated(*pMemoryStream, aLogicSize);
875 if (!pSizeHint && aLogicSize.getWidth() && aLogicSize.getHeight())
877 pSizeHint = &aLogicSize;
881 aGraphic.SetGfxLink(std::make_shared<GfxLink>(aBinaryDataContainer, eLinkType));
882 aGraphic.ImplGetImpGraphic()->setPrepared(bAnimated, pSizeHint);
886 // Set error code or try to set native buffer
887 if (nStatus != ERRCODE_NONE)
888 ImplSetError(nStatus, &rIStream);
890 if (nStatus != ERRCODE_NONE || eLinkType == GfxLinkType::NONE)
891 rIStream.Seek(nStreamBegin);
893 return aGraphic;
896 ErrCode GraphicFilter::readGIF(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
898 if (ImportGIF(rStream, rGraphic))
900 rLinkType = GfxLinkType::NativeGif;
901 return ERRCODE_NONE;
903 else
904 return ERRCODE_GRFILTER_FILTERERROR;
907 ErrCode GraphicFilter::readPNG(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType, BinaryDataContainer& rpGraphicContent)
909 ErrCode aReturnCode = ERRCODE_NONE;
911 // check if this PNG contains a GIF chunk!
912 if (auto aMSGifChunk = vcl::PngImageReader::getMicrosoftGifChunk(rStream);
913 !aMSGifChunk.isEmpty())
915 std::shared_ptr<SvStream> pIStrm(aMSGifChunk.getAsStream());
916 ImportGIF(*pIStrm, rGraphic);
917 rLinkType = GfxLinkType::NativeGif;
918 rpGraphicContent = std::move(aMSGifChunk);
919 return aReturnCode;
922 // PNG has no GIF chunk
923 Graphic aGraphic;
924 vcl::PngImageReader aPNGReader(rStream);
925 aPNGReader.read(aGraphic);
926 if (!aGraphic.GetBitmapEx().IsEmpty())
928 rGraphic = std::move(aGraphic);
929 rLinkType = GfxLinkType::NativePng;
931 else
932 aReturnCode = ERRCODE_GRFILTER_FILTERERROR;
934 return aReturnCode;
937 ErrCode GraphicFilter::readJPEG(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType, GraphicFilterImportFlags nImportFlags)
939 ErrCode aReturnCode = ERRCODE_NONE;
941 // set LOGSIZE flag always, if not explicitly disabled
942 // (see #90508 and #106763)
943 if (!(nImportFlags & GraphicFilterImportFlags::DontSetLogsizeForJpeg))
945 nImportFlags |= GraphicFilterImportFlags::SetLogsizeForJpeg;
948 sal_uInt64 nPosition = rStream.Tell();
949 if (!ImportJPEG(rStream, rGraphic, nImportFlags | GraphicFilterImportFlags::OnlyCreateBitmap, nullptr))
950 aReturnCode = ERRCODE_GRFILTER_FILTERERROR;
951 else
953 Bitmap& rBitmap = const_cast<Bitmap&>(rGraphic.GetBitmapExRef().GetBitmap());
954 BitmapScopedWriteAccess pWriteAccess(rBitmap);
955 rStream.Seek(nPosition);
956 if (!ImportJPEG(rStream, rGraphic, nImportFlags | GraphicFilterImportFlags::UseExistingBitmap, &pWriteAccess))
957 aReturnCode = ERRCODE_GRFILTER_FILTERERROR;
958 else
959 rLinkType = GfxLinkType::NativeJpg;
962 return aReturnCode;
965 ErrCode GraphicFilter::readSVG(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType, BinaryDataContainer& rpGraphicContent)
967 ErrCode aReturnCode = ERRCODE_NONE;
969 const sal_uInt64 nStreamPosition(rStream.Tell());
970 const sal_uInt64 nStreamLength(rStream.remainingSize());
972 bool bOkay(false);
974 if (nStreamLength > 0)
976 std::vector<sal_uInt8> aTwoBytes(2);
977 rStream.ReadBytes(aTwoBytes.data(), 2);
978 rStream.Seek(nStreamPosition);
980 if (aTwoBytes[0] == 0x1F && aTwoBytes[1] == 0x8B)
982 SvMemoryStream aMemStream;
983 ZCodec aCodec;
984 tools::Long nMemoryLength;
986 aCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, /*gzLib*/true);
987 nMemoryLength = aCodec.Decompress(rStream, aMemStream);
988 aCodec.EndCompression();
990 if (!rStream.GetError() && nMemoryLength >= 0)
992 aMemStream.Seek(STREAM_SEEK_TO_BEGIN);
993 rpGraphicContent = BinaryDataContainer(aMemStream, nMemoryLength);
995 // Make a uncompressed copy for GfxLink
996 if (!aMemStream.GetError())
998 auto aVectorGraphicDataPtr = std::make_shared<VectorGraphicData>(rpGraphicContent, VectorGraphicDataType::Svg);
999 rGraphic = Graphic(aVectorGraphicDataPtr);
1000 bOkay = true;
1004 else
1006 BinaryDataContainer aNewData(rStream, nStreamLength);
1008 if (!rStream.GetError())
1010 auto aVectorGraphicDataPtr = std::make_shared<VectorGraphicData>(aNewData, VectorGraphicDataType::Svg);
1011 rGraphic = Graphic(aVectorGraphicDataPtr);
1012 bOkay = true;
1017 if (bOkay)
1019 rLinkType = GfxLinkType::NativeSvg;
1021 else
1023 aReturnCode = ERRCODE_GRFILTER_FILTERERROR;
1026 return aReturnCode;
1029 ErrCode GraphicFilter::readXBM(SvStream & rStream, Graphic & rGraphic)
1031 if (ImportXBM(rStream, rGraphic))
1032 return ERRCODE_NONE;
1033 else
1034 return ERRCODE_GRFILTER_FILTERERROR;
1037 ErrCode GraphicFilter::readXPM(SvStream & rStream, Graphic & rGraphic)
1039 if (ImportXPM(rStream, rGraphic))
1040 return ERRCODE_NONE;
1041 else
1042 return ERRCODE_GRFILTER_FILTERERROR;
1045 ErrCode GraphicFilter::readWMF_EMF(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType, VectorGraphicDataType eType)
1047 // use new UNO API service, do not directly import but create a
1048 // Graphic that contains the original data and decomposes to
1049 // primitives on demand
1050 sal_uInt32 nStreamLength(rStream.remainingSize());
1051 SvStream* aNewStream = &rStream;
1052 ErrCode aReturnCode = ERRCODE_GRFILTER_FILTERERROR;
1053 SvMemoryStream aMemStream;
1054 if (ZCodec::IsZCompressed(rStream))
1056 ZCodec aCodec;
1057 aCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, /*gzLib*/true);
1058 auto nDecompressLength = aCodec.Decompress(rStream, aMemStream);
1059 aCodec.EndCompression();
1060 aMemStream.Seek(STREAM_SEEK_TO_BEGIN);
1061 if (nDecompressLength >= 0)
1063 nStreamLength = nDecompressLength;
1064 aNewStream = &aMemStream;
1067 BinaryDataContainer aNewData(*aNewStream, nStreamLength);
1068 if (!aNewStream->GetError())
1070 auto aVectorGraphicDataPtr = std::make_shared<VectorGraphicData>(aNewData, eType);
1072 rGraphic = Graphic(aVectorGraphicDataPtr);
1073 rLinkType = GfxLinkType::NativeWmf;
1074 aReturnCode = ERRCODE_NONE;
1077 return aReturnCode;
1080 ErrCode GraphicFilter::readWMF(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
1082 return readWMF_EMF(rStream, rGraphic, rLinkType,VectorGraphicDataType::Wmf);
1085 ErrCode GraphicFilter::readEMF(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
1087 return readWMF_EMF(rStream, rGraphic, rLinkType, VectorGraphicDataType::Emf);
1090 ErrCode GraphicFilter::readPDF(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
1092 if (vcl::ImportPDF(rStream, rGraphic))
1094 rLinkType = GfxLinkType::NativePdf;
1095 return ERRCODE_NONE;
1097 else
1098 return ERRCODE_GRFILTER_FILTERERROR;
1101 ErrCode GraphicFilter::readTIFF(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
1103 if (ImportTiffGraphicImport(rStream, rGraphic))
1105 rLinkType = GfxLinkType::NativeTif;
1106 return ERRCODE_NONE;
1108 else
1109 return ERRCODE_GRFILTER_FILTERERROR;
1112 ErrCode GraphicFilter::readWithTypeSerializer(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType, std::u16string_view aFilterName)
1114 ErrCode aReturnCode = ERRCODE_GRFILTER_FILTERERROR;
1116 // SV internal filters for import bitmaps and MetaFiles
1117 TypeSerializer aSerializer(rStream);
1118 aSerializer.readGraphic(rGraphic);
1120 if (!rStream.GetError())
1122 if (o3tl::equalsIgnoreAsciiCase(aFilterName, u"" IMP_MOV))
1124 rGraphic.SetDefaultType();
1125 rStream.Seek(STREAM_SEEK_TO_END);
1126 rLinkType = GfxLinkType::NativeMov;
1128 aReturnCode = ERRCODE_NONE;
1130 return aReturnCode;
1133 ErrCode GraphicFilter::readBMP(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
1135 if (BmpReader(rStream, rGraphic))
1137 rLinkType = GfxLinkType::NativeBmp;
1138 return ERRCODE_NONE;
1140 else
1141 return ERRCODE_GRFILTER_FILTERERROR;
1144 ErrCode GraphicFilter::readTGA(SvStream & rStream, Graphic & rGraphic)
1146 if (ImportTgaGraphic(rStream, rGraphic))
1147 return ERRCODE_NONE;
1148 else
1149 return ERRCODE_GRFILTER_FILTERERROR;
1152 ErrCode GraphicFilter::readPICT(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
1154 if (ImportPictGraphic(rStream, rGraphic))
1156 rLinkType = GfxLinkType::NativePct;
1157 return ERRCODE_NONE;
1159 else
1160 return ERRCODE_GRFILTER_FILTERERROR;
1163 ErrCode GraphicFilter::readMET(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
1165 if (ImportMetGraphic(rStream, rGraphic))
1167 rLinkType = GfxLinkType::NativeMet;
1168 return ERRCODE_NONE;
1170 else
1171 return ERRCODE_GRFILTER_FILTERERROR;
1174 ErrCode GraphicFilter::readRAS(SvStream & rStream, Graphic & rGraphic)
1176 if (ImportRasGraphic(rStream, rGraphic))
1177 return ERRCODE_NONE;
1178 else
1179 return ERRCODE_GRFILTER_FILTERERROR;
1182 ErrCode GraphicFilter::readPCX(SvStream & rStream, Graphic & rGraphic)
1184 if (ImportPcxGraphic(rStream, rGraphic))
1185 return ERRCODE_NONE;
1186 else
1187 return ERRCODE_GRFILTER_FILTERERROR;
1190 ErrCode GraphicFilter::readEPS(SvStream & rStream, Graphic & rGraphic)
1192 if (ImportEpsGraphic(rStream, rGraphic))
1193 return ERRCODE_NONE;
1194 else
1195 return ERRCODE_GRFILTER_FILTERERROR;
1198 ErrCode GraphicFilter::readPSD(SvStream & rStream, Graphic & rGraphic)
1200 if (ImportPsdGraphic(rStream, rGraphic))
1201 return ERRCODE_NONE;
1202 else
1203 return ERRCODE_GRFILTER_FILTERERROR;
1206 ErrCode GraphicFilter::readPCD(SvStream & rStream, Graphic & rGraphic)
1208 std::unique_ptr<FilterConfigItem> pFilterConfigItem;
1209 if (!comphelper::IsFuzzing())
1211 OUString aFilterConfigPath( u"Office.Common/Filter/Graphic/Import/PCD"_ustr );
1212 pFilterConfigItem = std::make_unique<FilterConfigItem>(aFilterConfigPath);
1215 if (ImportPcdGraphic(rStream, rGraphic, pFilterConfigItem.get()))
1216 return ERRCODE_NONE;
1217 else
1218 return ERRCODE_GRFILTER_FILTERERROR;
1221 ErrCode GraphicFilter::readPBM(SvStream & rStream, Graphic & rGraphic)
1223 if (ImportPbmGraphic(rStream, rGraphic))
1224 return ERRCODE_NONE;
1225 else
1226 return ERRCODE_GRFILTER_FILTERERROR;
1229 ErrCode GraphicFilter::readDXF(SvStream & rStream, Graphic & rGraphic)
1231 if (ImportDxfGraphic(rStream, rGraphic))
1232 return ERRCODE_NONE;
1233 else
1234 return ERRCODE_GRFILTER_FILTERERROR;
1237 ErrCode GraphicFilter::readWEBP(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
1239 if (ImportWebpGraphic(rStream, rGraphic))
1241 if(supportNativeWebp())
1242 rLinkType = GfxLinkType::NativeWebp;
1243 return ERRCODE_NONE;
1245 else
1246 return ERRCODE_GRFILTER_FILTERERROR;
1249 ErrCode GraphicFilter::ImportGraphic(Graphic& rGraphic, std::u16string_view rPath, SvStream& rIStream,
1250 sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat, GraphicFilterImportFlags nImportFlags)
1252 OUString aFilterName;
1253 sal_uInt64 nStreamBegin;
1254 ErrCode nStatus;
1255 GfxLinkType eLinkType = GfxLinkType::NONE;
1256 const bool bLinkSet = rGraphic.IsGfxLink();
1258 BinaryDataContainer aGraphicContent;
1260 ResetLastError();
1263 bool bDummyContext = rGraphic.IsDummyContext();
1264 if( bDummyContext )
1266 rGraphic.SetDummyContext( false );
1267 nStreamBegin = 0;
1269 else
1270 nStreamBegin = rIStream.Tell();
1272 nStatus = ImpTestOrFindFormat( rPath, rIStream, nFormat );
1273 // if pending, return ERRCODE_NONE in order to request more bytes
1274 if( rIStream.GetError() == ERRCODE_IO_PENDING )
1276 rGraphic.SetDummyContext(true);
1277 rIStream.ResetError();
1278 rIStream.Seek( nStreamBegin );
1279 return ImplSetError( ERRCODE_NONE );
1282 rIStream.Seek( nStreamBegin );
1284 if( ( nStatus != ERRCODE_NONE ) || rIStream.GetError() )
1285 return ImplSetError( ( nStatus != ERRCODE_NONE ) ? nStatus : ERRCODE_GRFILTER_OPENERROR, &rIStream );
1287 if( pDeterminedFormat )
1288 *pDeterminedFormat = nFormat;
1290 aFilterName = pConfig->GetImportFilterName( nFormat );
1293 // read graphic
1295 if (aFilterName.equalsIgnoreAsciiCase(IMP_GIF))
1297 nStatus = readGIF(rIStream, rGraphic, eLinkType);
1299 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PNG))
1301 nStatus = readPNG(rIStream, rGraphic, eLinkType, aGraphicContent);
1303 else if (aFilterName.equalsIgnoreAsciiCase(IMP_JPEG))
1305 nStatus = readJPEG(rIStream, rGraphic, eLinkType, nImportFlags);
1307 else if (aFilterName.equalsIgnoreAsciiCase(IMP_SVG) || aFilterName.equalsIgnoreAsciiCase(IMP_SVGZ))
1309 nStatus = readSVG(rIStream, rGraphic, eLinkType, aGraphicContent);
1311 else if( aFilterName.equalsIgnoreAsciiCase( IMP_XBM ) )
1313 nStatus = readXBM(rIStream, rGraphic);
1315 else if( aFilterName.equalsIgnoreAsciiCase( IMP_XPM ) )
1317 nStatus = readXPM(rIStream, rGraphic);
1319 else if (aFilterName.equalsIgnoreAsciiCase(IMP_BMP))
1321 nStatus = readBMP(rIStream, rGraphic, eLinkType);
1323 else if (aFilterName.equalsIgnoreAsciiCase(IMP_SVMETAFILE))
1325 nStatus = readWithTypeSerializer(rIStream, rGraphic, eLinkType, aFilterName);
1327 else if( aFilterName.equalsIgnoreAsciiCase(IMP_MOV))
1329 nStatus = readWithTypeSerializer(rIStream, rGraphic, eLinkType, aFilterName);
1331 else if (aFilterName.equalsIgnoreAsciiCase(IMP_WMF) || aFilterName.equalsIgnoreAsciiCase(IMP_WMZ))
1333 nStatus = readWMF(rIStream, rGraphic, eLinkType);
1335 else if (aFilterName.equalsIgnoreAsciiCase(IMP_EMF) || aFilterName.equalsIgnoreAsciiCase(IMP_EMZ))
1337 nStatus = readEMF(rIStream, rGraphic, eLinkType);
1339 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PDF))
1341 nStatus = readPDF(rIStream, rGraphic, eLinkType);
1343 else if (aFilterName.equalsIgnoreAsciiCase(IMP_TIFF) )
1345 nStatus = readTIFF(rIStream, rGraphic, eLinkType);
1347 else if (aFilterName.equalsIgnoreAsciiCase(IMP_TGA) )
1349 nStatus = readTGA(rIStream, rGraphic);
1351 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PICT))
1353 nStatus = readPICT(rIStream, rGraphic, eLinkType);
1355 else if (aFilterName.equalsIgnoreAsciiCase(IMP_MET))
1357 nStatus = readMET(rIStream, rGraphic, eLinkType);
1359 else if (aFilterName.equalsIgnoreAsciiCase(IMP_RAS))
1361 nStatus = readRAS(rIStream, rGraphic);
1363 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PCX))
1365 nStatus = readPCX(rIStream, rGraphic);
1367 else if (aFilterName.equalsIgnoreAsciiCase(IMP_EPS))
1369 nStatus = readEPS(rIStream, rGraphic);
1371 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PSD))
1373 nStatus = readPSD(rIStream, rGraphic);
1375 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PCD))
1377 nStatus = readPCD(rIStream, rGraphic);
1379 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PBM))
1381 nStatus = readPBM(rIStream, rGraphic);
1383 else if (aFilterName.equalsIgnoreAsciiCase(IMP_DXF))
1385 nStatus = readDXF(rIStream, rGraphic);
1387 else if (aFilterName.equalsIgnoreAsciiCase(IMP_WEBP))
1389 nStatus = readWEBP(rIStream, rGraphic, eLinkType);
1391 else
1392 nStatus = ERRCODE_GRFILTER_FILTERERROR;
1395 if (nStatus == ERRCODE_NONE && eLinkType != GfxLinkType::NONE && !bLinkSet)
1397 if (aGraphicContent.isEmpty())
1399 const sal_uInt64 nStreamEnd = rIStream.Tell();
1400 const sal_uInt64 nGraphicContentSize = nStreamEnd - nStreamBegin;
1402 if (nGraphicContentSize > 0)
1406 rIStream.Seek(nStreamBegin);
1407 aGraphicContent = BinaryDataContainer(rIStream, nGraphicContentSize);
1409 catch (const std::bad_alloc&)
1411 nStatus = ERRCODE_GRFILTER_TOOBIG;
1415 if( nStatus == ERRCODE_NONE )
1417 rGraphic.SetGfxLink(std::make_shared<GfxLink>(aGraphicContent, eLinkType));
1421 // Set error code or try to set native buffer
1422 if( nStatus != ERRCODE_NONE )
1424 ImplSetError( nStatus, &rIStream );
1425 rIStream.Seek( nStreamBegin );
1426 rGraphic.Clear();
1429 return nStatus;
1432 ErrCode GraphicFilter::ExportGraphic( const Graphic& rGraphic, const INetURLObject& rPath,
1433 sal_uInt16 nFormat, const css::uno::Sequence< css::beans::PropertyValue >* pFilterData )
1435 SAL_INFO( "vcl.filter", "GraphicFilter::ExportGraphic() (thb)" );
1436 ErrCode nRetValue = ERRCODE_GRFILTER_FORMATERROR;
1437 SAL_WARN_IF( rPath.GetProtocol() == INetProtocol::NotValid, "vcl.filter", "GraphicFilter::ExportGraphic() : ProtType == INetProtocol::NotValid" );
1439 OUString aMainUrl(rPath.GetMainURL(INetURLObject::DecodeMechanism::NONE));
1440 bool bAlreadyExists = utl::UCBContentHelper::IsDocument(aMainUrl);
1442 std::unique_ptr<SvStream> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl, StreamMode::WRITE | StreamMode::TRUNC ));
1443 if (xStream)
1445 nRetValue = ExportGraphic( rGraphic, aMainUrl, *xStream, nFormat, pFilterData );
1446 xStream.reset();
1448 if( ( ERRCODE_NONE != nRetValue ) && !bAlreadyExists )
1449 utl::UCBContentHelper::Kill(aMainUrl);
1451 return nRetValue;
1454 ErrCode GraphicFilter::ExportGraphic( const Graphic& rGraphic, std::u16string_view rPath,
1455 SvStream& rOStm, sal_uInt16 nFormat, const css::uno::Sequence< css::beans::PropertyValue >* pFilterData )
1457 SAL_INFO( "vcl.filter", "GraphicFilter::ExportGraphic() (thb)" );
1458 sal_uInt16 nFormatCount = GetExportFormatCount();
1460 ResetLastError();
1461 bool bShouldCompress = false;
1462 SvMemoryStream rCompressableStm;
1464 if( nFormat == GRFILTER_FORMAT_DONTKNOW )
1466 OUString aExt = ImpGetExtension( rPath );
1467 for( sal_uInt16 i = 0; i < nFormatCount; i++ )
1469 if ( pConfig->GetExportFormatExtension( i ).equalsIgnoreAsciiCase( aExt ) )
1471 nFormat=i;
1472 break;
1476 if( nFormat >= nFormatCount )
1477 return ImplSetError( ERRCODE_GRFILTER_FORMATERROR );
1479 FilterConfigItem aConfigItem( pFilterData );
1480 OUString aFilterName( pConfig->GetExportFilterName( nFormat ) );
1481 ErrCode nStatus = ERRCODE_NONE;
1482 GraphicType eType;
1483 Graphic aGraphic = ImpGetScaledGraphic( rGraphic, aConfigItem );
1484 eType = aGraphic.GetType();
1486 if( pConfig->IsExportPixelFormat( nFormat ) )
1488 if( eType != GraphicType::Bitmap )
1490 Size aSizePixel;
1491 sal_uLong nBitsPerPixel,nNeededMem,nMaxMem;
1492 ScopedVclPtrInstance< VirtualDevice > aVirDev;
1494 nMaxMem = 1024;
1495 nMaxMem *= 1024; // In Bytes
1497 // Calculate how big the image would normally be:
1498 aSizePixel=aVirDev->LogicToPixel(aGraphic.GetPrefSize(),aGraphic.GetPrefMapMode());
1500 // Calculate how much memory the image will take up
1501 nBitsPerPixel=aVirDev->GetBitCount();
1502 nNeededMem=(static_cast<sal_uLong>(aSizePixel.Width())*static_cast<sal_uLong>(aSizePixel.Height())*nBitsPerPixel+7)/8;
1504 // is the image larger than available memory?
1505 if (nMaxMem<nNeededMem)
1507 double fFak=sqrt(static_cast<double>(nMaxMem)/static_cast<double>(nNeededMem));
1508 aSizePixel.setWidth(static_cast<sal_uLong>(static_cast<double>(aSizePixel.Width())*fFak) );
1509 aSizePixel.setHeight(static_cast<sal_uLong>(static_cast<double>(aSizePixel.Height())*fFak) );
1512 aVirDev->SetMapMode(MapMode(MapUnit::MapPixel));
1513 aVirDev->SetOutputSizePixel(aSizePixel);
1514 Graphic aGraphic2=aGraphic;
1515 aGraphic2.Draw(*aVirDev, Point(0, 0), aSizePixel); // this changes the MapMode
1516 aVirDev->SetMapMode(MapMode(MapUnit::MapPixel));
1517 aGraphic=Graphic(aVirDev->GetBitmapEx(Point(0,0),aSizePixel));
1520 if( rOStm.GetError() )
1521 nStatus = ERRCODE_GRFILTER_IOERROR;
1522 if( ERRCODE_NONE == nStatus )
1524 if( aFilterName.equalsIgnoreAsciiCase( EXP_BMP ) )
1526 if (!BmpWriter(rOStm, aGraphic, &aConfigItem))
1527 nStatus = ERRCODE_GRFILTER_FORMATERROR;
1528 if (rOStm.GetError())
1529 nStatus = ERRCODE_GRFILTER_IOERROR;
1531 else if (aFilterName.equalsIgnoreAsciiCase(EXP_TIFF))
1533 if (!ExportTiffGraphicImport(rOStm, aGraphic, &aConfigItem))
1534 nStatus = ERRCODE_GRFILTER_FORMATERROR;
1536 if( rOStm.GetError() )
1537 nStatus = ERRCODE_GRFILTER_IOERROR;
1539 else if (aFilterName.equalsIgnoreAsciiCase(EXP_GIF))
1541 if (!ExportGifGraphic(rOStm, aGraphic, &aConfigItem))
1542 nStatus = ERRCODE_GRFILTER_FORMATERROR;
1544 if( rOStm.GetError() )
1545 nStatus = ERRCODE_GRFILTER_IOERROR;
1547 else if( aFilterName.equalsIgnoreAsciiCase( EXP_SVMETAFILE ) )
1549 sal_Int32 nVersion = aConfigItem.ReadInt32( u"Version"_ustr, 0 ) ;
1550 if ( nVersion )
1551 rOStm.SetVersion( nVersion );
1553 // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
1554 const GDIMetaFile& aMTF(aGraphic.GetGDIMetaFile());
1556 SvmWriter aWriter( rOStm );
1557 aWriter.Write( aMTF );
1559 if( rOStm.GetError() )
1560 nStatus = ERRCODE_GRFILTER_IOERROR;
1562 else if ( aFilterName.equalsIgnoreAsciiCase( EXP_WMF ) || aFilterName.equalsIgnoreAsciiCase( EXP_WMZ ) )
1564 bool bDone(false);
1565 SvStream* rTempStm = &rOStm;
1566 if (aFilterName.equalsIgnoreAsciiCase(EXP_WMZ))
1568 // Write to a different stream so that we can compress to rOStm later
1569 rCompressableStm.SetBufferSize( rOStm.GetBufferSize() );
1570 rTempStm = &rCompressableStm;
1571 bShouldCompress = true;
1573 // do we have a native Vector Graphic Data RenderGraphic, whose data can be written directly?
1574 auto const & rVectorGraphicDataPtr(rGraphic.getVectorGraphicData());
1576 bool bIsEMF = rGraphic.GetGfxLink().IsEMF();
1578 // VectorGraphicDataType::Wmf means WMF or EMF, allow direct write in the WMF case
1579 // only.
1580 if (rVectorGraphicDataPtr
1581 && rVectorGraphicDataPtr->getType() == VectorGraphicDataType::Wmf
1582 && !rVectorGraphicDataPtr->getBinaryDataContainer().isEmpty()
1583 && !bIsEMF)
1585 rVectorGraphicDataPtr->getBinaryDataContainer().writeToStream(*rTempStm);
1586 if (rTempStm->GetError())
1588 nStatus = ERRCODE_GRFILTER_IOERROR;
1590 else
1592 bDone = true;
1596 if (!bDone)
1598 // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
1599 if (!ConvertGraphicToWMF(aGraphic, *rTempStm, &aConfigItem))
1600 nStatus = ERRCODE_GRFILTER_FORMATERROR;
1602 if (rTempStm->GetError())
1603 nStatus = ERRCODE_GRFILTER_IOERROR;
1606 else if ( aFilterName.equalsIgnoreAsciiCase( EXP_EMF ) || aFilterName.equalsIgnoreAsciiCase( EXP_EMZ ) )
1608 bool bDone(false);
1609 SvStream* rTempStm = &rOStm;
1610 if (aFilterName.equalsIgnoreAsciiCase(EXP_EMZ))
1612 // Write to a different stream so that we can compress to rOStm later
1613 rCompressableStm.SetBufferSize( rOStm.GetBufferSize() );
1614 rTempStm = &rCompressableStm;
1615 bShouldCompress = true;
1617 // do we have a native Vector Graphic Data RenderGraphic, whose data can be written directly?
1618 auto const & rVectorGraphicDataPtr(rGraphic.getVectorGraphicData());
1620 if (rVectorGraphicDataPtr
1621 && rVectorGraphicDataPtr->getType() == VectorGraphicDataType::Emf
1622 && !rVectorGraphicDataPtr->getBinaryDataContainer().isEmpty())
1624 rVectorGraphicDataPtr->getBinaryDataContainer().writeToStream(*rTempStm);
1625 if (rTempStm->GetError())
1627 nStatus = ERRCODE_GRFILTER_IOERROR;
1629 else
1631 bDone = true;
1635 if (!bDone)
1637 // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
1638 if (!ConvertGDIMetaFileToEMF(aGraphic.GetGDIMetaFile(), *rTempStm))
1639 nStatus = ERRCODE_GRFILTER_FORMATERROR;
1641 if (rTempStm->GetError())
1642 nStatus = ERRCODE_GRFILTER_IOERROR;
1645 else if( aFilterName.equalsIgnoreAsciiCase( EXP_JPEG ) )
1647 bool bExportedGrayJPEG = false;
1648 if( !ExportJPEG( rOStm, aGraphic, pFilterData, &bExportedGrayJPEG ) )
1649 nStatus = ERRCODE_GRFILTER_FORMATERROR;
1651 if( rOStm.GetError() )
1652 nStatus = ERRCODE_GRFILTER_IOERROR;
1654 else if (aFilterName.equalsIgnoreAsciiCase(EXP_EPS))
1656 if (!ExportEpsGraphic(rOStm, aGraphic, &aConfigItem))
1657 nStatus = ERRCODE_GRFILTER_FORMATERROR;
1659 if (rOStm.GetError())
1660 nStatus = ERRCODE_GRFILTER_IOERROR;
1662 else if ( aFilterName.equalsIgnoreAsciiCase( EXP_PNG ) )
1664 auto aBitmapEx = aGraphic.GetBitmapEx();
1665 vcl::PngImageWriter aPNGWriter( rOStm );
1666 if ( pFilterData )
1667 aPNGWriter.setParameters( *pFilterData );
1668 aPNGWriter.write( aBitmapEx );
1670 if( rOStm.GetError() )
1671 nStatus = ERRCODE_GRFILTER_IOERROR;
1673 else if ( aFilterName.equalsIgnoreAsciiCase( EXP_APNG ) )
1675 vcl::PngImageWriter aPNGWriter( rOStm );
1676 if ( pFilterData )
1677 aPNGWriter.setParameters( *pFilterData );
1678 aPNGWriter.write( aGraphic );
1680 if( rOStm.GetError() )
1681 nStatus = ERRCODE_GRFILTER_IOERROR;
1683 else if( aFilterName.equalsIgnoreAsciiCase( EXP_SVG ) || aFilterName.equalsIgnoreAsciiCase( EXP_SVGZ ) )
1685 bool bDone(false);
1686 SvStream* rTempStm = &rOStm;
1687 if (aFilterName.equalsIgnoreAsciiCase(EXP_SVGZ))
1689 // Write to a different stream so that we can compress to rOStm later
1690 rCompressableStm.SetBufferSize(rOStm.GetBufferSize());
1691 rTempStm = &rCompressableStm;
1692 bShouldCompress = true;
1695 // do we have a native Vector Graphic Data RenderGraphic, whose data can be written directly?
1696 auto const & rVectorGraphicDataPtr(rGraphic.getVectorGraphicData());
1698 if (rVectorGraphicDataPtr
1699 && rVectorGraphicDataPtr->getType() == VectorGraphicDataType::Svg
1700 && !rVectorGraphicDataPtr->getBinaryDataContainer().isEmpty())
1702 rVectorGraphicDataPtr->getBinaryDataContainer().writeToStream(*rTempStm);
1703 if( rTempStm->GetError() )
1705 nStatus = ERRCODE_GRFILTER_IOERROR;
1707 else
1709 bDone = true;
1713 if( !bDone )
1715 // do the normal GDIMetaFile export instead
1718 const css::uno::Reference< css::uno::XComponentContext >& xContext( ::comphelper::getProcessComponentContext() );
1720 css::uno::Reference< css::xml::sax::XDocumentHandler > xSaxWriter(
1721 css::xml::sax::Writer::create( xContext ), css::uno::UNO_QUERY_THROW);
1722 css::uno::Sequence< css::uno::Any > aArguments{ css::uno::Any(
1723 aConfigItem.GetFilterData()) };
1724 css::uno::Reference< css::svg::XSVGWriter > xSVGWriter(
1725 xContext->getServiceManager()->createInstanceWithArgumentsAndContext( u"com.sun.star.svg.SVGWriter"_ustr, aArguments, xContext),
1726 css::uno::UNO_QUERY );
1727 if( xSaxWriter.is() && xSVGWriter.is() )
1729 css::uno::Reference< css::io::XActiveDataSource > xActiveDataSource(
1730 xSaxWriter, css::uno::UNO_QUERY );
1732 if( xActiveDataSource.is() )
1734 const css::uno::Reference< css::uno::XInterface > xStmIf(
1735 getXWeak( new ImpFilterOutputStream( *rTempStm ) ) );
1737 SvMemoryStream aMemStm( 65535, 65535 );
1739 // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
1740 SvmWriter aWriter( aMemStm );
1741 aWriter.Write( aGraphic.GetGDIMetaFile() );
1743 xActiveDataSource->setOutputStream( css::uno::Reference< css::io::XOutputStream >(
1744 xStmIf, css::uno::UNO_QUERY ) );
1745 css::uno::Sequence< sal_Int8 > aMtfSeq( static_cast<sal_Int8 const *>(aMemStm.GetData()), aMemStm.Tell() );
1746 xSVGWriter->write( xSaxWriter, aMtfSeq );
1750 catch(const css::uno::Exception&)
1752 nStatus = ERRCODE_GRFILTER_IOERROR;
1756 else if (aFilterName.equalsIgnoreAsciiCase(EXP_WEBP))
1758 if (!ExportWebpGraphic(rOStm, aGraphic, &aConfigItem))
1759 nStatus = ERRCODE_GRFILTER_FORMATERROR;
1761 if( rOStm.GetError() )
1762 nStatus = ERRCODE_GRFILTER_IOERROR;
1764 else
1765 nStatus = ERRCODE_GRFILTER_FILTERERROR;
1767 if( nStatus != ERRCODE_NONE )
1769 ImplSetError( nStatus, &rOStm );
1771 else if ( bShouldCompress )
1773 sal_uInt32 nUncompressedCRC32
1774 = rtl_crc32( 0, rCompressableStm.GetData(), rCompressableStm.GetSize() );
1775 ZCodec aCodec;
1776 rCompressableStm.Seek( 0 );
1777 aCodec.BeginCompression( ZCODEC_DEFAULT_COMPRESSION, /*gzLib*/true );
1778 // the inner modify time/filename doesn't really matter in this context because
1779 // compressed graphic formats are meant to be opened as is - not to be extracted
1780 aCodec.SetCompressionMetadata( "inner"_ostr, 0, nUncompressedCRC32 );
1781 aCodec.Compress( rCompressableStm, rOStm );
1782 tools::Long nCompressedLength = aCodec.EndCompression();
1783 if ( rOStm.GetError() || nCompressedLength <= 0 )
1784 nStatus = ERRCODE_GRFILTER_IOERROR;
1786 return nStatus;
1790 void GraphicFilter::ResetLastError()
1792 mxErrorEx = ERRCODE_NONE;
1795 Link<ConvertData&,bool> GraphicFilter::GetFilterCallback() const
1797 Link<ConvertData&,bool> aLink( LINK( const_cast<GraphicFilter*>(this), GraphicFilter, FilterCallback ) );
1798 return aLink;
1801 IMPL_LINK( GraphicFilter, FilterCallback, ConvertData&, rData, bool )
1803 bool bRet = false;
1805 sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
1806 OUString aShortName;
1807 css::uno::Sequence< css::beans::PropertyValue > aFilterData;
1808 switch( rData.mnFormat )
1810 case ConvertDataFormat::BMP: aShortName = BMP_SHORTNAME; break;
1811 case ConvertDataFormat::GIF: aShortName = GIF_SHORTNAME; break;
1812 case ConvertDataFormat::JPG: aShortName = JPG_SHORTNAME; break;
1813 case ConvertDataFormat::MET: aShortName = MET_SHORTNAME; break;
1814 case ConvertDataFormat::PCT: aShortName = PCT_SHORTNAME; break;
1815 case ConvertDataFormat::PNG: aShortName = PNG_SHORTNAME; break;
1816 case ConvertDataFormat::SVM: aShortName = SVM_SHORTNAME; break;
1817 case ConvertDataFormat::TIF: aShortName = TIF_SHORTNAME; break;
1818 case ConvertDataFormat::WMF: aShortName = WMF_SHORTNAME; break;
1819 case ConvertDataFormat::EMF: aShortName = EMF_SHORTNAME; break;
1820 case ConvertDataFormat::SVG: aShortName = SVG_SHORTNAME; break;
1821 case ConvertDataFormat::WEBP: aShortName = WEBP_SHORTNAME; break;
1823 default:
1824 break;
1826 if (GraphicType::NONE == rData.maGraphic.GetType()) // Import
1828 // Import
1829 nFormat = GetImportFormatNumberForShortName( aShortName );
1830 bRet = ImportGraphic( rData.maGraphic, u"", rData.mrStm, nFormat ) == ERRCODE_NONE;
1832 else if( !aShortName.isEmpty() )
1834 // Export
1835 #if defined(IOS) || defined(ANDROID)
1836 if (aShortName == PNG_SHORTNAME)
1838 aFilterData.realloc(aFilterData.getLength() + 1);
1839 auto pFilterData = aFilterData.getArray();
1840 pFilterData[aFilterData.getLength() - 1].Name = "Compression";
1841 // We "know" that this gets passed to zlib's deflateInit2_(). 1 means best speed.
1842 pFilterData[aFilterData.getLength() - 1].Value <<= static_cast<sal_Int32>(1);
1844 #endif
1845 nFormat = GetExportFormatNumberForShortName( aShortName );
1846 bRet = ExportGraphic( rData.maGraphic, u"", rData.mrStm, nFormat, &aFilterData ) == ERRCODE_NONE;
1849 return bRet;
1852 namespace
1854 class StandardGraphicFilter
1856 public:
1857 StandardGraphicFilter()
1859 m_aFilter.GetImportFormatCount();
1861 GraphicFilter m_aFilter;
1865 GraphicFilter& GraphicFilter::GetGraphicFilter()
1867 static StandardGraphicFilter gStandardFilter;
1868 return gStandardFilter.m_aFilter;
1871 ErrCode GraphicFilter::LoadGraphic( const OUString &rPath, const OUString &rFilterName,
1872 Graphic& rGraphic, GraphicFilter* pFilter,
1873 sal_uInt16* pDeterminedFormat )
1875 if ( !pFilter )
1876 pFilter = &GetGraphicFilter();
1878 const sal_uInt16 nFilter = !rFilterName.isEmpty() && pFilter->GetImportFormatCount()
1879 ? pFilter->GetImportFormatNumber( rFilterName )
1880 : GRFILTER_FORMAT_DONTKNOW;
1882 INetURLObject aURL( rPath );
1883 if ( aURL.HasError() )
1885 aURL.SetSmartProtocol( INetProtocol::File );
1886 aURL.SetSmartURL( rPath );
1889 std::unique_ptr<SvStream> pStream;
1890 if ( INetProtocol::File != aURL.GetProtocol() )
1891 pStream = ::utl::UcbStreamHelper::CreateStream( rPath, StreamMode::READ );
1893 ErrCode nRes = ERRCODE_NONE;
1894 if ( !pStream )
1895 nRes = pFilter->ImportGraphic( rGraphic, aURL, nFilter, pDeterminedFormat );
1896 else
1897 nRes = pFilter->ImportGraphic( rGraphic, rPath, *pStream, nFilter, pDeterminedFormat );
1899 #ifdef DBG_UTIL
1900 OUString aReturnString;
1902 if (nRes == ERRCODE_GRFILTER_OPENERROR)
1903 aReturnString="open error";
1904 else if (nRes == ERRCODE_GRFILTER_IOERROR)
1905 aReturnString="IO error";
1906 else if (nRes == ERRCODE_GRFILTER_FORMATERROR)
1907 aReturnString="format error";
1908 else if (nRes == ERRCODE_GRFILTER_VERSIONERROR)
1909 aReturnString="version error";
1910 else if (nRes == ERRCODE_GRFILTER_FILTERERROR)
1911 aReturnString="filter error";
1912 else if (nRes == ERRCODE_GRFILTER_TOOBIG)
1913 aReturnString="graphic is too big";
1915 SAL_INFO_IF( nRes, "vcl.filter", "Problem importing graphic " << rPath << ". Reason: " << aReturnString );
1916 #endif
1918 return nRes;
1921 ErrCode GraphicFilter::compressAsPNG(const Graphic& rGraphic, SvStream& rOutputStream)
1923 css::uno::Sequence< css::beans::PropertyValue > aFilterData{ comphelper::makePropertyValue(
1924 u"Compression"_ustr, sal_uInt32(9)) };
1926 sal_uInt16 nFilterFormat = GetExportFormatNumberForShortName(u"PNG");
1927 return ExportGraphic(rGraphic, u"", rOutputStream, nFilterFormat, &aFilterData);
1930 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */