Bump version to 6.4-15
[LibreOffice.git] / svx / source / core / graphichelper.cxx
blob7302d752d072c5d7aa964a73f7af3936c597657e
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 <sal/log.hxx>
29 #include <tools/diagnose_ex.h>
30 #include <vcl/svapp.hxx>
31 #include <vcl/weld.hxx>
33 #include <cppuhelper/exc_hlp.hxx>
34 #include <comphelper/processfactory.hxx>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/beans/PropertyValues.hpp>
38 #include <com/sun/star/beans/PropertyValue.hpp>
39 #include <com/sun/star/document/XExporter.hpp>
40 #include <com/sun/star/document/XFilter.hpp>
41 #include <com/sun/star/drawing/GraphicExportFilter.hpp>
42 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
43 #include <com/sun/star/lang/XComponent.hpp>
44 #include <com/sun/star/io/XInputStream.hpp>
45 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
46 #include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
47 #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
48 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
49 #include <com/sun/star/container/XNameAccess.hpp>
50 #include <com/sun/star/beans/XPropertyAccess.hpp>
51 #include <com/sun/star/task/ErrorCodeIOException.hpp>
52 #include <com/sun/star/task/InteractionHandler.hpp>
53 #include <com/sun/star/graphic/XGraphic.hpp>
55 #include <map>
57 using namespace css::uno;
58 using namespace css::lang;
59 using namespace css::graphic;
60 using namespace css::ucb;
61 using namespace css::beans;
62 using namespace css::io;
63 using namespace css::document;
64 using namespace css::ui::dialogs;
65 using namespace css::container;
66 using namespace com::sun::star::task;
67 using namespace css::frame;
69 using namespace sfx2;
71 namespace drawing = com::sun::star::drawing;
73 void GraphicHelper::GetPreferredExtension( OUString& rExtension, const Graphic& rGraphic )
75 OUString aExtension = "png";
76 const VectorGraphicDataPtr& aVectorGraphicDataPtr(rGraphic.getVectorGraphicData());
78 if (aVectorGraphicDataPtr.get() && aVectorGraphicDataPtr->getVectorGraphicDataArrayLength())
80 switch (aVectorGraphicDataPtr->getVectorGraphicDataType())
82 case VectorGraphicDataType::Wmf:
83 aExtension = "wmf";
84 break;
85 case VectorGraphicDataType::Emf:
86 aExtension = "emf";
87 break;
88 default: // case VectorGraphicDataType::Svg:
89 aExtension = "svg";
90 break;
93 rExtension = aExtension;
94 return;
97 switch( rGraphic.GetGfxLink().GetType() )
99 case GfxLinkType::NativeGif:
100 aExtension = "gif";
101 break;
102 case GfxLinkType::NativeTif:
103 aExtension = "tif";
104 break;
105 case GfxLinkType::NativeWmf:
106 aExtension = "wmf";
107 break;
108 case GfxLinkType::NativeMet:
109 aExtension = "met";
110 break;
111 case GfxLinkType::NativePct:
112 aExtension = "pct";
113 break;
114 case GfxLinkType::NativeJpg:
115 aExtension = "jpg";
116 break;
117 case GfxLinkType::NativeBmp:
118 aExtension = "bmp";
119 break;
120 case GfxLinkType::NativeSvg:
121 aExtension = "svg";
122 break;
123 case GfxLinkType::NativePdf:
124 aExtension = "pdf";
125 break;
126 default:
127 break;
129 rExtension = aExtension;
132 namespace {
135 bool lcl_ExecuteFilterDialog( const Sequence< PropertyValue >& rPropsForDialog,
136 Sequence< PropertyValue >& rFilterData )
138 bool bStatus = false;
141 const OUString aServiceName("com.sun.star.svtools.SvFilterOptionsDialog");
142 Reference< XExecutableDialog > xFilterDialog(
143 comphelper::getProcessServiceFactory()->createInstance( aServiceName ), UNO_QUERY );
144 Reference< XPropertyAccess > xFilterProperties( xFilterDialog, UNO_QUERY );
146 if( xFilterDialog.is() && xFilterProperties.is() )
148 xFilterProperties->setPropertyValues( rPropsForDialog );
149 if( xFilterDialog->execute() )
151 bStatus = true;
152 const Sequence< PropertyValue > aPropsFromDialog = xFilterProperties->getPropertyValues();
153 for ( const auto& rProp : aPropsFromDialog )
155 if (rProp.Name == "FilterData")
157 rProp.Value >>= rFilterData;
163 catch( const NoSuchElementException& e )
165 // the filter name is unknown
166 throw ErrorCodeIOException(
167 ("lcl_ExecuteFilterDialog: NoSuchElementException"
168 " \"" + e.Message + "\": ERRCODE_IO_ABORT"),
169 Reference< XInterface >(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER));
171 catch( const ErrorCodeIOException& )
173 throw;
175 catch( const Exception& )
177 TOOLS_WARN_EXCEPTION("sfx.doc", "ignoring");
180 return bStatus;
182 } // anonymous ns
184 OUString GraphicHelper::ExportGraphic(weld::Window* pParent, const Graphic& rGraphic, const OUString& rGraphicName)
186 SvtPathOptions aPathOpt;
187 OUString sGraphicsPath( aPathOpt.GetGraphicPath() );
189 FileDialogHelper aDialogHelper(TemplateDescription::FILESAVE_AUTOEXTENSION, FileDialogFlags::NONE, pParent);
190 Reference < XFilePicker3 > xFilePicker = aDialogHelper.GetFilePicker();
192 INetURLObject aPath;
193 aPath.SetSmartURL( sGraphicsPath );
195 // fish out the graphic's name
197 aDialogHelper.SetTitle( SvxResId(RID_SVXSTR_EXPORT_GRAPHIC_TITLE));
198 aDialogHelper.SetDisplayDirectory( aPath.GetMainURL(INetURLObject::DecodeMechanism::ToIUri) );
199 INetURLObject aURL;
200 aURL.SetSmartURL( rGraphicName );
201 aDialogHelper.SetFileName(aURL.GetLastName());
203 GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
204 const sal_uInt16 nCount = rGraphicFilter.GetExportFormatCount();
206 OUString aExtension(aURL.GetFileExtension());
207 if( aExtension.isEmpty() )
209 GetPreferredExtension( aExtension, rGraphic );
212 aExtension = aExtension.toAsciiLowerCase();
213 sal_uInt16 nDefaultFilter = USHRT_MAX;
215 for ( sal_uInt16 i = 0; i < nCount; i++ )
217 xFilePicker->appendFilter( rGraphicFilter.GetExportFormatName( i ), rGraphicFilter.GetExportWildcard( i ) );
218 OUString aFormatShortName = rGraphicFilter.GetExportFormatShortName( i );
219 if ( aFormatShortName.equalsIgnoreAsciiCase( aExtension ) )
221 nDefaultFilter = i;
224 if ( USHRT_MAX == nDefaultFilter )
226 // "wrong" extension?
227 GetPreferredExtension( aExtension, rGraphic );
228 for ( sal_uInt16 i = 0; i < nCount; ++i )
229 if ( aExtension == rGraphicFilter.GetExportFormatShortName( i ).toAsciiLowerCase() )
231 nDefaultFilter = i;
232 break;
236 if( USHRT_MAX != nDefaultFilter )
238 xFilePicker->setCurrentFilter( rGraphicFilter.GetExportFormatName( nDefaultFilter ) ) ;
240 if( aDialogHelper.Execute() == ERRCODE_NONE )
242 OUString sPath( xFilePicker->getFiles().getConstArray()[0] );
243 // remember used path - please don't optimize away!
244 aPath.SetSmartURL( sPath);
245 sGraphicsPath = aPath.GetPath();
247 if( !rGraphicName.isEmpty() &&
248 nDefaultFilter == rGraphicFilter.GetExportFormatNumber( xFilePicker->getCurrentFilter()))
250 // try to save the original graphic
251 SfxMedium aIn( rGraphicName, StreamMode::READ | StreamMode::NOCREATE );
252 if( aIn.GetInStream() && !aIn.GetInStream()->GetError() )
254 SfxMedium aOut( sPath, StreamMode::WRITE | StreamMode::SHARE_DENYNONE);
255 if( aOut.GetOutStream() && !aOut.GetOutStream()->GetError())
257 aOut.GetOutStream()->WriteStream( *aIn.GetInStream() );
258 if ( ERRCODE_NONE == aIn.GetError() )
260 aOut.Close();
261 aOut.Commit();
262 if ( ERRCODE_NONE == aOut.GetError() )
263 return sPath;
269 sal_uInt16 nFilter;
270 if ( !xFilePicker->getCurrentFilter().isEmpty() && rGraphicFilter.GetExportFormatCount() )
272 nFilter = rGraphicFilter.GetExportFormatNumber( xFilePicker->getCurrentFilter() );
274 else
276 nFilter = GRFILTER_FORMAT_DONTKNOW;
278 OUString aFilter( rGraphicFilter.GetExportFormatShortName( nFilter ) );
280 if ( rGraphic.GetType() == GraphicType::Bitmap )
282 Graphic aGraphic = rGraphic;
283 Reference<XGraphic> xGraphic = aGraphic.GetXGraphic();
285 OUString aExportFilter = rGraphicFilter.GetExportInternalFilterName(nFilter);
287 Sequence< PropertyValue > aPropsForDialog(2);
288 aPropsForDialog[0].Name = "Graphic";
289 aPropsForDialog[0].Value <<= xGraphic;
290 aPropsForDialog[1].Name = "FilterName";
291 aPropsForDialog[1].Value <<= aExportFilter;
293 Sequence< PropertyValue > aFilterData;
294 bool bStatus = lcl_ExecuteFilterDialog(aPropsForDialog, aFilterData);
295 if (bStatus)
297 sal_Int32 nWidth = 0;
298 sal_Int32 nHeight = 0;
300 for (const auto& rProp : std::as_const(aFilterData))
302 if (rProp.Name == "PixelWidth")
304 rProp.Value >>= nWidth;
306 else if (rProp.Name == "PixelHeight")
308 rProp.Value >>= nHeight;
312 // scaling must performed here because png/jpg writer s
313 // do not take care of that.
314 Size aSizePixel( aGraphic.GetSizePixel() );
315 if( nWidth && nHeight &&
316 ( ( nWidth != aSizePixel.Width() ) ||
317 ( nHeight != aSizePixel.Height() ) ) )
319 BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
320 // export: use highest quality
321 aBmpEx.Scale( Size( nWidth, nHeight ), BmpScaleFlag::Lanczos );
322 aGraphic = aBmpEx;
325 XOutBitmap::WriteGraphic( aGraphic, sPath, aFilter,
326 XOutFlags::DontExpandFilename |
327 XOutFlags::DontAddExtension |
328 XOutFlags::UseNativeIfPossible,
329 nullptr, &aFilterData );
330 return sPath;
333 else
335 XOutBitmap::WriteGraphic( rGraphic, sPath, aFilter,
336 XOutFlags::DontExpandFilename |
337 XOutFlags::DontAddExtension |
338 XOutFlags::UseNativeIfPossible );
342 return OUString();
345 void GraphicHelper::SaveShapeAsGraphic(weld::Window* pParent, const Reference< drawing::XShape >& xShape)
349 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
350 Reference< XPropertySet > xShapeSet( xShape, UNO_QUERY_THROW );
352 SvtPathOptions aPathOpt;
353 const OUString& sGraphicPath( aPathOpt.GetGraphicPath() );
355 FileDialogHelper aDialogHelper(TemplateDescription::FILESAVE_AUTOEXTENSION, FileDialogFlags::NONE, pParent);
356 Reference < XFilePicker3 > xFilePicker = aDialogHelper.GetFilePicker();
358 aDialogHelper.SetTitle( SvxResId(RID_SVXSTR_SAVEAS_IMAGE) );
360 INetURLObject aPath;
361 aPath.SetSmartURL( sGraphicPath );
362 xFilePicker->setDisplayDirectory( aPath.GetMainURL(INetURLObject::DecodeMechanism::ToIUri) );
364 // populate filter dialog filter list and select default filter to match graphic mime type
366 GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
367 const OUString aDefaultMimeType("image/png");
368 OUString aDefaultFormatName;
369 sal_uInt16 nCount = rGraphicFilter.GetExportFormatCount();
371 std::map< OUString, OUString > aMimeTypeMap;
373 for ( sal_uInt16 i = 0; i < nCount; i++ )
375 const OUString aExportFormatName( rGraphicFilter.GetExportFormatName( i ) );
376 const OUString aFilterMimeType( rGraphicFilter.GetExportFormatMediaType( i ) );
377 xFilePicker->appendFilter( aExportFormatName, rGraphicFilter.GetExportWildcard( i ) );
378 aMimeTypeMap[ aExportFormatName ] = aFilterMimeType;
379 if( aDefaultMimeType == aFilterMimeType )
380 aDefaultFormatName = aExportFormatName;
383 if( !aDefaultFormatName.isEmpty() )
384 xFilePicker->setCurrentFilter( aDefaultFormatName );
386 // execute dialog
388 if( aDialogHelper.Execute() == ERRCODE_NONE )
390 OUString sPath( xFilePicker->getFiles().getConstArray()[0] );
391 OUString aExportMimeType( aMimeTypeMap[xFilePicker->getCurrentFilter()] );
393 Reference< XInputStream > xGraphStream;
395 if( xGraphStream.is() )
397 Reference<XSimpleFileAccess3> xFileAccess = SimpleFileAccess::create( xContext );
398 xFileAccess->writeFile( sPath, xGraphStream );
400 else
402 Reference<css::drawing::XGraphicExportFilter> xGraphicExporter = css::drawing::GraphicExportFilter::create( xContext );
404 Sequence<PropertyValue> aDescriptor( 2 );
405 aDescriptor[0].Name = "MediaType";
406 aDescriptor[0].Value <<= aExportMimeType;
407 aDescriptor[1].Name = "URL";
408 aDescriptor[1].Value <<= sPath;
410 Reference< XComponent > xSourceDocument( xShape, UNO_QUERY_THROW );
411 xGraphicExporter->setSourceDocument( xSourceDocument );
412 xGraphicExporter->filter( aDescriptor );
416 catch( Exception& )
421 short GraphicHelper::HasToSaveTransformedImage(weld::Widget* pWin)
423 OUString aMsg(SvxResId(RID_SVXSTR_SAVE_MODIFIED_IMAGE));
424 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pWin,
425 VclMessageType::Question, VclButtonsType::YesNo, aMsg));
426 return xBox->run();
429 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */