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 <sal/config.h>
21 #include <sal/log.hxx>
23 #include <comphelper/fileformat.h>
24 #include <comphelper/processfactory.hxx>
25 #include <tools/fract.hxx>
26 #include <tools/vcompat.hxx>
27 #include <tools/urlobj.hxx>
28 #include <tools/stream.hxx>
29 #include <ucbhelper/content.hxx>
30 #include <unotools/ucbstreamhelper.hxx>
31 #include <unotools/tempfile.hxx>
32 #include <vcl/outdev.hxx>
33 #include <vcl/graphicfilter.hxx>
34 #include <vcl/virdev.hxx>
35 #include <vcl/gfxlink.hxx>
36 #include <vcl/cvtgrf.hxx>
37 #include <vcl/graph.hxx>
38 #include <vcl/metaact.hxx>
39 #include <impgraph.hxx>
40 #include <com/sun/star/ucb/CommandAbortedException.hpp>
41 #include <com/sun/star/ucb/ContentCreationException.hpp>
42 #include <com/sun/star/graphic/XPrimitive2D.hpp>
43 #include <vcl/dibtools.hxx>
46 #include <vcl/gdimetafiletools.hxx>
47 #include <TypeSerializer.hxx>
48 #include <vcl/pdfread.hxx>
50 #define GRAPHIC_MTFTOBMP_MAXEXT 2048
51 #define GRAPHIC_STREAMBUFSIZE 8192UL
53 #define SYS_WINMETAFILE 0x00000003L
54 #define SYS_WNTMETAFILE 0x00000004L
55 #define SYS_OS2METAFILE 0x00000005L
56 #define SYS_MACMETAFILE 0x00000006L
58 #define GRAPHIC_FORMAT_50 COMPAT_FORMAT( 'G', 'R', 'F', '5' )
59 #define NATIVE_FORMAT_50 COMPAT_FORMAT( 'N', 'A', 'T', '5' )
61 const sal_uInt32
nPdfMagic((sal_uInt32('p') << 24) | (sal_uInt32('d') << 16) | (sal_uInt32('f') << 8) | sal_uInt32('0'));
63 using namespace com::sun::star
;
67 INetURLObject aSwapURL
;
78 GraphicReader::GraphicReader()
82 GraphicReader::~GraphicReader()
86 void GraphicReader::DisablePreviewMode()
89 mpReaderData
->maPreviewSize
= Size( 0, 0 );
92 void GraphicReader::SetPreviewSize( const Size
& rSize
)
95 mpReaderData
.reset( new ReaderData
);
96 mpReaderData
->maPreviewSize
= rSize
;
99 Size
GraphicReader::GetPreviewSize() const
103 aSize
= mpReaderData
->maPreviewSize
;
107 GraphicID::GraphicID(ImpGraphic
const & rGraphic
)
109 rGraphic
.ensureAvailable();
111 mnID1
= static_cast<sal_uLong
>(rGraphic
.ImplGetType()) << 28;
112 mnID2
= mnID3
= mnID4
= 0;
114 if (rGraphic
.ImplGetType() == GraphicType::Bitmap
)
116 if (rGraphic
.getVectorGraphicData().get())
118 const VectorGraphicDataPtr
& rVectorGraphicDataPtr
= rGraphic
.getVectorGraphicData();
119 const basegfx::B2DRange
& rRange
= rVectorGraphicDataPtr
->getRange();
121 mnID1
|= rVectorGraphicDataPtr
->getVectorGraphicDataArrayLength();
122 mnID2
= basegfx::fround(rRange
.getWidth());
123 mnID3
= basegfx::fround(rRange
.getHeight());
124 mnID4
= vcl_get_checksum(0, rVectorGraphicDataPtr
->getVectorGraphicDataArray().getConstArray(), rVectorGraphicDataPtr
->getVectorGraphicDataArrayLength());
126 else if (rGraphic
.hasPdfData())
128 std::shared_ptr
<std::vector
<sal_Int8
>> pPdfData
= rGraphic
.getPdfData();
129 const BitmapEx
& rBmpEx
= rGraphic
.ImplGetBitmapExRef();
131 mnID1
|= (rGraphic
.mnPageNumber
& 0x0fffffff);
132 mnID2
= rBmpEx
.GetSizePixel().Width();
133 mnID3
= rBmpEx
.GetSizePixel().Height();
134 mnID4
= vcl_get_checksum(0, pPdfData
->data(), pPdfData
->size());
136 else if (rGraphic
.ImplIsAnimated())
138 const Animation
aAnimation(rGraphic
.ImplGetAnimation());
140 mnID1
|= ( aAnimation
.Count() & 0x0fffffff );
141 mnID2
= aAnimation
.GetDisplaySizePixel().Width();
142 mnID3
= aAnimation
.GetDisplaySizePixel().Height();
143 mnID4
= rGraphic
.ImplGetChecksum();
147 const BitmapEx
aBmpEx(rGraphic
.ImplGetBitmapEx(GraphicConversionParameters()));
149 mnID1
|= ( ( ( static_cast<sal_uLong
>(aBmpEx
.GetTransparentType()) << 8 ) | ( aBmpEx
.IsAlpha() ? 1 : 0 ) ) & 0x0fffffff );
150 mnID2
= aBmpEx
.GetSizePixel().Width();
151 mnID3
= aBmpEx
.GetSizePixel().Height();
152 mnID4
= rGraphic
.ImplGetChecksum();
155 else if (rGraphic
.ImplGetType() == GraphicType::GdiMetafile
)
157 const GDIMetaFile
& rMtf
= rGraphic
.ImplGetGDIMetaFile();
159 mnID1
|= ( rMtf
.GetActionSize() & 0x0fffffff );
160 mnID2
= rMtf
.GetPrefSize().Width();
161 mnID3
= rMtf
.GetPrefSize().Height();
162 mnID4
= rGraphic
.ImplGetChecksum();
166 OString
GraphicID::getIDString() const
168 static const char aHexData
[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
170 sal_Int32 nShift
, nIndex
= 0;
171 sal_Int32 nLen
= 24 + (2 * BITMAP_CHECKSUM_SIZE
);
172 OStringBuffer
aHexStr(nLen
);
173 aHexStr
.setLength(nLen
);
175 for( nShift
= 28; nShift
>= 0; nShift
-= 4 )
176 aHexStr
[nIndex
++] = aHexData
[ ( mnID1
>> static_cast<sal_uInt32
>(nShift
) ) & 0xf ];
178 for( nShift
= 28; nShift
>= 0; nShift
-= 4 )
179 aHexStr
[nIndex
++] = aHexData
[ ( mnID2
>> static_cast<sal_uInt32
>(nShift
) ) & 0xf ];
181 for( nShift
= 28; nShift
>= 0; nShift
-= 4 )
182 aHexStr
[nIndex
++] = aHexData
[ ( mnID3
>> static_cast<sal_uInt32
>(nShift
) ) & 0xf ];
184 for( nShift
= ( 8 * BITMAP_CHECKSUM_SIZE
) - 4; nShift
>= 0; nShift
-= 4 )
185 aHexStr
[nIndex
++] = aHexData
[ ( mnID4
>> static_cast<sal_uInt32
>(nShift
) ) & 0xf ];
187 return aHexStr
.makeStringAndClear();
190 ImpGraphic::ImpGraphic() :
191 meType ( GraphicType::NONE
),
194 mbDummyContext ( false ),
195 maLastUsed (std::chrono::high_resolution_clock::now()),
196 mbPrepared ( false ),
201 ImpGraphic::ImpGraphic(const ImpGraphic
& rImpGraphic
)
202 : maMetaFile(rImpGraphic
.maMetaFile
)
203 , maEx(rImpGraphic
.maEx
)
204 , maSwapInfo(rImpGraphic
.maSwapInfo
)
205 , mpContext(rImpGraphic
.mpContext
)
206 , mpSwapFile(rImpGraphic
.mpSwapFile
)
207 , mpGfxLink(rImpGraphic
.mpGfxLink
)
208 , meType(rImpGraphic
.meType
)
209 , mnSizeBytes(rImpGraphic
.mnSizeBytes
)
210 , mbSwapOut(rImpGraphic
.mbSwapOut
)
211 , mbDummyContext(rImpGraphic
.mbDummyContext
)
212 , maVectorGraphicData(rImpGraphic
.maVectorGraphicData
)
213 , mpPdfData(rImpGraphic
.mpPdfData
)
214 , maGraphicExternalLink(rImpGraphic
.maGraphicExternalLink
)
215 , maLastUsed (std::chrono::high_resolution_clock::now())
216 , mbPrepared (rImpGraphic
.mbPrepared
)
217 , mnPageNumber(rImpGraphic
.mnPageNumber
)
219 if( rImpGraphic
.mpAnimation
)
221 mpAnimation
= std::make_unique
<Animation
>( *rImpGraphic
.mpAnimation
);
222 maEx
= mpAnimation
->GetBitmapEx();
226 ImpGraphic::ImpGraphic(ImpGraphic
&& rImpGraphic
) noexcept
227 : maMetaFile(std::move(rImpGraphic
.maMetaFile
))
228 , maEx(std::move(rImpGraphic
.maEx
))
229 , maSwapInfo(std::move(rImpGraphic
.maSwapInfo
))
230 , mpAnimation(std::move(rImpGraphic
.mpAnimation
))
231 , mpContext(std::move(rImpGraphic
.mpContext
))
232 , mpSwapFile(std::move(rImpGraphic
.mpSwapFile
))
233 , mpGfxLink(std::move(rImpGraphic
.mpGfxLink
))
234 , meType(rImpGraphic
.meType
)
235 , mnSizeBytes(rImpGraphic
.mnSizeBytes
)
236 , mbSwapOut(rImpGraphic
.mbSwapOut
)
237 , mbDummyContext(rImpGraphic
.mbDummyContext
)
238 , maVectorGraphicData(std::move(rImpGraphic
.maVectorGraphicData
))
239 , mpPdfData(std::move(rImpGraphic
.mpPdfData
))
240 , maGraphicExternalLink(rImpGraphic
.maGraphicExternalLink
)
241 , maLastUsed (std::chrono::high_resolution_clock::now())
242 , mbPrepared (rImpGraphic
.mbPrepared
)
243 , mnPageNumber(rImpGraphic
.mnPageNumber
)
245 rImpGraphic
.ImplClear();
246 rImpGraphic
.mbDummyContext
= false;
249 ImpGraphic::ImpGraphic(GraphicExternalLink
const & rGraphicExternalLink
) :
250 meType ( GraphicType::Default
),
253 mbDummyContext ( false ),
254 maGraphicExternalLink(rGraphicExternalLink
),
255 maLastUsed (std::chrono::high_resolution_clock::now()),
261 ImpGraphic::ImpGraphic( const Bitmap
& rBitmap
) :
263 meType ( !rBitmap
.IsEmpty() ? GraphicType::Bitmap
: GraphicType::NONE
),
266 mbDummyContext ( false ),
267 maLastUsed (std::chrono::high_resolution_clock::now()),
273 ImpGraphic::ImpGraphic( const BitmapEx
& rBitmapEx
) :
275 meType ( !rBitmapEx
.IsEmpty() ? GraphicType::Bitmap
: GraphicType::NONE
),
278 mbDummyContext ( false ),
279 maLastUsed (std::chrono::high_resolution_clock::now()),
285 ImpGraphic::ImpGraphic(const VectorGraphicDataPtr
& rVectorGraphicDataPtr
)
286 : meType( rVectorGraphicDataPtr
.get() ? GraphicType::Bitmap
: GraphicType::NONE
),
289 mbDummyContext ( false ),
290 maVectorGraphicData(rVectorGraphicDataPtr
),
291 maLastUsed (std::chrono::high_resolution_clock::now()),
297 ImpGraphic::ImpGraphic( const Animation
& rAnimation
) :
298 maEx ( rAnimation
.GetBitmapEx() ),
299 mpAnimation ( std::make_unique
<Animation
>( rAnimation
) ),
300 meType ( GraphicType::Bitmap
),
303 mbDummyContext ( false ),
304 maLastUsed (std::chrono::high_resolution_clock::now()),
310 ImpGraphic::ImpGraphic( const GDIMetaFile
& rMtf
) :
312 meType ( GraphicType::GdiMetafile
),
315 mbDummyContext ( false ),
316 maLastUsed (std::chrono::high_resolution_clock::now()),
322 ImpGraphic::~ImpGraphic()
324 vcl::graphic::Manager::get().unregisterGraphic(this);
327 ImpGraphic
& ImpGraphic::operator=( const ImpGraphic
& rImpGraphic
)
329 if( &rImpGraphic
!= this )
331 sal_Int64 aOldSizeBytes
= mnSizeBytes
;
333 maMetaFile
= rImpGraphic
.maMetaFile
;
334 meType
= rImpGraphic
.meType
;
335 mnSizeBytes
= rImpGraphic
.mnSizeBytes
;
337 maSwapInfo
= rImpGraphic
.maSwapInfo
;
338 mpContext
= rImpGraphic
.mpContext
;
339 mbDummyContext
= rImpGraphic
.mbDummyContext
;
340 mnPageNumber
= rImpGraphic
.mnPageNumber
;
341 maGraphicExternalLink
= rImpGraphic
.maGraphicExternalLink
;
345 if ( rImpGraphic
.mpAnimation
)
347 mpAnimation
= std::make_unique
<Animation
>( *rImpGraphic
.mpAnimation
);
348 maEx
= mpAnimation
->GetBitmapEx();
352 maEx
= rImpGraphic
.maEx
;
355 mbSwapOut
= rImpGraphic
.mbSwapOut
;
356 mpSwapFile
= rImpGraphic
.mpSwapFile
;
357 mbPrepared
= rImpGraphic
.mbPrepared
;
359 mpGfxLink
= rImpGraphic
.mpGfxLink
;
361 maVectorGraphicData
= rImpGraphic
.maVectorGraphicData
;
362 mpPdfData
= rImpGraphic
.mpPdfData
;
363 maLastUsed
= std::chrono::high_resolution_clock::now();
365 vcl::graphic::Manager::get().changeExisting(this, aOldSizeBytes
);
371 ImpGraphic
& ImpGraphic::operator=(ImpGraphic
&& rImpGraphic
)
373 sal_Int64 aOldSizeBytes
= mnSizeBytes
;
375 maMetaFile
= std::move(rImpGraphic
.maMetaFile
);
376 meType
= rImpGraphic
.meType
;
377 mnSizeBytes
= rImpGraphic
.mnSizeBytes
;
378 maSwapInfo
= std::move(rImpGraphic
.maSwapInfo
);
379 mpContext
= std::move(rImpGraphic
.mpContext
);
380 mbDummyContext
= rImpGraphic
.mbDummyContext
;
381 mnPageNumber
= rImpGraphic
.mnPageNumber
;
382 mpAnimation
= std::move(rImpGraphic
.mpAnimation
);
383 maEx
= std::move(rImpGraphic
.maEx
);
384 mbSwapOut
= rImpGraphic
.mbSwapOut
;
385 mpSwapFile
= std::move(rImpGraphic
.mpSwapFile
);
386 mpGfxLink
= std::move(rImpGraphic
.mpGfxLink
);
387 maVectorGraphicData
= std::move(rImpGraphic
.maVectorGraphicData
);
388 mpPdfData
= std::move(rImpGraphic
.mpPdfData
);
389 maGraphicExternalLink
= rImpGraphic
.maGraphicExternalLink
;
390 mbPrepared
= rImpGraphic
.mbPrepared
;
392 rImpGraphic
.ImplClear();
393 rImpGraphic
.mbDummyContext
= false;
394 maLastUsed
= std::chrono::high_resolution_clock::now();
396 vcl::graphic::Manager::get().changeExisting(this, aOldSizeBytes
);
398 rImpGraphic
.mnPageNumber
= -1;
403 bool ImpGraphic::operator==( const ImpGraphic
& rImpGraphic
) const
407 if( this == &rImpGraphic
)
409 else if (mbPrepared
&& rImpGraphic
.mbPrepared
)
411 bRet
= (*mpGfxLink
== *rImpGraphic
.mpGfxLink
);
413 else if (isAvailable() && rImpGraphic
.isAvailable())
417 case GraphicType::NONE
:
421 case GraphicType::GdiMetafile
:
423 if( rImpGraphic
.maMetaFile
== maMetaFile
)
428 case GraphicType::Bitmap
:
430 if(maVectorGraphicData
.get())
432 if(maVectorGraphicData
== rImpGraphic
.maVectorGraphicData
)
437 else if(rImpGraphic
.maVectorGraphicData
)
440 bRet
= (*maVectorGraphicData
) == (*rImpGraphic
.maVectorGraphicData
);
443 else if (mpPdfData
&& !mpPdfData
->empty())
445 bRet
= (rImpGraphic
.mpPdfData
&& *mpPdfData
== *rImpGraphic
.mpPdfData
);
447 else if( mpAnimation
)
449 if( rImpGraphic
.mpAnimation
&& ( *rImpGraphic
.mpAnimation
== *mpAnimation
) )
452 else if( !rImpGraphic
.mpAnimation
&& ( rImpGraphic
.maEx
== maEx
) )
467 const VectorGraphicDataPtr
& ImpGraphic::getVectorGraphicData() const
471 return maVectorGraphicData
;
474 void ImpGraphic::setPdfData(const std::shared_ptr
<std::vector
<sal_Int8
>>& rPdfData
)
478 mpPdfData
= rPdfData
;
481 const std::shared_ptr
<std::vector
<sal_Int8
>> & ImpGraphic::getPdfData() const
488 void ImpGraphic::ImplCreateSwapInfo()
490 if (!ImplIsSwapOut())
492 maSwapInfo
.maPrefMapMode
= ImplGetPrefMapMode();
493 maSwapInfo
.maPrefSize
= ImplGetPrefSize();
494 maSwapInfo
.mbIsAnimated
= ImplIsAnimated();
495 maSwapInfo
.mbIsEPS
= ImplIsEPS();
496 maSwapInfo
.mbIsTransparent
= ImplIsTransparent();
497 maSwapInfo
.mbIsAlpha
= ImplIsAlpha();
498 maSwapInfo
.mnAnimationLoopCount
= ImplGetAnimationLoopCount();
502 void ImpGraphic::ImplClearGraphics()
508 maVectorGraphicData
.reset();
512 ImpSwapFile::~ImpSwapFile()
516 ::ucbhelper::Content
aCnt( aSwapURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
),
517 css::uno::Reference
< css::ucb::XCommandEnvironment
>(),
518 comphelper::getProcessComponentContext() );
520 aCnt
.executeCommand( "delete", css::uno::makeAny( true ) );
522 catch( const css::ucb::ContentCreationException
& )
525 catch( const css::uno::RuntimeException
& )
528 catch( const css::ucb::CommandAbortedException
& )
531 catch( const css::uno::Exception
& )
536 void ImpGraphic::ImplSetPrepared(bool bAnimated
, const Size
* pSizeHint
)
540 meType
= GraphicType::Bitmap
;
542 SvMemoryStream
aMemoryStream(const_cast<sal_uInt8
*>(mpGfxLink
->GetData()), mpGfxLink
->GetDataSize(), StreamMode::READ
| StreamMode::WRITE
);
546 maSwapInfo
.maPrefSize
= *pSizeHint
;
547 maSwapInfo
.maPrefMapMode
= MapMode(MapUnit::Map100thMM
);
550 GraphicDescriptor
aDescriptor(aMemoryStream
, nullptr);
551 if (aDescriptor
.Detect(true))
555 // If we have logic size, work with that, as later pixel -> logic
556 // conversion will work with the output device DPI, not the graphic
558 Size aLogSize
= aDescriptor
.GetSize_100TH_MM();
559 if (aLogSize
.getWidth() && aLogSize
.getHeight())
561 maSwapInfo
.maPrefSize
= aLogSize
;
562 maSwapInfo
.maPrefMapMode
= MapMode(MapUnit::Map100thMM
);
566 maSwapInfo
.maPrefSize
= aDescriptor
.GetSizePixel();
567 maSwapInfo
.maPrefMapMode
= MapMode(MapUnit::MapPixel
);
571 maSwapInfo
.maSizePixel
= aDescriptor
.GetSizePixel();
572 maSwapInfo
.mbIsTransparent
= aDescriptor
.IsTransparent();
573 maSwapInfo
.mbIsAlpha
= aDescriptor
.IsAlpha();
575 maSwapInfo
.mbIsTransparent
= false;
576 maSwapInfo
.mbIsAlpha
= false;
579 maSwapInfo
.mnAnimationLoopCount
= 0;
580 maSwapInfo
.mbIsEPS
= false;
581 maSwapInfo
.mbIsAnimated
= bAnimated
;
584 void ImpGraphic::ImplClear()
592 meType
= GraphicType::NONE
;
593 sal_Int64 nOldSize
= mnSizeBytes
;
595 vcl::graphic::Manager::get().changeExisting(this, nOldSize
);
596 maGraphicExternalLink
.msURL
.clear();
599 void ImpGraphic::ImplSetDefaultType()
602 meType
= GraphicType::Default
;
605 bool ImpGraphic::ImplIsSupportedGraphic() const
607 return( meType
!= GraphicType::NONE
);
610 bool ImpGraphic::ImplIsTransparent() const
616 bRet
= maSwapInfo
.mbIsTransparent
;
618 else if (meType
== GraphicType::Bitmap
&& !maVectorGraphicData
.get())
620 bRet
= mpAnimation
? mpAnimation
->IsTransparent() : maEx
.IsTransparent();
626 bool ImpGraphic::ImplIsAlpha() const
632 bRet
= maSwapInfo
.mbIsAlpha
;
634 else if (maVectorGraphicData
.get())
638 else if (meType
== GraphicType::Bitmap
)
640 bRet
= (nullptr == mpAnimation
&& maEx
.IsAlpha());
646 bool ImpGraphic::ImplIsAnimated() const
648 return mbSwapOut
? maSwapInfo
.mbIsAnimated
: mpAnimation
!= nullptr;
651 bool ImpGraphic::ImplIsEPS() const
654 return maSwapInfo
.mbIsEPS
;
656 return( ( meType
== GraphicType::GdiMetafile
) &&
657 ( maMetaFile
.GetActionSize() > 0 ) &&
658 ( maMetaFile
.GetAction( 0 )->GetType() == MetaActionType::EPS
) );
661 bool ImpGraphic::isAvailable() const
663 return !mbPrepared
&& !mbSwapOut
;
666 bool ImpGraphic::makeAvailable()
668 return ensureAvailable();
671 Bitmap
ImpGraphic::ImplGetBitmap(const GraphicConversionParameters
& rParameters
) const
677 if( meType
== GraphicType::Bitmap
)
679 if(maVectorGraphicData
.get() && maEx
.IsEmpty())
681 // use maEx as local buffer for rendered svg
682 const_cast< ImpGraphic
* >(this)->maEx
= maVectorGraphicData
->getReplacement();
685 const BitmapEx
& rRetBmpEx
= ( mpAnimation
? mpAnimation
->GetBitmapEx() : maEx
);
686 const Color
aReplaceColor( COL_WHITE
);
688 aRetBmp
= rRetBmpEx
.GetBitmap( &aReplaceColor
);
690 if(rParameters
.getSizePixel().Width() || rParameters
.getSizePixel().Height())
691 aRetBmp
.Scale(rParameters
.getSizePixel());
693 else if( ( meType
!= GraphicType::Default
) && ImplIsSupportedGraphic() )
698 ScopedVclPtrInstance
< VirtualDevice
> aVDev
;
699 Size
aDrawSize(aVDev
->LogicToPixel(maMetaFile
.GetPrefSize(), maMetaFile
.GetPrefMapMode()));
701 if(rParameters
.getSizePixel().Width() && rParameters
.getSizePixel().Height())
703 // apply given size if exists
704 aDrawSize
= rParameters
.getSizePixel();
707 if(aDrawSize
.Width() && aDrawSize
.Height() && !rParameters
.getUnlimitedSize()
708 && (aDrawSize
.Width() > GRAPHIC_MTFTOBMP_MAXEXT
|| aDrawSize
.Height() > GRAPHIC_MTFTOBMP_MAXEXT
))
710 // limit bitmap size to a maximum of GRAPHIC_MTFTOBMP_MAXEXT x GRAPHIC_MTFTOBMP_MAXEXT
711 double fWH(static_cast<double>(aDrawSize
.Width()) / static_cast<double>(aDrawSize
.Height()));
715 aDrawSize
.setWidth(basegfx::fround(GRAPHIC_MTFTOBMP_MAXEXT
* fWH
));
716 aDrawSize
.setHeight(GRAPHIC_MTFTOBMP_MAXEXT
);
720 aDrawSize
.setWidth(GRAPHIC_MTFTOBMP_MAXEXT
);
721 aDrawSize
.setHeight(basegfx::fround(GRAPHIC_MTFTOBMP_MAXEXT
/ fWH
));
725 // calculate pixel size. Normally, it's the same as aDrawSize, but may
726 // need to be extended when hairlines are on the right or bottom edge
727 Size
aPixelSize(aDrawSize
);
729 if(GraphicType::GdiMetafile
== ImplGetType())
731 // get hairline and full bound rect
732 tools::Rectangle aHairlineRect
;
733 const tools::Rectangle
aRect(maMetaFile
.GetBoundRect(*aVDev
, &aHairlineRect
));
735 if(!aRect
.IsEmpty() && !aHairlineRect
.IsEmpty())
737 // expand if needed to allow bottom and right hairlines to be added
738 if(aRect
.Right() == aHairlineRect
.Right())
740 aPixelSize
.setWidth(aPixelSize
.getWidth() + 1);
743 if(aRect
.Bottom() == aHairlineRect
.Bottom())
745 aPixelSize
.setHeight(aPixelSize
.getHeight() + 1);
750 if(aVDev
->SetOutputSizePixel(aPixelSize
))
752 if(rParameters
.getAntiAliase())
754 aVDev
->SetAntialiasing(aVDev
->GetAntialiasing() | AntialiasingFlags::EnableB2dDraw
);
757 if(rParameters
.getSnapHorVerLines())
759 aVDev
->SetAntialiasing(aVDev
->GetAntialiasing() | AntialiasingFlags::PixelSnapHairline
);
762 ImplDraw( aVDev
.get(), Point(), aDrawSize
);
764 // use maEx as local buffer for rendered metafile
765 const_cast< ImpGraphic
* >(this)->maEx
= aVDev
->GetBitmapEx( Point(), aVDev
->GetOutputSizePixel() );
769 aRetBmp
= maEx
.GetBitmap();
774 aRetBmp
.SetPrefMapMode( ImplGetPrefMapMode() );
775 aRetBmp
.SetPrefSize( ImplGetPrefSize() );
781 BitmapEx
ImpGraphic::ImplGetBitmapEx(const GraphicConversionParameters
& rParameters
) const
787 if( meType
== GraphicType::Bitmap
)
789 if(maVectorGraphicData
.get() && maEx
.IsEmpty())
791 // use maEx as local buffer for rendered svg
792 const_cast< ImpGraphic
* >(this)->maEx
= maVectorGraphicData
->getReplacement();
795 aRetBmpEx
= ( mpAnimation
? mpAnimation
->GetBitmapEx() : maEx
);
797 if(rParameters
.getSizePixel().Width() || rParameters
.getSizePixel().Height())
800 rParameters
.getSizePixel(),
804 else if( ( meType
!= GraphicType::Default
) && ImplIsSupportedGraphic() )
808 const ImpGraphic
aMonoMask( maMetaFile
.GetMonochromeMtf( COL_BLACK
) );
810 // use maEx as local buffer for rendered metafile
811 const_cast< ImpGraphic
* >(this)->maEx
= BitmapEx(ImplGetBitmap(rParameters
), aMonoMask
.ImplGetBitmap(rParameters
));
820 Animation
ImpGraphic::ImplGetAnimation() const
822 Animation aAnimation
;
826 aAnimation
= *mpAnimation
;
831 const BitmapEx
& ImpGraphic::ImplGetBitmapExRef() const
837 const GDIMetaFile
& ImpGraphic::ImplGetGDIMetaFile() const
840 if (!maMetaFile
.GetActionSize()
841 && maVectorGraphicData
.get()
842 && (VectorGraphicDataType::Emf
== maVectorGraphicData
->getVectorGraphicDataType()
843 || VectorGraphicDataType::Wmf
== maVectorGraphicData
->getVectorGraphicDataType()))
845 // If we have a Emf/Wmf VectorGraphic object, we
846 // need a way to get the Metafile data out of the primitive
847 // representation. Use a strict virtual hook (MetafileAccessor)
848 // to access the MetafilePrimitive2D directly. Also see comments in
849 // XEmfParser about this.
850 const std::deque
< css::uno::Reference
< css::graphic::XPrimitive2D
> > aSequence(maVectorGraphicData
->getPrimitive2DSequence());
852 if (1 == aSequence
.size())
854 // try to cast to MetafileAccessor implementation
855 const css::uno::Reference
< css::graphic::XPrimitive2D
> xReference(aSequence
[0]);
856 const MetafileAccessor
* pMetafileAccessor
= dynamic_cast< const MetafileAccessor
* >(xReference
.get());
858 if (pMetafileAccessor
)
860 // it is a MetafileAccessor implementation, get Metafile
861 pMetafileAccessor
->accessMetafile(const_cast< ImpGraphic
* >(this)->maMetaFile
);
866 if (GraphicType::Bitmap
== meType
&& !maMetaFile
.GetActionSize())
869 // Use the local maMetaFile as container for a metafile-representation
870 // of the bitmap graphic. This will be done only once, thus be buffered.
871 // I checked all usages of maMetaFile, it is only used when type is not
872 // GraphicType::Bitmap. In operator= it will get copied, thus buffering will
873 // survive copying (change this if not wanted)
874 ImpGraphic
* pThat
= const_cast< ImpGraphic
* >(this);
876 if(maVectorGraphicData
.get() && !maEx
)
878 // use maEx as local buffer for rendered svg
879 pThat
->maEx
= maVectorGraphicData
->getReplacement();
882 // #123983# directly create a metafile with the same PrefSize and PrefMapMode
883 // the bitmap has, this will be an always correct metafile
884 if(maEx
.IsTransparent())
886 pThat
->maMetaFile
.AddAction(new MetaBmpExScaleAction(Point(), maEx
.GetPrefSize(), maEx
));
890 pThat
->maMetaFile
.AddAction(new MetaBmpScaleAction(Point(), maEx
.GetPrefSize(), maEx
.GetBitmap()));
893 pThat
->maMetaFile
.Stop();
894 pThat
->maMetaFile
.WindStart();
895 pThat
->maMetaFile
.SetPrefSize(maEx
.GetPrefSize());
896 pThat
->maMetaFile
.SetPrefMapMode(maEx
.GetPrefMapMode());
902 Size
ImpGraphic::ImplGetSizePixel() const
907 aSize
= maSwapInfo
.maSizePixel
;
909 aSize
= ImplGetBitmapEx(GraphicConversionParameters()).GetSizePixel();
914 Size
ImpGraphic::ImplGetPrefSize() const
920 aSize
= maSwapInfo
.maPrefSize
;
926 case GraphicType::NONE
:
927 case GraphicType::Default
:
930 case GraphicType::Bitmap
:
932 if(maVectorGraphicData
.get() && maEx
.IsEmpty())
934 // svg not yet buffered in maEx, return size derived from range
935 const basegfx::B2DRange
& rRange
= maVectorGraphicData
->getRange();
937 aSize
= Size(basegfx::fround(rRange
.getWidth()), basegfx::fround(rRange
.getHeight()));
941 aSize
= maEx
.GetPrefSize();
943 if( !aSize
.Width() || !aSize
.Height() )
945 aSize
= maEx
.GetSizePixel();
953 if( ImplIsSupportedGraphic() )
954 aSize
= maMetaFile
.GetPrefSize();
963 void ImpGraphic::ImplSetPrefSize( const Size
& rPrefSize
)
969 case GraphicType::NONE
:
970 case GraphicType::Default
:
973 case GraphicType::Bitmap
:
975 // used when importing a writer FlyFrame with SVG as graphic, added conversion
976 // to allow setting the PrefSize at the BitmapEx to hold it
977 if(maVectorGraphicData
.get() && maEx
.IsEmpty())
979 // use maEx as local buffer for rendered svg
980 maEx
= maVectorGraphicData
->getReplacement();
983 // #108077# Push through pref size to animation object,
984 // will be lost on copy otherwise
985 if( ImplIsAnimated() )
987 const_cast< BitmapEx
& >(mpAnimation
->GetBitmapEx()).SetPrefSize( rPrefSize
);
990 maEx
.SetPrefSize( rPrefSize
);
996 if( ImplIsSupportedGraphic() )
997 maMetaFile
.SetPrefSize( rPrefSize
);
1003 MapMode
ImpGraphic::ImplGetPrefMapMode() const
1007 if (ImplIsSwapOut())
1009 aMapMode
= maSwapInfo
.maPrefMapMode
;
1015 case GraphicType::NONE
:
1016 case GraphicType::Default
:
1019 case GraphicType::Bitmap
:
1021 if(maVectorGraphicData
.get() && maEx
.IsEmpty())
1023 // svg not yet buffered in maEx, return default PrefMapMode
1024 aMapMode
= MapMode(MapUnit::Map100thMM
);
1028 const Size
aSize( maEx
.GetPrefSize() );
1030 if ( aSize
.Width() && aSize
.Height() )
1031 aMapMode
= maEx
.GetPrefMapMode();
1038 if( ImplIsSupportedGraphic() )
1039 return maMetaFile
.GetPrefMapMode();
1048 void ImpGraphic::ImplSetPrefMapMode( const MapMode
& rPrefMapMode
)
1054 case GraphicType::NONE
:
1055 case GraphicType::Default
:
1058 case GraphicType::Bitmap
:
1060 if(maVectorGraphicData
.get())
1062 // ignore for Vector Graphic Data. If this is really used (except the grfcache)
1063 // it can be extended by using maEx as buffer for maVectorGraphicData->getReplacement()
1067 // #108077# Push through pref mapmode to animation object,
1068 // will be lost on copy otherwise
1069 if( ImplIsAnimated() )
1071 const_cast< BitmapEx
& >(mpAnimation
->GetBitmapEx()).SetPrefMapMode( rPrefMapMode
);
1074 maEx
.SetPrefMapMode( rPrefMapMode
);
1081 if( ImplIsSupportedGraphic() )
1082 maMetaFile
.SetPrefMapMode( rPrefMapMode
);
1088 sal_uLong
ImpGraphic::ImplGetSizeBytes() const
1090 if( 0 == mnSizeBytes
)
1095 if( meType
== GraphicType::Bitmap
)
1097 if(maVectorGraphicData
.get())
1099 std::pair
<VectorGraphicData::State
, size_t> tmp(maVectorGraphicData
->getSizeBytes());
1100 if (VectorGraphicData::State::UNPARSED
== tmp
.first
)
1102 return tmp
.second
; // don't cache it until Vector Graphic Data is parsed
1104 mnSizeBytes
= tmp
.second
;
1108 mnSizeBytes
= mpAnimation
? mpAnimation
->GetSizeBytes() : maEx
.GetSizeBytes();
1111 else if( meType
== GraphicType::GdiMetafile
)
1113 mnSizeBytes
= maMetaFile
.GetSizeBytes();
1120 void ImpGraphic::ImplDraw( OutputDevice
* pOutDev
, const Point
& rDestPt
) const
1123 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() )
1127 case GraphicType::Default
:
1130 case GraphicType::Bitmap
:
1132 if(maVectorGraphicData
.get() && !maEx
)
1134 // use maEx as local buffer for rendered svg
1135 const_cast< ImpGraphic
* >(this)->maEx
= maVectorGraphicData
->getReplacement();
1140 mpAnimation
->Draw( pOutDev
, rDestPt
);
1144 maEx
.Draw( pOutDev
, rDestPt
);
1150 ImplDraw( pOutDev
, rDestPt
, maMetaFile
.GetPrefSize() );
1156 void ImpGraphic::ImplDraw( OutputDevice
* pOutDev
,
1157 const Point
& rDestPt
, const Size
& rDestSize
) const
1160 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() )
1164 case GraphicType::Default
:
1167 case GraphicType::Bitmap
:
1169 if(maVectorGraphicData
.get() && maEx
.IsEmpty())
1171 // use maEx as local buffer for rendered svg
1172 const_cast< ImpGraphic
* >(this)->maEx
= maVectorGraphicData
->getReplacement();
1177 mpAnimation
->Draw( pOutDev
, rDestPt
, rDestSize
);
1181 maEx
.Draw( pOutDev
, rDestPt
, rDestSize
);
1188 const_cast<ImpGraphic
*>(this)->maMetaFile
.WindStart();
1189 const_cast<ImpGraphic
*>(this)->maMetaFile
.Play( pOutDev
, rDestPt
, rDestSize
);
1190 const_cast<ImpGraphic
*>(this)->maMetaFile
.WindStart();
1197 void ImpGraphic::ImplStartAnimation( OutputDevice
* pOutDev
, const Point
& rDestPt
,
1198 const Size
& rDestSize
, long nExtraData
,
1199 OutputDevice
* pFirstFrameOutDev
)
1203 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation
)
1204 mpAnimation
->Start( pOutDev
, rDestPt
, rDestSize
, nExtraData
, pFirstFrameOutDev
);
1207 void ImpGraphic::ImplStopAnimation( OutputDevice
* pOutDev
, long nExtraData
)
1211 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation
)
1212 mpAnimation
->Stop( pOutDev
, nExtraData
);
1215 void ImpGraphic::ImplSetAnimationNotifyHdl( const Link
<Animation
*,void>& rLink
)
1220 mpAnimation
->SetNotifyHdl( rLink
);
1223 Link
<Animation
*,void> ImpGraphic::ImplGetAnimationNotifyHdl() const
1225 Link
<Animation
*,void> aLink
;
1230 aLink
= mpAnimation
->GetNotifyHdl();
1235 sal_uInt32
ImpGraphic::ImplGetAnimationLoopCount() const
1238 return maSwapInfo
.mnAnimationLoopCount
;
1240 return mpAnimation
? mpAnimation
->GetLoopCount() : 0;
1243 void ImpGraphic::ImplSetContext( const std::shared_ptr
<GraphicReader
>& pReader
)
1245 mpContext
= pReader
;
1246 mbDummyContext
= false;
1249 bool ImpGraphic::ImplReadEmbedded( SvStream
& rIStm
)
1257 const SvStreamEndian nOldFormat
= rIStm
.GetEndian();
1260 rIStm
.SetEndian( SvStreamEndian::LITTLE
);
1261 rIStm
.ReadUInt32( nId
);
1264 if( GRAPHIC_FORMAT_50
== nId
)
1266 // read new style header
1267 std::unique_ptr
<VersionCompat
> pCompat( new VersionCompat( rIStm
, StreamMode::READ
) );
1269 rIStm
.ReadInt32( nType
);
1271 rIStm
.ReadInt32( nLen
);
1272 TypeSerializer
aSerializer(rIStm
);
1273 aSerializer
.readSize(aSize
);
1274 ReadMapMode( rIStm
, aMapMode
);
1278 // read old style header
1279 sal_Int32 nWidth
, nHeight
;
1280 sal_Int32 nMapMode
, nScaleNumX
, nScaleDenomX
;
1281 sal_Int32 nScaleNumY
, nScaleDenomY
, nOffsX
, nOffsY
;
1283 rIStm
.SeekRel( -4 );
1286 rIStm
.ReadInt32( nType
).ReadInt32( nLen
).ReadInt32( nWidth
).ReadInt32( nHeight
);
1287 rIStm
.ReadInt32( nMapMode
).ReadInt32( nScaleNumX
).ReadInt32( nScaleDenomX
).ReadInt32( nScaleNumY
);
1288 rIStm
.ReadInt32( nScaleDenomY
).ReadInt32( nOffsX
).ReadInt32( nOffsY
);
1293 nType
= OSL_SWAPDWORD( nType
);
1294 nWidth
= OSL_SWAPDWORD( nWidth
);
1295 nHeight
= OSL_SWAPDWORD( nHeight
);
1296 nMapMode
= OSL_SWAPDWORD( nMapMode
);
1297 nScaleNumX
= OSL_SWAPDWORD( nScaleNumX
);
1298 nScaleDenomX
= OSL_SWAPDWORD( nScaleDenomX
);
1299 nScaleNumY
= OSL_SWAPDWORD( nScaleNumY
);
1300 nScaleDenomY
= OSL_SWAPDWORD( nScaleDenomY
);
1301 nOffsX
= OSL_SWAPDWORD( nOffsX
);
1302 nOffsY
= OSL_SWAPDWORD( nOffsY
);
1305 aSize
= Size( nWidth
, nHeight
);
1306 aMapMode
= MapMode( static_cast<MapUnit
>(nMapMode
), Point( nOffsX
, nOffsY
),
1307 Fraction( nScaleNumX
, nScaleDenomX
),
1308 Fraction( nScaleNumY
, nScaleDenomY
) );
1311 meType
= static_cast<GraphicType
>(nType
);
1313 if( meType
!= GraphicType::NONE
)
1315 if( meType
== GraphicType::Bitmap
)
1317 if(maVectorGraphicData
.get() && maEx
.IsEmpty())
1319 // use maEx as local buffer for rendered svg
1320 maEx
= maVectorGraphicData
->getReplacement();
1323 maEx
.SetSizePixel(aSize
);
1325 if( aMapMode
!= MapMode() )
1327 maEx
.SetPrefMapMode( aMapMode
);
1328 maEx
.SetPrefSize( aSize
);
1333 maMetaFile
.SetPrefMapMode( aMapMode
);
1334 maMetaFile
.SetPrefSize( aSize
);
1337 if( meType
== GraphicType::Bitmap
|| meType
== GraphicType::GdiMetafile
)
1339 ReadImpGraphic( rIStm
, *this );
1340 bRet
= rIStm
.GetError() == ERRCODE_NONE
;
1342 else if( sal::static_int_cast
<sal_uLong
>(meType
) >= SYS_WINMETAFILE
1343 && sal::static_int_cast
<sal_uLong
>(meType
) <= SYS_MACMETAFILE
)
1345 Graphic aSysGraphic
;
1346 ConvertDataFormat nCvtType
;
1348 switch( sal::static_int_cast
<sal_uLong
>(meType
) )
1350 case SYS_WINMETAFILE
:
1351 case SYS_WNTMETAFILE
: nCvtType
= ConvertDataFormat::WMF
; break;
1352 case SYS_OS2METAFILE
: nCvtType
= ConvertDataFormat::MET
; break;
1353 case SYS_MACMETAFILE
: nCvtType
= ConvertDataFormat::PCT
; break;
1356 nCvtType
= ConvertDataFormat::Unknown
;
1360 if( nType
&& GraphicConverter::Import( rIStm
, aSysGraphic
, nCvtType
) == ERRCODE_NONE
)
1362 *this = ImpGraphic( aSysGraphic
.GetGDIMetaFile() );
1363 bRet
= rIStm
.GetError() == ERRCODE_NONE
;
1366 meType
= GraphicType::Default
;
1371 ImplSetPrefMapMode( aMapMode
);
1372 ImplSetPrefSize( aSize
);
1378 rIStm
.SetEndian( nOldFormat
);
1383 bool ImpGraphic::ImplWriteEmbedded( SvStream
& rOStm
)
1389 if( ( meType
!= GraphicType::NONE
) && ( meType
!= GraphicType::Default
) && !ImplIsSwapOut() )
1391 const MapMode
aMapMode( ImplGetPrefMapMode() );
1392 const Size
aSize( ImplGetPrefSize() );
1393 const SvStreamEndian nOldFormat
= rOStm
.GetEndian();
1394 sal_uLong nDataFieldPos
;
1396 rOStm
.SetEndian( SvStreamEndian::LITTLE
);
1398 // write correct version ( old style/new style header )
1399 if( rOStm
.GetVersion() >= SOFFICE_FILEFORMAT_50
)
1401 // write ID for new format (5.0)
1402 rOStm
.WriteUInt32( GRAPHIC_FORMAT_50
);
1404 // write new style header
1405 std::unique_ptr
<VersionCompat
> pCompat( new VersionCompat( rOStm
, StreamMode::WRITE
, 1 ) );
1407 rOStm
.WriteInt32( static_cast<sal_Int32
>(meType
) );
1409 // data size is updated later
1410 nDataFieldPos
= rOStm
.Tell();
1411 rOStm
.WriteInt32( 0 );
1413 TypeSerializer
aSerializer(rOStm
);
1414 aSerializer
.writeSize(aSize
);
1416 WriteMapMode( rOStm
, aMapMode
);
1420 // write old style (<=4.0) header
1421 rOStm
.WriteInt32( static_cast<sal_Int32
>(meType
) );
1423 // data size is updated later
1424 nDataFieldPos
= rOStm
.Tell();
1425 rOStm
.WriteInt32( 0 );
1426 rOStm
.WriteInt32( aSize
.Width() );
1427 rOStm
.WriteInt32( aSize
.Height() );
1428 rOStm
.WriteInt32( static_cast<sal_uInt16
>(aMapMode
.GetMapUnit()) );
1429 rOStm
.WriteInt32( aMapMode
.GetScaleX().GetNumerator() );
1430 rOStm
.WriteInt32( aMapMode
.GetScaleX().GetDenominator() );
1431 rOStm
.WriteInt32( aMapMode
.GetScaleY().GetNumerator() );
1432 rOStm
.WriteInt32( aMapMode
.GetScaleY().GetDenominator() );
1433 rOStm
.WriteInt32( aMapMode
.GetOrigin().X() );
1434 rOStm
.WriteInt32( aMapMode
.GetOrigin().Y() );
1438 if( !rOStm
.GetError() )
1440 const sal_uLong nDataStart
= rOStm
.Tell();
1442 if( ImplIsSupportedGraphic() )
1443 WriteImpGraphic( rOStm
, *this );
1445 if( !rOStm
.GetError() )
1447 const sal_uLong nStmPos2
= rOStm
.Tell();
1448 rOStm
.Seek( nDataFieldPos
);
1449 rOStm
.WriteInt32( nStmPos2
- nDataStart
);
1450 rOStm
.Seek( nStmPos2
);
1455 rOStm
.SetEndian( nOldFormat
);
1461 bool ImpGraphic::ImplSwapOut()
1465 if( !ImplIsSwapOut() )
1467 ::utl::TempFile aTempFile
;
1468 const INetURLObject
aTmpURL( aTempFile
.GetURL() );
1470 if( !aTmpURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
).isEmpty() )
1472 std::unique_ptr
<SvStream
> xOStm
;
1475 xOStm
= ::utl::UcbStreamHelper::CreateStream( aTmpURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
);
1477 catch( const css::uno::Exception
& )
1482 xOStm
->SetVersion( SOFFICE_FILEFORMAT_50
);
1483 xOStm
->SetCompressMode( SvStreamCompressFlags::NATIVE
);
1485 bRet
= ImplSwapOut( xOStm
.get() );
1488 mpSwapFile
= std::make_unique
<ImpSwapFile
>();
1489 mpSwapFile
->aSwapURL
= aTmpURL
;
1490 mpSwapFile
->maOriginURL
= getOriginURL();
1498 ::ucbhelper::Content
aCnt( aTmpURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
),
1499 css::uno::Reference
< css::ucb::XCommandEnvironment
>(),
1500 comphelper::getProcessComponentContext() );
1502 aCnt
.executeCommand( "delete", css::uno::makeAny( true ) );
1504 catch( const css::ucb::ContentCreationException
& )
1507 catch( const css::uno::RuntimeException
& )
1510 catch( const css::ucb::CommandAbortedException
& )
1513 catch( const css::uno::Exception
& )
1522 vcl::graphic::Manager::get().swappedOut(this);
1526 bool ImpGraphic::ImplSwapOut( SvStream
* xOStm
)
1532 xOStm
->SetBufferSize( GRAPHIC_STREAMBUFSIZE
);
1534 if( !xOStm
->GetError() && ImplWriteEmbedded( *xOStm
) )
1538 if( !xOStm
->GetError() )
1540 ImplCreateSwapInfo();
1541 ImplClearGraphics();
1542 bRet
= mbSwapOut
= true;
1548 SAL_WARN("vcl.gdi", "Graphic SwapOut: No stream for swap out!");
1554 bool ImpGraphic::ensureAvailable() const
1556 auto pThis
= const_cast<ImpGraphic
*>(this);
1558 if (ImplIsSwapOut())
1559 return pThis
->ImplSwapIn();
1561 pThis
->maLastUsed
= std::chrono::high_resolution_clock::now();
1565 bool ImpGraphic::loadPrepared()
1568 if (mpGfxLink
->LoadNative(aGraphic
))
1570 GraphicExternalLink aLink
= maGraphicExternalLink
;
1572 Size aPrefSize
= maSwapInfo
.maPrefSize
;
1573 *this = *aGraphic
.ImplGetImpGraphic();
1574 if (aPrefSize
.getWidth() && aPrefSize
.getHeight())
1576 // Use custom preferred size if it was set when the graphic was still unloaded.
1577 ImplSetPrefSize(aPrefSize
);
1580 maGraphicExternalLink
= aLink
;
1587 bool ImpGraphic::ImplSwapIn()
1591 if (!ImplIsSwapOut())
1596 bRet
= loadPrepared();
1603 aSwapURL
= mpSwapFile
->aSwapURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1605 if( !aSwapURL
.isEmpty() )
1607 std::unique_ptr
<SvStream
> xIStm
;
1610 xIStm
= ::utl::UcbStreamHelper::CreateStream( aSwapURL
, StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
);
1612 catch( const css::uno::Exception
& )
1618 xIStm
->SetVersion( SOFFICE_FILEFORMAT_50
);
1619 xIStm
->SetCompressMode( SvStreamCompressFlags::NATIVE
);
1621 bRet
= ImplSwapIn( xIStm
.get() );
1624 setOriginURL(mpSwapFile
->maOriginURL
);
1631 vcl::graphic::Manager::get().swappedIn(this);
1636 bool ImpGraphic::ImplSwapIn( SvStream
* xIStm
)
1642 xIStm
->SetBufferSize( GRAPHIC_STREAMBUFSIZE
);
1644 if( !xIStm
->GetError() )
1646 //keep the swap file alive, because its quite possibly the backing storage
1648 std::shared_ptr
<ImpSwapFile
> xSwapFile(std::move(mpSwapFile
));
1649 assert(!mpSwapFile
);
1651 std::shared_ptr
<GraphicReader
> xContext(std::move(mpContext
));
1654 bool bDummyContext
= mbDummyContext
;
1655 mbDummyContext
= false;
1657 bRet
= ImplReadEmbedded( *xIStm
);
1659 //restore ownership of the swap file and context
1660 mpSwapFile
= std::move(xSwapFile
);
1661 mpContext
= std::move(xContext
);
1662 mbDummyContext
= bDummyContext
;
1666 //throw away swapfile, etc.
1677 void ImpGraphic::ImplSetLink(const std::shared_ptr
<GfxLink
>& rGfxLink
)
1681 mpGfxLink
= rGfxLink
;
1684 std::shared_ptr
<GfxLink
> ImpGraphic::ImplGetSharedGfxLink() const
1689 GfxLink
ImpGraphic::ImplGetLink()
1693 return( mpGfxLink
? *mpGfxLink
: GfxLink() );
1696 bool ImpGraphic::ImplIsLink() const
1698 return ( bool(mpGfxLink
) );
1701 BitmapChecksum
ImpGraphic::ImplGetChecksum() const
1703 if (mnChecksum
!= 0)
1706 BitmapChecksum nRet
= 0;
1710 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() )
1714 case GraphicType::Default
:
1717 case GraphicType::Bitmap
:
1719 if(maVectorGraphicData
)
1720 nRet
= maVectorGraphicData
->GetChecksum();
1721 else if (mpPdfData
&& !mpPdfData
->empty())
1722 // Include the PDF data in the checksum, so a metafile with
1723 // and without PDF data is considered to be different.
1724 nRet
= vcl_get_checksum(nRet
, mpPdfData
->data(), mpPdfData
->size());
1725 else if( mpAnimation
)
1726 nRet
= mpAnimation
->GetChecksum();
1728 nRet
= maEx
.GetChecksum();
1733 nRet
= maMetaFile
.GetChecksum();
1742 bool ImpGraphic::ImplExportNative( SvStream
& rOStm
) const
1744 bool bResult
= false;
1748 if( !rOStm
.GetError() )
1750 if( !ImplIsSwapOut() )
1752 if( mpGfxLink
&& mpGfxLink
->IsNative() )
1753 bResult
= mpGfxLink
->ExportNative( rOStm
);
1756 WriteImpGraphic( rOStm
, *this );
1757 bResult
= ( rOStm
.GetError() == ERRCODE_NONE
);
1761 rOStm
.SetError( SVSTREAM_GENERALERROR
);
1767 static std::map
<BitmapChecksum
, std::shared_ptr
<std::vector
<sal_Int8
>>> sPdfDataCache
;
1769 void ReadImpGraphic( SvStream
& rIStm
, ImpGraphic
& rImpGraphic
)
1771 if (rIStm
.GetError())
1774 const sal_uLong nStmPos1
= rIStm
.Tell();
1777 rImpGraphic
.ImplClear();
1780 rIStm
.ReadUInt32( nTmp
);
1782 // if there is no more data, avoid further expensive
1783 // reading which will create VDevs and other stuff, just to
1784 // read nothing. CAUTION: Eof is only true AFTER reading another
1785 // byte, a speciality of SvMemoryStream (!)
1789 if (NATIVE_FORMAT_50
== nTmp
)
1795 std::unique_ptr
<VersionCompat
> pCompat(new VersionCompat( rIStm
, StreamMode::READ
));
1796 pCompat
.reset(); // destructor writes stuff into the header
1798 ReadGfxLink( rIStm
, aLink
);
1800 // set dummy link to avoid creation of additional link after filtering;
1801 // we set a default link to avoid unnecessary swapping of native data
1802 aGraphic
.SetGfxLink(std::make_shared
<GfxLink
>());
1804 if( !rIStm
.GetError() && aLink
.LoadNative( aGraphic
) )
1806 // set link only, if no other link was set
1807 const bool bSetLink
= !rImpGraphic
.mpGfxLink
;
1810 rImpGraphic
= *aGraphic
.ImplGetImpGraphic();
1812 if( aLink
.IsPrefMapModeValid() )
1813 rImpGraphic
.ImplSetPrefMapMode( aLink
.GetPrefMapMode() );
1815 if( aLink
.IsPrefSizeValid() )
1816 rImpGraphic
.ImplSetPrefSize( aLink
.GetPrefSize() );
1819 rImpGraphic
.ImplSetLink(std::make_shared
<GfxLink
>(aLink
));
1823 rIStm
.Seek( nStmPos1
);
1824 rIStm
.SetError( ERRCODE_IO_WRONGFORMAT
);
1830 const SvStreamEndian nOldFormat
= rIStm
.GetEndian();
1832 rIStm
.SeekRel( -4 );
1833 rIStm
.SetEndian( SvStreamEndian::LITTLE
);
1834 ReadDIBBitmapEx(aBmpEx
, rIStm
);
1836 if( !rIStm
.GetError() )
1838 sal_uInt32
nMagic1(0), nMagic2(0);
1839 sal_uLong nActPos
= rIStm
.Tell();
1841 rIStm
.ReadUInt32( nMagic1
).ReadUInt32( nMagic2
);
1842 rIStm
.Seek( nActPos
);
1844 rImpGraphic
= ImpGraphic( aBmpEx
);
1846 if( !rIStm
.GetError() && ( 0x5344414e == nMagic1
) && ( 0x494d4931 == nMagic2
) )
1848 rImpGraphic
.mpAnimation
= std::make_unique
<Animation
>();
1849 ReadAnimation( rIStm
, *rImpGraphic
.mpAnimation
);
1851 // #108077# manually set loaded BmpEx to Animation
1852 // (which skips loading its BmpEx if already done)
1853 rImpGraphic
.mpAnimation
->SetBitmapEx(aBmpEx
);
1862 rIStm
.Seek( nStmPos1
);
1864 ReadGDIMetaFile( rIStm
, aMtf
);
1866 if( !rIStm
.GetError() )
1872 ErrCode nOrigError
= rIStm
.GetErrorCode();
1873 // try to stream in Svg defining data (length, byte array and evtl. path)
1874 // See below (operator<<) for more information
1875 const sal_uInt32
nSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0'));
1876 const sal_uInt32
nWmfMagic((sal_uInt32('w') << 24) | (sal_uInt32('m') << 16) | (sal_uInt32('f') << 8) | sal_uInt32('0'));
1877 const sal_uInt32
nEmfMagic((sal_uInt32('e') << 24) | (sal_uInt32('m') << 16) | (sal_uInt32('f') << 8) | sal_uInt32('0'));
1879 rIStm
.Seek(nStmPos1
);
1881 rIStm
.ReadUInt32( nMagic
);
1883 if (nSvgMagic
== nMagic
|| nWmfMagic
== nMagic
|| nEmfMagic
== nMagic
)
1885 sal_uInt32
nVectorGraphicDataArrayLength(0);
1886 rIStm
.ReadUInt32(nVectorGraphicDataArrayLength
);
1888 if (nVectorGraphicDataArrayLength
)
1890 VectorGraphicDataArray
aNewData(nVectorGraphicDataArrayLength
);
1892 rIStm
.ReadBytes(aNewData
.getArray(), nVectorGraphicDataArrayLength
);
1893 OUString aPath
= rIStm
.ReadUniOrByteString(rIStm
.GetStreamCharSet());
1895 if (!rIStm
.GetError())
1897 VectorGraphicDataType
aDataType(VectorGraphicDataType::Svg
);
1899 if (nWmfMagic
== nMagic
)
1901 aDataType
= VectorGraphicDataType::Wmf
;
1903 else if (nEmfMagic
== nMagic
)
1905 aDataType
= VectorGraphicDataType::Emf
;
1908 VectorGraphicDataPtr
aVectorGraphicDataPtr(new VectorGraphicData(aNewData
, aPath
, aDataType
));
1909 rImpGraphic
= aVectorGraphicDataPtr
;
1913 else if (nMagic
== nPdfMagic
)
1915 // Stream in PDF data.
1916 BitmapChecksum nPdfId
= 0;
1917 rIStm
.ReadUInt64(nPdfId
);
1919 rImpGraphic
.mnPageNumber
= 0;
1920 rIStm
.ReadInt32(rImpGraphic
.mnPageNumber
);
1922 auto it
= sPdfDataCache
.find(nPdfId
);
1923 assert(it
!= sPdfDataCache
.end());
1925 rImpGraphic
.mpPdfData
= it
->second
;
1928 rImpGraphic
.maEx
= aBitmap
;
1930 std::vector
<Bitmap
> aBitmaps
;
1931 if (vcl::RenderPDFBitmaps(rImpGraphic
.mpPdfData
->data(), rImpGraphic
.mpPdfData
->size(), aBitmaps
, rImpGraphic
.mnPageNumber
, 1) == 1)
1932 rImpGraphic
.maEx
= aBitmaps
[0];
1934 rImpGraphic
.meType
= GraphicType::Bitmap
;
1938 rIStm
.SetError(nOrigError
);
1941 rIStm
.Seek(nStmPos1
);
1945 rIStm
.SetEndian( nOldFormat
);
1948 void WriteImpGraphic(SvStream
& rOStm
, const ImpGraphic
& rImpGraphic
)
1950 if (rOStm
.GetError())
1953 rImpGraphic
.ensureAvailable();
1955 if (rImpGraphic
.ImplIsSwapOut())
1957 rOStm
.SetError( SVSTREAM_GENERALERROR
);
1961 if( ( rOStm
.GetVersion() >= SOFFICE_FILEFORMAT_50
) &&
1962 ( rOStm
.GetCompressMode() & SvStreamCompressFlags::NATIVE
) &&
1963 rImpGraphic
.mpGfxLink
&& rImpGraphic
.mpGfxLink
->IsNative() &&
1964 !rImpGraphic
.hasPdfData())
1967 rOStm
.WriteUInt32( NATIVE_FORMAT_50
);
1969 // write compat info
1970 std::unique_ptr
<VersionCompat
> pCompat(new VersionCompat( rOStm
, StreamMode::WRITE
, 1 ));
1971 pCompat
.reset(); // destructor writes stuff into the header
1973 rImpGraphic
.mpGfxLink
->SetPrefMapMode( rImpGraphic
.ImplGetPrefMapMode() );
1974 rImpGraphic
.mpGfxLink
->SetPrefSize( rImpGraphic
.ImplGetPrefSize() );
1975 WriteGfxLink( rOStm
, *rImpGraphic
.mpGfxLink
);
1980 const SvStreamEndian nOldFormat
= rOStm
.GetEndian();
1981 rOStm
.SetEndian( SvStreamEndian::LITTLE
);
1983 switch( rImpGraphic
.ImplGetType() )
1985 case GraphicType::NONE
:
1986 case GraphicType::Default
:
1989 case GraphicType::Bitmap
:
1991 if(rImpGraphic
.getVectorGraphicData().get())
1993 // stream out Vector Graphic defining data (length, byte array and evtl. path)
1994 // this is used e.g. in swapping out graphic data and in transporting it over UNO API
1995 // as sequence of bytes, but AFAIK not written anywhere to any kind of file, so it should be
1996 // no problem to extend it; only used at runtime
1997 switch (rImpGraphic
.getVectorGraphicData()->getVectorGraphicDataType())
1999 case VectorGraphicDataType::Wmf
:
2001 const sal_uInt32
nWmfMagic((sal_uInt32('w') << 24) | (sal_uInt32('m') << 16) | (sal_uInt32('f') << 8) | sal_uInt32('0'));
2002 rOStm
.WriteUInt32(nWmfMagic
);
2005 case VectorGraphicDataType::Emf
:
2007 const sal_uInt32
nEmfMagic((sal_uInt32('e') << 24) | (sal_uInt32('m') << 16) | (sal_uInt32('f') << 8) | sal_uInt32('0'));
2008 rOStm
.WriteUInt32(nEmfMagic
);
2011 default: // case VectorGraphicDataType::Svg:
2013 const sal_uInt32
nSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0'));
2014 rOStm
.WriteUInt32(nSvgMagic
);
2019 rOStm
.WriteUInt32( rImpGraphic
.getVectorGraphicData()->getVectorGraphicDataArrayLength() );
2020 rOStm
.WriteBytes(rImpGraphic
.getVectorGraphicData()->getVectorGraphicDataArray().getConstArray(),
2021 rImpGraphic
.getVectorGraphicData()->getVectorGraphicDataArrayLength());
2022 rOStm
.WriteUniOrByteString(rImpGraphic
.getVectorGraphicData()->getPath(),
2023 rOStm
.GetStreamCharSet());
2025 else if (rImpGraphic
.hasPdfData())
2027 BitmapChecksum nPdfId
= vcl_get_checksum(0, rImpGraphic
.mpPdfData
->data(), rImpGraphic
.mpPdfData
->size());
2028 if (sPdfDataCache
.find(nPdfId
) == sPdfDataCache
.end())
2029 sPdfDataCache
.emplace(nPdfId
, rImpGraphic
.mpPdfData
);
2031 // Stream out PDF data.
2032 rOStm
.WriteUInt32(nPdfMagic
);
2033 rOStm
.WriteUInt64(nPdfId
);
2034 rOStm
.WriteInt32(rImpGraphic
.mnPageNumber
);
2036 else if( rImpGraphic
.ImplIsAnimated())
2038 WriteAnimation( rOStm
, *rImpGraphic
.mpAnimation
);
2042 WriteDIBBitmapEx(rImpGraphic
.maEx
, rOStm
);
2049 if( rImpGraphic
.ImplIsSupportedGraphic() )
2050 WriteGDIMetaFile( rOStm
, rImpGraphic
.maMetaFile
);
2055 rOStm
.SetEndian( nOldFormat
);
2059 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */