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/base64.hxx>
24 #include <comphelper/graphicmimetype.hxx>
25 #include <tools/debug.hxx>
26 #include <vcl/virdev.hxx>
27 #include <sfx2/docfile.hxx>
28 #include <svx/xoutbmp.hxx>
29 #include <vcl/graphicfilter.hxx>
30 #include <vcl/cvtgrf.hxx>
33 #define FORMAT_BMP u"bmp"
34 #define FORMAT_GIF u"gif"
35 #define FORMAT_JPG u"jpg"
36 #define FORMAT_PNG u"png"
38 using namespace com::sun::star
;
40 Animation
XOutBitmap::MirrorAnimation( const Animation
& rAnimation
, bool bHMirr
, bool bVMirr
)
42 Animation
aNewAnim( rAnimation
);
44 if( bHMirr
|| bVMirr
)
46 const Size
& rGlobalSize
= aNewAnim
.GetDisplaySizePixel();
47 BmpMirrorFlags nMirrorFlags
= BmpMirrorFlags::NONE
;
50 nMirrorFlags
|= BmpMirrorFlags::Horizontal
;
53 nMirrorFlags
|= BmpMirrorFlags::Vertical
;
55 for( sal_uInt16 i
= 0, nCount
= aNewAnim
.Count(); i
< nCount
; i
++ )
57 AnimationBitmap
aAnimationBitmap( aNewAnim
.Get( i
) );
59 // mirror the BitmapEx
60 aAnimationBitmap
.maBitmapEx
.Mirror( nMirrorFlags
);
62 // Adjust the positions inside the whole bitmap
64 aAnimationBitmap
.maPositionPixel
.setX(rGlobalSize
.Width() - aAnimationBitmap
.maPositionPixel
.X() -
65 aAnimationBitmap
.maSizePixel
.Width());
68 aAnimationBitmap
.maPositionPixel
.setY(rGlobalSize
.Height() - aAnimationBitmap
.maPositionPixel
.Y() -
69 aAnimationBitmap
.maSizePixel
.Height());
71 aNewAnim
.Replace(aAnimationBitmap
, i
);
78 Graphic
XOutBitmap::MirrorGraphic( const Graphic
& rGraphic
, const BmpMirrorFlags nMirrorFlags
)
82 if( nMirrorFlags
!= BmpMirrorFlags::NONE
)
84 if( rGraphic
.IsAnimated() )
86 aRetGraphic
= MirrorAnimation( rGraphic
.GetAnimation(),
87 bool( nMirrorFlags
& BmpMirrorFlags::Horizontal
),
88 bool( nMirrorFlags
& BmpMirrorFlags::Vertical
) );
92 BitmapEx
aBmp( rGraphic
.GetBitmapEx() );
93 aBmp
.Mirror( nMirrorFlags
);
98 aRetGraphic
= rGraphic
;
103 ErrCode
XOutBitmap::WriteGraphic( const Graphic
& rGraphic
, OUString
& rFileName
,
104 const OUString
& rFilterName
, const XOutFlags nFlags
,
105 const Size
* pMtfSize_100TH_MM
,
106 const css::uno::Sequence
< css::beans::PropertyValue
>* pFilterData
)
108 if( rGraphic
.GetType() == GraphicType::NONE
)
111 INetURLObject
aURL( rFileName
);
114 GraphicFilter
& rFilter
= GraphicFilter::GetGraphicFilter();
115 ErrCode nErr
= ERRCODE_GRFILTER_FILTERERROR
;
116 bool bTransparent
= rGraphic
.IsTransparent(), bAnimated
= rGraphic
.IsAnimated();
118 DBG_ASSERT( aURL
.GetProtocol() != INetProtocol::NotValid
, "XOutBitmap::WriteGraphic(...): invalid URL" );
120 // calculate correct file name
121 if( !( nFlags
& XOutFlags::DontExpandFilename
) )
123 OUString
aStr( OUString::number( rGraphic
.GetChecksum(), 16 ) );
124 if ( aStr
[0] == '-' )
125 aStr
= OUString::Concat("m") + aStr
.subView(1);
126 OUString aName
= aURL
.getBase() + "_" + aURL
.getExtension() + "_" + aStr
;
127 aURL
.setBase( aName
);
130 // #i121128# use shortcut to write Vector Graphic Data data in original form (if possible)
131 auto const & rVectorGraphicDataPtr(rGraphic
.getVectorGraphicData());
133 if (rVectorGraphicDataPtr
&& rVectorGraphicDataPtr
->getBinaryDataContainer().getSize())
135 const bool bIsSvg(rFilterName
.equalsIgnoreAsciiCase("svg") && VectorGraphicDataType::Svg
== rVectorGraphicDataPtr
->getType());
136 const bool bIsWmf(rFilterName
.equalsIgnoreAsciiCase("wmf") && VectorGraphicDataType::Wmf
== rVectorGraphicDataPtr
->getType());
137 const bool bIsEmf(rFilterName
.equalsIgnoreAsciiCase("emf") && VectorGraphicDataType::Emf
== rVectorGraphicDataPtr
->getType());
138 const bool bIsPdf(rFilterName
.equalsIgnoreAsciiCase("pdf") && VectorGraphicDataType::Pdf
== rVectorGraphicDataPtr
->getType());
140 if (bIsSvg
|| bIsWmf
|| bIsEmf
|| bIsPdf
)
142 if (!(nFlags
& XOutFlags::DontAddExtension
))
144 aURL
.setExtension(rFilterName
);
147 rFileName
= aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
);
148 SfxMedium
aMedium(aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
), StreamMode::WRITE
| StreamMode::SHARE_DENYNONE
| StreamMode::TRUNC
);
149 SvStream
* pOStm
= aMedium
.GetOutStream();
153 auto & rDataContainer
= rVectorGraphicDataPtr
->getBinaryDataContainer();
154 pOStm
->WriteBytes(rDataContainer
.getData(), rDataContainer
.getSize());
157 if (!aMedium
.GetError())
163 if( ( nFlags
& XOutFlags::UseNativeIfPossible
) &&
164 !( nFlags
& XOutFlags::MirrorHorz
) &&
165 !( nFlags
& XOutFlags::MirrorVert
) &&
166 ( rGraphic
.GetType() != GraphicType::GdiMetafile
) && rGraphic
.IsGfxLink() )
168 // try to write native link
169 const GfxLink
aGfxLink( rGraphic
.GetGfxLink() );
171 switch( aGfxLink
.GetType() )
173 case GfxLinkType::NativeGif
: aExt
= FORMAT_GIF
; break;
175 // #i15508# added BMP type for better exports (no call/trigger found, prob used in HTML export)
176 case GfxLinkType::NativeBmp
: aExt
= FORMAT_BMP
; break;
178 case GfxLinkType::NativeJpg
: aExt
= FORMAT_JPG
; break;
179 case GfxLinkType::NativePng
: aExt
= FORMAT_PNG
; break;
185 // tdf#60684: use native format if possible but it must correspond to filter name
186 // or no specific format has been required
187 // without this, you may save for example file with png extension but jpg content
188 if( !aExt
.isEmpty() && (aExt
== rFilterName
|| rFilterName
.isEmpty()) )
190 if( !(nFlags
& XOutFlags::DontAddExtension
) )
191 aURL
.setExtension( aExt
);
192 rFileName
= aURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
194 SfxMedium
aMedium(aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
), StreamMode::WRITE
| StreamMode::SHARE_DENYNONE
| StreamMode::TRUNC
);
195 SvStream
* pOStm
= aMedium
.GetOutStream();
197 if( pOStm
&& aGfxLink
.GetDataSize() && aGfxLink
.GetData() )
199 pOStm
->WriteBytes(aGfxLink
.GetData(), aGfxLink
.GetDataSize());
202 if( !aMedium
.GetError() )
208 OUString
aFilter( rFilterName
);
209 bool bWriteTransGrf
= ( aFilter
.equalsIgnoreAsciiCase( "transgrf" ) ) ||
210 ( aFilter
.equalsIgnoreAsciiCase( "gif" ) ) ||
211 ( nFlags
& XOutFlags::UseGifIfPossible
) ||
212 ( ( nFlags
& XOutFlags::UseGifIfSensible
) && ( bAnimated
|| bTransparent
) );
214 // get filter and extension
216 aFilter
= FORMAT_GIF
;
218 sal_uInt16 nFilter
= rFilter
.GetExportFormatNumberForShortName( aFilter
);
220 if( GRFILTER_FORMAT_NOTFOUND
== nFilter
)
222 nFilter
= rFilter
.GetExportFormatNumberForShortName( FORMAT_PNG
);
224 if( GRFILTER_FORMAT_NOTFOUND
== nFilter
)
225 nFilter
= rFilter
.GetExportFormatNumberForShortName( FORMAT_BMP
);
228 if( GRFILTER_FORMAT_NOTFOUND
!= nFilter
)
230 aExt
= rFilter
.GetExportFormatShortName( nFilter
).toAsciiLowerCase();
238 if( pMtfSize_100TH_MM
&& ( rGraphic
.GetType() != GraphicType::Bitmap
) )
240 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
241 const Size
aSize(pVDev
->LogicToPixel(*pMtfSize_100TH_MM
, MapMode(MapUnit::Map100thMM
)));
243 if( pVDev
->SetOutputSizePixel( aSize
) )
245 const Wallpaper
aWallpaper( pVDev
->GetBackground() );
248 pVDev
->SetBackground( Wallpaper( COL_BLACK
) );
250 rGraphic
.Draw(*pVDev
, aPt
, aSize
);
252 const Bitmap
aBitmap( pVDev
->GetBitmap( aPt
, aSize
) );
254 pVDev
->SetBackground( aWallpaper
);
256 rGraphic
.Draw(*pVDev
, aPt
, aSize
);
258 pVDev
->SetRasterOp( RasterOp::Xor
);
259 pVDev
->DrawBitmap( aPt
, aSize
, aBitmap
);
260 aGraphic
= BitmapEx( aBitmap
, pVDev
->GetBitmap( aPt
, aSize
) );
263 aGraphic
= rGraphic
.GetBitmapEx();
266 aGraphic
= rGraphic
.GetBitmapEx();
271 if( pMtfSize_100TH_MM
&& ( rGraphic
.GetType() != GraphicType::Bitmap
) )
273 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
274 const Size
aSize(pVDev
->LogicToPixel(*pMtfSize_100TH_MM
, MapMode(MapUnit::Map100thMM
)));
276 if( pVDev
->SetOutputSizePixel( aSize
) )
278 rGraphic
.Draw(*pVDev
, Point(), aSize
);
279 aGraphic
= BitmapEx(pVDev
->GetBitmap(Point(), aSize
));
282 aGraphic
= rGraphic
.GetBitmapEx();
285 aGraphic
= rGraphic
.GetBitmapEx();
289 if( ( nFlags
& XOutFlags::MirrorHorz
) || ( nFlags
& XOutFlags::MirrorVert
) )
291 BmpMirrorFlags nBmpMirrorFlags
= BmpMirrorFlags::NONE
;
292 if( nFlags
& XOutFlags::MirrorHorz
)
293 nBmpMirrorFlags
|= BmpMirrorFlags::Horizontal
;
294 if( nFlags
& XOutFlags::MirrorVert
)
295 nBmpMirrorFlags
|= BmpMirrorFlags::Vertical
;
296 aGraphic
= MirrorGraphic( aGraphic
, nBmpMirrorFlags
);
299 if (aGraphic
.GetType() != GraphicType::NONE
)
301 if( !(nFlags
& XOutFlags::DontAddExtension
) )
302 aURL
.setExtension( aExt
);
303 rFileName
= aURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
304 nErr
= ExportGraphic( aGraphic
, aURL
, rFilter
, nFilter
, pFilterData
);
311 bool XOutBitmap::GraphicToBase64(const Graphic
& rGraphic
, OUString
& rOUString
, bool bAddPrefix
,
312 ConvertDataFormat aTargetFormat
)
314 SvMemoryStream aOStm
;
315 GfxLink aLink
= rGraphic
.GetGfxLink();
317 if (aTargetFormat
== ConvertDataFormat::Unknown
)
319 switch (aLink
.GetType())
321 case GfxLinkType::NativeJpg
:
322 aTargetFormat
= ConvertDataFormat::JPG
;
324 case GfxLinkType::NativePng
:
325 aTargetFormat
= ConvertDataFormat::PNG
;
327 case GfxLinkType::NativeSvg
:
328 aTargetFormat
= ConvertDataFormat::SVG
;
331 // save everything else (including gif) into png
332 aTargetFormat
= ConvertDataFormat::PNG
;
337 ErrCode nErr
= GraphicConverter::Export(aOStm
,rGraphic
,aTargetFormat
);
340 SAL_WARN("svx", "XOutBitmap::GraphicToBase64() invalid Graphic? error: " << nErr
);
343 css::uno::Sequence
<sal_Int8
> aOStmSeq( static_cast<sal_Int8
const *>(aOStm
.GetData()),aOStm
.TellEnd() );
344 OUStringBuffer aStrBuffer
;
345 ::comphelper::Base64::encode(aStrBuffer
,aOStmSeq
);
346 rOUString
= aStrBuffer
.makeStringAndClear();
351 = comphelper::GraphicMimeTypeHelper::GetMimeTypeForConvertDataFormat(aTargetFormat
);
352 rOUString
= aMimeType
+ ";base64," + rOUString
;
358 ErrCode
XOutBitmap::ExportGraphic( const Graphic
& rGraphic
, const INetURLObject
& rURL
,
359 GraphicFilter
& rFilter
, const sal_uInt16 nFormat
,
360 const css::uno::Sequence
< css::beans::PropertyValue
>* pFilterData
)
362 DBG_ASSERT( rURL
.GetProtocol() != INetProtocol::NotValid
, "XOutBitmap::ExportGraphic(...): invalid URL" );
364 SfxMedium
aMedium( rURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), StreamMode::WRITE
| StreamMode::SHARE_DENYNONE
| StreamMode::TRUNC
);
365 SvStream
* pOStm
= aMedium
.GetOutStream();
366 ErrCode nRet
= ERRCODE_GRFILTER_IOERROR
;
370 nRet
= rFilter
.ExportGraphic( rGraphic
, rURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), *pOStm
, nFormat
, pFilterData
);
374 if( aMedium
.GetError() && ( ERRCODE_NONE
== nRet
) )
375 nRet
= ERRCODE_GRFILTER_IOERROR
;
382 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */