bump product version to 7.2.5.1
[LibreOffice.git] / svx / source / xoutdev / _xoutbmp.cxx
blobef2b31716a2fbcbbe57a52939c2c3b4732fcf6c9
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>
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>
31 #include <memory>
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;
49 if( bHMirr )
50 nMirrorFlags |= BmpMirrorFlags::Horizontal;
52 if( bVMirr )
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
63 if( bHMirr )
64 aAnimationBitmap.maPositionPixel.setX(rGlobalSize.Width() - aAnimationBitmap.maPositionPixel.X() -
65 aAnimationBitmap.maSizePixel.Width());
67 if( bVMirr )
68 aAnimationBitmap.maPositionPixel.setY(rGlobalSize.Height() - aAnimationBitmap.maPositionPixel.Y() -
69 aAnimationBitmap.maSizePixel.Height());
71 aNewAnim.Replace(aAnimationBitmap, i);
75 return aNewAnim;
78 Graphic XOutBitmap::MirrorGraphic( const Graphic& rGraphic, const BmpMirrorFlags nMirrorFlags )
80 Graphic aRetGraphic;
82 if( nMirrorFlags != BmpMirrorFlags::NONE )
84 if( rGraphic.IsAnimated() )
86 aRetGraphic = MirrorAnimation( rGraphic.GetAnimation(),
87 bool( nMirrorFlags & BmpMirrorFlags::Horizontal ),
88 bool( nMirrorFlags & BmpMirrorFlags::Vertical ) );
90 else
92 BitmapEx aBmp( rGraphic.GetBitmapEx() );
93 aBmp.Mirror( nMirrorFlags );
94 aRetGraphic = aBmp;
97 else
98 aRetGraphic = rGraphic;
100 return aRetGraphic;
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 )
109 return ERRCODE_NONE;
111 INetURLObject aURL( rFileName );
112 Graphic aGraphic;
113 OUString aExt;
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();
151 if (pOStm)
153 auto & rDataContainer = rVectorGraphicDataPtr->getBinaryDataContainer();
154 pOStm->WriteBytes(rDataContainer.getData(), rDataContainer.getSize());
155 aMedium.Commit();
157 if (!aMedium.GetError())
158 return ERRCODE_NONE;
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;
181 default:
182 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());
200 aMedium.Commit();
202 if( !aMedium.GetError() )
203 return ERRCODE_NONE;
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
215 if( bWriteTransGrf )
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();
232 if( bWriteTransGrf )
234 if( bAnimated )
235 aGraphic = rGraphic;
236 else
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() );
246 const Point aPt;
248 pVDev->SetBackground( Wallpaper( COL_BLACK ) );
249 pVDev->Erase();
250 rGraphic.Draw(*pVDev, aPt, aSize);
252 const Bitmap aBitmap( pVDev->GetBitmap( aPt, aSize ) );
254 pVDev->SetBackground( aWallpaper );
255 pVDev->Erase();
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 ) );
262 else
263 aGraphic = rGraphic.GetBitmapEx();
265 else
266 aGraphic = rGraphic.GetBitmapEx();
269 else
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));
281 else
282 aGraphic = rGraphic.GetBitmapEx();
284 else
285 aGraphic = rGraphic.GetBitmapEx();
288 // mirror?
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 );
308 return nErr;
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;
323 break;
324 case GfxLinkType::NativePng:
325 aTargetFormat = ConvertDataFormat::PNG;
326 break;
327 case GfxLinkType::NativeSvg:
328 aTargetFormat = ConvertDataFormat::SVG;
329 break;
330 default:
331 // save everything else (including gif) into png
332 aTargetFormat = ConvertDataFormat::PNG;
333 break;
337 ErrCode nErr = GraphicConverter::Export(aOStm,rGraphic,aTargetFormat);
338 if ( nErr )
340 SAL_WARN("svx", "XOutBitmap::GraphicToBase64() invalid Graphic? error: " << nErr );
341 return false;
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();
348 if (bAddPrefix)
350 OUString aMimeType
351 = comphelper::GraphicMimeTypeHelper::GetMimeTypeForConvertDataFormat(aTargetFormat);
352 rOUString = aMimeType + ";base64," + rOUString;
355 return true;
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;
368 if( pOStm )
370 nRet = rFilter.ExportGraphic( rGraphic, rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), *pOStm, nFormat, pFilterData );
372 aMedium.Commit();
374 if( aMedium.GetError() && ( ERRCODE_NONE == nRet ) )
375 nRet = ERRCODE_GRFILTER_IOERROR;
378 return nRet;
382 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */