Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / core / graphichelper.cxx
blob54e8fc8361b28038c691fcae32d912c344eb1e59
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 <vcl/graphicfilter.hxx>
21 #include <sfx2/docfile.hxx>
22 #include <sfx2/filedlghelper.hxx>
23 #include <svx/xoutbmp.hxx>
24 #include <svx/dialmgr.hxx>
25 #include <svx/graphichelper.hxx>
26 #include <svx/strings.hrc>
27 #include <comphelper/diagnose_ex.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/weld.hxx>
31 #include <comphelper/processfactory.hxx>
32 #include <comphelper/propertyvalue.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>
49 #include <com/sun/star/drawing/ShapeCollection.hpp>
51 #include <map>
53 #include <unotools/streamwrap.hxx>
55 using namespace css::uno;
56 using namespace css::lang;
57 using namespace css::graphic;
58 using namespace css::ucb;
59 using namespace css::beans;
60 using namespace css::io;
61 using namespace css::document;
62 using namespace css::ui::dialogs;
63 using namespace css::container;
64 using namespace com::sun::star::task;
66 using namespace sfx2;
68 namespace drawing = com::sun::star::drawing;
70 void GraphicHelper::GetPreferredExtension( OUString& rExtension, const Graphic& rGraphic )
72 OUString aExtension = "png";
73 auto const & rVectorGraphicDataPtr(rGraphic.getVectorGraphicData());
75 if (rVectorGraphicDataPtr && !rVectorGraphicDataPtr->getBinaryDataContainer().isEmpty())
77 switch (rVectorGraphicDataPtr->getType())
79 case VectorGraphicDataType::Wmf:
80 aExtension = "wmf";
81 break;
82 case VectorGraphicDataType::Emf:
83 aExtension = "emf";
84 break;
85 default: // case VectorGraphicDataType::Svg:
86 aExtension = "svg";
87 break;
90 rExtension = aExtension;
91 return;
94 switch( rGraphic.GetGfxLink().GetType() )
96 case GfxLinkType::NativeGif:
97 aExtension = "gif";
98 break;
99 case GfxLinkType::NativeTif:
100 aExtension = "tif";
101 break;
102 case GfxLinkType::NativeWmf:
103 aExtension = "wmf";
104 break;
105 case GfxLinkType::NativeMet:
106 aExtension = "met";
107 break;
108 case GfxLinkType::NativePct:
109 aExtension = "pct";
110 break;
111 case GfxLinkType::NativeJpg:
112 aExtension = "jpg";
113 break;
114 case GfxLinkType::NativeBmp:
115 aExtension = "bmp";
116 break;
117 case GfxLinkType::NativeSvg:
118 aExtension = "svg";
119 break;
120 case GfxLinkType::NativePdf:
121 aExtension = "pdf";
122 break;
123 case GfxLinkType::NativeWebp:
124 aExtension = "webp";
125 break;
126 default:
127 break;
129 rExtension = aExtension;
132 OUString GraphicHelper::GetImageType(const Graphic& rGraphic)
134 OUString aGraphicTypeString = SvxResId(STR_IMAGE_UNKNOWN);
135 auto pGfxLink = rGraphic.GetSharedGfxLink();
136 if (pGfxLink)
138 switch (pGfxLink->GetType())
140 case GfxLinkType::NativeGif:
141 aGraphicTypeString = SvxResId(STR_IMAGE_GIF);
142 break;
143 case GfxLinkType::NativeJpg:
144 aGraphicTypeString = SvxResId(STR_IMAGE_JPEG);
145 break;
146 case GfxLinkType::NativePng:
147 aGraphicTypeString = SvxResId(STR_IMAGE_PNG);
148 break;
149 case GfxLinkType::NativeTif:
150 aGraphicTypeString = SvxResId(STR_IMAGE_TIFF);
151 break;
152 case GfxLinkType::NativeWmf:
153 aGraphicTypeString = SvxResId(STR_IMAGE_WMF);
154 break;
155 case GfxLinkType::NativeMet:
156 aGraphicTypeString = SvxResId(STR_IMAGE_MET);
157 break;
158 case GfxLinkType::NativePct:
159 aGraphicTypeString = SvxResId(STR_IMAGE_PCT);
160 break;
161 case GfxLinkType::NativeSvg:
162 aGraphicTypeString = SvxResId(STR_IMAGE_SVG);
163 break;
164 case GfxLinkType::NativeBmp:
165 aGraphicTypeString = SvxResId(STR_IMAGE_BMP);
166 break;
167 case GfxLinkType::NativeWebp:
168 aGraphicTypeString = SvxResId(STR_IMAGE_WEBP);
169 break;
170 default:
171 break;
174 return aGraphicTypeString;
176 namespace {
179 bool lcl_ExecuteFilterDialog( const Sequence< PropertyValue >& rPropsForDialog,
180 Sequence< PropertyValue >& rFilterData )
182 bool bStatus = false;
185 Reference< XExecutableDialog > xFilterDialog(
186 comphelper::getProcessServiceFactory()->createInstance( "com.sun.star.svtools.SvFilterOptionsDialog" ), UNO_QUERY );
187 Reference< XPropertyAccess > xFilterProperties( xFilterDialog, UNO_QUERY );
189 if( xFilterDialog.is() && xFilterProperties.is() )
191 xFilterProperties->setPropertyValues( rPropsForDialog );
192 if( xFilterDialog->execute() )
194 bStatus = true;
195 const Sequence< PropertyValue > aPropsFromDialog = xFilterProperties->getPropertyValues();
196 for ( const auto& rProp : aPropsFromDialog )
198 if (rProp.Name == "FilterData")
200 rProp.Value >>= rFilterData;
206 catch( const NoSuchElementException& e )
208 // the filter name is unknown
209 throw ErrorCodeIOException(
210 ("lcl_ExecuteFilterDialog: NoSuchElementException"
211 " \"" + e.Message + "\": ERRCODE_IO_ABORT"),
212 Reference< XInterface >(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER));
214 catch( const ErrorCodeIOException& )
216 throw;
218 catch( const Exception& )
220 TOOLS_WARN_EXCEPTION("sfx.doc", "ignoring");
223 return bStatus;
225 } // anonymous ns
227 OUString GraphicHelper::ExportGraphic(weld::Window* pParent, const Graphic& rGraphic, const OUString& rGraphicName)
229 FileDialogHelper aDialogHelper(TemplateDescription::FILESAVE_AUTOEXTENSION, FileDialogFlags::NONE, pParent);
230 Reference < XFilePicker3 > xFilePicker = aDialogHelper.GetFilePicker();
232 // fish out the graphic's name
233 aDialogHelper.SetContext(FileDialogHelper::ExportImage);
234 aDialogHelper.SetTitle( SvxResId(RID_SVXSTR_EXPORT_GRAPHIC_TITLE));
235 INetURLObject aURL;
236 aURL.SetSmartURL( rGraphicName );
237 aDialogHelper.SetFileName(aURL.GetLastName());
239 GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
240 const sal_uInt16 nCount = rGraphicFilter.GetExportFormatCount();
242 OUString aExtension(aURL.GetFileExtension());
243 if( aExtension.isEmpty() )
245 GetPreferredExtension( aExtension, rGraphic );
248 aExtension = aExtension.toAsciiLowerCase();
249 sal_uInt16 nDefaultFilter = USHRT_MAX;
251 for ( sal_uInt16 i = 0; i < nCount; i++ )
253 xFilePicker->appendFilter( rGraphicFilter.GetExportFormatName( i ), rGraphicFilter.GetExportWildcard( i ) );
254 OUString aFormatShortName = rGraphicFilter.GetExportFormatShortName( i );
255 if ( aFormatShortName.equalsIgnoreAsciiCase( aExtension ) )
257 nDefaultFilter = i;
260 if ( USHRT_MAX == nDefaultFilter )
262 // "wrong" extension?
263 GetPreferredExtension( aExtension, rGraphic );
264 for ( sal_uInt16 i = 0; i < nCount; ++i )
265 if ( aExtension == rGraphicFilter.GetExportFormatShortName( i ).toAsciiLowerCase() )
267 nDefaultFilter = i;
268 break;
272 if( USHRT_MAX != nDefaultFilter )
274 xFilePicker->setCurrentFilter( rGraphicFilter.GetExportFormatName( nDefaultFilter ) ) ;
276 if( aDialogHelper.Execute() == ERRCODE_NONE )
278 OUString sPath( xFilePicker->getFiles().getConstArray()[0] );
279 if( !rGraphicName.isEmpty() &&
280 nDefaultFilter == rGraphicFilter.GetExportFormatNumber( xFilePicker->getCurrentFilter()))
282 // try to save the original graphic
283 SfxMedium aIn( rGraphicName, StreamMode::READ | StreamMode::NOCREATE );
284 if( aIn.GetInStream() && !aIn.GetInStream()->GetError() )
286 SfxMedium aOut( sPath, StreamMode::WRITE | StreamMode::SHARE_DENYNONE);
287 if( aOut.GetOutStream() && !aOut.GetOutStream()->GetError())
289 aOut.GetOutStream()->WriteStream( *aIn.GetInStream() );
290 if ( ERRCODE_NONE == aIn.GetError() )
292 aOut.Close();
293 aOut.Commit();
294 if ( ERRCODE_NONE == aOut.GetError() )
295 return sPath;
301 sal_uInt16 nFilter;
302 if ( !xFilePicker->getCurrentFilter().isEmpty() && rGraphicFilter.GetExportFormatCount() )
304 nFilter = rGraphicFilter.GetExportFormatNumber( xFilePicker->getCurrentFilter() );
306 else
308 nFilter = GRFILTER_FORMAT_DONTKNOW;
310 OUString aFilter( rGraphicFilter.GetExportFormatShortName( nFilter ) );
312 if ( rGraphic.GetType() == GraphicType::Bitmap )
314 Graphic aGraphic = rGraphic;
315 Reference<XGraphic> xGraphic = aGraphic.GetXGraphic();
317 OUString aExportFilter = rGraphicFilter.GetExportInternalFilterName(nFilter);
319 Sequence< PropertyValue > aPropsForDialog{
320 comphelper::makePropertyValue("Graphic", xGraphic),
321 comphelper::makePropertyValue("FilterName", aExportFilter)
324 Sequence< PropertyValue > aFilterData;
325 bool bStatus = lcl_ExecuteFilterDialog(aPropsForDialog, aFilterData);
326 if (bStatus)
328 sal_Int32 nWidth = 0;
329 sal_Int32 nHeight = 0;
331 for (const auto& rProp : std::as_const(aFilterData))
333 if (rProp.Name == "PixelWidth")
335 rProp.Value >>= nWidth;
337 else if (rProp.Name == "PixelHeight")
339 rProp.Value >>= nHeight;
343 // scaling must performed here because png/jpg writer s
344 // do not take care of that.
345 Size aSizePixel( aGraphic.GetSizePixel() );
346 if( nWidth && nHeight &&
347 ( ( nWidth != aSizePixel.Width() ) ||
348 ( nHeight != aSizePixel.Height() ) ) )
350 BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
351 // export: use highest quality
352 aBmpEx.Scale( Size( nWidth, nHeight ), BmpScaleFlag::Lanczos );
353 aGraphic = aBmpEx;
356 XOutBitmap::WriteGraphic( aGraphic, sPath, aFilter,
357 XOutFlags::DontExpandFilename |
358 XOutFlags::DontAddExtension |
359 XOutFlags::UseNativeIfPossible,
360 nullptr, &aFilterData );
361 return sPath;
364 else
366 XOutBitmap::WriteGraphic( rGraphic, sPath, aFilter,
367 XOutFlags::DontExpandFilename |
368 XOutFlags::DontAddExtension |
369 XOutFlags::UseNativeIfPossible );
373 return OUString();
376 void GraphicHelper::SaveShapeAsGraphicToPath(
377 const css::uno::Reference<css::lang::XComponent>& xComponent,
378 const css::uno::Reference<css::drawing::XShape>& xShape, const OUString& aExportMimeType,
379 const OUString& sPath)
381 Reference<XComponentContext> xContext(::comphelper::getProcessComponentContext());
382 Reference<XInputStream> xGraphStream;
384 if (xGraphStream.is())
386 Reference<XSimpleFileAccess3> xFileAccess = SimpleFileAccess::create(xContext);
387 xFileAccess->writeFile(sPath, xGraphStream);
389 else if (xComponent.is() && aExportMimeType == "application/pdf")
391 css::uno::Reference<css::lang::XMultiServiceFactory> xMSF(xContext->getServiceManager(),
392 css::uno::UNO_QUERY);
393 css::uno::Reference<css::document::XExporter> xExporter(
394 xMSF->createInstance("com.sun.star.comp.PDF.PDFFilter"), css::uno::UNO_QUERY);
395 xExporter->setSourceDocument(xComponent);
397 css::uno::Reference<css::drawing::XShapes> xShapes
398 = css::drawing::ShapeCollection::create(comphelper::getProcessComponentContext());
399 xShapes->add(xShape);
400 css::uno::Sequence<PropertyValue> aFilterData{
401 comphelper::makePropertyValue("Selection", xShapes),
403 SvFileStream aStream(sPath, StreamMode::READWRITE | StreamMode::TRUNC);
404 css::uno::Reference<css::io::XOutputStream> xStream(new utl::OStreamWrapper(aStream));
405 css::uno::Sequence<PropertyValue> aDescriptor{
406 comphelper::makePropertyValue("FilterData", aFilterData),
407 comphelper::makePropertyValue("OutputStream", xStream)
409 css::uno::Reference<css::document::XFilter> xFilter(xExporter, css::uno::UNO_QUERY);
410 xFilter->filter(aDescriptor);
412 else
414 Reference<css::drawing::XGraphicExportFilter> xGraphicExporter
415 = css::drawing::GraphicExportFilter::create(xContext);
417 Sequence<PropertyValue> aDescriptor{ comphelper::makePropertyValue("MediaType",
418 aExportMimeType),
419 comphelper::makePropertyValue("URL", sPath) };
421 Reference<XComponent> xSourceDocument(xShape, UNO_QUERY_THROW);
422 xGraphicExporter->setSourceDocument(xSourceDocument);
423 xGraphicExporter->filter(aDescriptor);
427 void GraphicHelper::SaveShapeAsGraphic(weld::Window* pParent,
428 const css::uno::Reference<css::lang::XComponent>& xComponent,
429 const Reference<drawing::XShape>& xShape)
433 Reference< XPropertySet > xShapeSet( xShape, UNO_QUERY_THROW );
435 FileDialogHelper aDialogHelper(TemplateDescription::FILESAVE_AUTOEXTENSION, FileDialogFlags::NONE, pParent);
436 Reference < XFilePicker3 > xFilePicker = aDialogHelper.GetFilePicker();
437 aDialogHelper.SetContext(FileDialogHelper::ExportImage);
438 aDialogHelper.SetTitle( SvxResId(RID_SVXSTR_SAVEAS_IMAGE) );
440 // populate filter dialog filter list and select default filter to match graphic mime type
442 GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
443 static const OUStringLiteral aDefaultMimeType(u"image/png");
444 OUString aDefaultFormatName;
445 sal_uInt16 nCount = rGraphicFilter.GetExportFormatCount();
447 std::map< OUString, OUString > aMimeTypeMap;
449 for ( sal_uInt16 i = 0; i < nCount; i++ )
451 const OUString aExportFormatName( rGraphicFilter.GetExportFormatName( i ) );
452 const OUString aFilterMimeType( rGraphicFilter.GetExportFormatMediaType( i ) );
453 xFilePicker->appendFilter( aExportFormatName, rGraphicFilter.GetExportWildcard( i ) );
454 aMimeTypeMap[ aExportFormatName ] = aFilterMimeType;
455 if( aDefaultMimeType == aFilterMimeType )
456 aDefaultFormatName = aExportFormatName;
459 if( !aDefaultFormatName.isEmpty() )
460 xFilePicker->setCurrentFilter( aDefaultFormatName );
462 // execute dialog
464 if( aDialogHelper.Execute() == ERRCODE_NONE )
466 OUString sPath( xFilePicker->getFiles().getConstArray()[0] );
467 OUString aExportMimeType( aMimeTypeMap[xFilePicker->getCurrentFilter()] );
469 GraphicHelper::SaveShapeAsGraphicToPath(xComponent, xShape, aExportMimeType, sPath);
472 catch( Exception& )
477 short GraphicHelper::HasToSaveTransformedImage(weld::Widget* pWin)
479 OUString aMsg(SvxResId(RID_SVXSTR_SAVE_MODIFIED_IMAGE));
480 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pWin,
481 VclMessageType::Question, VclButtonsType::YesNo, aMsg));
482 return xBox->run();
485 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */