Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / svx / source / core / graphichelper.cxx
blobfb483c5bfe5463df22d215c8df006f24de8970ca
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 <unotools/pathoptions.hxx>
21 #include <vcl/graphicfilter.hxx>
22 #include <sfx2/docfile.hxx>
23 #include <sfx2/filedlghelper.hxx>
24 #include <svx/xoutbmp.hxx>
25 #include <svx/dialmgr.hxx>
26 #include <svx/graphichelper.hxx>
27 #include <svx/strings.hrc>
28 #include <tools/diagnose_ex.h>
29 #include <vcl/svapp.hxx>
30 #include <vcl/weld.hxx>
32 #include <comphelper/processfactory.hxx>
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/beans/PropertyValue.hpp>
36 #include <com/sun/star/container/NoSuchElementException.hpp>
37 #include <com/sun/star/document/XExporter.hpp>
38 #include <com/sun/star/drawing/GraphicExportFilter.hpp>
39 #include <com/sun/star/drawing/XShape.hpp>
40 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
41 #include <com/sun/star/lang/XComponent.hpp>
42 #include <com/sun/star/io/XInputStream.hpp>
43 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
44 #include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
45 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
46 #include <com/sun/star/beans/XPropertyAccess.hpp>
47 #include <com/sun/star/task/ErrorCodeIOException.hpp>
48 #include <com/sun/star/graphic/XGraphic.hpp>
50 #include <map>
52 using namespace css::uno;
53 using namespace css::lang;
54 using namespace css::graphic;
55 using namespace css::ucb;
56 using namespace css::beans;
57 using namespace css::io;
58 using namespace css::document;
59 using namespace css::ui::dialogs;
60 using namespace css::container;
61 using namespace com::sun::star::task;
63 using namespace sfx2;
65 namespace drawing = com::sun::star::drawing;
67 void GraphicHelper::GetPreferredExtension( OUString& rExtension, const Graphic& rGraphic )
69 OUString aExtension = "png";
70 auto const & rVectorGraphicDataPtr(rGraphic.getVectorGraphicData());
72 if (rVectorGraphicDataPtr && rVectorGraphicDataPtr->getVectorGraphicDataArrayLength())
74 switch (rVectorGraphicDataPtr->getVectorGraphicDataType())
76 case VectorGraphicDataType::Wmf:
77 aExtension = "wmf";
78 break;
79 case VectorGraphicDataType::Emf:
80 aExtension = "emf";
81 break;
82 default: // case VectorGraphicDataType::Svg:
83 aExtension = "svg";
84 break;
87 rExtension = aExtension;
88 return;
91 switch( rGraphic.GetGfxLink().GetType() )
93 case GfxLinkType::NativeGif:
94 aExtension = "gif";
95 break;
96 case GfxLinkType::NativeTif:
97 aExtension = "tif";
98 break;
99 case GfxLinkType::NativeWmf:
100 aExtension = "wmf";
101 break;
102 case GfxLinkType::NativeMet:
103 aExtension = "met";
104 break;
105 case GfxLinkType::NativePct:
106 aExtension = "pct";
107 break;
108 case GfxLinkType::NativeJpg:
109 aExtension = "jpg";
110 break;
111 case GfxLinkType::NativeBmp:
112 aExtension = "bmp";
113 break;
114 case GfxLinkType::NativeSvg:
115 aExtension = "svg";
116 break;
117 case GfxLinkType::NativePdf:
118 aExtension = "pdf";
119 break;
120 default:
121 break;
123 rExtension = aExtension;
126 namespace {
129 bool lcl_ExecuteFilterDialog( const Sequence< PropertyValue >& rPropsForDialog,
130 Sequence< PropertyValue >& rFilterData )
132 bool bStatus = false;
135 Reference< XExecutableDialog > xFilterDialog(
136 comphelper::getProcessServiceFactory()->createInstance( "com.sun.star.svtools.SvFilterOptionsDialog" ), UNO_QUERY );
137 Reference< XPropertyAccess > xFilterProperties( xFilterDialog, UNO_QUERY );
139 if( xFilterDialog.is() && xFilterProperties.is() )
141 xFilterProperties->setPropertyValues( rPropsForDialog );
142 if( xFilterDialog->execute() )
144 bStatus = true;
145 const Sequence< PropertyValue > aPropsFromDialog = xFilterProperties->getPropertyValues();
146 for ( const auto& rProp : aPropsFromDialog )
148 if (rProp.Name == "FilterData")
150 rProp.Value >>= rFilterData;
156 catch( const NoSuchElementException& e )
158 // the filter name is unknown
159 throw ErrorCodeIOException(
160 ("lcl_ExecuteFilterDialog: NoSuchElementException"
161 " \"" + e.Message + "\": ERRCODE_IO_ABORT"),
162 Reference< XInterface >(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER));
164 catch( const ErrorCodeIOException& )
166 throw;
168 catch( const Exception& )
170 TOOLS_WARN_EXCEPTION("sfx.doc", "ignoring");
173 return bStatus;
175 } // anonymous ns
177 OUString GraphicHelper::ExportGraphic(weld::Window* pParent, const Graphic& rGraphic, const OUString& rGraphicName)
179 SvtPathOptions aPathOpt;
180 OUString sGraphicsPath( aPathOpt.GetGraphicPath() );
182 FileDialogHelper aDialogHelper(TemplateDescription::FILESAVE_AUTOEXTENSION, FileDialogFlags::NONE, pParent);
183 Reference < XFilePicker3 > xFilePicker = aDialogHelper.GetFilePicker();
185 INetURLObject aPath;
186 aPath.SetSmartURL( sGraphicsPath );
188 // fish out the graphic's name
190 aDialogHelper.SetTitle( SvxResId(RID_SVXSTR_EXPORT_GRAPHIC_TITLE));
191 aDialogHelper.SetDisplayDirectory( aPath.GetMainURL(INetURLObject::DecodeMechanism::ToIUri) );
192 INetURLObject aURL;
193 aURL.SetSmartURL( rGraphicName );
194 aDialogHelper.SetFileName(aURL.GetLastName());
196 GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
197 const sal_uInt16 nCount = rGraphicFilter.GetExportFormatCount();
199 OUString aExtension(aURL.GetFileExtension());
200 if( aExtension.isEmpty() )
202 GetPreferredExtension( aExtension, rGraphic );
205 aExtension = aExtension.toAsciiLowerCase();
206 sal_uInt16 nDefaultFilter = USHRT_MAX;
208 for ( sal_uInt16 i = 0; i < nCount; i++ )
210 xFilePicker->appendFilter( rGraphicFilter.GetExportFormatName( i ), rGraphicFilter.GetExportWildcard( i ) );
211 OUString aFormatShortName = rGraphicFilter.GetExportFormatShortName( i );
212 if ( aFormatShortName.equalsIgnoreAsciiCase( aExtension ) )
214 nDefaultFilter = i;
217 if ( USHRT_MAX == nDefaultFilter )
219 // "wrong" extension?
220 GetPreferredExtension( aExtension, rGraphic );
221 for ( sal_uInt16 i = 0; i < nCount; ++i )
222 if ( aExtension == rGraphicFilter.GetExportFormatShortName( i ).toAsciiLowerCase() )
224 nDefaultFilter = i;
225 break;
229 if( USHRT_MAX != nDefaultFilter )
231 xFilePicker->setCurrentFilter( rGraphicFilter.GetExportFormatName( nDefaultFilter ) ) ;
233 if( aDialogHelper.Execute() == ERRCODE_NONE )
235 OUString sPath( xFilePicker->getFiles().getConstArray()[0] );
236 // remember used path - please don't optimize away!
237 aPath.SetSmartURL( sPath);
238 sGraphicsPath = aPath.GetPath();
240 if( !rGraphicName.isEmpty() &&
241 nDefaultFilter == rGraphicFilter.GetExportFormatNumber( xFilePicker->getCurrentFilter()))
243 // try to save the original graphic
244 SfxMedium aIn( rGraphicName, StreamMode::READ | StreamMode::NOCREATE );
245 if( aIn.GetInStream() && !aIn.GetInStream()->GetError() )
247 SfxMedium aOut( sPath, StreamMode::WRITE | StreamMode::SHARE_DENYNONE);
248 if( aOut.GetOutStream() && !aOut.GetOutStream()->GetError())
250 aOut.GetOutStream()->WriteStream( *aIn.GetInStream() );
251 if ( ERRCODE_NONE == aIn.GetError() )
253 aOut.Close();
254 aOut.Commit();
255 if ( ERRCODE_NONE == aOut.GetError() )
256 return sPath;
262 sal_uInt16 nFilter;
263 if ( !xFilePicker->getCurrentFilter().isEmpty() && rGraphicFilter.GetExportFormatCount() )
265 nFilter = rGraphicFilter.GetExportFormatNumber( xFilePicker->getCurrentFilter() );
267 else
269 nFilter = GRFILTER_FORMAT_DONTKNOW;
271 OUString aFilter( rGraphicFilter.GetExportFormatShortName( nFilter ) );
273 if ( rGraphic.GetType() == GraphicType::Bitmap )
275 Graphic aGraphic = rGraphic;
276 Reference<XGraphic> xGraphic = aGraphic.GetXGraphic();
278 OUString aExportFilter = rGraphicFilter.GetExportInternalFilterName(nFilter);
280 Sequence< PropertyValue > aPropsForDialog(2);
281 aPropsForDialog[0].Name = "Graphic";
282 aPropsForDialog[0].Value <<= xGraphic;
283 aPropsForDialog[1].Name = "FilterName";
284 aPropsForDialog[1].Value <<= aExportFilter;
286 Sequence< PropertyValue > aFilterData;
287 bool bStatus = lcl_ExecuteFilterDialog(aPropsForDialog, aFilterData);
288 if (bStatus)
290 sal_Int32 nWidth = 0;
291 sal_Int32 nHeight = 0;
293 for (const auto& rProp : std::as_const(aFilterData))
295 if (rProp.Name == "PixelWidth")
297 rProp.Value >>= nWidth;
299 else if (rProp.Name == "PixelHeight")
301 rProp.Value >>= nHeight;
305 // scaling must performed here because png/jpg writer s
306 // do not take care of that.
307 Size aSizePixel( aGraphic.GetSizePixel() );
308 if( nWidth && nHeight &&
309 ( ( nWidth != aSizePixel.Width() ) ||
310 ( nHeight != aSizePixel.Height() ) ) )
312 BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
313 // export: use highest quality
314 aBmpEx.Scale( Size( nWidth, nHeight ), BmpScaleFlag::Lanczos );
315 aGraphic = aBmpEx;
318 XOutBitmap::WriteGraphic( aGraphic, sPath, aFilter,
319 XOutFlags::DontExpandFilename |
320 XOutFlags::DontAddExtension |
321 XOutFlags::UseNativeIfPossible,
322 nullptr, &aFilterData );
323 return sPath;
326 else
328 XOutBitmap::WriteGraphic( rGraphic, sPath, aFilter,
329 XOutFlags::DontExpandFilename |
330 XOutFlags::DontAddExtension |
331 XOutFlags::UseNativeIfPossible );
335 return OUString();
338 void GraphicHelper::SaveShapeAsGraphic(weld::Window* pParent, const Reference< drawing::XShape >& xShape)
342 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
343 Reference< XPropertySet > xShapeSet( xShape, UNO_QUERY_THROW );
345 SvtPathOptions aPathOpt;
346 const OUString& sGraphicPath( aPathOpt.GetGraphicPath() );
348 FileDialogHelper aDialogHelper(TemplateDescription::FILESAVE_AUTOEXTENSION, FileDialogFlags::NONE, pParent);
349 Reference < XFilePicker3 > xFilePicker = aDialogHelper.GetFilePicker();
351 aDialogHelper.SetTitle( SvxResId(RID_SVXSTR_SAVEAS_IMAGE) );
353 INetURLObject aPath;
354 aPath.SetSmartURL( sGraphicPath );
355 xFilePicker->setDisplayDirectory( aPath.GetMainURL(INetURLObject::DecodeMechanism::ToIUri) );
357 // populate filter dialog filter list and select default filter to match graphic mime type
359 GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
360 const OUString aDefaultMimeType("image/png");
361 OUString aDefaultFormatName;
362 sal_uInt16 nCount = rGraphicFilter.GetExportFormatCount();
364 std::map< OUString, OUString > aMimeTypeMap;
366 for ( sal_uInt16 i = 0; i < nCount; i++ )
368 const OUString aExportFormatName( rGraphicFilter.GetExportFormatName( i ) );
369 const OUString aFilterMimeType( rGraphicFilter.GetExportFormatMediaType( i ) );
370 xFilePicker->appendFilter( aExportFormatName, rGraphicFilter.GetExportWildcard( i ) );
371 aMimeTypeMap[ aExportFormatName ] = aFilterMimeType;
372 if( aDefaultMimeType == aFilterMimeType )
373 aDefaultFormatName = aExportFormatName;
376 if( !aDefaultFormatName.isEmpty() )
377 xFilePicker->setCurrentFilter( aDefaultFormatName );
379 // execute dialog
381 if( aDialogHelper.Execute() == ERRCODE_NONE )
383 OUString sPath( xFilePicker->getFiles().getConstArray()[0] );
384 OUString aExportMimeType( aMimeTypeMap[xFilePicker->getCurrentFilter()] );
386 Reference< XInputStream > xGraphStream;
388 if( xGraphStream.is() )
390 Reference<XSimpleFileAccess3> xFileAccess = SimpleFileAccess::create( xContext );
391 xFileAccess->writeFile( sPath, xGraphStream );
393 else
395 Reference<css::drawing::XGraphicExportFilter> xGraphicExporter = css::drawing::GraphicExportFilter::create( xContext );
397 Sequence<PropertyValue> aDescriptor( 2 );
398 aDescriptor[0].Name = "MediaType";
399 aDescriptor[0].Value <<= aExportMimeType;
400 aDescriptor[1].Name = "URL";
401 aDescriptor[1].Value <<= sPath;
403 Reference< XComponent > xSourceDocument( xShape, UNO_QUERY_THROW );
404 xGraphicExporter->setSourceDocument( xSourceDocument );
405 xGraphicExporter->filter( aDescriptor );
409 catch( Exception& )
414 short GraphicHelper::HasToSaveTransformedImage(weld::Widget* pWin)
416 OUString aMsg(SvxResId(RID_SVXSTR_SAVE_MODIFIED_IMAGE));
417 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pWin,
418 VclMessageType::Question, VclButtonsType::YesNo, aMsg));
419 return xBox->run();
422 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */