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"
22 #include <comphelper/processfactory.hxx>
23 #include <tools/fract.hxx>
24 #include <tools/vcompat.hxx>
25 #include <tools/urlobj.hxx>
26 #include <tools/debug.hxx>
27 #include <tools/stream.hxx>
28 #include <tools/helpers.hxx>
29 #include <ucbhelper/content.hxx>
30 #include <unotools/ucbstreamhelper.hxx>
31 #include <unotools/tempfile.hxx>
32 #include <vcl/outdev.hxx>
33 #include <vcl/virdev.hxx>
34 #include <vcl/gfxlink.hxx>
35 #include <vcl/cvtgrf.hxx>
36 #include <vcl/graph.hxx>
37 #include <vcl/metaact.hxx>
38 #include <impgraph.hxx>
39 #include <com/sun/star/ucb/CommandAbortedException.hpp>
40 #include <vcl/dibtools.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 static_cast<sal_uInt32>(COMPAT_FORMAT( 'G', 'R', 'F', '5' ))
52 #define NATIVE_FORMAT_50 static_cast<sal_uInt32>(COMPAT_FORMAT( 'N', 'A', 'T', '5' ))
56 INetURLObject aSwapURL
;
66 GraphicReader::~GraphicReader()
71 void GraphicReader::DisablePreviewMode()
74 mpReaderData
->maPreviewSize
= Size( 0, 0 );
77 void GraphicReader::SetPreviewSize( const Size
& rSize
)
80 mpReaderData
= new ReaderData
;
81 mpReaderData
->maPreviewSize
= rSize
;
84 Size
GraphicReader::GetPreviewSize() const
88 aSize
= mpReaderData
->maPreviewSize
;
92 ImpGraphic::ImpGraphic() :
97 meType ( GRAPHIC_NONE
),
101 mbSwapUnderway ( false )
105 ImpGraphic::ImpGraphic( const ImpGraphic
& rImpGraphic
) :
106 maMetaFile ( rImpGraphic
.maMetaFile
),
107 maEx ( rImpGraphic
.maEx
),
109 mpSwapFile ( rImpGraphic
.mpSwapFile
),
110 meType ( rImpGraphic
.meType
),
111 mnSizeBytes ( rImpGraphic
.mnSizeBytes
),
113 mbSwapOut ( rImpGraphic
.mbSwapOut
),
114 mbSwapUnderway ( false )
117 mpSwapFile
->nRefCount
++;
119 if( rImpGraphic
.mpGfxLink
)
120 mpGfxLink
= new GfxLink( *rImpGraphic
.mpGfxLink
);
124 if( rImpGraphic
.mpAnimation
)
126 mpAnimation
= new Animation( *rImpGraphic
.mpAnimation
);
127 maEx
= mpAnimation
->GetBitmapEx();
132 maSvgData
= rImpGraphic
.maSvgData
;
135 ImpGraphic::ImpGraphic( const Bitmap
& rBitmap
) :
137 mpAnimation ( NULL
),
141 meType ( !rBitmap
.IsEmpty() ? GRAPHIC_BITMAP
: GRAPHIC_NONE
),
145 mbSwapUnderway ( false )
149 ImpGraphic::ImpGraphic( const BitmapEx
& rBitmapEx
) :
151 mpAnimation ( NULL
),
155 meType ( !rBitmapEx
.IsEmpty() ? GRAPHIC_BITMAP
: GRAPHIC_NONE
),
159 mbSwapUnderway ( false )
163 ImpGraphic::ImpGraphic(const SvgDataPtr
& rSvgDataPtr
)
164 : mpAnimation( NULL
),
168 meType( rSvgDataPtr
.get() ? GRAPHIC_BITMAP
: GRAPHIC_NONE
),
172 mbSwapUnderway( false ),
173 maSvgData(rSvgDataPtr
)
177 ImpGraphic::ImpGraphic( const Animation
& rAnimation
) :
178 maEx ( rAnimation
.GetBitmapEx() ),
179 mpAnimation ( new Animation( rAnimation
) ),
183 meType ( GRAPHIC_BITMAP
),
187 mbSwapUnderway ( false )
191 ImpGraphic::ImpGraphic( const GDIMetaFile
& rMtf
) :
193 mpAnimation ( NULL
),
197 meType ( GRAPHIC_GDIMETAFILE
),
201 mbSwapUnderway ( false )
205 ImpGraphic::~ImpGraphic()
209 if( reinterpret_cast<sal_uLong
>(mpContext
) > 1UL )
213 ImpGraphic
& ImpGraphic::operator=( const ImpGraphic
& rImpGraphic
)
215 if( &rImpGraphic
!= this )
217 if( !mbSwapUnderway
)
220 maMetaFile
= rImpGraphic
.maMetaFile
;
221 meType
= rImpGraphic
.meType
;
222 mnSizeBytes
= rImpGraphic
.mnSizeBytes
;
226 if ( rImpGraphic
.mpAnimation
)
228 mpAnimation
= new Animation( *rImpGraphic
.mpAnimation
);
229 maEx
= mpAnimation
->GetBitmapEx();
234 maEx
= rImpGraphic
.maEx
;
237 if( !mbSwapUnderway
)
239 mbSwapOut
= rImpGraphic
.mbSwapOut
;
240 mpSwapFile
= rImpGraphic
.mpSwapFile
;
243 mpSwapFile
->nRefCount
++;
248 if( rImpGraphic
.mpGfxLink
)
249 mpGfxLink
= new GfxLink( *rImpGraphic
.mpGfxLink
);
253 maSvgData
= rImpGraphic
.maSvgData
;
259 bool ImpGraphic::operator==( const ImpGraphic
& rImpGraphic
) const
263 if( this == &rImpGraphic
)
265 else if( !ImplIsSwapOut() && ( rImpGraphic
.meType
== meType
) )
269 case( GRAPHIC_NONE
):
273 case( GRAPHIC_GDIMETAFILE
):
275 if( rImpGraphic
.maMetaFile
== maMetaFile
)
280 case( GRAPHIC_BITMAP
):
284 if(maSvgData
== rImpGraphic
.maSvgData
)
288 else if(rImpGraphic
.maSvgData
)
290 if(maSvgData
->getSvgDataArrayLength() == rImpGraphic
.maSvgData
->getSvgDataArrayLength())
293 maSvgData
->getSvgDataArray().get(),
294 rImpGraphic
.maSvgData
->getSvgDataArray().get(),
295 maSvgData
->getSvgDataArrayLength()))
302 else if( mpAnimation
)
304 if( rImpGraphic
.mpAnimation
&& ( *rImpGraphic
.mpAnimation
== *mpAnimation
) )
307 else if( !rImpGraphic
.mpAnimation
&& ( rImpGraphic
.maEx
== maEx
) )
322 void ImpGraphic::ImplClearGraphics( bool bCreateSwapInfo
)
324 if( bCreateSwapInfo
&& !ImplIsSwapOut() )
326 maSwapInfo
.maPrefMapMode
= ImplGetPrefMapMode();
327 maSwapInfo
.maPrefSize
= ImplGetPrefSize();
335 mpAnimation
->Clear();
349 void ImpGraphic::ImplClear()
353 if( mpSwapFile
->nRefCount
> 1 )
354 mpSwapFile
->nRefCount
--;
359 ::ucbhelper::Content
aCnt( mpSwapFile
->aSwapURL
.GetMainURL( INetURLObject::NO_DECODE
),
360 ::com::sun::star::uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
>(),
361 comphelper::getProcessComponentContext() );
363 aCnt
.executeCommand( OUString("delete"),
364 ::com::sun::star::uno::makeAny( true ) );
366 catch( const ::com::sun::star::ucb::ContentCreationException
& )
369 catch( const ::com::sun::star::uno::RuntimeException
& )
372 catch( const ::com::sun::star::ucb::CommandAbortedException
& )
375 catch( const ::com::sun::star::uno::Exception
& )
388 ImplClearGraphics( false );
389 meType
= GRAPHIC_NONE
;
394 void ImpGraphic::ImplSetDefaultType()
397 meType
= GRAPHIC_DEFAULT
;
400 bool ImpGraphic::ImplIsSupportedGraphic() const
402 return( meType
!= GRAPHIC_NONE
);
405 bool ImpGraphic::ImplIsTransparent() const
409 if( meType
== GRAPHIC_BITMAP
&& !maSvgData
.get())
411 bRet
= ( mpAnimation
? mpAnimation
->IsTransparent() : maEx
.IsTransparent() );
417 bool ImpGraphic::ImplIsAlpha() const
425 else if( meType
== GRAPHIC_BITMAP
)
427 bRet
= ( NULL
== mpAnimation
) && maEx
.IsAlpha();
433 bool ImpGraphic::ImplIsAnimated() const
435 return( mpAnimation
!= NULL
);
438 bool ImpGraphic::ImplIsEPS() const
440 return( ( meType
== GRAPHIC_GDIMETAFILE
) &&
441 ( maMetaFile
.GetActionSize() > 0 ) &&
442 ( maMetaFile
.GetAction( 0 )->GetType() == MetaActionType::EPS
) );
445 Bitmap
ImpGraphic::ImplGetBitmap(const GraphicConversionParameters
& rParameters
) const
449 if( meType
== GRAPHIC_BITMAP
)
451 if(maSvgData
.get() && maEx
.IsEmpty())
453 // use maEx as local buffer for rendered svg
454 const_cast< ImpGraphic
* >(this)->maEx
= maSvgData
->getReplacement();
457 const BitmapEx
& rRetBmpEx
= ( mpAnimation
? mpAnimation
->GetBitmapEx() : maEx
);
458 const Color
aReplaceColor( COL_WHITE
);
460 aRetBmp
= rRetBmpEx
.GetBitmap( &aReplaceColor
);
462 if(rParameters
.getSizePixel().Width() || rParameters
.getSizePixel().Height())
463 aRetBmp
.Scale(rParameters
.getSizePixel());
465 else if( ( meType
!= GRAPHIC_DEFAULT
) && ImplIsSupportedGraphic() )
470 ScopedVclPtrInstance
< VirtualDevice
> aVDev
;
471 Size
aDrawSize(aVDev
->LogicToPixel(maMetaFile
.GetPrefSize(), maMetaFile
.GetPrefMapMode()));
473 if(rParameters
.getSizePixel().Width() && rParameters
.getSizePixel().Height())
475 // apply given size if exists
476 aDrawSize
= rParameters
.getSizePixel();
479 if(aDrawSize
.Width() && aDrawSize
.Height() && !rParameters
.getUnlimitedSize()
480 && (aDrawSize
.Width() > GRAPHIC_MTFTOBMP_MAXEXT
|| aDrawSize
.Height() > GRAPHIC_MTFTOBMP_MAXEXT
))
482 // limit bitmap size to a maximum of GRAPHIC_MTFTOBMP_MAXEXT x GRAPHIC_MTFTOBMP_MAXEXT
483 double fWH((double)aDrawSize
.Width() / (double)aDrawSize
.Height());
487 aDrawSize
.setWidth(basegfx::fround(GRAPHIC_MTFTOBMP_MAXEXT
* fWH
));
488 aDrawSize
.setHeight(GRAPHIC_MTFTOBMP_MAXEXT
);
492 aDrawSize
.setWidth(GRAPHIC_MTFTOBMP_MAXEXT
);
493 aDrawSize
.setHeight(basegfx::fround(GRAPHIC_MTFTOBMP_MAXEXT
/ fWH
));
497 // calculate pixel size. Normally, it's the same as aDrawSize, but may
498 // need to be extended when hairlines are on the right or bottom edge
499 Size
aPixelSize(aDrawSize
);
501 if(GRAPHIC_GDIMETAFILE
== ImplGetType())
503 // get hairline and full bound rect
504 Rectangle aHairlineRect
;
505 const Rectangle
aRect(maMetaFile
.GetBoundRect(*aVDev
.get(), &aHairlineRect
));
507 if(!aRect
.IsEmpty() && !aHairlineRect
.IsEmpty())
509 // expand if needed to allow bottom and right hairlines to be added
510 if(aRect
.Right() == aHairlineRect
.Right())
512 aPixelSize
.setWidth(aPixelSize
.getWidth() + 1);
515 if(aRect
.Bottom() == aHairlineRect
.Bottom())
517 aPixelSize
.setHeight(aPixelSize
.getHeight() + 1);
522 if(aVDev
->SetOutputSizePixel(aPixelSize
))
524 if(rParameters
.getAntiAliase())
526 aVDev
->SetAntialiasing(aVDev
->GetAntialiasing() | AntialiasingFlags::EnableB2dDraw
);
529 if(rParameters
.getSnapHorVerLines())
531 aVDev
->SetAntialiasing(aVDev
->GetAntialiasing() | AntialiasingFlags::PixelSnapHairline
);
534 ImplDraw( aVDev
.get(), Point(), aDrawSize
);
536 // use maEx as local buffer for rendered metafile
537 const_cast< ImpGraphic
* >(this)->maEx
= aVDev
->GetBitmap( Point(), aVDev
->GetOutputSizePixel() );
541 aRetBmp
= maEx
.GetBitmap();
546 aRetBmp
.SetPrefMapMode( ImplGetPrefMapMode() );
547 aRetBmp
.SetPrefSize( ImplGetPrefSize() );
553 BitmapEx
ImpGraphic::ImplGetBitmapEx(const GraphicConversionParameters
& rParameters
) const
557 if( meType
== GRAPHIC_BITMAP
)
559 if(maSvgData
.get() && maEx
.IsEmpty())
561 // use maEx as local buffer for rendered svg
562 const_cast< ImpGraphic
* >(this)->maEx
= maSvgData
->getReplacement();
565 aRetBmpEx
= ( mpAnimation
? mpAnimation
->GetBitmapEx() : maEx
);
567 if(rParameters
.getSizePixel().Width() || rParameters
.getSizePixel().Height())
570 rParameters
.getSizePixel(),
571 rParameters
.getScaleHighQuality() ? BmpScaleFlag::Interpolate
: BmpScaleFlag::Fast
);
574 else if( ( meType
!= GRAPHIC_DEFAULT
) && ImplIsSupportedGraphic() )
578 const ImpGraphic
aMonoMask( maMetaFile
.GetMonochromeMtf( COL_BLACK
) );
580 // use maEx as local buffer for rendered metafile
581 const_cast< ImpGraphic
* >(this)->maEx
= BitmapEx(ImplGetBitmap(rParameters
), aMonoMask
.ImplGetBitmap(rParameters
));
590 Animation
ImpGraphic::ImplGetAnimation() const
592 Animation aAnimation
;
595 aAnimation
= *mpAnimation
;
600 const GDIMetaFile
& ImpGraphic::ImplGetGDIMetaFile() const
602 if (GRAPHIC_BITMAP
== meType
&& !maMetaFile
.GetActionSize())
605 // Use the local maMetaFile as container for a metafile-representation
606 // of the bitmap graphic. This will be done only once, thus be buffered.
607 // I checked all usages of maMetaFile, it is only used when type is not
608 // GRAPHIC_BITMAP. In operator= it will get copied, thus buffering will
609 // survive copying (change this if not wanted)
610 ImpGraphic
* pThat
= const_cast< ImpGraphic
* >(this);
612 if(maSvgData
.get() && !maEx
)
614 // use maEx as local buffer for rendered svg
615 pThat
->maEx
= maSvgData
->getReplacement();
618 // #123983# directly create a metafile with the same PrefSize and PrefMapMode
619 // the bitmap has, this will be an always correct metafile
620 if(maEx
.IsTransparent())
622 pThat
->maMetaFile
.AddAction(new MetaBmpExScaleAction(Point(), maEx
.GetPrefSize(), maEx
));
626 pThat
->maMetaFile
.AddAction(new MetaBmpScaleAction(Point(), maEx
.GetPrefSize(), maEx
.GetBitmap()));
629 pThat
->maMetaFile
.Stop();
630 pThat
->maMetaFile
.WindStart();
631 pThat
->maMetaFile
.SetPrefSize(maEx
.GetPrefSize());
632 pThat
->maMetaFile
.SetPrefMapMode(maEx
.GetPrefMapMode());
638 Size
ImpGraphic::ImplGetPrefSize() const
642 if( ImplIsSwapOut() )
643 aSize
= maSwapInfo
.maPrefSize
;
648 case( GRAPHIC_NONE
):
649 case( GRAPHIC_DEFAULT
):
652 case( GRAPHIC_BITMAP
):
654 if(maSvgData
.get() && maEx
.IsEmpty())
656 // svg not yet buffered in maEx, return size derived from range
657 const basegfx::B2DRange
& rRange
= maSvgData
->getRange();
659 aSize
= Size(basegfx::fround(rRange
.getWidth()), basegfx::fround(rRange
.getHeight()));
663 aSize
= maEx
.GetPrefSize();
665 if( !aSize
.Width() || !aSize
.Height() )
667 aSize
= maEx
.GetSizePixel();
675 if( ImplIsSupportedGraphic() )
676 aSize
= maMetaFile
.GetPrefSize();
685 void ImpGraphic::ImplSetPrefSize( const Size
& rPrefSize
)
689 case( GRAPHIC_NONE
):
690 case( GRAPHIC_DEFAULT
):
693 case( GRAPHIC_BITMAP
):
695 //UUUU used when importing a writer FlyFrame with SVG as graphic, added conversion
696 // to allow setting the PrefSize at the BitmapEx to hold it
697 if(maSvgData
.get() && maEx
.IsEmpty())
699 // use maEx as local buffer for rendered svg
700 const_cast< ImpGraphic
* >(this)->maEx
= maSvgData
->getReplacement();
703 // #108077# Push through pref size to animation object,
704 // will be lost on copy otherwise
705 if( ImplIsAnimated() )
707 const_cast< BitmapEx
& >(mpAnimation
->GetBitmapEx()).SetPrefSize( rPrefSize
);
710 maEx
.SetPrefSize( rPrefSize
);
716 if( ImplIsSupportedGraphic() )
717 maMetaFile
.SetPrefSize( rPrefSize
);
723 MapMode
ImpGraphic::ImplGetPrefMapMode() const
727 if( ImplIsSwapOut() )
728 aMapMode
= maSwapInfo
.maPrefMapMode
;
733 case( GRAPHIC_NONE
):
734 case( GRAPHIC_DEFAULT
):
737 case( GRAPHIC_BITMAP
):
739 if(maSvgData
.get() && maEx
.IsEmpty())
741 // svg not yet buffered in maEx, return default PrefMapMode
742 aMapMode
= MapMode(MAP_100TH_MM
);
746 const Size
aSize( maEx
.GetPrefSize() );
748 if ( aSize
.Width() && aSize
.Height() )
749 aMapMode
= maEx
.GetPrefMapMode();
756 if( ImplIsSupportedGraphic() )
757 return maMetaFile
.GetPrefMapMode();
766 void ImpGraphic::ImplSetPrefMapMode( const MapMode
& rPrefMapMode
)
770 case( GRAPHIC_NONE
):
771 case( GRAPHIC_DEFAULT
):
774 case( GRAPHIC_BITMAP
):
778 // ignore for Svg. If this is really used (except the grfcache)
779 // it can be extended by using maEx as buffer for maSvgData->getReplacement()
783 // #108077# Push through pref mapmode to animation object,
784 // will be lost on copy otherwise
785 if( ImplIsAnimated() )
787 const_cast< BitmapEx
& >(mpAnimation
->GetBitmapEx()).SetPrefMapMode( rPrefMapMode
);
790 maEx
.SetPrefMapMode( rPrefMapMode
);
797 if( ImplIsSupportedGraphic() )
798 maMetaFile
.SetPrefMapMode( rPrefMapMode
);
804 sal_uLong
ImpGraphic::ImplGetSizeBytes() const
806 if( 0 == mnSizeBytes
)
808 if( meType
== GRAPHIC_BITMAP
)
812 mnSizeBytes
= maSvgData
->getSvgDataArrayLength();
816 mnSizeBytes
= mpAnimation
? mpAnimation
->GetSizeBytes() : maEx
.GetSizeBytes();
819 else if( meType
== GRAPHIC_GDIMETAFILE
)
821 mnSizeBytes
= maMetaFile
.GetSizeBytes();
828 void ImpGraphic::ImplDraw( OutputDevice
* pOutDev
, const Point
& rDestPt
) const
830 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() )
834 case( GRAPHIC_DEFAULT
):
837 case( GRAPHIC_BITMAP
):
839 if(maSvgData
.get() && !maEx
)
841 // use maEx as local buffer for rendered svg
842 const_cast< ImpGraphic
* >(this)->maEx
= maSvgData
->getReplacement();
847 mpAnimation
->Draw( pOutDev
, rDestPt
);
851 maEx
.Draw( pOutDev
, rDestPt
);
857 ImplDraw( pOutDev
, rDestPt
, maMetaFile
.GetPrefSize() );
863 void ImpGraphic::ImplDraw( OutputDevice
* pOutDev
,
864 const Point
& rDestPt
, const Size
& rDestSize
) const
866 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() )
870 case( GRAPHIC_DEFAULT
):
873 case( GRAPHIC_BITMAP
):
875 if(maSvgData
.get() && maEx
.IsEmpty())
877 // use maEx as local buffer for rendered svg
878 const_cast< ImpGraphic
* >(this)->maEx
= maSvgData
->getReplacement();
883 mpAnimation
->Draw( pOutDev
, rDestPt
, rDestSize
);
887 maEx
.Draw( pOutDev
, rDestPt
, rDestSize
);
894 const_cast<ImpGraphic
*>(this)->maMetaFile
.WindStart();
895 const_cast<ImpGraphic
*>(this)->maMetaFile
.Play( pOutDev
, rDestPt
, rDestSize
);
896 const_cast<ImpGraphic
*>(this)->maMetaFile
.WindStart();
903 void ImpGraphic::ImplStartAnimation( OutputDevice
* pOutDev
, const Point
& rDestPt
,
904 const Size
& rDestSize
, long nExtraData
,
905 OutputDevice
* pFirstFrameOutDev
)
907 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation
)
908 mpAnimation
->Start( pOutDev
, rDestPt
, rDestSize
, nExtraData
, pFirstFrameOutDev
);
911 void ImpGraphic::ImplStopAnimation( OutputDevice
* pOutDev
, long nExtraData
)
913 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation
)
914 mpAnimation
->Stop( pOutDev
, nExtraData
);
917 void ImpGraphic::ImplSetAnimationNotifyHdl( const Link
<>& rLink
)
920 mpAnimation
->SetNotifyHdl( rLink
);
923 Link
<> ImpGraphic::ImplGetAnimationNotifyHdl() const
928 aLink
= mpAnimation
->GetNotifyHdl();
933 sal_uLong
ImpGraphic::ImplGetAnimationLoopCount() const
935 return( mpAnimation
? mpAnimation
->GetLoopCount() : 0UL );
939 void ImpGraphic::ImplSetContext( GraphicReader
* pReader
)
944 bool ImpGraphic::ImplReadEmbedded( SvStream
& rIStm
)
951 const SvStreamEndian nOldFormat
= rIStm
.GetEndian();
954 rIStm
.SetEndian( SvStreamEndian::LITTLE
);
955 rIStm
.ReadUInt32( nId
);
958 if( GRAPHIC_FORMAT_50
== nId
)
960 // read new style header
961 VersionCompat
* pCompat
= new VersionCompat( rIStm
, StreamMode::READ
);
963 rIStm
.ReadInt32( nType
);
964 rIStm
.ReadInt32( nLen
);
965 ReadPair( rIStm
, aSize
);
966 ReadMapMode( rIStm
, aMapMode
);
972 // read old style header
973 sal_Int32 nWidth
, nHeight
;
974 sal_Int32 nMapMode
, nScaleNumX
, nScaleDenomX
;
975 sal_Int32 nScaleNumY
, nScaleDenomY
, nOffsX
, nOffsY
;
977 rIStm
.SeekRel( -4L );
979 rIStm
.ReadInt32( nType
).ReadInt32( nLen
).ReadInt32( nWidth
).ReadInt32( nHeight
);
980 rIStm
.ReadInt32( nMapMode
).ReadInt32( nScaleNumX
).ReadInt32( nScaleDenomX
).ReadInt32( nScaleNumY
);
981 rIStm
.ReadInt32( nScaleDenomY
).ReadInt32( nOffsX
).ReadInt32( nOffsY
);
986 nType
= OSL_SWAPDWORD( nType
);
987 nLen
= OSL_SWAPDWORD( nLen
);
988 nWidth
= OSL_SWAPDWORD( nWidth
);
989 nHeight
= OSL_SWAPDWORD( nHeight
);
990 nMapMode
= OSL_SWAPDWORD( nMapMode
);
991 nScaleNumX
= OSL_SWAPDWORD( nScaleNumX
);
992 nScaleDenomX
= OSL_SWAPDWORD( nScaleDenomX
);
993 nScaleNumY
= OSL_SWAPDWORD( nScaleNumY
);
994 nScaleDenomY
= OSL_SWAPDWORD( nScaleDenomY
);
995 nOffsX
= OSL_SWAPDWORD( nOffsX
);
996 nOffsY
= OSL_SWAPDWORD( nOffsY
);
999 aSize
= Size( nWidth
, nHeight
);
1000 aMapMode
= MapMode( (MapUnit
) nMapMode
, Point( nOffsX
, nOffsY
),
1001 Fraction( nScaleNumX
, nScaleDenomX
),
1002 Fraction( nScaleNumY
, nScaleDenomY
) );
1005 meType
= (GraphicType
) nType
;
1009 if( meType
== GRAPHIC_BITMAP
)
1011 if(maSvgData
.get() && maEx
.IsEmpty())
1013 // use maEx as local buffer for rendered svg
1014 maEx
= maSvgData
->getReplacement();
1017 maEx
.aBitmapSize
= aSize
;
1019 if( aMapMode
!= MapMode() )
1021 maEx
.SetPrefMapMode( aMapMode
);
1022 maEx
.SetPrefSize( aSize
);
1027 maMetaFile
.SetPrefMapMode( aMapMode
);
1028 maMetaFile
.SetPrefSize( aSize
);
1031 if( meType
== GRAPHIC_BITMAP
|| meType
== GRAPHIC_GDIMETAFILE
)
1033 ReadImpGraphic( rIStm
, *this );
1034 bRet
= ( rIStm
.GetError() == 0UL );
1036 else if( sal::static_int_cast
<sal_uLong
>(meType
) >= SYS_WINMETAFILE
1037 && sal::static_int_cast
<sal_uLong
>(meType
) <= SYS_MACMETAFILE
)
1039 Graphic aSysGraphic
;
1042 switch( sal::static_int_cast
<sal_uLong
>(meType
) )
1044 case( SYS_WINMETAFILE
):
1045 case( SYS_WNTMETAFILE
): nCvtType
= CVT_WMF
; break;
1046 case( SYS_OS2METAFILE
): nCvtType
= CVT_MET
; break;
1047 case( SYS_MACMETAFILE
): nCvtType
= CVT_PCT
; break;
1050 nCvtType
= CVT_UNKNOWN
;
1054 if( nType
&& GraphicConverter::Import( rIStm
, aSysGraphic
, nCvtType
) == ERRCODE_NONE
)
1056 *this = ImpGraphic( aSysGraphic
.GetGDIMetaFile() );
1057 bRet
= ( rIStm
.GetError() == 0UL );
1060 meType
= GRAPHIC_DEFAULT
;
1065 ImplSetPrefMapMode( aMapMode
);
1066 ImplSetPrefSize( aSize
);
1072 rIStm
.SetEndian( nOldFormat
);
1077 bool ImpGraphic::ImplWriteEmbedded( SvStream
& rOStm
)
1081 if( ( meType
!= GRAPHIC_NONE
) && ( meType
!= GRAPHIC_DEFAULT
) && !ImplIsSwapOut() )
1083 const MapMode
aMapMode( ImplGetPrefMapMode() );
1084 const Size
aSize( ImplGetPrefSize() );
1085 const SvStreamEndian nOldFormat
= rOStm
.GetEndian();
1086 sal_uLong nDataFieldPos
;
1088 rOStm
.SetEndian( SvStreamEndian::LITTLE
);
1090 // write correct version ( old style/new style header )
1091 if( rOStm
.GetVersion() >= SOFFICE_FILEFORMAT_50
)
1093 // write ID for new format (5.0)
1094 rOStm
.WriteUInt32( GRAPHIC_FORMAT_50
);
1096 // write new style header
1097 VersionCompat
* pCompat
= new VersionCompat( rOStm
, StreamMode::WRITE
, 1 );
1099 rOStm
.WriteInt32( meType
);
1101 // data size is updated later
1102 nDataFieldPos
= rOStm
.Tell();
1103 rOStm
.WriteInt32( 0 );
1105 WritePair( rOStm
, aSize
);
1106 WriteMapMode( rOStm
, aMapMode
);
1112 // write old style (<=4.0) header
1113 rOStm
.WriteInt32( meType
);
1115 // data size is updated later
1116 nDataFieldPos
= rOStm
.Tell();
1117 rOStm
.WriteInt32( 0 );
1118 rOStm
.WriteInt32( aSize
.Width() );
1119 rOStm
.WriteInt32( aSize
.Height() );
1120 rOStm
.WriteInt32( aMapMode
.GetMapUnit() );
1121 rOStm
.WriteInt32( aMapMode
.GetScaleX().GetNumerator() );
1122 rOStm
.WriteInt32( aMapMode
.GetScaleX().GetDenominator() );
1123 rOStm
.WriteInt32( aMapMode
.GetScaleY().GetNumerator() );
1124 rOStm
.WriteInt32( aMapMode
.GetScaleY().GetDenominator() );
1125 rOStm
.WriteInt32( aMapMode
.GetOrigin().X() );
1126 rOStm
.WriteInt32( aMapMode
.GetOrigin().Y() );
1130 if( !rOStm
.GetError() )
1132 const sal_uLong nDataStart
= rOStm
.Tell();
1134 if( ImplIsSupportedGraphic() )
1135 WriteImpGraphic( rOStm
, *this );
1137 if( !rOStm
.GetError() )
1139 const sal_uLong nStmPos2
= rOStm
.Tell();
1140 rOStm
.Seek( nDataFieldPos
);
1141 rOStm
.WriteInt32( nStmPos2
- nDataStart
);
1142 rOStm
.Seek( nStmPos2
);
1147 rOStm
.SetEndian( nOldFormat
);
1153 bool ImpGraphic::ImplSwapOut()
1157 if( !ImplIsSwapOut() )
1159 ::utl::TempFile aTempFile
;
1160 const INetURLObject
aTmpURL( aTempFile
.GetURL() );
1162 if( !aTmpURL
.GetMainURL( INetURLObject::NO_DECODE
).isEmpty() )
1164 std::unique_ptr
<SvStream
> xOStm
;
1167 xOStm
.reset(::utl::UcbStreamHelper::CreateStream( aTmpURL
.GetMainURL( INetURLObject::NO_DECODE
), STREAM_READWRITE
| StreamMode::SHARE_DENYWRITE
));
1169 catch( const ::com::sun::star::uno::Exception
& )
1174 xOStm
->SetVersion( SOFFICE_FILEFORMAT_50
);
1175 xOStm
->SetCompressMode( SvStreamCompressFlags::NATIVE
);
1177 if( ( bRet
= ImplSwapOut( xOStm
.get() ) ) )
1179 mpSwapFile
= new ImpSwapFile
;
1180 mpSwapFile
->nRefCount
= 1;
1181 mpSwapFile
->aSwapURL
= aTmpURL
;
1189 ::ucbhelper::Content
aCnt( aTmpURL
.GetMainURL( INetURLObject::NO_DECODE
),
1190 ::com::sun::star::uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
>(),
1191 comphelper::getProcessComponentContext() );
1193 aCnt
.executeCommand( OUString("delete"),
1194 ::com::sun::star::uno::makeAny( true ) );
1196 catch( const ::com::sun::star::ucb::ContentCreationException
& )
1199 catch( const ::com::sun::star::uno::RuntimeException
& )
1202 catch( const ::com::sun::star::ucb::CommandAbortedException
& )
1205 catch( const ::com::sun::star::uno::Exception
& )
1216 void ImpGraphic::ImplSwapOutAsLink()
1218 ImplClearGraphics( true );
1222 bool ImpGraphic::ImplSwapOut( SvStream
* xOStm
)
1228 xOStm
->SetBufferSize( GRAPHIC_STREAMBUFSIZE
);
1230 if( !xOStm
->GetError() && ImplWriteEmbedded( *xOStm
) )
1234 if( !xOStm
->GetError() )
1236 ImplClearGraphics( true );
1237 bRet
= mbSwapOut
= true;
1243 SAL_WARN("vcl.gdi", "Graphic SwapOut: No stream for swap out!");
1249 bool ImpGraphic::ImplSwapIn()
1253 if( ImplIsSwapOut() )
1258 aSwapURL
= mpSwapFile
->aSwapURL
.GetMainURL( INetURLObject::NO_DECODE
);
1260 if( !aSwapURL
.isEmpty() )
1262 std::unique_ptr
<SvStream
> xIStm
;
1265 xIStm
.reset(::utl::UcbStreamHelper::CreateStream( aSwapURL
, STREAM_READWRITE
| StreamMode::SHARE_DENYWRITE
));
1267 catch( const ::com::sun::star::uno::Exception
& )
1273 xIStm
->SetVersion( SOFFICE_FILEFORMAT_50
);
1274 xIStm
->SetCompressMode( SvStreamCompressFlags::NATIVE
);
1276 bRet
= ImplSwapIn( xIStm
.get() );
1281 if( mpSwapFile
->nRefCount
> 1 )
1282 mpSwapFile
->nRefCount
--;
1287 ::ucbhelper::Content
aCnt( aSwapURL
,
1288 ::com::sun::star::uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
>(),
1289 comphelper::getProcessComponentContext() );
1291 aCnt
.executeCommand( OUString("delete"),
1292 ::com::sun::star::uno::makeAny( true ) );
1294 catch( const ::com::sun::star::ucb::ContentCreationException
& )
1297 catch( const ::com::sun::star::uno::RuntimeException
& )
1300 catch( const ::com::sun::star::ucb::CommandAbortedException
& )
1303 catch( const ::com::sun::star::uno::Exception
& )
1319 bool ImpGraphic::ImplSwapIn( SvStream
* xIStm
)
1325 xIStm
->SetBufferSize( GRAPHIC_STREAMBUFSIZE
);
1327 if( !xIStm
->GetError() )
1329 mbSwapUnderway
= true;
1330 bRet
= ImplReadEmbedded( *xIStm
);
1331 mbSwapUnderway
= false;
1344 void ImpGraphic::ImplSetLink( const GfxLink
& rGfxLink
)
1347 mpGfxLink
= new GfxLink( rGfxLink
);
1349 if( mpGfxLink
->IsNative() )
1350 mpGfxLink
->SwapOut();
1353 GfxLink
ImpGraphic::ImplGetLink()
1355 return( mpGfxLink
? *mpGfxLink
: GfxLink() );
1358 bool ImpGraphic::ImplIsLink() const
1360 return ( mpGfxLink
!= NULL
);
1363 BitmapChecksum
ImpGraphic::ImplGetChecksum() const
1365 BitmapChecksum nRet
= 0;
1367 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() )
1371 case( GRAPHIC_DEFAULT
):
1374 case( GRAPHIC_BITMAP
):
1376 if(maSvgData
.get() && maEx
.IsEmpty())
1378 // use maEx as local buffer for rendered svg
1379 const_cast< ImpGraphic
* >(this)->maEx
= maSvgData
->getReplacement();
1384 nRet
= mpAnimation
->GetChecksum();
1388 nRet
= maEx
.GetChecksum();
1394 nRet
= maMetaFile
.GetChecksum();
1402 bool ImpGraphic::ImplExportNative( SvStream
& rOStm
) const
1404 bool bResult
= false;
1406 if( !rOStm
.GetError() )
1408 if( !ImplIsSwapOut() )
1410 if( mpGfxLink
&& mpGfxLink
->IsNative() )
1411 bResult
= mpGfxLink
->ExportNative( rOStm
);
1414 WriteImpGraphic( rOStm
, *this );
1415 bResult
= ( rOStm
.GetError() == ERRCODE_NONE
);
1419 rOStm
.SetError( SVSTREAM_GENERALERROR
);
1426 SvStream
& ReadImpGraphic( SvStream
& rIStm
, ImpGraphic
& rImpGraphic
)
1428 if( !rIStm
.GetError() )
1430 const sal_uLong nStmPos1
= rIStm
.Tell();
1433 if ( !rImpGraphic
.mbSwapUnderway
)
1434 rImpGraphic
.ImplClear();
1437 rIStm
.ReadUInt32( nTmp
);
1439 // if there is no more data, avoid further expensive
1440 // reading which will create VDevs and other stuff, just to
1441 // read nothing. CAUTION: Eof is only true AFTER reading another
1442 // byte, a speciality of SvMemoryStream (!)
1443 if(!rIStm
.GetError() && !rIStm
.IsEof())
1445 if( NATIVE_FORMAT_50
== nTmp
)
1449 VersionCompat
* pCompat
;
1452 pCompat
= new VersionCompat( rIStm
, StreamMode::READ
);
1455 ReadGfxLink( rIStm
, aLink
);
1457 // set dummy link to avoid creation of additional link after filtering;
1458 // we set a default link to avoid unnecessary swapping of native data
1459 aGraphic
.SetLink( GfxLink() );
1461 if( !rIStm
.GetError() && aLink
.LoadNative( aGraphic
) )
1463 // set link only, if no other link was set
1464 const bool bSetLink
= ( rImpGraphic
.mpGfxLink
== NULL
);
1467 rImpGraphic
= *aGraphic
.ImplGetImpGraphic();
1469 if( aLink
.IsPrefMapModeValid() )
1470 rImpGraphic
.ImplSetPrefMapMode( aLink
.GetPrefMapMode() );
1472 if( aLink
.IsPrefSizeValid() )
1473 rImpGraphic
.ImplSetPrefSize( aLink
.GetPrefSize() );
1476 rImpGraphic
.ImplSetLink( aLink
);
1480 rIStm
.Seek( nStmPos1
);
1481 rIStm
.SetError( ERRCODE_IO_WRONGFORMAT
);
1487 const SvStreamEndian nOldFormat
= rIStm
.GetEndian();
1489 rIStm
.SeekRel( -4 );
1490 rIStm
.SetEndian( SvStreamEndian::LITTLE
);
1491 ReadDIBBitmapEx(aBmpEx
, rIStm
);
1493 if( !rIStm
.GetError() )
1495 sal_uInt32
nMagic1(0), nMagic2(0);
1496 sal_uLong nActPos
= rIStm
.Tell();
1498 rIStm
.ReadUInt32( nMagic1
).ReadUInt32( nMagic2
);
1499 rIStm
.Seek( nActPos
);
1501 rImpGraphic
= ImpGraphic( aBmpEx
);
1503 if( !rIStm
.GetError() && ( 0x5344414e == nMagic1
) && ( 0x494d4931 == nMagic2
) )
1505 delete rImpGraphic
.mpAnimation
;
1506 rImpGraphic
.mpAnimation
= new Animation
;
1507 ReadAnimation( rIStm
, *rImpGraphic
.mpAnimation
);
1509 // #108077# manually set loaded BmpEx to Animation
1510 // (which skips loading its BmpEx if already done)
1511 rImpGraphic
.mpAnimation
->SetBitmapEx(aBmpEx
);
1520 rIStm
.Seek( nStmPos1
);
1522 ReadGDIMetaFile( rIStm
, aMtf
);
1524 if( !rIStm
.GetError() )
1530 // try to stream in Svg defining data (length, byte array and evtl. path)
1531 // See below (operator<<) for more information
1532 const sal_uInt32
nSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0'));
1534 rIStm
.Seek(nStmPos1
);
1536 rIStm
.ReadUInt32( nMagic
);
1538 if(nSvgMagic
== nMagic
)
1540 sal_uInt32
mnSvgDataArrayLength(0);
1541 rIStm
.ReadUInt32( mnSvgDataArrayLength
);
1543 if(mnSvgDataArrayLength
)
1545 SvgDataArray
aNewData(new sal_uInt8
[mnSvgDataArrayLength
]);
1548 rIStm
.Read(aNewData
.get(), mnSvgDataArrayLength
);
1549 aPath
= rIStm
.ReadUniOrByteString(rIStm
.GetStreamCharSet());
1551 if(!rIStm
.GetError())
1553 SvgDataPtr
aSvgDataPtr(
1556 mnSvgDataArrayLength
,
1559 rImpGraphic
= aSvgDataPtr
;
1564 rIStm
.Seek(nStmPos1
);
1568 rIStm
.SetEndian( nOldFormat
);
1576 SvStream
& WriteImpGraphic( SvStream
& rOStm
, const ImpGraphic
& rImpGraphic
)
1578 if( !rOStm
.GetError() )
1580 if( !rImpGraphic
.ImplIsSwapOut() )
1582 if( ( rOStm
.GetVersion() >= SOFFICE_FILEFORMAT_50
) &&
1583 ( rOStm
.GetCompressMode() & SvStreamCompressFlags::NATIVE
) &&
1584 rImpGraphic
.mpGfxLink
&& rImpGraphic
.mpGfxLink
->IsNative() )
1586 VersionCompat
* pCompat
;
1589 rOStm
.WriteUInt32( NATIVE_FORMAT_50
);
1591 // write compat info
1592 pCompat
= new VersionCompat( rOStm
, StreamMode::WRITE
, 1 );
1595 rImpGraphic
.mpGfxLink
->SetPrefMapMode( rImpGraphic
.ImplGetPrefMapMode() );
1596 rImpGraphic
.mpGfxLink
->SetPrefSize( rImpGraphic
.ImplGetPrefSize() );
1597 WriteGfxLink( rOStm
, *rImpGraphic
.mpGfxLink
);
1602 const SvStreamEndian nOldFormat
= rOStm
.GetEndian();
1603 rOStm
.SetEndian( SvStreamEndian::LITTLE
);
1605 switch( rImpGraphic
.ImplGetType() )
1607 case( GRAPHIC_NONE
):
1608 case( GRAPHIC_DEFAULT
):
1611 case GRAPHIC_BITMAP
:
1613 if(rImpGraphic
.getSvgData().get())
1615 // stream out Svg defining data (length, byte array and evtl. path)
1616 // this is used e.g. in swapping out graphic data and in transporting it over UNO API
1617 // as sequence of bytes, but AFAIK not written anywhere to any kind of file, so it should be
1618 // no problem to extend it; only used at runtime
1619 const sal_uInt32
nSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0'));
1621 rOStm
.WriteUInt32( nSvgMagic
);
1622 rOStm
.WriteUInt32( rImpGraphic
.getSvgData()->getSvgDataArrayLength() );
1623 rOStm
.Write(rImpGraphic
.getSvgData()->getSvgDataArray().get(), rImpGraphic
.getSvgData()->getSvgDataArrayLength());
1624 rOStm
.WriteUniOrByteString(rImpGraphic
.getSvgData()->getPath(),
1625 rOStm
.GetStreamCharSet());
1627 else if( rImpGraphic
.ImplIsAnimated())
1629 WriteAnimation( rOStm
, *rImpGraphic
.mpAnimation
);
1633 WriteDIBBitmapEx(rImpGraphic
.maEx
, rOStm
);
1640 if( rImpGraphic
.ImplIsSupportedGraphic() )
1641 WriteGDIMetaFile( rOStm
, rImpGraphic
.maMetaFile
);
1646 rOStm
.SetEndian( nOldFormat
);
1650 rOStm
.SetError( SVSTREAM_GENERALERROR
);
1656 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */