1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_folders.h>
22 #include <sal/log.hxx>
23 #include <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>
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>
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
;
117 class ImpFilterOutputStream
: public ::cppu::WeakImplHelper
< css::io::XOutputStream
>
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
{}
129 explicit ImpFilterOutputStream( SvStream
& rStm
) : mrStm( rStm
) {}
136 static OUString
ImpGetExtension( std::u16string_view rPath
)
139 INetURLObject
aURL( rPath
);
140 aExt
= aURL
.GetFileExtension().toAsciiUpperCase();
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
)
150 if (vcl::peekGraphicFormat(rStream
, aFormatExt
, false))
152 rFormat
= pConfig
->GetImportFormatNumberForExtension( aFormatExt
);
153 if( rFormat
!= GRFILTER_FORMAT_DONTKNOW
)
156 // determine filter by file extension
159 OUString
aExt( ImpGetExtension( rPath
) );
160 rFormat
= pConfig
->GetImportFormatNumberForExtension( aExt
);
161 if( rFormat
!= GRFILTER_FORMAT_DONTKNOW
)
164 return ERRCODE_GRFILTER_FORMATERROR
;
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" ) )
177 else if ( pConfig
->GetImportFilterType( rFormat
).equalsIgnoreAsciiCase( "pcd_Photo_CD_Base16" ) )
179 FilterConfigItem
aFilterConfigItem( u
"Office.Common/Filter/Graphic/Import/PCD" );
180 aFilterConfigItem
.WriteInt32( u
"Resolution"_ustr
, nBase
);
187 static Graphic
ImpGetScaledGraphic( const Graphic
& rGraphic
, FilterConfigItem
& rConfigItem
)
189 if ( rGraphic
.GetType() == GraphicType::NONE
)
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
)
203 Size
aPrefSize( rGraphic
.GetPrefSize() );
205 MapMode
aPrefMapMode( rGraphic
.GetPrefMapMode() );
206 if (aPrefMapMode
.GetMapUnit() == MapUnit::MapPixel
)
207 aOriginalSize
= Application::GetDefaultDevice()->PixelToLogic(aPrefSize
, MapMode(MapUnit::Map100thMM
));
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
)
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();
232 aGraphic
.SetPrefMapMode( aMap
);
233 aGraphic
.SetPrefSize( Size( aOldSize
.Width() * 100,
234 aOldSize
.Height() * 100 ) );
237 else if( nMode
== 2 )
240 aGraphic
.SetPrefMapMode( MapMode( MapUnit::Map100thMM
) );
241 aGraphic
.SetPrefSize( Size( nLogicalWidth
, nLogicalHeight
) );
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
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
);
277 GraphicFilter::GraphicFilter()
280 std::scoped_lock
aGuard( getListMutex() );
282 if ( gaFilterHdlList
.empty() )
283 pConfig
= new FilterConfigCache
;
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() )
308 ErrCode
GraphicFilter::ImplSetError( ErrCode nError
, const SvStream
* pStm
)
310 mxErrorEx
= pStm
? pStm
->GetError() : ERRCODE_NONE
;
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
);
345 OUString
GraphicFilter::GetImportFormatMediaType( sal_uInt16 nFormat
)
347 return pConfig
->GetImportFormatMediaType( nFormat
);
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
));
426 nRetValue
= CanImportGraphic( aMainUrl
, *xStream
, nFormat
, pDeterminedFormat
);
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
));
462 nRetValue
= ImportGraphic( rGraphic
, aMainUrl
, *xStream
, nFormat
, pDeterminedFormat
, nImportFlags
);
469 /// Contains a stream and other associated data to import pixels into a
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
;
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
),
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();
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.
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
);
576 rSharedPool
.pushTask(std::make_unique
<GraphicImportTask
>(pTag
, rContext
));
578 GraphicImportTask::doImport(rContext
);
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
);
606 rSharedPool
.pushTask(std::make_unique
<GraphicImportTask
>(pTag
, rContext
));
608 GraphicImportTask::doImport(rContext
);
611 rContext
.m_nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
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
);
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());
703 BinaryDataContainer
insertContentOrDecompressFromZ(SvStream
& rStream
, sal_uInt32 nStreamLength
)
705 BinaryDataContainer aGraphicContent
;
707 if (ZCodec::IsZCompressed(rStream
))
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
);
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
;
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
);
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
);
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
;
820 } // end anonymous namespace
822 Graphic
GraphicFilter::ImportUnloadedGraphic(SvStream
& rIStream
, sal_uInt64 sizeLimit
,
823 const Size
* pSizeHint
)
826 sal_uInt16 nFormat
= GRFILTER_FORMAT_DONTKNOW
;
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
)
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;
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
);
896 ErrCode
GraphicFilter::readGIF(SvStream
& rStream
, Graphic
& rGraphic
, GfxLinkType
& rLinkType
)
898 if (ImportGIF(rStream
, rGraphic
))
900 rLinkType
= GfxLinkType::NativeGif
;
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
);
922 // PNG has no GIF chunk
924 vcl::PngImageReader
aPNGReader(rStream
);
925 aPNGReader
.read(aGraphic
);
926 if (!aGraphic
.GetBitmapEx().IsEmpty())
928 rGraphic
= std::move(aGraphic
);
929 rLinkType
= GfxLinkType::NativePng
;
932 aReturnCode
= ERRCODE_GRFILTER_FILTERERROR
;
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
;
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
;
959 rLinkType
= GfxLinkType::NativeJpg
;
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());
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
;
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
);
1006 BinaryDataContainer
aNewData(rStream
, nStreamLength
);
1008 if (!rStream
.GetError())
1010 auto aVectorGraphicDataPtr
= std::make_shared
<VectorGraphicData
>(aNewData
, VectorGraphicDataType::Svg
);
1011 rGraphic
= Graphic(aVectorGraphicDataPtr
);
1019 rLinkType
= GfxLinkType::NativeSvg
;
1023 aReturnCode
= ERRCODE_GRFILTER_FILTERERROR
;
1029 ErrCode
GraphicFilter::readXBM(SvStream
& rStream
, Graphic
& rGraphic
)
1031 if (ImportXBM(rStream
, rGraphic
))
1032 return ERRCODE_NONE
;
1034 return ERRCODE_GRFILTER_FILTERERROR
;
1037 ErrCode
GraphicFilter::readXPM(SvStream
& rStream
, Graphic
& rGraphic
)
1039 if (ImportXPM(rStream
, rGraphic
))
1040 return ERRCODE_NONE
;
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
))
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
;
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
;
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
;
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
;
1133 ErrCode
GraphicFilter::readBMP(SvStream
& rStream
, Graphic
& rGraphic
, GfxLinkType
& rLinkType
)
1135 if (BmpReader(rStream
, rGraphic
))
1137 rLinkType
= GfxLinkType::NativeBmp
;
1138 return ERRCODE_NONE
;
1141 return ERRCODE_GRFILTER_FILTERERROR
;
1144 ErrCode
GraphicFilter::readTGA(SvStream
& rStream
, Graphic
& rGraphic
)
1146 if (ImportTgaGraphic(rStream
, rGraphic
))
1147 return ERRCODE_NONE
;
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
;
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
;
1171 return ERRCODE_GRFILTER_FILTERERROR
;
1174 ErrCode
GraphicFilter::readRAS(SvStream
& rStream
, Graphic
& rGraphic
)
1176 if (ImportRasGraphic(rStream
, rGraphic
))
1177 return ERRCODE_NONE
;
1179 return ERRCODE_GRFILTER_FILTERERROR
;
1182 ErrCode
GraphicFilter::readPCX(SvStream
& rStream
, Graphic
& rGraphic
)
1184 if (ImportPcxGraphic(rStream
, rGraphic
))
1185 return ERRCODE_NONE
;
1187 return ERRCODE_GRFILTER_FILTERERROR
;
1190 ErrCode
GraphicFilter::readEPS(SvStream
& rStream
, Graphic
& rGraphic
)
1192 if (ImportEpsGraphic(rStream
, rGraphic
))
1193 return ERRCODE_NONE
;
1195 return ERRCODE_GRFILTER_FILTERERROR
;
1198 ErrCode
GraphicFilter::readPSD(SvStream
& rStream
, Graphic
& rGraphic
)
1200 if (ImportPsdGraphic(rStream
, rGraphic
))
1201 return ERRCODE_NONE
;
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
;
1218 return ERRCODE_GRFILTER_FILTERERROR
;
1221 ErrCode
GraphicFilter::readPBM(SvStream
& rStream
, Graphic
& rGraphic
)
1223 if (ImportPbmGraphic(rStream
, rGraphic
))
1224 return ERRCODE_NONE
;
1226 return ERRCODE_GRFILTER_FILTERERROR
;
1229 ErrCode
GraphicFilter::readDXF(SvStream
& rStream
, Graphic
& rGraphic
)
1231 if (ImportDxfGraphic(rStream
, rGraphic
))
1232 return ERRCODE_NONE
;
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
;
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
;
1255 GfxLinkType eLinkType
= GfxLinkType::NONE
;
1256 const bool bLinkSet
= rGraphic
.IsGfxLink();
1258 BinaryDataContainer aGraphicContent
;
1263 bool bDummyContext
= rGraphic
.IsDummyContext();
1266 rGraphic
.SetDummyContext( false );
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
);
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
);
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
);
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
));
1445 nRetValue
= ExportGraphic( rGraphic
, aMainUrl
, *xStream
, nFormat
, pFilterData
);
1448 if( ( ERRCODE_NONE
!= nRetValue
) && !bAlreadyExists
)
1449 utl::UCBContentHelper::Kill(aMainUrl
);
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();
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
) )
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
;
1483 Graphic aGraphic
= ImpGetScaledGraphic( rGraphic
, aConfigItem
);
1484 eType
= aGraphic
.GetType();
1486 if( pConfig
->IsExportPixelFormat( nFormat
) )
1488 if( eType
!= GraphicType::Bitmap
)
1491 sal_uLong nBitsPerPixel
,nNeededMem
,nMaxMem
;
1492 ScopedVclPtrInstance
< VirtualDevice
> aVirDev
;
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 ) ;
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
) )
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
1580 if (rVectorGraphicDataPtr
1581 && rVectorGraphicDataPtr
->getType() == VectorGraphicDataType::Wmf
1582 && !rVectorGraphicDataPtr
->getBinaryDataContainer().isEmpty()
1585 rVectorGraphicDataPtr
->getBinaryDataContainer().writeToStream(*rTempStm
);
1586 if (rTempStm
->GetError())
1588 nStatus
= ERRCODE_GRFILTER_IOERROR
;
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
) )
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
;
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
);
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
);
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
) )
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
;
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
;
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() );
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
;
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
) );
1801 IMPL_LINK( GraphicFilter
, FilterCallback
, ConvertData
&, rData
, bool )
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;
1826 if (GraphicType::NONE
== rData
.maGraphic
.GetType()) // Import
1829 nFormat
= GetImportFormatNumberForShortName( aShortName
);
1830 bRet
= ImportGraphic( rData
.maGraphic
, u
"", rData
.mrStm
, nFormat
) == ERRCODE_NONE
;
1832 else if( !aShortName
.isEmpty() )
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);
1845 nFormat
= GetExportFormatNumberForShortName( aShortName
);
1846 bRet
= ExportGraphic( rData
.maGraphic
, u
"", rData
.mrStm
, nFormat
, &aFilterData
) == ERRCODE_NONE
;
1854 class StandardGraphicFilter
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
)
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
;
1895 nRes
= pFilter
->ImportGraphic( rGraphic
, aURL
, nFilter
, pDeterminedFormat
);
1897 nRes
= pFilter
->ImportGraphic( rGraphic
, rPath
, *pStream
, nFilter
, pDeterminedFormat
);
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
);
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: */