Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / source / gdi / impgraph.cxx
blobb31dbf4828bab708b92dbd98b355192c1bb869d6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sal/config.h"
22 #include <comphelper/processfactory.hxx>
23 #include <tools/fract.hxx>
24 #include <tools/vcompat.hxx>
25 #include <tools/urlobj.hxx>
26 #include <tools/stream.hxx>
27 #include <tools/helpers.hxx>
28 #include <ucbhelper/content.hxx>
29 #include <unotools/ucbstreamhelper.hxx>
30 #include <unotools/tempfile.hxx>
31 #include <vcl/outdev.hxx>
32 #include <vcl/virdev.hxx>
33 #include <vcl/gfxlink.hxx>
34 #include <vcl/cvtgrf.hxx>
35 #include <vcl/graph.hxx>
36 #include <vcl/metaact.hxx>
37 #include <impgraph.hxx>
38 #include <com/sun/star/ucb/CommandAbortedException.hpp>
39 #include <vcl/dibtools.hxx>
40 #include <memory>
41 #include <o3tl/make_unique.hxx>
43 #define GRAPHIC_MTFTOBMP_MAXEXT 2048
44 #define GRAPHIC_STREAMBUFSIZE 8192UL
46 #define SYS_WINMETAFILE 0x00000003L
47 #define SYS_WNTMETAFILE 0x00000004L
48 #define SYS_OS2METAFILE 0x00000005L
49 #define SYS_MACMETAFILE 0x00000006L
51 #define GRAPHIC_FORMAT_50 COMPAT_FORMAT( 'G', 'R', 'F', '5' )
52 #define NATIVE_FORMAT_50 COMPAT_FORMAT( 'N', 'A', 'T', '5' )
54 const sal_uInt32 nPdfMagic((sal_uInt32('p') << 24) | (sal_uInt32('d') << 16) | (sal_uInt32('f') << 8) | sal_uInt32('0'));
56 using namespace com::sun::star;
58 struct ImpSwapFile
60 INetURLObject aSwapURL;
61 ~ImpSwapFile();
64 class ReaderData
66 public:
67 Size maPreviewSize;
70 GraphicReader::GraphicReader()
74 GraphicReader::~GraphicReader()
78 void GraphicReader::DisablePreviewMode()
80 if( mpReaderData )
81 mpReaderData->maPreviewSize = Size( 0, 0 );
84 void GraphicReader::SetPreviewSize( const Size& rSize )
86 if( !mpReaderData )
87 mpReaderData.reset( new ReaderData );
88 mpReaderData->maPreviewSize = rSize;
91 Size GraphicReader::GetPreviewSize() const
93 Size aSize( 0, 0 );
94 if( mpReaderData )
95 aSize = mpReaderData->maPreviewSize;
96 return aSize;
99 ImpGraphic::ImpGraphic() :
100 meType ( GraphicType::NONE ),
101 mnSizeBytes ( 0UL ),
102 mbSwapOut ( false ),
103 mbDummyContext ( false )
107 ImpGraphic::ImpGraphic(const ImpGraphic& rImpGraphic)
108 : maMetaFile(rImpGraphic.maMetaFile)
109 , maEx(rImpGraphic.maEx)
110 , maSwapInfo(rImpGraphic.maSwapInfo)
111 , mpContext(rImpGraphic.mpContext)
112 , mpSwapFile(rImpGraphic.mpSwapFile)
113 , meType(rImpGraphic.meType)
114 , mnSizeBytes(rImpGraphic.mnSizeBytes)
115 , mbSwapOut(rImpGraphic.mbSwapOut)
116 , mbDummyContext(rImpGraphic.mbDummyContext)
117 , maSvgData(rImpGraphic.maSvgData)
118 , maPdfData(rImpGraphic.maPdfData)
120 if( rImpGraphic.mpGfxLink )
121 mpGfxLink = o3tl::make_unique<GfxLink>( *rImpGraphic.mpGfxLink );
123 if( rImpGraphic.mpAnimation )
125 mpAnimation = o3tl::make_unique<Animation>( *rImpGraphic.mpAnimation );
126 maEx = mpAnimation->GetBitmapEx();
130 ImpGraphic::ImpGraphic(ImpGraphic&& rImpGraphic)
131 : maMetaFile(std::move(rImpGraphic.maMetaFile))
132 , maEx(std::move(rImpGraphic.maEx))
133 , maSwapInfo(std::move(rImpGraphic.maSwapInfo))
134 , mpAnimation(std::move(rImpGraphic.mpAnimation))
135 , mpContext(std::move(rImpGraphic.mpContext))
136 , mpSwapFile(std::move(rImpGraphic.mpSwapFile))
137 , mpGfxLink(std::move(rImpGraphic.mpGfxLink))
138 , meType(rImpGraphic.meType)
139 , mnSizeBytes(rImpGraphic.mnSizeBytes)
140 , mbSwapOut(rImpGraphic.mbSwapOut)
141 , mbDummyContext(rImpGraphic.mbDummyContext)
142 , maSvgData(std::move(rImpGraphic.maSvgData))
143 , maPdfData(std::move(rImpGraphic.maPdfData))
145 rImpGraphic.ImplClear();
146 rImpGraphic.mbDummyContext = false;
149 ImpGraphic::ImpGraphic( const Bitmap& rBitmap ) :
150 maEx ( rBitmap ),
151 meType ( !rBitmap.IsEmpty() ? GraphicType::Bitmap : GraphicType::NONE ),
152 mnSizeBytes ( 0UL ),
153 mbSwapOut ( false ),
154 mbDummyContext ( false )
158 ImpGraphic::ImpGraphic( const BitmapEx& rBitmapEx ) :
159 maEx ( rBitmapEx ),
160 meType ( !rBitmapEx.IsEmpty() ? GraphicType::Bitmap : GraphicType::NONE ),
161 mnSizeBytes ( 0UL ),
162 mbSwapOut ( false ),
163 mbDummyContext ( false )
167 ImpGraphic::ImpGraphic(const SvgDataPtr& rSvgDataPtr)
168 : meType( rSvgDataPtr.get() ? GraphicType::Bitmap : GraphicType::NONE ),
169 mnSizeBytes( 0UL ),
170 mbSwapOut( false ),
171 mbDummyContext ( false ),
172 maSvgData(rSvgDataPtr)
176 ImpGraphic::ImpGraphic( const Animation& rAnimation ) :
177 maEx ( rAnimation.GetBitmapEx() ),
178 mpAnimation ( o3tl::make_unique<Animation>( rAnimation ) ),
179 meType ( GraphicType::Bitmap ),
180 mnSizeBytes ( 0UL ),
181 mbSwapOut ( false ),
182 mbDummyContext ( false )
186 ImpGraphic::ImpGraphic( const GDIMetaFile& rMtf ) :
187 maMetaFile ( rMtf ),
188 meType ( GraphicType::GdiMetafile ),
189 mnSizeBytes ( 0UL ),
190 mbSwapOut ( false ),
191 mbDummyContext ( false )
195 ImpGraphic::~ImpGraphic()
199 ImpGraphic& ImpGraphic::operator=( const ImpGraphic& rImpGraphic )
201 if( &rImpGraphic != this )
203 maMetaFile = rImpGraphic.maMetaFile;
204 meType = rImpGraphic.meType;
205 mnSizeBytes = rImpGraphic.mnSizeBytes;
207 maSwapInfo = rImpGraphic.maSwapInfo;
208 mpContext = rImpGraphic.mpContext;
209 mbDummyContext = rImpGraphic.mbDummyContext;
211 mpAnimation.reset();
213 if ( rImpGraphic.mpAnimation )
215 mpAnimation = o3tl::make_unique<Animation>( *rImpGraphic.mpAnimation );
216 maEx = mpAnimation->GetBitmapEx();
218 else
220 maEx = rImpGraphic.maEx;
223 mbSwapOut = rImpGraphic.mbSwapOut;
224 mpSwapFile = rImpGraphic.mpSwapFile;
226 mpGfxLink.reset();
228 if( rImpGraphic.mpGfxLink )
229 mpGfxLink = o3tl::make_unique<GfxLink>( *rImpGraphic.mpGfxLink );
231 maSvgData = rImpGraphic.maSvgData;
232 maPdfData = rImpGraphic.maPdfData;
235 return *this;
238 ImpGraphic& ImpGraphic::operator=(ImpGraphic&& rImpGraphic)
240 maMetaFile = std::move(rImpGraphic.maMetaFile);
241 meType = rImpGraphic.meType;
242 mnSizeBytes = rImpGraphic.mnSizeBytes;
243 maSwapInfo = std::move(rImpGraphic.maSwapInfo);
244 mpContext = std::move(rImpGraphic.mpContext);
245 mbDummyContext = rImpGraphic.mbDummyContext;
246 mpAnimation = std::move(rImpGraphic.mpAnimation);
247 maEx = std::move(rImpGraphic.maEx);
248 mbSwapOut = rImpGraphic.mbSwapOut;
249 mpSwapFile = std::move(rImpGraphic.mpSwapFile);
250 mpGfxLink = std::move(rImpGraphic.mpGfxLink);
251 maSvgData = std::move(rImpGraphic.maSvgData);
252 maPdfData = std::move(rImpGraphic.maPdfData);
254 rImpGraphic.ImplClear();
255 rImpGraphic.mbDummyContext = false;
257 return *this;
260 bool ImpGraphic::operator==( const ImpGraphic& rImpGraphic ) const
262 bool bRet = false;
264 if( this == &rImpGraphic )
265 bRet = true;
266 else if( !ImplIsSwapOut() && ( rImpGraphic.meType == meType ) )
268 switch( meType )
270 case GraphicType::NONE:
271 bRet = true;
272 break;
274 case GraphicType::GdiMetafile:
276 if( rImpGraphic.maMetaFile == maMetaFile )
277 bRet = true;
279 break;
281 case GraphicType::Bitmap:
283 if(maSvgData.get())
285 if(maSvgData == rImpGraphic.maSvgData)
287 bRet = true;
289 else if(rImpGraphic.maSvgData)
291 if(maSvgData->getSvgDataArrayLength() == rImpGraphic.maSvgData->getSvgDataArrayLength())
293 if(0 == memcmp(
294 maSvgData->getSvgDataArray().getConstArray(),
295 rImpGraphic.maSvgData->getSvgDataArray().getConstArray(),
296 maSvgData->getSvgDataArrayLength()))
298 bRet = true;
303 else if (maPdfData.hasElements())
305 bRet = maPdfData == rImpGraphic.maPdfData;
307 else if( mpAnimation )
309 if( rImpGraphic.mpAnimation && ( *rImpGraphic.mpAnimation == *mpAnimation ) )
310 bRet = true;
312 else if( !rImpGraphic.mpAnimation && ( rImpGraphic.maEx == maEx ) )
314 bRet = true;
317 break;
319 default:
320 break;
324 return bRet;
327 void ImpGraphic::ImplCreateSwapInfo()
329 if (!ImplIsSwapOut())
331 maSwapInfo.maPrefMapMode = ImplGetPrefMapMode();
332 maSwapInfo.maPrefSize = ImplGetPrefSize();
336 void ImpGraphic::ImplClearGraphics()
338 maEx.Clear();
339 maMetaFile.Clear();
340 mpAnimation.reset();
341 mpGfxLink.reset();
342 maSvgData.reset();
343 maPdfData = uno::Sequence<sal_Int8>();
346 ImpSwapFile::~ImpSwapFile()
350 ::ucbhelper::Content aCnt( aSwapURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
351 css::uno::Reference< css::ucb::XCommandEnvironment >(),
352 comphelper::getProcessComponentContext() );
354 aCnt.executeCommand( "delete", css::uno::makeAny( true ) );
356 catch( const css::ucb::ContentCreationException& )
359 catch( const css::uno::RuntimeException& )
362 catch( const css::ucb::CommandAbortedException& )
365 catch( const css::uno::Exception& )
370 void ImpGraphic::ImplClear()
372 mpSwapFile.reset();
373 mbSwapOut = false;
375 // cleanup
376 ImplClearGraphics();
377 meType = GraphicType::NONE;
378 mnSizeBytes = 0;
381 void ImpGraphic::ImplSetDefaultType()
383 ImplClear();
384 meType = GraphicType::Default;
387 bool ImpGraphic::ImplIsSupportedGraphic() const
389 return( meType != GraphicType::NONE );
392 bool ImpGraphic::ImplIsTransparent() const
394 bool bRet(true);
396 if( meType == GraphicType::Bitmap && !maSvgData.get())
398 bRet = ( mpAnimation ? mpAnimation->IsTransparent() : maEx.IsTransparent() );
401 return bRet;
404 bool ImpGraphic::ImplIsAlpha() const
406 bool bRet(false);
408 if(maSvgData.get())
410 bRet = true;
412 else if( meType == GraphicType::Bitmap )
414 bRet = ( nullptr == mpAnimation ) && maEx.IsAlpha();
417 return bRet;
420 bool ImpGraphic::ImplIsAnimated() const
422 return( mpAnimation != nullptr );
425 bool ImpGraphic::ImplIsEPS() const
427 return( ( meType == GraphicType::GdiMetafile ) &&
428 ( maMetaFile.GetActionSize() > 0 ) &&
429 ( maMetaFile.GetAction( 0 )->GetType() == MetaActionType::EPS ) );
432 Bitmap ImpGraphic::ImplGetBitmap(const GraphicConversionParameters& rParameters) const
434 Bitmap aRetBmp;
436 if( meType == GraphicType::Bitmap )
438 if(maSvgData.get() && maEx.IsEmpty())
440 // use maEx as local buffer for rendered svg
441 const_cast< ImpGraphic* >(this)->maEx = maSvgData->getReplacement();
444 const BitmapEx& rRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maEx );
445 const Color aReplaceColor( COL_WHITE );
447 aRetBmp = rRetBmpEx.GetBitmap( &aReplaceColor );
449 if(rParameters.getSizePixel().Width() || rParameters.getSizePixel().Height())
450 aRetBmp.Scale(rParameters.getSizePixel());
452 else if( ( meType != GraphicType::Default ) && ImplIsSupportedGraphic() )
454 if(maEx.IsEmpty())
456 // calculate size
457 ScopedVclPtrInstance< VirtualDevice > aVDev;
458 Size aDrawSize(aVDev->LogicToPixel(maMetaFile.GetPrefSize(), maMetaFile.GetPrefMapMode()));
460 if(rParameters.getSizePixel().Width() && rParameters.getSizePixel().Height())
462 // apply given size if exists
463 aDrawSize = rParameters.getSizePixel();
466 if(aDrawSize.Width() && aDrawSize.Height() && !rParameters.getUnlimitedSize()
467 && (aDrawSize.Width() > GRAPHIC_MTFTOBMP_MAXEXT || aDrawSize.Height() > GRAPHIC_MTFTOBMP_MAXEXT))
469 // limit bitmap size to a maximum of GRAPHIC_MTFTOBMP_MAXEXT x GRAPHIC_MTFTOBMP_MAXEXT
470 double fWH((double)aDrawSize.Width() / (double)aDrawSize.Height());
472 if(fWH <= 1.0)
474 aDrawSize.setWidth(basegfx::fround(GRAPHIC_MTFTOBMP_MAXEXT * fWH));
475 aDrawSize.setHeight(GRAPHIC_MTFTOBMP_MAXEXT);
477 else
479 aDrawSize.setWidth(GRAPHIC_MTFTOBMP_MAXEXT);
480 aDrawSize.setHeight(basegfx::fround(GRAPHIC_MTFTOBMP_MAXEXT / fWH));
484 // calculate pixel size. Normally, it's the same as aDrawSize, but may
485 // need to be extended when hairlines are on the right or bottom edge
486 Size aPixelSize(aDrawSize);
488 if(GraphicType::GdiMetafile == ImplGetType())
490 // get hairline and full bound rect
491 tools::Rectangle aHairlineRect;
492 const tools::Rectangle aRect(maMetaFile.GetBoundRect(*aVDev.get(), &aHairlineRect));
494 if(!aRect.IsEmpty() && !aHairlineRect.IsEmpty())
496 // expand if needed to allow bottom and right hairlines to be added
497 if(aRect.Right() == aHairlineRect.Right())
499 aPixelSize.setWidth(aPixelSize.getWidth() + 1);
502 if(aRect.Bottom() == aHairlineRect.Bottom())
504 aPixelSize.setHeight(aPixelSize.getHeight() + 1);
509 if(aVDev->SetOutputSizePixel(aPixelSize))
511 if(rParameters.getAntiAliase())
513 aVDev->SetAntialiasing(aVDev->GetAntialiasing() | AntialiasingFlags::EnableB2dDraw);
516 if(rParameters.getSnapHorVerLines())
518 aVDev->SetAntialiasing(aVDev->GetAntialiasing() | AntialiasingFlags::PixelSnapHairline);
521 ImplDraw( aVDev.get(), Point(), aDrawSize );
523 // use maEx as local buffer for rendered metafile
524 const_cast< ImpGraphic* >(this)->maEx = aVDev->GetBitmap( Point(), aVDev->GetOutputSizePixel() );
528 aRetBmp = maEx.GetBitmap();
531 if( !!aRetBmp )
533 aRetBmp.SetPrefMapMode( ImplGetPrefMapMode() );
534 aRetBmp.SetPrefSize( ImplGetPrefSize() );
537 return aRetBmp;
540 BitmapEx ImpGraphic::ImplGetBitmapEx(const GraphicConversionParameters& rParameters) const
542 BitmapEx aRetBmpEx;
544 if( meType == GraphicType::Bitmap )
546 if(maSvgData.get() && maEx.IsEmpty())
548 // use maEx as local buffer for rendered svg
549 const_cast< ImpGraphic* >(this)->maEx = maSvgData->getReplacement();
552 aRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maEx );
554 if(rParameters.getSizePixel().Width() || rParameters.getSizePixel().Height())
556 aRetBmpEx.Scale(
557 rParameters.getSizePixel(),
558 BmpScaleFlag::Fast);
561 else if( ( meType != GraphicType::Default ) && ImplIsSupportedGraphic() )
563 if(maEx.IsEmpty())
565 const ImpGraphic aMonoMask( maMetaFile.GetMonochromeMtf( COL_BLACK ) );
567 // use maEx as local buffer for rendered metafile
568 const_cast< ImpGraphic* >(this)->maEx = BitmapEx(ImplGetBitmap(rParameters), aMonoMask.ImplGetBitmap(rParameters));
571 aRetBmpEx = maEx;
574 return aRetBmpEx;
577 Animation ImpGraphic::ImplGetAnimation() const
579 Animation aAnimation;
581 if( mpAnimation )
582 aAnimation = *mpAnimation;
584 return aAnimation;
587 const BitmapEx& ImpGraphic::ImplGetBitmapExRef() const
589 return maEx;
592 const GDIMetaFile& ImpGraphic::ImplGetGDIMetaFile() const
594 if (GraphicType::Bitmap == meType && !maMetaFile.GetActionSize())
596 // #i119735#
597 // Use the local maMetaFile as container for a metafile-representation
598 // of the bitmap graphic. This will be done only once, thus be buffered.
599 // I checked all usages of maMetaFile, it is only used when type is not
600 // GraphicType::Bitmap. In operator= it will get copied, thus buffering will
601 // survive copying (change this if not wanted)
602 ImpGraphic* pThat = const_cast< ImpGraphic* >(this);
604 if(maSvgData.get() && !maEx)
606 // use maEx as local buffer for rendered svg
607 pThat->maEx = maSvgData->getReplacement();
610 // #123983# directly create a metafile with the same PrefSize and PrefMapMode
611 // the bitmap has, this will be an always correct metafile
612 if(maEx.IsTransparent())
614 pThat->maMetaFile.AddAction(new MetaBmpExScaleAction(Point(), maEx.GetPrefSize(), maEx));
616 else
618 pThat->maMetaFile.AddAction(new MetaBmpScaleAction(Point(), maEx.GetPrefSize(), maEx.GetBitmap()));
621 pThat->maMetaFile.Stop();
622 pThat->maMetaFile.WindStart();
623 pThat->maMetaFile.SetPrefSize(maEx.GetPrefSize());
624 pThat->maMetaFile.SetPrefMapMode(maEx.GetPrefMapMode());
627 return maMetaFile;
630 Size ImpGraphic::ImplGetPrefSize() const
632 Size aSize;
634 if( ImplIsSwapOut() )
635 aSize = maSwapInfo.maPrefSize;
636 else
638 switch( meType )
640 case GraphicType::NONE:
641 case GraphicType::Default:
642 break;
644 case GraphicType::Bitmap:
646 if(maSvgData.get() && maEx.IsEmpty())
648 // svg not yet buffered in maEx, return size derived from range
649 const basegfx::B2DRange& rRange = maSvgData->getRange();
651 aSize = Size(basegfx::fround(rRange.getWidth()), basegfx::fround(rRange.getHeight()));
653 else
655 aSize = maEx.GetPrefSize();
657 if( !aSize.Width() || !aSize.Height() )
659 aSize = maEx.GetSizePixel();
663 break;
665 default:
667 if( ImplIsSupportedGraphic() )
668 aSize = maMetaFile.GetPrefSize();
670 break;
674 return aSize;
677 void ImpGraphic::ImplSetPrefSize( const Size& rPrefSize )
679 switch( meType )
681 case GraphicType::NONE:
682 case GraphicType::Default:
683 break;
685 case GraphicType::Bitmap:
687 // used when importing a writer FlyFrame with SVG as graphic, added conversion
688 // to allow setting the PrefSize at the BitmapEx to hold it
689 if(maSvgData.get() && maEx.IsEmpty())
691 // use maEx as local buffer for rendered svg
692 maEx = maSvgData->getReplacement();
695 // #108077# Push through pref size to animation object,
696 // will be lost on copy otherwise
697 if( ImplIsAnimated() )
699 const_cast< BitmapEx& >(mpAnimation->GetBitmapEx()).SetPrefSize( rPrefSize );
702 maEx.SetPrefSize( rPrefSize );
704 break;
706 default:
708 if( ImplIsSupportedGraphic() )
709 maMetaFile.SetPrefSize( rPrefSize );
711 break;
715 MapMode ImpGraphic::ImplGetPrefMapMode() const
717 MapMode aMapMode;
719 if( ImplIsSwapOut() )
720 aMapMode = maSwapInfo.maPrefMapMode;
721 else
723 switch( meType )
725 case GraphicType::NONE:
726 case GraphicType::Default:
727 break;
729 case GraphicType::Bitmap:
731 if(maSvgData.get() && maEx.IsEmpty())
733 // svg not yet buffered in maEx, return default PrefMapMode
734 aMapMode = MapMode(MapUnit::Map100thMM);
736 else
738 const Size aSize( maEx.GetPrefSize() );
740 if ( aSize.Width() && aSize.Height() )
741 aMapMode = maEx.GetPrefMapMode();
744 break;
746 default:
748 if( ImplIsSupportedGraphic() )
749 return maMetaFile.GetPrefMapMode();
751 break;
755 return aMapMode;
758 void ImpGraphic::ImplSetPrefMapMode( const MapMode& rPrefMapMode )
760 switch( meType )
762 case GraphicType::NONE:
763 case GraphicType::Default:
764 break;
766 case GraphicType::Bitmap:
768 if(maSvgData.get())
770 // ignore for Svg. If this is really used (except the grfcache)
771 // it can be extended by using maEx as buffer for maSvgData->getReplacement()
773 else
775 // #108077# Push through pref mapmode to animation object,
776 // will be lost on copy otherwise
777 if( ImplIsAnimated() )
779 const_cast< BitmapEx& >(mpAnimation->GetBitmapEx()).SetPrefMapMode( rPrefMapMode );
782 maEx.SetPrefMapMode( rPrefMapMode );
785 break;
787 default:
789 if( ImplIsSupportedGraphic() )
790 maMetaFile.SetPrefMapMode( rPrefMapMode );
792 break;
796 sal_uLong ImpGraphic::ImplGetSizeBytes() const
798 if( 0 == mnSizeBytes )
800 if( meType == GraphicType::Bitmap )
802 if(maSvgData.get())
804 std::pair<SvgData::State, size_t> tmp(maSvgData->getSizeBytes());
805 if (SvgData::State::UNPARSED == tmp.first)
807 return tmp.second; // don't cache it until SVG is parsed
809 mnSizeBytes = tmp.second;
811 else
813 mnSizeBytes = mpAnimation ? mpAnimation->GetSizeBytes() : maEx.GetSizeBytes();
816 else if( meType == GraphicType::GdiMetafile )
818 mnSizeBytes = maMetaFile.GetSizeBytes();
822 return mnSizeBytes;
825 void ImpGraphic::ImplDraw( OutputDevice* pOutDev, const Point& rDestPt ) const
827 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() )
829 switch( meType )
831 case GraphicType::Default:
832 break;
834 case GraphicType::Bitmap:
836 if(maSvgData.get() && !maEx)
838 // use maEx as local buffer for rendered svg
839 const_cast< ImpGraphic* >(this)->maEx = maSvgData->getReplacement();
842 if ( mpAnimation )
844 mpAnimation->Draw( pOutDev, rDestPt );
846 else
848 maEx.Draw( pOutDev, rDestPt );
851 break;
853 default:
854 ImplDraw( pOutDev, rDestPt, maMetaFile.GetPrefSize() );
855 break;
860 void ImpGraphic::ImplDraw( OutputDevice* pOutDev,
861 const Point& rDestPt, const Size& rDestSize ) const
863 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() )
865 switch( meType )
867 case GraphicType::Default:
868 break;
870 case GraphicType::Bitmap:
872 if(maSvgData.get() && maEx.IsEmpty())
874 // use maEx as local buffer for rendered svg
875 const_cast< ImpGraphic* >(this)->maEx = maSvgData->getReplacement();
878 if( mpAnimation )
880 mpAnimation->Draw( pOutDev, rDestPt, rDestSize );
882 else
884 maEx.Draw( pOutDev, rDestPt, rDestSize );
887 break;
889 default:
891 const_cast<ImpGraphic*>(this)->maMetaFile.WindStart();
892 const_cast<ImpGraphic*>(this)->maMetaFile.Play( pOutDev, rDestPt, rDestSize );
893 const_cast<ImpGraphic*>(this)->maMetaFile.WindStart();
895 break;
900 void ImpGraphic::ImplStartAnimation( OutputDevice* pOutDev, const Point& rDestPt,
901 const Size& rDestSize, long nExtraData,
902 OutputDevice* pFirstFrameOutDev )
904 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation )
905 mpAnimation->Start( pOutDev, rDestPt, rDestSize, nExtraData, pFirstFrameOutDev );
908 void ImpGraphic::ImplStopAnimation( OutputDevice* pOutDev, long nExtraData )
910 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation )
911 mpAnimation->Stop( pOutDev, nExtraData );
914 void ImpGraphic::ImplSetAnimationNotifyHdl( const Link<Animation*,void>& rLink )
916 if( mpAnimation )
917 mpAnimation->SetNotifyHdl( rLink );
920 Link<Animation*,void> ImpGraphic::ImplGetAnimationNotifyHdl() const
922 Link<Animation*,void> aLink;
924 if( mpAnimation )
925 aLink = mpAnimation->GetNotifyHdl();
927 return aLink;
930 sal_uLong ImpGraphic::ImplGetAnimationLoopCount() const
932 return( mpAnimation ? mpAnimation->GetLoopCount() : 0UL );
936 void ImpGraphic::ImplSetContext( const std::shared_ptr<GraphicReader>& pReader )
938 mpContext = pReader;
939 mbDummyContext = false;
942 bool ImpGraphic::ImplReadEmbedded( SvStream& rIStm )
944 MapMode aMapMode;
945 Size aSize;
946 sal_uInt32 nId;
947 sal_Int32 nType;
948 const SvStreamEndian nOldFormat = rIStm.GetEndian();
949 bool bRet = false;
951 rIStm.SetEndian( SvStreamEndian::LITTLE );
952 rIStm.ReadUInt32( nId );
954 // check version
955 if( GRAPHIC_FORMAT_50 == nId )
957 // read new style header
958 std::unique_ptr<VersionCompat> pCompat( new VersionCompat( rIStm, StreamMode::READ ) );
960 rIStm.ReadInt32( nType );
961 sal_Int32 nLen;
962 rIStm.ReadInt32( nLen );
963 ReadPair( rIStm, aSize );
964 ReadMapMode( rIStm, aMapMode );
966 else
968 // read old style header
969 sal_Int32 nWidth, nHeight;
970 sal_Int32 nMapMode, nScaleNumX, nScaleDenomX;
971 sal_Int32 nScaleNumY, nScaleDenomY, nOffsX, nOffsY;
973 rIStm.SeekRel( -4 );
975 sal_Int32 nLen;
976 rIStm.ReadInt32( nType ).ReadInt32( nLen ).ReadInt32( nWidth ).ReadInt32( nHeight );
977 rIStm.ReadInt32( nMapMode ).ReadInt32( nScaleNumX ).ReadInt32( nScaleDenomX ).ReadInt32( nScaleNumY );
978 rIStm.ReadInt32( nScaleDenomY ).ReadInt32( nOffsX ).ReadInt32( nOffsY );
980 // swapped
981 if( nType > 100 )
983 nType = OSL_SWAPDWORD( nType );
984 nWidth = OSL_SWAPDWORD( nWidth );
985 nHeight = OSL_SWAPDWORD( nHeight );
986 nMapMode = OSL_SWAPDWORD( nMapMode );
987 nScaleNumX = OSL_SWAPDWORD( nScaleNumX );
988 nScaleDenomX = OSL_SWAPDWORD( nScaleDenomX );
989 nScaleNumY = OSL_SWAPDWORD( nScaleNumY );
990 nScaleDenomY = OSL_SWAPDWORD( nScaleDenomY );
991 nOffsX = OSL_SWAPDWORD( nOffsX );
992 nOffsY = OSL_SWAPDWORD( nOffsY );
995 aSize = Size( nWidth, nHeight );
996 aMapMode = MapMode( (MapUnit) nMapMode, Point( nOffsX, nOffsY ),
997 Fraction( nScaleNumX, nScaleDenomX ),
998 Fraction( nScaleNumY, nScaleDenomY ) );
1001 meType = (GraphicType) nType;
1003 if( meType != GraphicType::NONE )
1005 if( meType == GraphicType::Bitmap )
1007 if(maSvgData.get() && maEx.IsEmpty())
1009 // use maEx as local buffer for rendered svg
1010 maEx = maSvgData->getReplacement();
1013 maEx.aBitmapSize = aSize;
1015 if( aMapMode != MapMode() )
1017 maEx.SetPrefMapMode( aMapMode );
1018 maEx.SetPrefSize( aSize );
1021 else
1023 maMetaFile.SetPrefMapMode( aMapMode );
1024 maMetaFile.SetPrefSize( aSize );
1027 if( meType == GraphicType::Bitmap || meType == GraphicType::GdiMetafile )
1029 ReadImpGraphic( rIStm, *this );
1030 bRet = ( rIStm.GetError() == 0UL );
1032 else if( sal::static_int_cast<sal_uLong>(meType) >= SYS_WINMETAFILE
1033 && sal::static_int_cast<sal_uLong>(meType) <= SYS_MACMETAFILE )
1035 Graphic aSysGraphic;
1036 ConvertDataFormat nCvtType;
1038 switch( sal::static_int_cast<sal_uLong>(meType) )
1040 case SYS_WINMETAFILE:
1041 case SYS_WNTMETAFILE: nCvtType = ConvertDataFormat::WMF; break;
1042 case SYS_OS2METAFILE: nCvtType = ConvertDataFormat::MET; break;
1043 case SYS_MACMETAFILE: nCvtType = ConvertDataFormat::PCT; break;
1045 default:
1046 nCvtType = ConvertDataFormat::Unknown;
1047 break;
1050 if( nType && GraphicConverter::Import( rIStm, aSysGraphic, nCvtType ) == ERRCODE_NONE )
1052 *this = ImpGraphic( aSysGraphic.GetGDIMetaFile() );
1053 bRet = ( rIStm.GetError() == 0UL );
1055 else
1056 meType = GraphicType::Default;
1059 if( bRet )
1061 ImplSetPrefMapMode( aMapMode );
1062 ImplSetPrefSize( aSize );
1065 else
1066 bRet = true;
1068 rIStm.SetEndian( nOldFormat );
1070 return bRet;
1073 bool ImpGraphic::ImplWriteEmbedded( SvStream& rOStm )
1075 bool bRet = false;
1077 if( ( meType != GraphicType::NONE ) && ( meType != GraphicType::Default ) && !ImplIsSwapOut() )
1079 const MapMode aMapMode( ImplGetPrefMapMode() );
1080 const Size aSize( ImplGetPrefSize() );
1081 const SvStreamEndian nOldFormat = rOStm.GetEndian();
1082 sal_uLong nDataFieldPos;
1084 rOStm.SetEndian( SvStreamEndian::LITTLE );
1086 // write correct version ( old style/new style header )
1087 if( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50 )
1089 // write ID for new format (5.0)
1090 rOStm.WriteUInt32( GRAPHIC_FORMAT_50 );
1092 // write new style header
1093 std::unique_ptr<VersionCompat> pCompat( new VersionCompat( rOStm, StreamMode::WRITE, 1 ) );
1095 rOStm.WriteInt32( (sal_Int32)meType );
1097 // data size is updated later
1098 nDataFieldPos = rOStm.Tell();
1099 rOStm.WriteInt32( 0 );
1101 WritePair( rOStm, aSize );
1102 WriteMapMode( rOStm, aMapMode );
1104 else
1106 // write old style (<=4.0) header
1107 rOStm.WriteInt32( (sal_Int32)meType );
1109 // data size is updated later
1110 nDataFieldPos = rOStm.Tell();
1111 rOStm.WriteInt32( 0 );
1112 rOStm.WriteInt32( aSize.Width() );
1113 rOStm.WriteInt32( aSize.Height() );
1114 rOStm.WriteInt32( (sal_uInt16)aMapMode.GetMapUnit() );
1115 rOStm.WriteInt32( aMapMode.GetScaleX().GetNumerator() );
1116 rOStm.WriteInt32( aMapMode.GetScaleX().GetDenominator() );
1117 rOStm.WriteInt32( aMapMode.GetScaleY().GetNumerator() );
1118 rOStm.WriteInt32( aMapMode.GetScaleY().GetDenominator() );
1119 rOStm.WriteInt32( aMapMode.GetOrigin().X() );
1120 rOStm.WriteInt32( aMapMode.GetOrigin().Y() );
1123 // write data block
1124 if( !rOStm.GetError() )
1126 const sal_uLong nDataStart = rOStm.Tell();
1128 if( ImplIsSupportedGraphic() )
1129 WriteImpGraphic( rOStm, *this );
1131 if( !rOStm.GetError() )
1133 const sal_uLong nStmPos2 = rOStm.Tell();
1134 rOStm.Seek( nDataFieldPos );
1135 rOStm.WriteInt32( nStmPos2 - nDataStart );
1136 rOStm.Seek( nStmPos2 );
1137 bRet = true;
1141 rOStm.SetEndian( nOldFormat );
1144 return bRet;
1147 bool ImpGraphic::ImplSwapOut()
1149 bool bRet = false;
1151 if( !ImplIsSwapOut() )
1153 ::utl::TempFile aTempFile;
1154 const INetURLObject aTmpURL( aTempFile.GetURL() );
1156 if( !aTmpURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ).isEmpty() )
1158 std::unique_ptr<SvStream> xOStm;
1161 xOStm.reset(::utl::UcbStreamHelper::CreateStream( aTmpURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE ));
1163 catch( const css::uno::Exception& )
1166 if( xOStm )
1168 xOStm->SetVersion( SOFFICE_FILEFORMAT_50 );
1169 xOStm->SetCompressMode( SvStreamCompressFlags::NATIVE );
1171 bRet = ImplSwapOut( xOStm.get() );
1172 if( bRet )
1174 mpSwapFile = o3tl::make_unique<ImpSwapFile>();
1175 mpSwapFile->aSwapURL = aTmpURL;
1177 else
1179 xOStm.reset();
1183 ::ucbhelper::Content aCnt( aTmpURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
1184 css::uno::Reference< css::ucb::XCommandEnvironment >(),
1185 comphelper::getProcessComponentContext() );
1187 aCnt.executeCommand( "delete", css::uno::makeAny( true ) );
1189 catch( const css::ucb::ContentCreationException& )
1192 catch( const css::uno::RuntimeException& )
1195 catch( const css::ucb::CommandAbortedException& )
1198 catch( const css::uno::Exception& )
1206 return bRet;
1209 void ImpGraphic::ImplSwapOutAsLink()
1211 ImplCreateSwapInfo();
1212 ImplClearGraphics();
1213 mbSwapOut = true;
1216 bool ImpGraphic::ImplSwapOut( SvStream* xOStm )
1218 bool bRet = false;
1220 if( xOStm )
1222 xOStm->SetBufferSize( GRAPHIC_STREAMBUFSIZE );
1224 if( !xOStm->GetError() && ImplWriteEmbedded( *xOStm ) )
1226 xOStm->Flush();
1228 if( !xOStm->GetError() )
1230 ImplCreateSwapInfo();
1231 ImplClearGraphics();
1232 bRet = mbSwapOut = true;
1236 else
1238 SAL_WARN("vcl.gdi", "Graphic SwapOut: No stream for swap out!");
1241 return bRet;
1244 bool ImpGraphic::ImplSwapIn()
1246 bool bRet = false;
1248 if( ImplIsSwapOut() )
1250 OUString aSwapURL;
1252 if( mpSwapFile )
1253 aSwapURL = mpSwapFile->aSwapURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1255 if( !aSwapURL.isEmpty() )
1257 std::unique_ptr<SvStream> xIStm;
1260 xIStm.reset(::utl::UcbStreamHelper::CreateStream( aSwapURL, StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE ));
1262 catch( const css::uno::Exception& )
1266 if( xIStm )
1268 xIStm->SetVersion( SOFFICE_FILEFORMAT_50 );
1269 xIStm->SetCompressMode( SvStreamCompressFlags::NATIVE );
1271 bRet = ImplSwapIn( xIStm.get() );
1272 xIStm.reset();
1274 mpSwapFile.reset();
1279 return bRet;
1282 bool ImpGraphic::ImplSwapIn( SvStream* xIStm )
1284 bool bRet = false;
1286 if( xIStm )
1288 xIStm->SetBufferSize( GRAPHIC_STREAMBUFSIZE );
1290 if( !xIStm->GetError() )
1292 //keep the swap file alive, because its quite possibly the backing storage
1293 //for xIStm
1294 std::shared_ptr<ImpSwapFile> xSwapFile(std::move(mpSwapFile));
1295 assert(!mpSwapFile);
1297 std::shared_ptr<GraphicReader> xContext(std::move(mpContext));
1298 assert(!mpContext);
1300 bool bDummyContext = mbDummyContext;
1301 mbDummyContext = false;
1303 bRet = ImplReadEmbedded( *xIStm );
1305 //restore ownership of the swap file and context
1306 mpSwapFile = std::move(xSwapFile);
1307 mpContext = std::move(xContext);
1308 mbDummyContext = bDummyContext;
1310 if (!bRet)
1312 //throw away swapfile, etc.
1313 ImplClear();
1316 mbSwapOut = false;
1320 return bRet;
1323 void ImpGraphic::ImplSetLink( const GfxLink& rGfxLink )
1325 mpGfxLink = o3tl::make_unique<GfxLink>( rGfxLink );
1327 if( mpGfxLink->IsNative() )
1328 mpGfxLink->SwapOut();
1331 GfxLink ImpGraphic::ImplGetLink()
1333 return( mpGfxLink ? *mpGfxLink : GfxLink() );
1336 bool ImpGraphic::ImplIsLink() const
1338 return ( bool(mpGfxLink) );
1341 BitmapChecksum ImpGraphic::ImplGetChecksum() const
1343 BitmapChecksum nRet = 0;
1345 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() )
1347 switch( meType )
1349 case GraphicType::Default:
1350 break;
1352 case GraphicType::Bitmap:
1354 if(maSvgData.get() && maEx.IsEmpty())
1356 // use maEx as local buffer for rendered svg
1357 const_cast< ImpGraphic* >(this)->maEx = maSvgData->getReplacement();
1360 if( mpAnimation )
1362 nRet = mpAnimation->GetChecksum();
1364 else
1366 nRet = maEx.GetChecksum();
1369 if (maPdfData.hasElements())
1370 // Include the PDF data in the checksum, so a metafile with
1371 // and without PDF data is considered to be different.
1372 nRet = vcl_get_checksum(nRet, maPdfData.getConstArray(), maPdfData.getLength());
1374 break;
1376 default:
1377 nRet = maMetaFile.GetChecksum();
1378 break;
1382 return nRet;
1385 bool ImpGraphic::ImplExportNative( SvStream& rOStm ) const
1387 bool bResult = false;
1389 if( !rOStm.GetError() )
1391 if( !ImplIsSwapOut() )
1393 if( mpGfxLink && mpGfxLink->IsNative() )
1394 bResult = mpGfxLink->ExportNative( rOStm );
1395 else
1397 WriteImpGraphic( rOStm, *this );
1398 bResult = ( rOStm.GetError() == ERRCODE_NONE );
1401 else
1402 rOStm.SetError( SVSTREAM_GENERALERROR );
1405 return bResult;
1409 void ReadImpGraphic( SvStream& rIStm, ImpGraphic& rImpGraphic )
1411 if (rIStm.GetError())
1412 return;
1414 const sal_uLong nStmPos1 = rIStm.Tell();
1415 sal_uInt32 nTmp;
1417 rImpGraphic.ImplClear();
1419 // read Id
1420 rIStm.ReadUInt32( nTmp );
1422 // if there is no more data, avoid further expensive
1423 // reading which will create VDevs and other stuff, just to
1424 // read nothing. CAUTION: Eof is only true AFTER reading another
1425 // byte, a speciality of SvMemoryStream (!)
1426 if (rIStm.GetError() || rIStm.IsEof())
1427 return;
1429 if (NATIVE_FORMAT_50 == nTmp)
1431 Graphic aGraphic;
1432 GfxLink aLink;
1434 // read compat info
1435 std::unique_ptr<VersionCompat> pCompat(new VersionCompat( rIStm, StreamMode::READ ));
1436 pCompat.reset(); // destructor writes stuff into the header
1438 ReadGfxLink( rIStm, aLink );
1440 // set dummy link to avoid creation of additional link after filtering;
1441 // we set a default link to avoid unnecessary swapping of native data
1442 aGraphic.SetLink( GfxLink() );
1444 if( !rIStm.GetError() && aLink.LoadNative( aGraphic ) )
1446 // set link only, if no other link was set
1447 const bool bSetLink = ( !rImpGraphic.mpGfxLink );
1449 // assign graphic
1450 rImpGraphic = *aGraphic.ImplGetImpGraphic();
1452 if( aLink.IsPrefMapModeValid() )
1453 rImpGraphic.ImplSetPrefMapMode( aLink.GetPrefMapMode() );
1455 if( aLink.IsPrefSizeValid() )
1456 rImpGraphic.ImplSetPrefSize( aLink.GetPrefSize() );
1458 if( bSetLink )
1459 rImpGraphic.ImplSetLink( aLink );
1461 else
1463 rIStm.Seek( nStmPos1 );
1464 rIStm.SetError( ERRCODE_IO_WRONGFORMAT );
1466 return;
1469 BitmapEx aBmpEx;
1470 const SvStreamEndian nOldFormat = rIStm.GetEndian();
1472 rIStm.SeekRel( -4 );
1473 rIStm.SetEndian( SvStreamEndian::LITTLE );
1474 ReadDIBBitmapEx(aBmpEx, rIStm);
1476 if( !rIStm.GetError() )
1478 sal_uInt32 nMagic1(0), nMagic2(0);
1479 sal_uLong nActPos = rIStm.Tell();
1481 rIStm.ReadUInt32( nMagic1 ).ReadUInt32( nMagic2 );
1482 rIStm.Seek( nActPos );
1484 rImpGraphic = ImpGraphic( aBmpEx );
1486 if( !rIStm.GetError() && ( 0x5344414e == nMagic1 ) && ( 0x494d4931 == nMagic2 ) )
1488 rImpGraphic.mpAnimation = o3tl::make_unique<Animation>();
1489 ReadAnimation( rIStm, *rImpGraphic.mpAnimation );
1491 // #108077# manually set loaded BmpEx to Animation
1492 // (which skips loading its BmpEx if already done)
1493 rImpGraphic.mpAnimation->SetBitmapEx(aBmpEx);
1495 else
1496 rIStm.ResetError();
1498 else
1500 GDIMetaFile aMtf;
1502 rIStm.Seek( nStmPos1 );
1503 rIStm.ResetError();
1504 ReadGDIMetaFile( rIStm, aMtf );
1506 if( !rIStm.GetError() )
1508 rImpGraphic = aMtf;
1510 else
1512 sal_uInt32 nOrigError = rIStm.GetErrorCode();
1513 // try to stream in Svg defining data (length, byte array and evtl. path)
1514 // See below (operator<<) for more information
1515 const sal_uInt32 nSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0'));
1516 sal_uInt32 nMagic;
1517 rIStm.Seek(nStmPos1);
1518 rIStm.ResetError();
1519 rIStm.ReadUInt32( nMagic );
1521 if (nSvgMagic == nMagic)
1523 sal_uInt32 nSvgDataArrayLength(0);
1524 rIStm.ReadUInt32(nSvgDataArrayLength);
1526 if (nSvgDataArrayLength)
1528 SvgDataArray aNewData(nSvgDataArrayLength);
1530 rIStm.ReadBytes(aNewData.getArray(), nSvgDataArrayLength);
1531 OUString aPath = rIStm.ReadUniOrByteString(rIStm.GetStreamCharSet());
1533 if (!rIStm.GetError())
1535 SvgDataPtr aSvgDataPtr(new SvgData(aNewData, aPath));
1536 rImpGraphic = aSvgDataPtr;
1540 else if (nMagic == nPdfMagic)
1542 // Stream in PDF data.
1543 sal_uInt32 nPdfDataLength = 0;
1544 rIStm.ReadUInt32(nPdfDataLength);
1546 if (nPdfDataLength)
1548 uno::Sequence<sal_Int8> aPdfData(nPdfDataLength);
1549 rIStm.ReadBytes(aPdfData.getArray(), nPdfDataLength);
1550 if (!rIStm.GetError())
1551 rImpGraphic.maPdfData = aPdfData;
1554 else
1556 rIStm.SetError(nOrigError);
1559 rIStm.Seek(nStmPos1);
1563 rIStm.SetEndian( nOldFormat );
1566 void WriteImpGraphic(SvStream& rOStm, const ImpGraphic& rImpGraphic)
1568 if (rOStm.GetError())
1569 return;
1571 if (rImpGraphic.ImplIsSwapOut())
1573 rOStm.SetError( SVSTREAM_GENERALERROR );
1574 return;
1577 if( ( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50 ) &&
1578 ( rOStm.GetCompressMode() & SvStreamCompressFlags::NATIVE ) &&
1579 rImpGraphic.mpGfxLink && rImpGraphic.mpGfxLink->IsNative() &&
1580 !rImpGraphic.maPdfData.hasElements())
1582 // native format
1583 rOStm.WriteUInt32( NATIVE_FORMAT_50 );
1585 // write compat info
1586 std::unique_ptr<VersionCompat> pCompat(new VersionCompat( rOStm, StreamMode::WRITE, 1 ));
1587 pCompat.reset(); // destructor writes stuff into the header
1589 rImpGraphic.mpGfxLink->SetPrefMapMode( rImpGraphic.ImplGetPrefMapMode() );
1590 rImpGraphic.mpGfxLink->SetPrefSize( rImpGraphic.ImplGetPrefSize() );
1591 WriteGfxLink( rOStm, *rImpGraphic.mpGfxLink );
1593 else
1595 // own format
1596 const SvStreamEndian nOldFormat = rOStm.GetEndian();
1597 rOStm.SetEndian( SvStreamEndian::LITTLE );
1599 switch( rImpGraphic.ImplGetType() )
1601 case GraphicType::NONE:
1602 case GraphicType::Default:
1603 break;
1605 case GraphicType::Bitmap:
1607 if(rImpGraphic.getSvgData().get())
1609 // stream out Svg defining data (length, byte array and evtl. path)
1610 // this is used e.g. in swapping out graphic data and in transporting it over UNO API
1611 // as sequence of bytes, but AFAIK not written anywhere to any kind of file, so it should be
1612 // no problem to extend it; only used at runtime
1613 const sal_uInt32 nSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0'));
1615 rOStm.WriteUInt32( nSvgMagic );
1616 rOStm.WriteUInt32( rImpGraphic.getSvgData()->getSvgDataArrayLength() );
1617 rOStm.WriteBytes(rImpGraphic.getSvgData()->getSvgDataArray().getConstArray(),
1618 rImpGraphic.getSvgData()->getSvgDataArrayLength());
1619 rOStm.WriteUniOrByteString(rImpGraphic.getSvgData()->getPath(),
1620 rOStm.GetStreamCharSet());
1622 else if (rImpGraphic.maPdfData.hasElements())
1624 // Stream out PDF data.
1625 rOStm.WriteUInt32(nPdfMagic);
1626 rOStm.WriteUInt32(rImpGraphic.maPdfData.getLength());
1627 rOStm.WriteBytes(rImpGraphic.maPdfData.getConstArray(), rImpGraphic.maPdfData.getLength());
1629 else if( rImpGraphic.ImplIsAnimated())
1631 WriteAnimation( rOStm, *rImpGraphic.mpAnimation );
1633 else
1635 WriteDIBBitmapEx(rImpGraphic.maEx, rOStm);
1638 break;
1640 default:
1642 if( rImpGraphic.ImplIsSupportedGraphic() )
1643 WriteGDIMetaFile( rOStm, rImpGraphic.maMetaFile );
1645 break;
1648 rOStm.SetEndian( nOldFormat );
1652 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */