LibreOffice Module vcl (master) 1
graphicfilter.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <config_folders.h>
21
22#include <sal/log.hxx>
27#include <tools/fract.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>
39#include <vcl/virdev.hxx>
40#include <impgraph.hxx>
41#include <vcl/svapp.hxx>
42#include <osl/file.hxx>
43#include <vcl/graphicfilter.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>
80#include <rtl/bootstrap.hxx>
81#include <tools/svlibrary.h>
82#include <comphelper/string.hxx>
84#include <vector>
85#include <memory>
86#include <mutex>
87#include <string_view>
88#include <o3tl/string_view.hxx>
90
91#include "FilterConfigCache.hxx"
92
95
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.
101static bool supportNativeWebp()
102{
103 // Enable support only for unittests
104 const char* const testname = getenv("LO_TESTNAME");
105 if(testname)
106 return true;
107 return false;
108}
109
110static std::vector< GraphicFilter* > gaFilterHdlList;
111
112static std::mutex& getListMutex()
113{
114 static std::mutex s_aListProtection;
115 return s_aListProtection;
116}
117
118namespace {
119
120class ImpFilterOutputStream : public ::cppu::WeakImplHelper< css::io::XOutputStream >
121{
122 SvStream& mrStm;
123
124 virtual void SAL_CALL writeBytes( const css::uno::Sequence< sal_Int8 >& rData ) override
125 { mrStm.WriteBytes(rData.getConstArray(), rData.getLength()); }
126 virtual void SAL_CALL flush() override
127 { mrStm.FlushBuffer(); }
128 virtual void SAL_CALL closeOutput() override {}
129
130public:
131
132 explicit ImpFilterOutputStream( SvStream& rStm ) : mrStm( rStm ) {}
133};
134
135}
136
137// Helper functions
138
139static OUString ImpGetExtension( std::u16string_view rPath )
140{
141 OUString aExt;
142 INetURLObject aURL( rPath );
143 aExt = aURL.GetFileExtension().toAsciiUpperCase();
144 return aExt;
145}
146
147ErrCode GraphicFilter::ImpTestOrFindFormat( std::u16string_view rPath, SvStream& rStream, sal_uInt16& rFormat )
148{
149 // determine or check the filter/format by reading into it
150 if( rFormat == GRFILTER_FORMAT_DONTKNOW )
151 {
152 OUString aFormatExt;
153 if (vcl::peekGraphicFormat(rStream, aFormatExt, false))
154 {
155 rFormat = pConfig->GetImportFormatNumberForExtension( aFormatExt );
156 if( rFormat != GRFILTER_FORMAT_DONTKNOW )
157 return ERRCODE_NONE;
158 }
159 // determine filter by file extension
160 if( !rPath.empty() )
161 {
162 OUString aExt( ImpGetExtension( rPath ) );
164 if( rFormat != GRFILTER_FORMAT_DONTKNOW )
165 return ERRCODE_NONE;
166 }
168 }
169 else
170 {
171 OUString aTmpStr( pConfig->GetImportFormatExtension( rFormat ) );
172 aTmpStr = aTmpStr.toAsciiUpperCase();
173 if (!vcl::peekGraphicFormat(rStream, aTmpStr, true))
175 if ( pConfig->GetImportFormatExtension( rFormat ).equalsIgnoreAsciiCase( "pcd" ) )
176 {
177 sal_Int32 nBase = 2; // default Base0
178 if ( pConfig->GetImportFilterType( rFormat ).equalsIgnoreAsciiCase( "pcd_Photo_CD_Base4" ) )
179 nBase = 1;
180 else if ( pConfig->GetImportFilterType( rFormat ).equalsIgnoreAsciiCase( "pcd_Photo_CD_Base16" ) )
181 nBase = 0;
182 FilterConfigItem aFilterConfigItem( u"Office.Common/Filter/Graphic/Import/PCD" );
183 aFilterConfigItem.WriteInt32( "Resolution", nBase );
184 }
185 }
186
187 return ERRCODE_NONE;
188}
189
190static Graphic ImpGetScaledGraphic( const Graphic& rGraphic, FilterConfigItem& rConfigItem )
191{
192 Graphic aGraphic;
193
194 sal_Int32 nLogicalWidth = rConfigItem.ReadInt32( "LogicalWidth", 0 );
195 sal_Int32 nLogicalHeight = rConfigItem.ReadInt32( "LogicalHeight", 0 );
196
197 if ( rGraphic.GetType() != GraphicType::NONE )
198 {
199 sal_Int32 nMode = rConfigItem.ReadInt32( "ExportMode", -1 );
200
201 if ( nMode == -1 ) // the property is not there, this is possible, if the graphic filter
202 { // is called via UnoGraphicExporter and not from a graphic export Dialog
203 nMode = 0; // then we are defaulting this mode to 0
204 if ( nLogicalWidth || nLogicalHeight )
205 nMode = 2;
206 }
207
208 Size aOriginalSize;
209 Size aPrefSize( rGraphic.GetPrefSize() );
210 MapMode aPrefMapMode( rGraphic.GetPrefMapMode() );
211 if (aPrefMapMode.GetMapUnit() == MapUnit::MapPixel)
212 aOriginalSize = Application::GetDefaultDevice()->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM));
213 else
214 aOriginalSize = OutputDevice::LogicToLogic(aPrefSize, aPrefMapMode, MapMode(MapUnit::Map100thMM));
215 if ( !nLogicalWidth )
216 nLogicalWidth = aOriginalSize.Width();
217 if ( !nLogicalHeight )
218 nLogicalHeight = aOriginalSize.Height();
219 if( rGraphic.GetType() == GraphicType::Bitmap )
220 {
221
222 // Resolution is set
223 if( nMode == 1 )
224 {
225 BitmapEx aBitmap( rGraphic.GetBitmapEx() );
226 MapMode aMap( MapUnit::Map100thInch );
227
228 sal_Int32 nDPI = rConfigItem.ReadInt32( "Resolution", 75 );
229 Fraction aFrac( 1, std::clamp( nDPI, sal_Int32(75), sal_Int32(600) ) );
230
231 aMap.SetScaleX( aFrac );
232 aMap.SetScaleY( aFrac );
233
234 Size aOldSize = aBitmap.GetSizePixel();
235 aGraphic = rGraphic;
236 aGraphic.SetPrefMapMode( aMap );
237 aGraphic.SetPrefSize( Size( aOldSize.Width() * 100,
238 aOldSize.Height() * 100 ) );
239 }
240 // Size is set
241 else if( nMode == 2 )
242 {
243 aGraphic = rGraphic;
244 aGraphic.SetPrefMapMode( MapMode( MapUnit::Map100thMM ) );
245 aGraphic.SetPrefSize( Size( nLogicalWidth, nLogicalHeight ) );
246 }
247 else
248 aGraphic = rGraphic;
249
250 sal_Int32 nColors = rConfigItem.ReadInt32( "Color", 0 );
251 if ( nColors ) // graphic conversion necessary ?
252 {
253 BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
254 aBmpEx.Convert( static_cast<BmpConversion>(nColors) ); // the entries in the xml section have the same meaning as
255 aGraphic = aBmpEx; // they have in the BmpConversion enum, so it should be
256 } // allowed to cast them
257 }
258 else
259 {
260 if( ( nMode == 1 ) || ( nMode == 2 ) )
261 {
262 GDIMetaFile aMtf( rGraphic.GetGDIMetaFile() );
263 Size aNewSize( OutputDevice::LogicToLogic(Size(nLogicalWidth, nLogicalHeight), MapMode(MapUnit::Map100thMM), aMtf.GetPrefMapMode()) );
264
265 if( aNewSize.Width() && aNewSize.Height() )
266 {
267 const Size aPreferredSize( aMtf.GetPrefSize() );
268 aMtf.Scale( Fraction( aNewSize.Width(), aPreferredSize.Width() ),
269 Fraction( aNewSize.Height(), aPreferredSize.Height() ) );
270 }
271 aGraphic = Graphic( aMtf );
272 }
273 else
274 aGraphic = rGraphic;
275 }
276
277 }
278 else
279 aGraphic = rGraphic;
280
281 return aGraphic;
282}
283
285 : bUseConfig(bConfig)
286{
287 ImplInit();
288}
289
291{
292 {
293 std::scoped_lock aGuard( getListMutex() );
294 auto it = std::find(gaFilterHdlList.begin(), gaFilterHdlList.end(), this);
295 if( it != gaFilterHdlList.end() )
296 gaFilterHdlList.erase( it );
297
298 if( gaFilterHdlList.empty() )
299 delete pConfig;
300 }
301
302 mxErrorEx.reset();
303}
304
306{
307 {
308 std::scoped_lock aGuard( getListMutex() );
309
310 if ( gaFilterHdlList.empty() )
312 else
313 pConfig = gaFilterHdlList.front()->pConfig;
314
315 gaFilterHdlList.push_back( this );
316 }
317
318 if( bUseConfig )
319 {
320 OUString url("$BRAND_BASE_DIR/" LIBO_LIB_FOLDER);
321 rtl::Bootstrap::expandMacros(url); //TODO: detect failure
322 osl::FileBase::getSystemPathFromFileURL(url, aFilterPath);
323 }
324
326}
327
329{
330 mxErrorEx = pStm ? pStm->GetError() : ERRCODE_NONE;
331 return nError;
332}
333
335{
337}
338
339sal_uInt16 GraphicFilter::GetImportFormatNumber( std::u16string_view rFormatName )
340{
341 return pConfig->GetImportFormatNumber( rFormatName );
342}
343
344sal_uInt16 GraphicFilter::GetImportFormatNumberForShortName( std::u16string_view rShortName )
345{
346 return pConfig->GetImportFormatNumberForShortName( rShortName );
347}
348
349sal_uInt16 GraphicFilter::GetImportFormatNumberForTypeName( std::u16string_view rType )
350{
352}
353
354OUString GraphicFilter::GetImportFormatName( sal_uInt16 nFormat )
355{
356 return pConfig->GetImportFormatName( nFormat );
357}
358
359OUString GraphicFilter::GetImportFormatTypeName( sal_uInt16 nFormat )
360{
361 return pConfig->GetImportFilterTypeName( nFormat );
362}
363
364#ifdef _WIN32
365OUString GraphicFilter::GetImportFormatMediaType( sal_uInt16 nFormat )
366{
367 return pConfig->GetImportFormatMediaType( nFormat );
368}
369#endif
370
371OUString GraphicFilter::GetImportFormatShortName( sal_uInt16 nFormat )
372{
373 return pConfig->GetImportFormatShortName( nFormat );
374}
375
376OUString GraphicFilter::GetImportWildcard( sal_uInt16 nFormat, sal_Int32 nEntry )
377{
378 return pConfig->GetImportWildcard( nFormat, nEntry );
379}
380
382{
384}
385
386sal_uInt16 GraphicFilter::GetExportFormatNumber( std::u16string_view rFormatName )
387{
388 return pConfig->GetExportFormatNumber( rFormatName );
389}
390
391sal_uInt16 GraphicFilter::GetExportFormatNumberForMediaType( std::u16string_view rMediaType )
392{
393 return pConfig->GetExportFormatNumberForMediaType( rMediaType );
394}
395
396sal_uInt16 GraphicFilter::GetExportFormatNumberForShortName( std::u16string_view rShortName )
397{
398 return pConfig->GetExportFormatNumberForShortName( rShortName );
399}
400
401OUString GraphicFilter::GetExportInternalFilterName( sal_uInt16 nFormat )
402{
403 return pConfig->GetExportInternalFilterName( nFormat );
404}
405
406sal_uInt16 GraphicFilter::GetExportFormatNumberForTypeName( std::u16string_view rType )
407{
409}
410
411OUString GraphicFilter::GetExportFormatName( sal_uInt16 nFormat )
412{
413 return pConfig->GetExportFormatName( nFormat );
414}
415
416OUString GraphicFilter::GetExportFormatMediaType( sal_uInt16 nFormat )
417{
418 return pConfig->GetExportFormatMediaType( nFormat );
419}
420
421OUString GraphicFilter::GetExportFormatShortName( sal_uInt16 nFormat )
422{
423 return pConfig->GetExportFormatShortName( nFormat );
424}
425
426OUString GraphicFilter::GetExportWildcard( sal_uInt16 nFormat )
427{
428 return pConfig->GetExportWildcard( nFormat, 0 );
429}
430
431bool GraphicFilter::IsExportPixelFormat( sal_uInt16 nFormat )
432{
433 return pConfig->IsExportPixelFormat( nFormat );
434}
435
437 sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat )
438{
440 SAL_WARN_IF( rPath.GetProtocol() == INetProtocol::NotValid, "vcl.filter", "GraphicFilter::CanImportGraphic() : ProtType == INetProtocol::NotValid" );
441
442 OUString aMainUrl( rPath.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
443 std::unique_ptr<SvStream> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl, StreamMode::READ | StreamMode::SHARE_DENYNONE ));
444 if (xStream)
445 {
446 nRetValue = CanImportGraphic( aMainUrl, *xStream, nFormat, pDeterminedFormat );
447 }
448 return nRetValue;
449}
450
451ErrCode GraphicFilter::CanImportGraphic( std::u16string_view rMainUrl, SvStream& rIStream,
452 sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat )
453{
454 sal_uInt64 nStreamPos = rIStream.Tell();
455 ErrCode nRes = ImpTestOrFindFormat( rMainUrl, rIStream, nFormat );
456
457 rIStream.Seek(nStreamPos);
458
459 if( nRes==ERRCODE_NONE && pDeterminedFormat!=nullptr )
460 *pDeterminedFormat = nFormat;
461
462 return ImplSetError( nRes, &rIStream );
463}
464
465//SJ: TODO, we need to create a GraphicImporter component
467 sal_uInt16 nFormat, sal_uInt16 * pDeterminedFormat, GraphicFilterImportFlags nImportFlags )
468{
470 SAL_WARN_IF( rPath.GetProtocol() == INetProtocol::NotValid, "vcl.filter", "GraphicFilter::ImportGraphic() : ProtType == INetProtocol::NotValid" );
471
472 OUString aMainUrl( rPath.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
473 std::unique_ptr<SvStream> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl, StreamMode::READ | StreamMode::SHARE_DENYNONE ));
474 if (xStream)
475 {
476 nRetValue = ImportGraphic( rGraphic, aMainUrl, *xStream, nFormat, pDeterminedFormat, nImportFlags );
477 }
478 return nRetValue;
479}
480
481namespace {
482
485struct GraphicImportContext
486{
488 std::unique_ptr<SvStream> m_pStream;
490 std::shared_ptr<Graphic> m_pGraphic;
492 std::unique_ptr<BitmapScopedWriteAccess> m_pAccess;
493 std::unique_ptr<AlphaScopedWriteAccess> m_pAlphaAccess;
494 // Need to have an AlphaMask instance to keep its lifetime.
495 AlphaMask mAlphaMask;
499 GfxLinkType m_eLinkType = GfxLinkType::NONE;
501 sal_uInt64 m_nStreamBegin = 0;
504};
505
507class GraphicImportTask : public comphelper::ThreadTask
508{
509 GraphicImportContext& m_rContext;
510public:
511 GraphicImportTask(const std::shared_ptr<comphelper::ThreadTaskTag>& pTag, GraphicImportContext& rContext);
512 void doWork() override;
514 static void doImport(GraphicImportContext& rContext);
515};
516
517}
518
519GraphicImportTask::GraphicImportTask(const std::shared_ptr<comphelper::ThreadTaskTag>& pTag, GraphicImportContext& rContext)
520 : comphelper::ThreadTask(pTag),
521 m_rContext(rContext)
522{
523}
524
525void GraphicImportTask::doWork()
526{
527 GraphicImportTask::doImport(m_rContext);
528}
529
530void GraphicImportTask::doImport(GraphicImportContext& rContext)
531{
532 if(rContext.m_eLinkType == GfxLinkType::NativeJpg)
533 {
534 if (!ImportJPEG(*rContext.m_pStream, *rContext.m_pGraphic, rContext.m_nImportFlags | GraphicFilterImportFlags::UseExistingBitmap, rContext.m_pAccess.get()))
535 rContext.m_nStatus = ERRCODE_GRFILTER_FILTERERROR;
536 }
537 else if(rContext.m_eLinkType == GfxLinkType::NativePng)
538 {
539 if (!vcl::ImportPNG(*rContext.m_pStream, *rContext.m_pGraphic,
540 rContext.m_nImportFlags | GraphicFilterImportFlags::UseExistingBitmap,
541 rContext.m_pAccess.get(), rContext.m_pAlphaAccess.get()))
542 {
543 rContext.m_nStatus = ERRCODE_GRFILTER_FILTERERROR;
544 }
545 }
546}
547
548void GraphicFilter::ImportGraphics(std::vector< std::shared_ptr<Graphic> >& rGraphics, std::vector< std::unique_ptr<SvStream> > vStreams)
549{
550 static bool bThreads = !getenv("VCL_NO_THREAD_IMPORT");
551 std::vector<GraphicImportContext> aContexts;
552 aContexts.reserve(vStreams.size());
554 std::shared_ptr<comphelper::ThreadTaskTag> pTag = comphelper::ThreadPool::createThreadTaskTag();
555
556 for (auto& pStream : vStreams)
557 {
558 aContexts.emplace_back();
559 GraphicImportContext& rContext = aContexts.back();
560
561 if (pStream)
562 {
563 rContext.m_pStream = std::move(pStream);
564 rContext.m_pGraphic = std::make_shared<Graphic>();
565 rContext.m_nStatus = ERRCODE_NONE;
566
567 // Detect the format.
569 rContext.m_nStreamBegin = rContext.m_pStream->Tell();
570 sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
571 rContext.m_nStatus = ImpTestOrFindFormat(u"", *rContext.m_pStream, nFormat);
572 rContext.m_pStream->Seek(rContext.m_nStreamBegin);
573
574 // Import the graphic.
575 if (rContext.m_nStatus == ERRCODE_NONE && !rContext.m_pStream->GetError())
576 {
577 OUString aFilterName = pConfig->GetImportFilterName(nFormat);
578
579 if (aFilterName.equalsIgnoreAsciiCase(IMP_JPEG))
580 {
581 rContext.m_eLinkType = GfxLinkType::NativeJpg;
582 rContext.m_nImportFlags = GraphicFilterImportFlags::SetLogsizeForJpeg;
583
584 if (ImportJPEG( *rContext.m_pStream, *rContext.m_pGraphic, rContext.m_nImportFlags | GraphicFilterImportFlags::OnlyCreateBitmap, nullptr))
585 {
586 Bitmap& rBitmap = const_cast<Bitmap&>(rContext.m_pGraphic->GetBitmapExRef().GetBitmap());
587 rContext.m_pAccess = std::make_unique<BitmapScopedWriteAccess>(rBitmap);
588 rContext.m_pStream->Seek(rContext.m_nStreamBegin);
589 if (bThreads)
590 rSharedPool.pushTask(std::make_unique<GraphicImportTask>(pTag, rContext));
591 else
592 GraphicImportTask::doImport(rContext);
593 }
594 else
595 rContext.m_nStatus = ERRCODE_GRFILTER_FILTERERROR;
596 }
597 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PNG))
598 {
599 rContext.m_eLinkType = GfxLinkType::NativePng;
600
601 if (vcl::ImportPNG( *rContext.m_pStream, *rContext.m_pGraphic, rContext.m_nImportFlags | GraphicFilterImportFlags::OnlyCreateBitmap, nullptr, nullptr))
602 {
603 const BitmapEx& rBitmapEx = rContext.m_pGraphic->GetBitmapExRef();
604 Bitmap& rBitmap = const_cast<Bitmap&>(rBitmapEx.GetBitmap());
605 rContext.m_pAccess = std::make_unique<BitmapScopedWriteAccess>(rBitmap);
606 if(rBitmapEx.IsAlpha())
607 {
608 // The separate alpha bitmap causes a number of complications. Not only
609 // we need to have an extra bitmap access for it, but we also need
610 // to keep an AlphaMask instance in the context. This is because
611 // BitmapEx internally keeps Bitmap and not AlphaMask (because the Bitmap
612 // may be also a mask, not alpha). So BitmapEx::GetAlpha() returns
613 // a temporary, and direct access to the Bitmap wouldn't work
614 // with AlphaScopedBitmapAccess. *sigh*
615 rContext.mAlphaMask = rBitmapEx.GetAlphaMask();
616 rContext.m_pAlphaAccess = std::make_unique<AlphaScopedWriteAccess>(rContext.mAlphaMask);
617 }
618 rContext.m_pStream->Seek(rContext.m_nStreamBegin);
619 if (bThreads)
620 rSharedPool.pushTask(std::make_unique<GraphicImportTask>(pTag, rContext));
621 else
622 GraphicImportTask::doImport(rContext);
623 }
624 else
625 rContext.m_nStatus = ERRCODE_GRFILTER_FILTERERROR;
626 }
627 else
628 rContext.m_nStatus = ERRCODE_GRFILTER_FILTERERROR;
629 }
630 }
631 }
632
633 rSharedPool.waitUntilDone(pTag);
634
635 // Process data after import.
636 for (auto& rContext : aContexts)
637 {
638 if(rContext.m_pAlphaAccess) // Need to move the AlphaMask back to the BitmapEx.
639 *rContext.m_pGraphic = BitmapEx( rContext.m_pGraphic->GetBitmapExRef().GetBitmap(), rContext.mAlphaMask );
640 rContext.m_pAccess.reset();
641 rContext.m_pAlphaAccess.reset();
642
643 if (rContext.m_nStatus == ERRCODE_NONE && (rContext.m_eLinkType != GfxLinkType::NONE) && !rContext.m_pGraphic->GetReaderContext())
644 {
645 BinaryDataContainer aGraphicContent;
646
647 const sal_uInt64 nStreamEnd = rContext.m_pStream->Tell();
648 sal_Int32 nGraphicContentSize = nStreamEnd - rContext.m_nStreamBegin;
649
650 if (nGraphicContentSize > 0)
651 {
652 try
653 {
654 rContext.m_pStream->Seek(rContext.m_nStreamBegin);
655 aGraphicContent = BinaryDataContainer(*rContext.m_pStream, nGraphicContentSize);
656 }
657 catch (const std::bad_alloc&)
658 {
659 rContext.m_nStatus = ERRCODE_GRFILTER_TOOBIG;
660 }
661 }
662
663 if (rContext.m_nStatus == ERRCODE_NONE)
664 rContext.m_pGraphic->SetGfxLink(std::make_shared<GfxLink>(aGraphicContent, rContext.m_eLinkType));
665 }
666
667 if (rContext.m_nStatus != ERRCODE_NONE)
668 rContext.m_pGraphic = nullptr;
669
670 rGraphics.push_back(rContext.m_pGraphic);
671 }
672}
673
674void GraphicFilter::MakeGraphicsAvailableThreaded(std::vector<Graphic*>& graphics)
675{
676 // Graphic::makeAvailable() is not thread-safe. Only the jpeg and png loaders are, so here
677 // we process only jpeg and png images that also have their stream data, load new Graphic's
678 // from them and then update the passed objects using them.
679 std::vector< Graphic* > toLoad;
680 for(auto graphic : graphics)
681 {
682 // Need to use GetSharedGfxLink, to access the pointer without copying.
683 if(!graphic->isAvailable() && graphic->IsGfxLink()
684 && graphic->GetSharedGfxLink()->GetDataSize() != 0
685 && (graphic->GetSharedGfxLink()->GetType() == GfxLinkType::NativeJpg
686 || graphic->GetSharedGfxLink()->GetType() == GfxLinkType::NativePng))
687 {
688 // Graphic objects share internal ImpGraphic, do not process any of those twice.
689 const auto predicate = [graphic](Graphic* item) { return item->ImplGetImpGraphic() == graphic->ImplGetImpGraphic(); };
690 if( std::none_of(toLoad.begin(), toLoad.end(), predicate ))
691 toLoad.push_back( graphic );
692 }
693 }
694 if( toLoad.empty())
695 return;
696 std::vector< std::unique_ptr<SvStream>> streams;
697 for( auto graphic : toLoad )
698 {
699 streams.push_back( std::make_unique<SvMemoryStream>( const_cast<sal_uInt8*>(graphic->GetSharedGfxLink()->GetData()),
700 graphic->GetSharedGfxLink()->GetDataSize(), StreamMode::READ | StreamMode::WRITE));
701 }
702 std::vector< std::shared_ptr<Graphic>> loadedGraphics;
703 ImportGraphics(loadedGraphics, std::move(streams));
704 assert(loadedGraphics.size() == toLoad.size());
705 for( size_t i = 0; i < toLoad.size(); ++i )
706 {
707 if(loadedGraphics[ i ] != nullptr)
708 toLoad[ i ]->ImplGetImpGraphic()->updateFromLoadedGraphic(loadedGraphics[ i ]->ImplGetImpGraphic());
709 }
710}
711
713 const Size* pSizeHint)
714{
715 Graphic aGraphic;
716 sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
717 GfxLinkType eLinkType = GfxLinkType::NONE;
718
720
721 const sal_uInt64 nStreamBegin = rIStream.Tell();
722
723 rIStream.Seek(nStreamBegin);
724
725 ErrCode nStatus = ImpTestOrFindFormat(u"", rIStream, nFormat);
726
727 rIStream.Seek(nStreamBegin);
728 sal_uInt32 nStreamLength(rIStream.remainingSize());
729 if (sizeLimit && sizeLimit < nStreamLength)
730 nStreamLength = sizeLimit;
731
732 OUString aFilterName = pConfig->GetImportFilterName(nFormat);
733
734 BinaryDataContainer aGraphicContent;
735
736 // read graphic
737 {
738 if (aFilterName.equalsIgnoreAsciiCase(IMP_GIF))
739 {
740 eLinkType = GfxLinkType::NativeGif;
741 }
742 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PNG))
743 {
744 // check if this PNG contains a GIF chunk!
745 aGraphicContent = vcl::PngImageReader::getMicrosoftGifChunk(rIStream);
746 if (!aGraphicContent.isEmpty())
747 eLinkType = GfxLinkType::NativeGif;
748 else
749 eLinkType = GfxLinkType::NativePng;
750 }
751 else if (aFilterName.equalsIgnoreAsciiCase(IMP_JPEG))
752 {
753 eLinkType = GfxLinkType::NativeJpg;
754 }
755 else if (aFilterName.equalsIgnoreAsciiCase(IMP_SVG))
756 {
757 bool bOkay(false);
758
759 if (nStreamLength > 0)
760 {
761 std::vector<sal_uInt8> aTwoBytes(2);
762 rIStream.ReadBytes(aTwoBytes.data(), 2);
763 rIStream.Seek(nStreamBegin);
764
765 if (aTwoBytes[0] == 0x1F && aTwoBytes[1] == 0x8B)
766 {
767 SvMemoryStream aMemStream;
768 ZCodec aCodec;
769 tools::Long nMemoryLength;
770
771 aCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, /*gzLib*/true);
772 nMemoryLength = aCodec.Decompress(rIStream, aMemStream);
773 aCodec.EndCompression();
774
775 if (!rIStream.GetError() && nMemoryLength >= 0)
776 {
777 aMemStream.Seek(STREAM_SEEK_TO_BEGIN);
778 aGraphicContent = BinaryDataContainer(aMemStream, nMemoryLength);
779
780 bOkay = true;
781 }
782 }
783 else
784 {
785 aGraphicContent = BinaryDataContainer(rIStream, nStreamLength);
786
787 bOkay = true;
788 }
789 }
790
791 if (bOkay)
792 {
793 eLinkType = GfxLinkType::NativeSvg;
794 }
795 else
796 {
798 }
799 }
800 else if (aFilterName.equalsIgnoreAsciiCase(IMP_BMP))
801 {
802 eLinkType = GfxLinkType::NativeBmp;
803 }
804 else if (aFilterName.equalsIgnoreAsciiCase(IMP_MOV))
805 {
806 eLinkType = GfxLinkType::NativeMov;
807 }
808 else if (aFilterName.equalsIgnoreAsciiCase(IMP_WMF) ||
809 aFilterName.equalsIgnoreAsciiCase(IMP_EMF) ||
810 aFilterName.equalsIgnoreAsciiCase(IMP_WMZ) ||
811 aFilterName.equalsIgnoreAsciiCase(IMP_EMZ))
812 {
813 rIStream.Seek(nStreamBegin);
814 if (ZCodec::IsZCompressed(rIStream))
815 {
816 ZCodec aCodec;
817 SvMemoryStream aMemStream;
818 tools::Long nMemoryLength;
819 aCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, /*gzLib*/true);
820 nMemoryLength = aCodec.Decompress(rIStream, aMemStream);
821 aCodec.EndCompression();
822
823 if (!rIStream.GetError() && nMemoryLength >= 0)
824 {
825 aMemStream.Seek(STREAM_SEEK_TO_BEGIN);
826 aGraphicContent = BinaryDataContainer(aMemStream, nMemoryLength);
827 }
828 }
829 else
830 {
831 aGraphicContent = BinaryDataContainer(rIStream, nStreamLength);
832 }
833 if (!rIStream.GetError())
834 {
835 eLinkType = GfxLinkType::NativeWmf;
836 }
837 else
838 {
840 }
841 }
842 else if (aFilterName == IMP_PDF)
843 {
844 eLinkType = GfxLinkType::NativePdf;
845 }
846 else if (aFilterName == IMP_TIFF)
847 {
848 eLinkType = GfxLinkType::NativeTif;
849 }
850 else if (aFilterName == IMP_PICT)
851 {
852 eLinkType = GfxLinkType::NativePct;
853 }
854 else if (aFilterName == IMP_MET)
855 {
856 eLinkType = GfxLinkType::NativeMet;
857 }
858 else if (aFilterName.equalsIgnoreAsciiCase(IMP_WEBP))
859 {
861 eLinkType = GfxLinkType::NativeWebp;
862 else
864 }
865 else
866 {
868 }
869 }
870
871 if (nStatus == ERRCODE_NONE && eLinkType != GfxLinkType::NONE)
872 {
873 if (aGraphicContent.isEmpty())
874 {
875 if (nStreamLength > 0)
876 {
877 try
878 {
879 rIStream.Seek(nStreamBegin);
880 aGraphicContent = BinaryDataContainer(rIStream, nStreamLength);
881 }
882 catch (const std::bad_alloc&)
883 {
884 nStatus = ERRCODE_GRFILTER_TOOBIG;
885 }
886 }
887 }
888
889 if( nStatus == ERRCODE_NONE )
890 {
891 bool bAnimated = false;
892 Size aLogicSize;
893 if (eLinkType == GfxLinkType::NativeGif && !aGraphicContent.isEmpty())
894 {
895 std::shared_ptr<SvStream> pMemoryStream = aGraphicContent.getAsStream();
896 bAnimated = IsGIFAnimated(*pMemoryStream, aLogicSize);
897 if (!pSizeHint && aLogicSize.getWidth() && aLogicSize.getHeight())
898 {
899 pSizeHint = &aLogicSize;
900 }
901 }
902 aGraphic.SetGfxLink(std::make_shared<GfxLink>(aGraphicContent, eLinkType));
903 aGraphic.ImplGetImpGraphic()->setPrepared(bAnimated, pSizeHint);
904 }
905 }
906
907 // Set error code or try to set native buffer
908 if (nStatus != ERRCODE_NONE)
909 ImplSetError(nStatus, &rIStream);
910 if (nStatus != ERRCODE_NONE || eLinkType == GfxLinkType::NONE)
911 rIStream.Seek(nStreamBegin);
912
913 return aGraphic;
914}
915
916ErrCode GraphicFilter::readGIF(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
917{
918 if (ImportGIF(rStream, rGraphic))
919 {
920 rLinkType = GfxLinkType::NativeGif;
921 return ERRCODE_NONE;
922 }
923 else
925}
926
927ErrCode GraphicFilter::readPNG(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType, BinaryDataContainer& rpGraphicContent)
928{
929 ErrCode aReturnCode = ERRCODE_NONE;
930
931 // check if this PNG contains a GIF chunk!
932 if (auto aMSGifChunk = vcl::PngImageReader::getMicrosoftGifChunk(rStream);
933 !aMSGifChunk.isEmpty())
934 {
935 std::shared_ptr<SvStream> pIStrm(aMSGifChunk.getAsStream());
936 ImportGIF(*pIStrm, rGraphic);
937 rLinkType = GfxLinkType::NativeGif;
938 rpGraphicContent = aMSGifChunk;
939 return aReturnCode;
940 }
941
942 // PNG has no GIF chunk
943 Graphic aGraphic;
944 vcl::PngImageReader aPNGReader(rStream);
945 aPNGReader.read(aGraphic);
946 if (!aGraphic.GetBitmapEx().IsEmpty())
947 {
948 rGraphic = aGraphic;
949 rLinkType = GfxLinkType::NativePng;
950 }
951 else
952 aReturnCode = ERRCODE_GRFILTER_FILTERERROR;
953
954 return aReturnCode;
955}
956
958{
959 ErrCode aReturnCode = ERRCODE_NONE;
960
961 // set LOGSIZE flag always, if not explicitly disabled
962 // (see #90508 and #106763)
964 {
966 }
967
968 sal_uInt64 nPosition = rStream.Tell();
969 if (!ImportJPEG(rStream, rGraphic, nImportFlags | GraphicFilterImportFlags::OnlyCreateBitmap, nullptr))
970 aReturnCode = ERRCODE_GRFILTER_FILTERERROR;
971 else
972 {
973 Bitmap& rBitmap = const_cast<Bitmap&>(rGraphic.GetBitmapExRef().GetBitmap());
974 BitmapScopedWriteAccess pWriteAccess(rBitmap);
975 rStream.Seek(nPosition);
976 if (!ImportJPEG(rStream, rGraphic, nImportFlags | GraphicFilterImportFlags::UseExistingBitmap, &pWriteAccess))
977 aReturnCode = ERRCODE_GRFILTER_FILTERERROR;
978 else
979 rLinkType = GfxLinkType::NativeJpg;
980 }
981
982 return aReturnCode;
983}
984
985ErrCode GraphicFilter::readSVG(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType, BinaryDataContainer& rpGraphicContent)
986{
987 ErrCode aReturnCode = ERRCODE_NONE;
988
989 const sal_uInt64 nStreamPosition(rStream.Tell());
990 const sal_uInt64 nStreamLength(rStream.remainingSize());
991
992 bool bOkay(false);
993
994 if (nStreamLength > 0)
995 {
996 std::vector<sal_uInt8> aTwoBytes(2);
997 rStream.ReadBytes(aTwoBytes.data(), 2);
998 rStream.Seek(nStreamPosition);
999
1000 if (aTwoBytes[0] == 0x1F && aTwoBytes[1] == 0x8B)
1001 {
1002 SvMemoryStream aMemStream;
1003 ZCodec aCodec;
1004 tools::Long nMemoryLength;
1005
1006 aCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, /*gzLib*/true);
1007 nMemoryLength = aCodec.Decompress(rStream, aMemStream);
1008 aCodec.EndCompression();
1009
1010 if (!rStream.GetError() && nMemoryLength >= 0)
1011 {
1012 aMemStream.Seek(STREAM_SEEK_TO_BEGIN);
1013 rpGraphicContent = BinaryDataContainer(aMemStream, nMemoryLength);
1014
1015 // Make a uncompressed copy for GfxLink
1016 if (!aMemStream.GetError())
1017 {
1018 auto aVectorGraphicDataPtr = std::make_shared<VectorGraphicData>(rpGraphicContent, VectorGraphicDataType::Svg);
1019 rGraphic = Graphic(aVectorGraphicDataPtr);
1020 bOkay = true;
1021 }
1022 }
1023 }
1024 else
1025 {
1026 BinaryDataContainer aNewData(rStream, nStreamLength);
1027
1028 if (!rStream.GetError())
1029 {
1030 auto aVectorGraphicDataPtr = std::make_shared<VectorGraphicData>(aNewData, VectorGraphicDataType::Svg);
1031 rGraphic = Graphic(aVectorGraphicDataPtr);
1032 bOkay = true;
1033 }
1034 }
1035 }
1036
1037 if (bOkay)
1038 {
1039 rLinkType = GfxLinkType::NativeSvg;
1040 }
1041 else
1042 {
1043 aReturnCode = ERRCODE_GRFILTER_FILTERERROR;
1044 }
1045
1046 return aReturnCode;
1047}
1048
1050{
1051 if (ImportXBM(rStream, rGraphic))
1052 return ERRCODE_NONE;
1053 else
1055}
1056
1058{
1059 if (ImportXPM(rStream, rGraphic))
1060 return ERRCODE_NONE;
1061 else
1063}
1064
1066{
1067 // use new UNO API service, do not directly import but create a
1068 // Graphic that contains the original data and decomposes to
1069 // primitives on demand
1070 sal_uInt32 nStreamLength(rStream.remainingSize());
1071 SvStream* aNewStream = &rStream;
1073 SvMemoryStream aMemStream;
1074 if (ZCodec::IsZCompressed(rStream))
1075 {
1076 ZCodec aCodec;
1077 aCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, /*gzLib*/true);
1078 auto nDecompressLength = aCodec.Decompress(rStream, aMemStream);
1079 aCodec.EndCompression();
1080 aMemStream.Seek(STREAM_SEEK_TO_BEGIN);
1081 if (nDecompressLength >= 0)
1082 {
1083 nStreamLength = nDecompressLength;
1084 aNewStream = &aMemStream;
1085 }
1086 }
1087 BinaryDataContainer aNewData(*aNewStream, nStreamLength);
1088 if (!aNewStream->GetError())
1089 {
1090 auto aVectorGraphicDataPtr = std::make_shared<VectorGraphicData>(aNewData, eType);
1091
1092 rGraphic = Graphic(aVectorGraphicDataPtr);
1093 rLinkType = GfxLinkType::NativeWmf;
1094 aReturnCode = ERRCODE_NONE;
1095 }
1096
1097 return aReturnCode;
1098}
1099
1100ErrCode GraphicFilter::readWMF(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
1101{
1102 return readWMF_EMF(rStream, rGraphic, rLinkType,VectorGraphicDataType::Wmf);
1103}
1104
1105ErrCode GraphicFilter::readEMF(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
1106{
1107 return readWMF_EMF(rStream, rGraphic, rLinkType, VectorGraphicDataType::Emf);
1108}
1109
1110ErrCode GraphicFilter::readPDF(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
1111{
1112 if (vcl::ImportPDF(rStream, rGraphic))
1113 {
1114 rLinkType = GfxLinkType::NativePdf;
1115 return ERRCODE_NONE;
1116 }
1117 else
1119}
1120
1122{
1123 if (ImportTiffGraphicImport(rStream, rGraphic))
1124 {
1125 rLinkType = GfxLinkType::NativeTif;
1126 return ERRCODE_NONE;
1127 }
1128 else
1130}
1131
1132ErrCode GraphicFilter::readWithTypeSerializer(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType, std::u16string_view aFilterName)
1133{
1135
1136 // SV internal filters for import bitmaps and MetaFiles
1137 TypeSerializer aSerializer(rStream);
1138 aSerializer.readGraphic(rGraphic);
1139
1140 if (!rStream.GetError())
1141 {
1142 if (o3tl::equalsIgnoreAsciiCase(aFilterName, u"" IMP_MOV))
1143 {
1144 rGraphic.SetDefaultType();
1145 rStream.Seek(STREAM_SEEK_TO_END);
1146 rLinkType = GfxLinkType::NativeMov;
1147 }
1148 aReturnCode = ERRCODE_NONE;
1149 }
1150 return aReturnCode;
1151}
1152
1153ErrCode GraphicFilter::readBMP(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
1154{
1155 if (BmpReader(rStream, rGraphic))
1156 {
1157 rLinkType = GfxLinkType::NativeBmp;
1158 return ERRCODE_NONE;
1159 }
1160 else
1162}
1163
1165{
1166 if (ImportTgaGraphic(rStream, rGraphic))
1167 return ERRCODE_NONE;
1168 else
1170}
1171
1173{
1174 if (ImportPictGraphic(rStream, rGraphic))
1175 {
1176 rLinkType = GfxLinkType::NativePct;
1177 return ERRCODE_NONE;
1178 }
1179 else
1181}
1182
1183ErrCode GraphicFilter::readMET(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType)
1184{
1185 if (ImportMetGraphic(rStream, rGraphic))
1186 {
1187 rLinkType = GfxLinkType::NativeMet;
1188 return ERRCODE_NONE;
1189 }
1190 else
1192}
1193
1195{
1196 if (ImportRasGraphic(rStream, rGraphic))
1197 return ERRCODE_NONE;
1198 else
1200}
1201
1203{
1204 if (ImportPcxGraphic(rStream, rGraphic))
1205 return ERRCODE_NONE;
1206 else
1208}
1209
1211{
1212 if (ImportEpsGraphic(rStream, rGraphic))
1213 return ERRCODE_NONE;
1214 else
1216}
1217
1219{
1220 if (ImportPsdGraphic(rStream, rGraphic))
1221 return ERRCODE_NONE;
1222 else
1224}
1225
1227{
1228 std::unique_ptr<FilterConfigItem> pFilterConfigItem;
1230 {
1231 OUString aFilterConfigPath( "Office.Common/Filter/Graphic/Import/PCD" );
1232 pFilterConfigItem = std::make_unique<FilterConfigItem>(aFilterConfigPath);
1233 }
1234
1235 if (ImportPcdGraphic(rStream, rGraphic, pFilterConfigItem.get()))
1236 return ERRCODE_NONE;
1237 else
1239}
1240
1242{
1243 if (ImportPbmGraphic(rStream, rGraphic))
1244 return ERRCODE_NONE;
1245 else
1247}
1248
1250{
1251 if (ImportDxfGraphic(rStream, rGraphic))
1252 return ERRCODE_NONE;
1253 else
1255}
1256
1258{
1259 if (ImportWebpGraphic(rStream, rGraphic))
1260 {
1261 if(supportNativeWebp())
1262 rLinkType = GfxLinkType::NativeWebp;
1263 return ERRCODE_NONE;
1264 }
1265 else
1267}
1268
1269ErrCode GraphicFilter::ImportGraphic(Graphic& rGraphic, std::u16string_view rPath, SvStream& rIStream,
1270 sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat, GraphicFilterImportFlags nImportFlags)
1271{
1272 OUString aFilterName;
1273 sal_uInt64 nStreamBegin;
1274 ErrCode nStatus;
1275 GfxLinkType eLinkType = GfxLinkType::NONE;
1276 const bool bLinkSet = rGraphic.IsGfxLink();
1277
1278 BinaryDataContainer aGraphicContent;
1279
1281
1282 std::shared_ptr<GraphicReader> pContext = rGraphic.GetReaderContext();
1283 bool bDummyContext = rGraphic.IsDummyContext();
1284 if( !pContext || bDummyContext )
1285 {
1286 if( bDummyContext )
1287 {
1288 rGraphic.SetDummyContext( false );
1289 nStreamBegin = 0;
1290 }
1291 else
1292 nStreamBegin = rIStream.Tell();
1293
1294 nStatus = ImpTestOrFindFormat( rPath, rIStream, nFormat );
1295 // if pending, return ERRCODE_NONE in order to request more bytes
1296 if( rIStream.GetError() == ERRCODE_IO_PENDING )
1297 {
1298 rGraphic.SetDummyContext(true);
1299 rIStream.ResetError();
1300 rIStream.Seek( nStreamBegin );
1301 return ImplSetError( ERRCODE_NONE );
1302 }
1303
1304 rIStream.Seek( nStreamBegin );
1305
1306 if( ( nStatus != ERRCODE_NONE ) || rIStream.GetError() )
1307 return ImplSetError( ( nStatus != ERRCODE_NONE ) ? nStatus : ERRCODE_GRFILTER_OPENERROR, &rIStream );
1308
1309 if( pDeterminedFormat )
1310 *pDeterminedFormat = nFormat;
1311
1312 aFilterName = pConfig->GetImportFilterName( nFormat );
1313 }
1314 else
1315 {
1316 aFilterName = pContext->GetUpperFilterName();
1317
1318 nStreamBegin = 0;
1319 nStatus = ERRCODE_NONE;
1320 }
1321
1322 // read graphic
1323 {
1324 if (aFilterName.equalsIgnoreAsciiCase(IMP_GIF))
1325 {
1326 nStatus = readGIF(rIStream, rGraphic, eLinkType);
1327 }
1328 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PNG))
1329 {
1330 nStatus = readPNG(rIStream, rGraphic, eLinkType, aGraphicContent);
1331 }
1332 else if (aFilterName.equalsIgnoreAsciiCase(IMP_JPEG))
1333 {
1334 nStatus = readJPEG(rIStream, rGraphic, eLinkType, nImportFlags);
1335 }
1336 else if (aFilterName.equalsIgnoreAsciiCase(IMP_SVG) || aFilterName.equalsIgnoreAsciiCase(IMP_SVGZ))
1337 {
1338 nStatus = readSVG(rIStream, rGraphic, eLinkType, aGraphicContent);
1339 }
1340 else if( aFilterName.equalsIgnoreAsciiCase( IMP_XBM ) )
1341 {
1342 nStatus = readXBM(rIStream, rGraphic);
1343 }
1344 else if( aFilterName.equalsIgnoreAsciiCase( IMP_XPM ) )
1345 {
1346 nStatus = readXPM(rIStream, rGraphic);
1347 }
1348 else if (aFilterName.equalsIgnoreAsciiCase(IMP_BMP))
1349 {
1350 nStatus = readBMP(rIStream, rGraphic, eLinkType);
1351 }
1352 else if (aFilterName.equalsIgnoreAsciiCase(IMP_SVMETAFILE))
1353 {
1354 nStatus = readWithTypeSerializer(rIStream, rGraphic, eLinkType, aFilterName);
1355 }
1356 else if( aFilterName.equalsIgnoreAsciiCase(IMP_MOV))
1357 {
1358 nStatus = readWithTypeSerializer(rIStream, rGraphic, eLinkType, aFilterName);
1359 }
1360 else if (aFilterName.equalsIgnoreAsciiCase(IMP_WMF) || aFilterName.equalsIgnoreAsciiCase(IMP_WMZ))
1361 {
1362 nStatus = readWMF(rIStream, rGraphic, eLinkType);
1363 }
1364 else if (aFilterName.equalsIgnoreAsciiCase(IMP_EMF) || aFilterName.equalsIgnoreAsciiCase(IMP_EMZ))
1365 {
1366 nStatus = readEMF(rIStream, rGraphic, eLinkType);
1367 }
1368 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PDF))
1369 {
1370 nStatus = readPDF(rIStream, rGraphic, eLinkType);
1371 }
1372 else if (aFilterName.equalsIgnoreAsciiCase(IMP_TIFF) )
1373 {
1374 nStatus = readTIFF(rIStream, rGraphic, eLinkType);
1375 }
1376 else if (aFilterName.equalsIgnoreAsciiCase(IMP_TGA) )
1377 {
1378 nStatus = readTGA(rIStream, rGraphic);
1379 }
1380 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PICT))
1381 {
1382 nStatus = readPICT(rIStream, rGraphic, eLinkType);
1383 }
1384 else if (aFilterName.equalsIgnoreAsciiCase(IMP_MET))
1385 {
1386 nStatus = readMET(rIStream, rGraphic, eLinkType);
1387 }
1388 else if (aFilterName.equalsIgnoreAsciiCase(IMP_RAS))
1389 {
1390 nStatus = readRAS(rIStream, rGraphic);
1391 }
1392 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PCX))
1393 {
1394 nStatus = readPCX(rIStream, rGraphic);
1395 }
1396 else if (aFilterName.equalsIgnoreAsciiCase(IMP_EPS))
1397 {
1398 nStatus = readEPS(rIStream, rGraphic);
1399 }
1400 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PSD))
1401 {
1402 nStatus = readPSD(rIStream, rGraphic);
1403 }
1404 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PCD))
1405 {
1406 nStatus = readPCD(rIStream, rGraphic);
1407 }
1408 else if (aFilterName.equalsIgnoreAsciiCase(IMP_PBM))
1409 {
1410 nStatus = readPBM(rIStream, rGraphic);
1411 }
1412 else if (aFilterName.equalsIgnoreAsciiCase(IMP_DXF))
1413 {
1414 nStatus = readDXF(rIStream, rGraphic);
1415 }
1416 else if (aFilterName.equalsIgnoreAsciiCase(IMP_WEBP))
1417 {
1418 nStatus = readWEBP(rIStream, rGraphic, eLinkType);
1419 }
1420 else
1422 }
1423
1424 if( nStatus == ERRCODE_NONE && ( eLinkType != GfxLinkType::NONE ) && !rGraphic.GetReaderContext() && !bLinkSet )
1425 {
1426 if (aGraphicContent.isEmpty())
1427 {
1428 const sal_uInt64 nStreamEnd = rIStream.Tell();
1429 const sal_uInt64 nGraphicContentSize = nStreamEnd - nStreamBegin;
1430
1431 if (nGraphicContentSize > 0)
1432 {
1433 try
1434 {
1435 rIStream.Seek(nStreamBegin);
1436 aGraphicContent = BinaryDataContainer(rIStream, nGraphicContentSize);
1437 }
1438 catch (const std::bad_alloc&)
1439 {
1440 nStatus = ERRCODE_GRFILTER_TOOBIG;
1441 }
1442 }
1443 }
1444 if( nStatus == ERRCODE_NONE )
1445 {
1446 rGraphic.SetGfxLink(std::make_shared<GfxLink>(aGraphicContent, eLinkType));
1447 }
1448 }
1449
1450 // Set error code or try to set native buffer
1451 if( nStatus != ERRCODE_NONE )
1452 {
1453 ImplSetError( nStatus, &rIStream );
1454 rIStream.Seek( nStreamBegin );
1455 rGraphic.Clear();
1456 }
1457
1458 return nStatus;
1459}
1460
1462 sal_uInt16 nFormat, const css::uno::Sequence< css::beans::PropertyValue >* pFilterData )
1463{
1464 SAL_INFO( "vcl.filter", "GraphicFilter::ExportGraphic() (thb)" );
1466 SAL_WARN_IF( rPath.GetProtocol() == INetProtocol::NotValid, "vcl.filter", "GraphicFilter::ExportGraphic() : ProtType == INetProtocol::NotValid" );
1467
1468 OUString aMainUrl(rPath.GetMainURL(INetURLObject::DecodeMechanism::NONE));
1469 bool bAlreadyExists = utl::UCBContentHelper::IsDocument(aMainUrl);
1470
1471 std::unique_ptr<SvStream> xStream(::utl::UcbStreamHelper::CreateStream( aMainUrl, StreamMode::WRITE | StreamMode::TRUNC ));
1472 if (xStream)
1473 {
1474 nRetValue = ExportGraphic( rGraphic, aMainUrl, *xStream, nFormat, pFilterData );
1475 xStream.reset();
1476
1477 if( ( ERRCODE_NONE != nRetValue ) && !bAlreadyExists )
1479 }
1480 return nRetValue;
1481}
1482
1483ErrCode GraphicFilter::ExportGraphic( const Graphic& rGraphic, std::u16string_view rPath,
1484 SvStream& rOStm, sal_uInt16 nFormat, const css::uno::Sequence< css::beans::PropertyValue >* pFilterData )
1485{
1486 SAL_INFO( "vcl.filter", "GraphicFilter::ExportGraphic() (thb)" );
1487 sal_uInt16 nFormatCount = GetExportFormatCount();
1488
1490 bool bShouldCompress = false;
1491 SvMemoryStream rCompressableStm;
1492
1493 if( nFormat == GRFILTER_FORMAT_DONTKNOW )
1494 {
1495 OUString aExt = ImpGetExtension( rPath );
1496 for( sal_uInt16 i = 0; i < nFormatCount; i++ )
1497 {
1498 if ( pConfig->GetExportFormatExtension( i ).equalsIgnoreAsciiCase( aExt ) )
1499 {
1500 nFormat=i;
1501 break;
1502 }
1503 }
1504 }
1505 if( nFormat >= nFormatCount )
1507
1508 FilterConfigItem aConfigItem( pFilterData );
1509 OUString aFilterName( pConfig->GetExportFilterName( nFormat ) );
1510 ErrCode nStatus = ERRCODE_NONE;
1512 Graphic aGraphic = ImpGetScaledGraphic( rGraphic, aConfigItem );
1513 eType = aGraphic.GetType();
1514
1515 if( pConfig->IsExportPixelFormat( nFormat ) )
1516 {
1517 if( eType != GraphicType::Bitmap )
1518 {
1519 Size aSizePixel;
1520 sal_uLong nBitsPerPixel,nNeededMem,nMaxMem;
1522
1523 nMaxMem = 1024;
1524 nMaxMem *= 1024; // In Bytes
1525
1526 // Calculate how big the image would normally be:
1527 aSizePixel=aVirDev->LogicToPixel(aGraphic.GetPrefSize(),aGraphic.GetPrefMapMode());
1528
1529 // Calculate how much memory the image will take up
1530 nBitsPerPixel=aVirDev->GetBitCount();
1531 nNeededMem=(static_cast<sal_uLong>(aSizePixel.Width())*static_cast<sal_uLong>(aSizePixel.Height())*nBitsPerPixel+7)/8;
1532
1533 // is the image larger than available memory?
1534 if (nMaxMem<nNeededMem)
1535 {
1536 double fFak=sqrt(static_cast<double>(nMaxMem)/static_cast<double>(nNeededMem));
1537 aSizePixel.setWidth(static_cast<sal_uLong>(static_cast<double>(aSizePixel.Width())*fFak) );
1538 aSizePixel.setHeight(static_cast<sal_uLong>(static_cast<double>(aSizePixel.Height())*fFak) );
1539 }
1540
1541 aVirDev->SetMapMode(MapMode(MapUnit::MapPixel));
1542 aVirDev->SetOutputSizePixel(aSizePixel);
1543 Graphic aGraphic2=aGraphic;
1544 aGraphic2.Draw(*aVirDev, Point(0, 0), aSizePixel); // this changes the MapMode
1545 aVirDev->SetMapMode(MapMode(MapUnit::MapPixel));
1546 aGraphic=Graphic(aVirDev->GetBitmapEx(Point(0,0),aSizePixel));
1547 }
1548 }
1549 if( rOStm.GetError() )
1550 nStatus = ERRCODE_GRFILTER_IOERROR;
1551 if( ERRCODE_NONE == nStatus )
1552 {
1553 if( aFilterName.equalsIgnoreAsciiCase( EXP_BMP ) )
1554 {
1555 if (!BmpWriter(rOStm, aGraphic, &aConfigItem))
1557 if (rOStm.GetError())
1558 nStatus = ERRCODE_GRFILTER_IOERROR;
1559 }
1560 else if (aFilterName.equalsIgnoreAsciiCase(EXP_TIFF))
1561 {
1562 if (!ExportTiffGraphicImport(rOStm, aGraphic, &aConfigItem))
1564
1565 if( rOStm.GetError() )
1566 nStatus = ERRCODE_GRFILTER_IOERROR;
1567 }
1568 else if (aFilterName.equalsIgnoreAsciiCase(EXP_GIF))
1569 {
1570 if (!ExportGifGraphic(rOStm, aGraphic, &aConfigItem))
1572
1573 if( rOStm.GetError() )
1574 nStatus = ERRCODE_GRFILTER_IOERROR;
1575 }
1576 else if( aFilterName.equalsIgnoreAsciiCase( EXP_SVMETAFILE ) )
1577 {
1578 sal_Int32 nVersion = aConfigItem.ReadInt32( "Version", 0 ) ;
1579 if ( nVersion )
1580 rOStm.SetVersion( nVersion );
1581
1582 // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
1583 GDIMetaFile aMTF(aGraphic.GetGDIMetaFile());
1584
1585 SvmWriter aWriter( rOStm );
1586 aWriter.Write( aMTF );
1587
1588 if( rOStm.GetError() )
1589 nStatus = ERRCODE_GRFILTER_IOERROR;
1590 }
1591 else if ( aFilterName.equalsIgnoreAsciiCase( EXP_WMF ) || aFilterName.equalsIgnoreAsciiCase( EXP_WMZ ) )
1592 {
1593 bool bDone(false);
1594 SvStream* rTempStm = &rOStm;
1595 if (aFilterName.equalsIgnoreAsciiCase(EXP_WMZ))
1596 {
1597 // Write to a different stream so that we can compress to rOStm later
1598 rCompressableStm.SetBufferSize( rOStm.GetBufferSize() );
1599 rTempStm = &rCompressableStm;
1600 bShouldCompress = true;
1601 }
1602 // do we have a native Vector Graphic Data RenderGraphic, whose data can be written directly?
1603 auto const & rVectorGraphicDataPtr(rGraphic.getVectorGraphicData());
1604
1605 bool bIsEMF = rGraphic.GetGfxLink().IsEMF();
1606
1607 // VectorGraphicDataType::Wmf means WMF or EMF, allow direct write in the WMF case
1608 // only.
1609 if (rVectorGraphicDataPtr
1610 && rVectorGraphicDataPtr->getType() == VectorGraphicDataType::Wmf
1611 && !rVectorGraphicDataPtr->getBinaryDataContainer().isEmpty()
1612 && !bIsEMF)
1613 {
1614 rVectorGraphicDataPtr->getBinaryDataContainer().writeToStream(*rTempStm);
1615 if (rTempStm->GetError())
1616 {
1617 nStatus = ERRCODE_GRFILTER_IOERROR;
1618 }
1619 else
1620 {
1621 bDone = true;
1622 }
1623 }
1624
1625 if (!bDone)
1626 {
1627 // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
1628 if (!ConvertGraphicToWMF(aGraphic, *rTempStm, &aConfigItem))
1630
1631 if (rTempStm->GetError())
1632 nStatus = ERRCODE_GRFILTER_IOERROR;
1633 }
1634 }
1635 else if ( aFilterName.equalsIgnoreAsciiCase( EXP_EMF ) || aFilterName.equalsIgnoreAsciiCase( EXP_EMZ ) )
1636 {
1637 bool bDone(false);
1638 SvStream* rTempStm = &rOStm;
1639 if (aFilterName.equalsIgnoreAsciiCase(EXP_EMZ))
1640 {
1641 // Write to a different stream so that we can compress to rOStm later
1642 rCompressableStm.SetBufferSize( rOStm.GetBufferSize() );
1643 rTempStm = &rCompressableStm;
1644 bShouldCompress = true;
1645 }
1646 // do we have a native Vector Graphic Data RenderGraphic, whose data can be written directly?
1647 auto const & rVectorGraphicDataPtr(rGraphic.getVectorGraphicData());
1648
1649 if (rVectorGraphicDataPtr
1650 && rVectorGraphicDataPtr->getType() == VectorGraphicDataType::Emf
1651 && !rVectorGraphicDataPtr->getBinaryDataContainer().isEmpty())
1652 {
1653 rVectorGraphicDataPtr->getBinaryDataContainer().writeToStream(*rTempStm);
1654 if (rTempStm->GetError())
1655 {
1656 nStatus = ERRCODE_GRFILTER_IOERROR;
1657 }
1658 else
1659 {
1660 bDone = true;
1661 }
1662 }
1663
1664 if (!bDone)
1665 {
1666 // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
1667 if (!ConvertGDIMetaFileToEMF(aGraphic.GetGDIMetaFile(), *rTempStm))
1669
1670 if (rTempStm->GetError())
1671 nStatus = ERRCODE_GRFILTER_IOERROR;
1672 }
1673 }
1674 else if( aFilterName.equalsIgnoreAsciiCase( EXP_JPEG ) )
1675 {
1676 bool bExportedGrayJPEG = false;
1677 if( !ExportJPEG( rOStm, aGraphic, pFilterData, &bExportedGrayJPEG ) )
1679
1680 if( rOStm.GetError() )
1681 nStatus = ERRCODE_GRFILTER_IOERROR;
1682 }
1683 else if (aFilterName.equalsIgnoreAsciiCase(EXP_EPS))
1684 {
1685 if (!ExportEpsGraphic(rOStm, aGraphic, &aConfigItem))
1687
1688 if (rOStm.GetError())
1689 nStatus = ERRCODE_GRFILTER_IOERROR;
1690 }
1691 else if ( aFilterName.equalsIgnoreAsciiCase( EXP_PNG ) )
1692 {
1693 auto aBitmapEx = aGraphic.GetBitmapEx();
1694 vcl::PngImageWriter aPNGWriter( rOStm );
1695 if ( pFilterData )
1696 aPNGWriter.setParameters( *pFilterData );
1697 aPNGWriter.write( aBitmapEx );
1698
1699 if( rOStm.GetError() )
1700 nStatus = ERRCODE_GRFILTER_IOERROR;
1701 }
1702 else if( aFilterName.equalsIgnoreAsciiCase( EXP_SVG ) || aFilterName.equalsIgnoreAsciiCase( EXP_SVGZ ) )
1703 {
1704 bool bDone(false);
1705 SvStream* rTempStm = &rOStm;
1706 if (aFilterName.equalsIgnoreAsciiCase(EXP_SVGZ))
1707 {
1708 // Write to a different stream so that we can compress to rOStm later
1709 rCompressableStm.SetBufferSize(rOStm.GetBufferSize());
1710 rTempStm = &rCompressableStm;
1711 bShouldCompress = true;
1712 }
1713
1714 // do we have a native Vector Graphic Data RenderGraphic, whose data can be written directly?
1715 auto const & rVectorGraphicDataPtr(rGraphic.getVectorGraphicData());
1716
1717 if (rVectorGraphicDataPtr
1718 && rVectorGraphicDataPtr->getType() == VectorGraphicDataType::Svg
1719 && !rVectorGraphicDataPtr->getBinaryDataContainer().isEmpty())
1720 {
1721 rVectorGraphicDataPtr->getBinaryDataContainer().writeToStream(*rTempStm);
1722 if( rTempStm->GetError() )
1723 {
1724 nStatus = ERRCODE_GRFILTER_IOERROR;
1725 }
1726 else
1727 {
1728 bDone = true;
1729 }
1730 }
1731
1732 if( !bDone )
1733 {
1734 // do the normal GDIMetaFile export instead
1735 try
1736 {
1737 css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1738
1739 css::uno::Reference< css::xml::sax::XDocumentHandler > xSaxWriter(
1740 css::xml::sax::Writer::create( xContext ), css::uno::UNO_QUERY_THROW);
1741 css::uno::Sequence< css::uno::Any > aArguments{ css::uno::Any(
1742 aConfigItem.GetFilterData()) };
1743 css::uno::Reference< css::svg::XSVGWriter > xSVGWriter(
1744 xContext->getServiceManager()->createInstanceWithArgumentsAndContext( "com.sun.star.svg.SVGWriter", aArguments, xContext),
1745 css::uno::UNO_QUERY );
1746 if( xSaxWriter.is() && xSVGWriter.is() )
1747 {
1748 css::uno::Reference< css::io::XActiveDataSource > xActiveDataSource(
1749 xSaxWriter, css::uno::UNO_QUERY );
1750
1751 if( xActiveDataSource.is() )
1752 {
1753 const css::uno::Reference< css::uno::XInterface > xStmIf(
1754 getXWeak( new ImpFilterOutputStream( *rTempStm ) ) );
1755
1756 SvMemoryStream aMemStm( 65535, 65535 );
1757
1758 // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
1759 SvmWriter aWriter( aMemStm );
1760 aWriter.Write( aGraphic.GetGDIMetaFile() );
1761
1762 xActiveDataSource->setOutputStream( css::uno::Reference< css::io::XOutputStream >(
1763 xStmIf, css::uno::UNO_QUERY ) );
1764 css::uno::Sequence< sal_Int8 > aMtfSeq( static_cast<sal_Int8 const *>(aMemStm.GetData()), aMemStm.Tell() );
1765 xSVGWriter->write( xSaxWriter, aMtfSeq );
1766 }
1767 }
1768 }
1769 catch(const css::uno::Exception&)
1770 {
1771 nStatus = ERRCODE_GRFILTER_IOERROR;
1772 }
1773 }
1774 }
1775 else if (aFilterName.equalsIgnoreAsciiCase(EXP_WEBP))
1776 {
1777 if (!ExportWebpGraphic(rOStm, aGraphic, &aConfigItem))
1779
1780 if( rOStm.GetError() )
1781 nStatus = ERRCODE_GRFILTER_IOERROR;
1782 }
1783 else
1785 }
1786 if( nStatus != ERRCODE_NONE )
1787 {
1788 ImplSetError( nStatus, &rOStm );
1789 }
1790 else if ( bShouldCompress )
1791 {
1792 sal_uInt32 nUncompressedCRC32
1793 = rtl_crc32( 0, rCompressableStm.GetData(), rCompressableStm.GetSize() );
1794 ZCodec aCodec;
1795 rCompressableStm.Seek( 0 );
1796 aCodec.BeginCompression( ZCODEC_DEFAULT_COMPRESSION, /*gzLib*/true );
1797 // the inner modify time/filename doesn't really matter in this context because
1798 // compressed graphic formats are meant to be opened as is - not to be extracted
1799 aCodec.SetCompressionMetadata( "inner", 0, nUncompressedCRC32 );
1800 aCodec.Compress( rCompressableStm, rOStm );
1801 tools::Long nCompressedLength = aCodec.EndCompression();
1802 if ( rOStm.GetError() || nCompressedLength <= 0 )
1803 nStatus = ERRCODE_GRFILTER_IOERROR;
1804 }
1805 return nStatus;
1806}
1807
1808
1810{
1812}
1813
1815{
1816 Link<ConvertData&,bool> aLink( LINK( const_cast<GraphicFilter*>(this), GraphicFilter, FilterCallback ) );
1817 return aLink;
1818}
1819
1820IMPL_LINK( GraphicFilter, FilterCallback, ConvertData&, rData, bool )
1821{
1822 bool bRet = false;
1823
1824 sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
1825 OUString aShortName;
1826 css::uno::Sequence< css::beans::PropertyValue > aFilterData;
1827 switch( rData.mnFormat )
1828 {
1829 case ConvertDataFormat::BMP: aShortName = BMP_SHORTNAME; break;
1830 case ConvertDataFormat::GIF: aShortName = GIF_SHORTNAME; break;
1831 case ConvertDataFormat::JPG: aShortName = JPG_SHORTNAME; break;
1832 case ConvertDataFormat::MET: aShortName = MET_SHORTNAME; break;
1833 case ConvertDataFormat::PCT: aShortName = PCT_SHORTNAME; break;
1834 case ConvertDataFormat::PNG: aShortName = PNG_SHORTNAME; break;
1835 case ConvertDataFormat::SVM: aShortName = SVM_SHORTNAME; break;
1836 case ConvertDataFormat::TIF: aShortName = TIF_SHORTNAME; break;
1837 case ConvertDataFormat::WMF: aShortName = WMF_SHORTNAME; break;
1838 case ConvertDataFormat::EMF: aShortName = EMF_SHORTNAME; break;
1839 case ConvertDataFormat::SVG: aShortName = SVG_SHORTNAME; break;
1840 case ConvertDataFormat::WEBP: aShortName = WEBP_SHORTNAME; break;
1841
1842 default:
1843 break;
1844 }
1845 if( GraphicType::NONE == rData.maGraphic.GetType() || rData.maGraphic.GetReaderContext() ) // Import
1846 {
1847 // Import
1848 nFormat = GetImportFormatNumberForShortName( aShortName );
1849 bRet = ImportGraphic( rData.maGraphic, u"", rData.mrStm, nFormat ) == ERRCODE_NONE;
1850 }
1851 else if( !aShortName.isEmpty() )
1852 {
1853 // Export
1854#if defined(IOS) || defined(ANDROID)
1855 if (aShortName == PNG_SHORTNAME)
1856 {
1857 aFilterData.realloc(aFilterData.getLength() + 1);
1858 auto pFilterData = aFilterData.getArray();
1859 pFilterData[aFilterData.getLength() - 1].Name = "Compression";
1860 // We "know" that this gets passed to zlib's deflateInit2_(). 1 means best speed.
1861 pFilterData[aFilterData.getLength() - 1].Value <<= static_cast<sal_Int32>(1);
1862 }
1863#endif
1864 nFormat = GetExportFormatNumberForShortName( aShortName );
1865 bRet = ExportGraphic( rData.maGraphic, u"", rData.mrStm, nFormat, &aFilterData ) == ERRCODE_NONE;
1866 }
1867
1868 return bRet;
1869}
1870
1871namespace
1872{
1873 class StandardGraphicFilter
1874 {
1875 public:
1876 StandardGraphicFilter()
1877 {
1878 m_aFilter.GetImportFormatCount();
1879 }
1880 GraphicFilter m_aFilter;
1881 };
1882}
1883
1885{
1886 static StandardGraphicFilter gStandardFilter;
1887 return gStandardFilter.m_aFilter;
1888}
1889
1890ErrCode GraphicFilter::LoadGraphic( const OUString &rPath, const OUString &rFilterName,
1891 Graphic& rGraphic, GraphicFilter* pFilter,
1892 sal_uInt16* pDeterminedFormat )
1893{
1894 if ( !pFilter )
1895 pFilter = &GetGraphicFilter();
1896
1897 const sal_uInt16 nFilter = !rFilterName.isEmpty() && pFilter->GetImportFormatCount()
1898 ? pFilter->GetImportFormatNumber( rFilterName )
1900
1901 INetURLObject aURL( rPath );
1902 if ( aURL.HasError() )
1903 {
1904 aURL.SetSmartProtocol( INetProtocol::File );
1905 aURL.SetSmartURL( rPath );
1906 }
1907
1908 std::unique_ptr<SvStream> pStream;
1909 if ( INetProtocol::File != aURL.GetProtocol() )
1910 pStream = ::utl::UcbStreamHelper::CreateStream( rPath, StreamMode::READ );
1911
1912 ErrCode nRes = ERRCODE_NONE;
1913 if ( !pStream )
1914 nRes = pFilter->ImportGraphic( rGraphic, aURL, nFilter, pDeterminedFormat );
1915 else
1916 nRes = pFilter->ImportGraphic( rGraphic, rPath, *pStream, nFilter, pDeterminedFormat );
1917
1918#ifdef DBG_UTIL
1919 OUString aReturnString;
1920
1921 if (nRes == ERRCODE_GRFILTER_OPENERROR)
1922 aReturnString="open error";
1923 else if (nRes == ERRCODE_GRFILTER_IOERROR)
1924 aReturnString="IO error";
1925 else if (nRes == ERRCODE_GRFILTER_FORMATERROR)
1926 aReturnString="format error";
1927 else if (nRes == ERRCODE_GRFILTER_VERSIONERROR)
1928 aReturnString="version error";
1929 else if (nRes == ERRCODE_GRFILTER_FILTERERROR)
1930 aReturnString="filter error";
1931 else if (nRes == ERRCODE_GRFILTER_TOOBIG)
1932 aReturnString="graphic is too big";
1933
1934 SAL_INFO_IF( nRes, "vcl.filter", "Problem importing graphic " << rPath << ". Reason: " << aReturnString );
1935#endif
1936
1937 return nRes;
1938}
1939
1941{
1942 css::uno::Sequence< css::beans::PropertyValue > aFilterData{ comphelper::makePropertyValue(
1943 "Compression", sal_uInt32(9)) };
1944
1945 sal_uInt16 nFilterFormat = GetExportFormatNumberForShortName(u"PNG");
1946 return ExportGraphic(rGraphic, u"", rOutputStream, nFilterFormat, &aFilterData);
1947}
1948
1949/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool BmpReader(SvStream &rStream, Graphic &rGraphic)
Definition: BmpReader.cxx:23
bool BmpWriter(SvStream &rStream, const Graphic &rGraphic, FilterConfigItem *pFilterConfigItem)
Definition: BmpWriter.cxx:23
Reference< XInputStream > xStream
oslInterlockedCount m_nStatus
static OutputDevice * GetDefaultDevice()
Get the default "device" (in this case the default window).
Definition: svapp.cxx:1043
Container for the binary data, whose responsibility is to manage the make it as simple as possible to...
std::shared_ptr< SvStream > getAsStream()
const AlphaMask & GetAlphaMask() const
Definition: bitmapex.hxx:71
bool Convert(BmpConversion eConversion)
Convert bitmap format.
Definition: BitmapEx.cxx:383
bool IsAlpha() const
Definition: BitmapEx.cxx:207
bool IsEmpty() const
Definition: BitmapEx.cxx:186
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:217
const Size & GetSizePixel() const
Definition: bitmapex.hxx:73
Cache to keep list of graphic filters + the filters themselves.
bool IsExportPixelFormat(sal_uInt16 nFormat)
sal_uInt16 GetExportFormatNumberForShortName(std::u16string_view rShortName)
OUString GetImportFormatName(sal_uInt16 nFormat)
sal_uInt16 GetImportFormatNumber(std::u16string_view rFormatName)
sal_uInt16 GetExportFormatNumber(std::u16string_view rFormatName)
sal_uInt16 GetImportFormatNumberForShortName(std::u16string_view rShortName)
OUString GetExportWildcard(sal_uInt16 nFormat, sal_Int32 nEntry)
OUString GetImportFormatShortName(sal_uInt16 nFormat)
sal_uInt16 GetImportFormatNumberForExtension(std::u16string_view rExt)
get the index of the filter that matches this extension
OUString GetImportWildcard(sal_uInt16 nFormat, sal_Int32 nEntry)
OUString GetImportFilterTypeName(sal_uInt16 nFormat)
OUString GetExportFilterName(sal_uInt16 nFormat)
OUString GetExportFormatShortName(sal_uInt16 nFormat)
OUString GetExportFormatName(sal_uInt16 nFormat)
OUString GetExportFormatExtension(sal_uInt16 nFormat, sal_Int32 nEntry=0)
OUString GetImportFilterName(sal_uInt16 nFormat)
sal_uInt16 GetExportFormatNumberForTypeName(std::u16string_view rType)
sal_uInt16 GetImportFormatCount() const
sal_uInt16 GetExportFormatNumberForMediaType(std::u16string_view rMediaType)
sal_uInt16 GetImportFormatNumberForTypeName(std::u16string_view rType)
OUString GetImportFormatExtension(sal_uInt16 nFormat, sal_Int32 nEntry=0)
OUString GetImportFilterType(sal_uInt16 nFormat)
sal_uInt16 GetExportFormatCount() const
OUString GetExportFormatMediaType(sal_uInt16 nFormat)
OUString GetImportFormatMediaType(sal_uInt16 nFormat)
OUString GetExportInternalFilterName(sal_uInt16 nFormat)
void WriteInt32(const OUString &rKey, sal_Int32 nValue)
sal_Int32 ReadInt32(const OUString &rKey, sal_Int32 nDefault)
const css::uno::Sequence< css::beans::PropertyValue > & GetFilterData() const
void Scale(double fScaleX, double fScaleY)
Definition: gdimtf.cxx:748
const Size & GetPrefSize() const
Definition: gdimtf.hxx:176
const MapMode & GetPrefMapMode() const
Definition: gdimtf.hxx:179
Class to import and export graphic formats.
OUString GetImportFormatShortName(sal_uInt16 nFormat)
static ErrCode readEPS(SvStream &rStream, Graphic &rGraphic)
sal_uInt16 GetExportFormatNumberForShortName(std::u16string_view rShortName)
static ErrCode readPSD(SvStream &rStream, Graphic &rGraphic)
static ErrCode readWithTypeSerializer(SvStream &rStream, Graphic &rGraphic, GfxLinkType &rLinkType, std::u16string_view aFilterName)
ErrCode ImplSetError(ErrCode nError, const SvStream *pStm=nullptr)
sal_uInt16 GetExportFormatNumberForTypeName(std::u16string_view rType)
OUString aFilterPath
Graphic ImportUnloadedGraphic(SvStream &rIStream, sal_uInt64 sizeLimit=0, const Size *pSizeHint=nullptr)
void MakeGraphicsAvailableThreaded(std::vector< Graphic * > &rGraphics)
Tries to ensure all Graphic objects are available (Graphic::isAvailable()).
static ErrCode readPCD(SvStream &rStream, Graphic &rGraphic)
sal_uInt16 GetImportFormatNumberForTypeName(std::u16string_view rType)
static ErrCode readWEBP(SvStream &rStream, Graphic &rGraphic, GfxLinkType &rLinkType)
OUString GetExportWildcard(sal_uInt16 nFormat)
static GraphicFilter & GetGraphicFilter()
Link< ConvertData &, bool > GetFilterCallback() const
static ErrCode readDXF(SvStream &rStream, Graphic &rGraphic)
bool IsExportPixelFormat(sal_uInt16 nFormat)
static ErrCode readBMP(SvStream &rStream, Graphic &rGraphic, GfxLinkType &rLinkType)
static ErrCode readPDF(SvStream &rStream, Graphic &rGraphic, GfxLinkType &rLinkType)
static ErrCode readXPM(SvStream &rStream, Graphic &rGraphic)
sal_uInt16 GetExportFormatNumber(std::u16string_view rFormatName)
static ErrCode readJPEG(SvStream &rStream, Graphic &rGraphic, GfxLinkType &rLinkType, GraphicFilterImportFlags nImportFlags)
static ErrCode readMET(SvStream &rStream, Graphic &rGraphic, GfxLinkType &rLinkType)
static ErrCode readXBM(SvStream &rStream, Graphic &rGraphic)
sal_uInt16 GetExportFormatNumberForMediaType(std::u16string_view rShortName)
sal_uInt16 GetImportFormatNumber(std::u16string_view rFormatName)
ErrCode CanImportGraphic(const INetURLObject &rPath, sal_uInt16 nFormat, sal_uInt16 *pDeterminedFormat)
OUString GetExportFormatName(sal_uInt16 nFormat)
OUString GetImportFormatName(sal_uInt16 nFormat)
static ErrCode readEMF(SvStream &rStream, Graphic &rGraphic, GfxLinkType &rLinkType)
ErrCode ExportGraphic(const Graphic &rGraphic, const INetURLObject &rPath, sal_uInt16 nFormat, const css::uno::Sequence< css::beans::PropertyValue > *pFilterData=nullptr)
static ErrCode readPICT(SvStream &rStream, Graphic &rGraphic, GfxLinkType &rLinkType)
static ErrCode readWMF_EMF(SvStream &rStream, Graphic &rGraphic, GfxLinkType &rLinkType, VectorGraphicDataType eType)
sal_uInt16 GetImportFormatCount() const
sal_uInt16 GetExportFormatCount() const
static ErrCode readWMF(SvStream &rStream, Graphic &rGraphic, GfxLinkType &rLinkType)
OUString GetExportFormatShortName(sal_uInt16 nFormat)
static ErrCode readTGA(SvStream &rStream, Graphic &rGraphic)
sal_uInt16 GetImportFormatNumberForShortName(std::u16string_view rShortName)
static ErrCode readPBM(SvStream &rStream, Graphic &rGraphic)
ErrCode ImpTestOrFindFormat(std::u16string_view rPath, SvStream &rStream, sal_uInt16 &rFormat)
static ErrCode readRAS(SvStream &rStream, Graphic &rGraphic)
GraphicFilter(bool bUseConfig=true)
OUString GetImportWildcard(sal_uInt16 nFormat, sal_Int32 nEntry)
ErrCode ImportGraphic(Graphic &rGraphic, const INetURLObject &rPath, sal_uInt16 nFormat=GRFILTER_FORMAT_DONTKNOW, sal_uInt16 *pDeterminedFormat=nullptr, GraphicFilterImportFlags nImportFlags=GraphicFilterImportFlags::NONE)
static ErrCode readPCX(SvStream &rStream, Graphic &rGraphic)
FilterConfigCache * pConfig
OUString GetExportFormatMediaType(sal_uInt16 nFormat)
static ErrCode readGIF(SvStream &rStream, Graphic &rGraphic, GfxLinkType &rLinkType)
static ErrCode LoadGraphic(const OUString &rPath, const OUString &rFilter, Graphic &rGraphic, GraphicFilter *pFilter=nullptr, sal_uInt16 *pDeterminedFormat=nullptr)
OUString GetExportInternalFilterName(sal_uInt16 nFormat)
std::optional< ErrCode > mxErrorEx
Information about errors during the GraphicFilter operation.
OUString GetImportFormatTypeName(sal_uInt16 nFormat)
ErrCode compressAsPNG(const Graphic &rGraphic, SvStream &rOutputStream)
static ErrCode readSVG(SvStream &rStream, Graphic &rGraphic, GfxLinkType &rLinkType, BinaryDataContainer &rpGraphicContent)
static ErrCode readTIFF(SvStream &rStream, Graphic &rGraphic, GfxLinkType &rLinkType)
void ImportGraphics(std::vector< std::shared_ptr< Graphic > > &rGraphics, std::vector< std::unique_ptr< SvStream > > vStreams)
Imports multiple graphics.
static ErrCode readPNG(SvStream &rStream, Graphic &rGraphic, GfxLinkType &rLinkType, BinaryDataContainer &rpGraphicContent)
Size GetPrefSize() const
Definition: graph.cxx:364
void SetPrefMapMode(const MapMode &rPrefMapMode)
Definition: graph.cxx:380
void SetDummyContext(bool value)
Definition: graph.cxx:489
const GDIMetaFile & GetGDIMetaFile() const
Definition: graph.cxx:340
bool IsDummyContext() const
Definition: graph.cxx:494
GraphicType GetType() const
Definition: graph.cxx:294
void SetGfxLink(const std::shared_ptr< GfxLink > &rGfxLink)
Definition: graph.cxx:499
GfxLink GetGfxLink() const
Definition: graph.cxx:510
const BitmapEx & GetBitmapExRef() const
Gives direct access to the contained BitmapEx.
Definition: graph.cxx:345
BitmapEx GetBitmapEx(const GraphicConversionParameters &rParameters=GraphicConversionParameters()) const
Definition: graph.cxx:330
MapMode GetPrefMapMode() const
Definition: graph.cxx:375
void Clear()
Definition: graph.cxx:288
void Draw(OutputDevice &rOutDev, const Point &rDestPt) const
Definition: graph.cxx:429
bool IsGfxLink() const
Definition: graph.cxx:515
std::shared_ptr< GraphicReader > & GetReaderContext()
Definition: graph.cxx:479
void SetPrefSize(const Size &rPrefSize)
Definition: graph.cxx:369
const std::shared_ptr< VectorGraphicData > & getVectorGraphicData() const
Definition: graph.cxx:525
void SetDefaultType()
Definition: graph.cxx:299
SAL_DLLPRIVATE ImpGraphic * ImplGetImpGraphic() const
Definition: graph.hxx:89
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
INetProtocol GetProtocol() const
void setPrepared(bool bAnimated, const Size *pSizeHint)
Definition: impgraph.cxx:381
MapUnit GetMapUnit() const
Definition: mapmod.cxx:181
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1110
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1580
constexpr tools::Long getHeight() const
constexpr tools::Long Height() const
constexpr tools::Long getWidth() const
void setWidth(tools::Long nWidth)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
const void * GetData()
sal_uInt64 GetSize()
virtual void ResetError()
sal_uInt64 Tell() const
void SetBufferSize(sal_uInt16 m_nBufSize)
sal_uInt16 GetBufferSize() const
std::size_t WriteBytes(const void *pData, std::size_t nSize)
void SetVersion(sal_Int32 n)
sal_uInt64 Seek(sal_uInt64 nPos)
std::size_t ReadBytes(void *pData, std::size_t nSize)
ErrCode GetError() const
void FlushBuffer()
sal_uInt64 remainingSize()
SvStream & Write(const GDIMetaFile &rMetaFile)
Definition: SvmWriter.cxx:38
void readGraphic(Graphic &rGraphic)
tools::Long Decompress(SvStream &rIStm, SvStream &rOStm)
void SetCompressionMetadata(const OString &sFilename, sal_uInt32 nLastModifiedTime, sal_uInt32 nInBufCRC32)
static bool IsZCompressed(SvStream &rIStm)
tools::Long EndCompression()
void BeginCompression(int nCompressLevel=ZCODEC_DEFAULT_COMPRESSION, bool gzLib=false)
void Compress(SvStream &rIStm, SvStream &rOStm)
static ThreadPool & getSharedOptimalPool()
void waitUntilDone(const std::shared_ptr< ThreadTaskTag > &, bool bJoin=true)
static std::shared_ptr< ThreadTaskTag > createThreadTaskTag()
void pushTask(std::unique_ptr< ThreadTask > pTask)
virtual void doWork()=0
static bool IsFuzzing()
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
bool read(BitmapEx &rBitmap)
static BinaryDataContainer getMicrosoftGifChunk(SvStream &rStream)
void setParameters(css::uno::Sequence< css::beans::PropertyValue > const &rParameters)
bool write(const BitmapEx &rBitmap)
This template handles BitmapAccess the RAII way.
URL aURL
float u
bool ExportGifGraphic(SvStream &rStream, const Graphic &rGraphic, FilterConfigItem *pConfigItem)
Definition: egif.cxx:543
#define ERRCODE_IO_PENDING
#define ERRCODE_NONE
bool ExportTiffGraphicImport(SvStream &rStream, const Graphic &rGraphic, const FilterConfigItem *pFilterConfigItem)
Definition: etiff.cxx:580
sal_Int16 nVersion
bool ExportEpsGraphic(SvStream &rStream, const Graphic &rGraphic, FilterConfigItem *pFilterConfigItem)
DocumentType eType
VCL_DLLPUBLIC bool ImportGIF(SvStream &rStm, Graphic &rGraphic)
Definition: gifread.cxx:971
bool IsGIFAnimated(SvStream &rStm, Size &rLogicSize)
Definition: gifread.cxx:958
GraphicType
Definition: graph.hxx:35
static OUString ImpGetExtension(std::u16string_view rPath)
static Graphic ImpGetScaledGraphic(const Graphic &rGraphic, FilterConfigItem &rConfigItem)
static bool supportNativeWebp()
static std::mutex & getListMutex()
static std::vector< GraphicFilter * > gaFilterHdlList
IMPL_LINK(GraphicFilter, FilterCallback, ConvertData &, rData, bool)
constexpr OUStringLiteral SVG_SHORTNAME
#define GRFILTER_FORMAT_DONTKNOW
#define IMP_SVG
constexpr OUStringLiteral MET_SHORTNAME
#define IMP_BMP
#define EXP_SVMETAFILE
#define EXP_BMP
#define IMP_TIFF
#define IMP_PICT
#define EXP_SVGZ
#define IMP_PNG
constexpr OUStringLiteral PCT_SHORTNAME
#define ERRCODE_GRFILTER_OPENERROR
#define IMP_PCD
#define IMP_JPEG
constexpr OUStringLiteral GIF_SHORTNAME
#define IMP_XBM
#define EXP_EMZ
#define IMP_GIF
#define EXP_WMZ
#define IMP_WEBP
constexpr OUStringLiteral WEBP_SHORTNAME
#define EXP_SVG
constexpr OUStringLiteral TIF_SHORTNAME
#define IMP_PSD
constexpr OUStringLiteral WMF_SHORTNAME
#define IMP_WMF
#define IMP_XPM
#define EXP_GIF
constexpr OUStringLiteral BMP_SHORTNAME
#define IMP_SVMETAFILE
#define IMP_DXF
#define ERRCODE_GRFILTER_TOOBIG
#define IMP_EMF
#define IMP_MET
#define IMP_TGA
#define IMP_RAS
#define IMP_WMZ
#define ERRCODE_GRFILTER_FORMATERROR
#define EXP_TIFF
#define IMP_EMZ
#define ERRCODE_GRFILTER_FILTERERROR
#define IMP_SVGZ
#define ERRCODE_GRFILTER_IOERROR
#define IMP_PCX
GraphicFilterImportFlags
@ UseExistingBitmap
Read pixel data into an existing bitmap.
@ OnlyCreateBitmap
Only create a bitmap, do not read pixel data.
#define EXP_EMF
#define EXP_PNG
constexpr OUStringLiteral JPG_SHORTNAME
#define ERRCODE_GRFILTER_VERSIONERROR
#define IMP_PBM
#define IMP_PDF
constexpr OUStringLiteral EMF_SHORTNAME
#define IMP_EPS
constexpr OUStringLiteral PNG_SHORTNAME
constexpr OUStringLiteral SVM_SHORTNAME
#define EXP_EPS
#define EXP_JPEG
#define EXP_WEBP
#define EXP_WMF
#define IMP_MOV
GtkMediaStream * m_pStream
bool ImportDxfGraphic(SvStream &rStream, Graphic &rGraphic)
Definition: idxf.cxx:28
bool ImportEpsGraphic(SvStream &rStream, Graphic &rGraphic)
Definition: ieps.cxx:575
Sequence< PropertyValue > aArguments
bool ImportMetGraphic(SvStream &rStream, Graphic &rGraphic)
Definition: ios2met.cxx:2860
bool ImportPbmGraphic(SvStream &rStream, Graphic &rGraphic)
Definition: ipbm.cxx:534
bool ImportPcdGraphic(SvStream &rStream, Graphic &rGraphic, FilterConfigItem *pConfigItem)
Definition: ipcd.cxx:346
bool ImportPcxGraphic(SvStream &rStream, Graphic &rGraphic)
Definition: ipcx.cxx:402
bool ImportPictGraphic(SvStream &rIStm, Graphic &rGraphic)
Definition: ipict.cxx:2024
bool ImportPsdGraphic(SvStream &rStream, Graphic &rGraphic)
Definition: ipsd.cxx:769
bool ImportRasGraphic(SvStream &rStream, Graphic &rGraphic)
Definition: iras.cxx:398
bool ImportTgaGraphic(SvStream &rStream, Graphic &rGraphic)
Definition: itga.cxx:783
bool ImportTiffGraphicImport(SvStream &rTIFF, Graphic &rGraphic)
Definition: itiff.cxx:110
bool ExportJPEG(SvStream &rOutputStream, const Graphic &rGraphic, const css::uno::Sequence< css::beans::PropertyValue > *pFilterData, bool *pExportWasGrey)
Definition: jpeg.cxx:53
VCL_DLLPUBLIC bool ImportJPEG(SvStream &rInputStream, Graphic &rGraphic, GraphicFilterImportFlags nImportFlags, BitmapScopedWriteAccess *ppAccess)
Definition: jpeg.cxx:26
#define SAL_INFO_IF(condition, area, stream)
#define SAL_WARN_IF(condition, area, stream)
#define SAL_INFO(area, stream)
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
int i
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
long Long
UNOTOOLS_DLLPUBLIC bool IsDocument(OUString const &url)
UNOTOOLS_DLLPUBLIC bool Kill(OUString const &url)
bool ImportPDF(SvStream &rStream, Graphic &rGraphic)
Imports a PDF stream into rGraphic.
Definition: pdfread.cxx:142
bool ImportPNG(SvStream &rInputStream, Graphic &rGraphic, GraphicFilterImportFlags nImportFlags, BitmapScopedWriteAccess *pAccess, AlphaScopedWriteAccess *pAlphaAccess)
bool peekGraphicFormat(SvStream &rStream, OUString &rFormatExtension, bool bTest)
HashMap_OWString_Interface aMap
bool ImportWebpGraphic(SvStream &rStream, Graphic &rGraphic)
Definition: reader.cxx:298
sal_uIntPtr sal_uLong
#define STREAM_SEEK_TO_END
#define STREAM_SEEK_TO_BEGIN
const Reference< XComponentContext > & m_rContext
unsigned char sal_uInt8
signed char sal_Int8
VectorGraphicDataType
bool ConvertGraphicToWMF(const Graphic &rGraphic, SvStream &rTargetStream, FilterConfigItem const *pConfigItem, bool bPlaceable)
Definition: wmf.cxx:85
bool ConvertGDIMetaFileToEMF(const GDIMetaFile &rMTF, SvStream &rTargetStream)
Definition: wmf.cxx:111
bool ExportWebpGraphic(SvStream &rStream, const Graphic &rGraphic, FilterConfigItem *pFilterConfigItem)
Definition: writer.cxx:193
VCL_DLLPUBLIC bool ImportXBM(SvStream &rStm, Graphic &rGraphic)
Definition: xbmread.cxx:371
VCL_DLLPUBLIC bool ImportXPM(SvStream &rStm, Graphic &rGraphic)
Definition: xpmread.cxx:670
#define ZCODEC_DEFAULT_COMPRESSION