bump product version to 7.2.5.1
[LibreOffice.git] / svx / source / unodraw / UnoGraphicExporter.cxx
blob8785b910a0e6b4af35d2baca349f2ced3151a1b3
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 <vector>
21 #include <com/sun/star/io/XOutputStream.hpp>
22 #include <com/sun/star/beans/XPropertySet.hpp>
23 #include <com/sun/star/container/XChild.hpp>
24 #include <com/sun/star/lang/XServiceInfo.hpp>
25 #include <com/sun/star/lang/XComponent.hpp>
26 #include <com/sun/star/drawing/XShape.hpp>
27 #include <com/sun/star/drawing/XDrawPage.hpp>
28 #include <com/sun/star/drawing/XGraphicExportFilter.hpp>
29 #include <com/sun/star/graphic/XGraphic.hpp>
30 #include <com/sun/star/graphic/XGraphicRenderer.hpp>
31 #include <com/sun/star/task/XStatusIndicator.hpp>
32 #include <com/sun/star/task/XInteractionHandler.hpp>
33 #include <com/sun/star/task/XInteractionContinuation.hpp>
34 #include <com/sun/star/uno/XComponentContext.hpp>
36 #include <tools/debug.hxx>
37 #include <tools/diagnose_ex.h>
38 #include <tools/urlobj.hxx>
39 #include <comphelper/interaction.hxx>
40 #include <framework/interaction.hxx>
41 #include <com/sun/star/drawing/GraphicFilterRequest.hpp>
42 #include <com/sun/star/util/URL.hpp>
43 #include <cppuhelper/implbase.hxx>
44 #include <cppuhelper/supportsservice.hxx>
45 #include <vcl/metaact.hxx>
46 #include <vcl/svapp.hxx>
47 #include <vcl/virdev.hxx>
48 #include <svl/outstrm.hxx>
49 #include <sdr/contact/objectcontactofobjlistpainter.hxx>
50 #include <svx/sdr/contact/viewobjectcontact.hxx>
51 #include <svx/sdr/contact/viewcontact.hxx>
52 #include <svx/sdr/contact/displayinfo.hxx>
53 #include <editeng/numitem.hxx>
54 #include <svx/svdograf.hxx>
55 #include <svx/xoutbmp.hxx>
56 #include <vcl/graphicfilter.hxx>
57 #include <svx/unoapi.hxx>
58 #include <svx/svdpage.hxx>
59 #include <svx/svdmodel.hxx>
60 #include <svx/fmview.hxx>
61 #include <svx/fmmodel.hxx>
62 #include <svx/unopage.hxx>
63 #include <svx/svdoutl.hxx>
64 #include <svx/xlineit0.hxx>
65 #include <editeng/flditem.hxx>
66 #include "UnoGraphicExporter.hxx"
67 #include <memory>
69 #define MAX_EXT_PIX 2048
71 using namespace ::comphelper;
72 using namespace ::cppu;
73 using namespace ::com::sun::star;
74 using namespace ::com::sun::star::uno;
75 using namespace ::com::sun::star::util;
76 using namespace ::com::sun::star::container;
77 using namespace ::com::sun::star::drawing;
78 using namespace ::com::sun::star::lang;
79 using namespace ::com::sun::star::document;
80 using namespace ::com::sun::star::beans;
81 using namespace ::com::sun::star::task;
83 // #i102251#
84 #include <editeng/editstat.hxx>
86 namespace {
88 struct ExportSettings
90 OUString maFilterName;
91 OUString maMediaType;
92 URL maURL;
93 css::uno::Reference< css::io::XOutputStream > mxOutputStream;
94 css::uno::Reference< css::graphic::XGraphicRenderer > mxGraphicRenderer;
95 css::uno::Reference< css::task::XStatusIndicator > mxStatusIndicator;
96 css::uno::Reference< css::task::XInteractionHandler > mxInteractionHandler;
98 sal_Int32 mnWidth;
99 sal_Int32 mnHeight;
100 bool mbExportOnlyBackground;
101 bool mbScrollText;
102 bool mbUseHighContrast;
103 bool mbTranslucent;
105 Sequence< PropertyValue > maFilterData;
107 Fraction maScaleX;
108 Fraction maScaleY;
110 TriState meAntiAliasing = TRISTATE_INDET;
112 explicit ExportSettings(const SdrModel* pSdrModel);
115 ExportSettings::ExportSettings(const SdrModel* pSdrModel)
116 : mnWidth( 0 )
117 ,mnHeight( 0 )
118 ,mbExportOnlyBackground( false )
119 ,mbScrollText( false )
120 ,mbUseHighContrast( false )
121 ,mbTranslucent( false )
122 ,maScaleX( 1, 1 )
123 ,maScaleY( 1, 1 )
125 if (pSdrModel)
127 maScaleX = pSdrModel->GetScaleFraction();
128 maScaleY = pSdrModel->GetScaleFraction();
132 /** implements a component to export shapes or pages to external graphic formats.
134 @implements com.sun.star.drawing.GraphicExportFilter
136 class GraphicExporter : public WeakImplHelper< XGraphicExportFilter, XServiceInfo >
138 public:
139 GraphicExporter();
141 // XFilter
142 virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& aDescriptor ) override;
143 virtual void SAL_CALL cancel( ) override;
145 // XExporter
146 virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) override;
148 // XServiceInfo
149 virtual OUString SAL_CALL getImplementationName( ) override;
150 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
151 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
153 // XMimeTypeInfo
154 virtual sal_Bool SAL_CALL supportsMimeType( const OUString& MimeTypeName ) override;
155 virtual Sequence< OUString > SAL_CALL getSupportedMimeTypeNames( ) override;
157 VclPtr<VirtualDevice> CreatePageVDev( SdrPage* pPage, tools::Long nWidthPixel, tools::Long nHeightPixel ) const;
159 DECL_LINK( CalcFieldValueHdl, EditFieldInfo*, void );
161 void ParseSettings( const Sequence< PropertyValue >& aDescriptor, ExportSettings& rSettings );
162 bool GetGraphic( ExportSettings const & rSettings, Graphic& aGraphic, bool bVectorType );
164 private:
165 Reference< XShape > mxShape;
166 Reference< XDrawPage > mxPage;
167 Reference< XShapes > mxShapes;
168 Graphic maGraphic;
170 SvxDrawPage* mpUnoPage;
172 Link<EditFieldInfo*,void> maOldCalcFieldValueHdl;
173 sal_Int32 mnPageNumber;
174 SdrPage* mpCurrentPage;
175 SdrModel* mpDoc;
178 /** creates a bitmap that is optionally transparent from a metafile
180 BitmapEx GetBitmapFromMetaFile( const GDIMetaFile& rMtf,bool bIsSelection, const Size* pSize )
182 // use new primitive conversion tooling
183 basegfx::B2DRange aRange(basegfx::B2DPoint(0.0, 0.0));
184 sal_uInt32 nMaximumQuadraticPixels(500000);
186 if(pSize)
188 // use 100th mm for primitive bitmap converter tool, input is pixel
189 // use a real OutDev to get the correct DPI, the static LogicToLogic assumes 72dpi which is wrong (!)
190 const Size aSize100th(Application::GetDefaultDevice()->PixelToLogic(*pSize, MapMode(MapUnit::Map100thMM)));
192 aRange.expand(basegfx::B2DPoint(aSize100th.Width(), aSize100th.Height()));
194 // when explicitly pixels are requested from the GraphicExporter, use a *very* high limit
195 // of 16gb (4096x4096 pixels), else use the default for the converters
196 nMaximumQuadraticPixels = std::min(sal_uInt32(4096 * 4096), sal_uInt32(pSize->Width() * pSize->Height()));
198 else
200 // use 100th mm for primitive bitmap converter tool
201 const Size aSize100th(OutputDevice::LogicToLogic(rMtf.GetPrefSize(), rMtf.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)));
203 aRange.expand(basegfx::B2DPoint(aSize100th.Width(), aSize100th.Height()));
206 // get hairline and full bound rect to evtl. correct logic size by the
207 // equivalent of one pixel to make those visible at right and bottom
208 tools::Rectangle aHairlineRect;
209 const tools::Rectangle aRect(rMtf.GetBoundRect(*Application::GetDefaultDevice(), &aHairlineRect));
211 if(!aRect.IsEmpty())
213 GDIMetaFile aMtf(rMtf);
215 if (bIsSelection)
217 // tdf#105998 Correct the Metafile using information from it's real sizes measured
218 // using rMtf.GetBoundRect above and a copy
219 const Size aOnePixelInMtf(
220 Application::GetDefaultDevice()->PixelToLogic(
221 Size(1, 1),
222 rMtf.GetPrefMapMode()));
223 const Size aHalfPixelInMtf(
224 (aOnePixelInMtf.getWidth() + 1) / 2,
225 (aOnePixelInMtf.getHeight() + 1) / 2);
226 const bool bHairlineBR(
227 !aHairlineRect.IsEmpty() && (aRect.Right() == aHairlineRect.Right() || aRect.Bottom() == aHairlineRect.Bottom()));
229 // Move the content to (0,0), usually TopLeft ist slightly
230 // negative. For better visualization, add a half pixel, too
231 aMtf.Move(
232 aHalfPixelInMtf.getWidth() - aRect.Left(),
233 aHalfPixelInMtf.getHeight() - aRect.Top());
235 // Do not Scale, but set the PrefSize. Some levels deeper the
236 // MetafilePrimitive will add a mapping to the decomposition
237 // (and possibly a clipping) to map the graphic content to
238 // a unit coordinate system.
239 // Size is the measured size plus one pixel if needed (bHairlineBR)
240 // and the moved half pixwel from above
241 aMtf.SetPrefSize(
242 Size(
243 aRect.getWidth() + (bHairlineBR ? aOnePixelInMtf.getWidth() : 0) + aHalfPixelInMtf.getWidth(),
244 aRect.getHeight() + (bHairlineBR ? aOnePixelInMtf.getHeight() : 0) + aHalfPixelInMtf.getHeight()));
247 return convertMetafileToBitmapEx(aMtf, aRange, nMaximumQuadraticPixels);
250 return BitmapEx();
253 Size* CalcSize( sal_Int32 nWidth, sal_Int32 nHeight, const Size& aBoundSize, Size& aOutSize )
255 if( (nWidth == 0) && (nHeight == 0) )
256 return nullptr;
258 if( (nWidth == 0) && (nHeight != 0) && (aBoundSize.Height() != 0) )
260 nWidth = ( nHeight * aBoundSize.Width() ) / aBoundSize.Height();
262 else if( (nWidth != 0) && (nHeight == 0) && (aBoundSize.Width() != 0) )
264 nHeight = ( nWidth * aBoundSize.Height() ) / aBoundSize.Width();
267 aOutSize.setWidth( nWidth );
268 aOutSize.setHeight( nHeight );
270 return &aOutSize;
273 class ImplExportCheckVisisbilityRedirector : public sdr::contact::ViewObjectContactRedirector
275 public:
276 explicit ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage );
278 virtual drawinglayer::primitive2d::Primitive2DContainer createRedirectedPrimitive2DSequence(
279 const sdr::contact::ViewObjectContact& rOriginal,
280 const sdr::contact::DisplayInfo& rDisplayInfo) override;
282 private:
283 SdrPage* mpCurrentPage;
286 ImplExportCheckVisisbilityRedirector::ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage )
287 : ViewObjectContactRedirector(), mpCurrentPage( pCurrentPage )
291 drawinglayer::primitive2d::Primitive2DContainer ImplExportCheckVisisbilityRedirector::createRedirectedPrimitive2DSequence(
292 const sdr::contact::ViewObjectContact& rOriginal,
293 const sdr::contact::DisplayInfo& rDisplayInfo)
295 SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject();
297 if(pObject)
299 SdrPage* pPage = mpCurrentPage;
301 if(nullptr == pPage)
303 pPage = pObject->getSdrPageFromSdrObject();
306 if( (pPage == nullptr) || pPage->checkVisibility(rOriginal, rDisplayInfo, false) )
308 return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo);
311 return drawinglayer::primitive2d::Primitive2DContainer();
313 else
315 // not an object, maybe a page
316 return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo);
320 GraphicExporter::GraphicExporter()
321 : mpUnoPage( nullptr ), mnPageNumber(-1), mpCurrentPage(nullptr), mpDoc( nullptr )
325 IMPL_LINK(GraphicExporter, CalcFieldValueHdl, EditFieldInfo*, pInfo, void)
327 if( pInfo )
329 if( mpCurrentPage )
331 pInfo->SetSdrPage( mpCurrentPage );
333 else if( mnPageNumber != -1 )
335 const SvxFieldData* pField = pInfo->GetField().GetField();
336 if( dynamic_cast<const SvxPageField*>( pField) )
338 OUString aPageNumValue;
339 bool bUpper = false;
341 switch(mpDoc->GetPageNumType())
343 case css::style::NumberingType::CHARS_UPPER_LETTER:
344 aPageNumValue += OUStringChar( sal_Unicode((mnPageNumber - 1) % 26 + 'A') );
345 break;
346 case css::style::NumberingType::CHARS_LOWER_LETTER:
347 aPageNumValue += OUStringChar( sal_Unicode((mnPageNumber - 1) % 26 + 'a') );
348 break;
349 case css::style::NumberingType::ROMAN_UPPER:
350 bUpper = true;
351 [[fallthrough]];
352 case css::style::NumberingType::ROMAN_LOWER:
353 aPageNumValue += SvxNumberFormat::CreateRomanString(mnPageNumber, bUpper);
354 break;
355 case css::style::NumberingType::NUMBER_NONE:
356 aPageNumValue = " ";
357 break;
358 default:
359 aPageNumValue += OUString::number( mnPageNumber );
362 pInfo->SetRepresentation( aPageNumValue );
364 return;
369 maOldCalcFieldValueHdl.Call( pInfo );
371 if( pInfo && mpCurrentPage )
372 pInfo->SetSdrPage( nullptr );
375 /** creates a virtual device for the given page
377 @return the returned VirtualDevice is owned by the caller
379 VclPtr<VirtualDevice> GraphicExporter::CreatePageVDev( SdrPage* pPage, tools::Long nWidthPixel, tools::Long nHeightPixel ) const
381 VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create();
382 MapMode aMM( MapUnit::Map100thMM );
384 Point aPoint( 0, 0 );
385 Size aPageSize(pPage->GetSize());
387 // use scaling?
388 if( nWidthPixel != 0 )
390 const Fraction aFrac( nWidthPixel, pVDev->LogicToPixel( aPageSize, aMM ).Width() );
392 aMM.SetScaleX( aFrac );
394 if( nHeightPixel == 0 )
395 aMM.SetScaleY( aFrac );
398 if( nHeightPixel != 0 )
400 const Fraction aFrac( nHeightPixel, pVDev->LogicToPixel( aPageSize, aMM ).Height() );
402 if( nWidthPixel == 0 )
403 aMM.SetScaleX( aFrac );
405 aMM.SetScaleY( aFrac );
408 pVDev->SetMapMode( aMM );
409 bool bSuccess(false);
411 // #i122820# If available, use pixel size directly
412 if(nWidthPixel && nHeightPixel)
414 bSuccess = pVDev->SetOutputSizePixel(Size(nWidthPixel, nHeightPixel));
416 else
418 bSuccess = pVDev->SetOutputSize(aPageSize);
421 if(bSuccess)
423 SdrView aView(*mpDoc, pVDev);
425 aView.SetPageVisible( false );
426 aView.SetBordVisible( false );
427 aView.SetGridVisible( false );
428 aView.SetHlplVisible( false );
429 aView.SetGlueVisible( false );
430 aView.ShowSdrPage(pPage);
432 vcl::Region aRegion (tools::Rectangle( aPoint, aPageSize ) );
434 ImplExportCheckVisisbilityRedirector aRedirector( mpCurrentPage );
436 aView.CompleteRedraw(pVDev, aRegion, &aRedirector);
438 else
440 OSL_ENSURE(false, "Could not get a VirtualDevice of requested size (!)");
443 return pVDev;
446 void GraphicExporter::ParseSettings( const Sequence< PropertyValue >& aDescriptor, ExportSettings& rSettings )
448 for( const PropertyValue& rValue : aDescriptor )
450 if ( rValue.Name == "FilterName" )
452 rValue.Value >>= rSettings.maFilterName;
454 else if ( rValue.Name == "MediaType" )
456 rValue.Value >>= rSettings.maMediaType;
458 else if ( rValue.Name == "URL" )
460 if( !( rValue.Value >>= rSettings.maURL ) )
462 rValue.Value >>= rSettings.maURL.Complete;
465 else if ( rValue.Name == "OutputStream" )
467 rValue.Value >>= rSettings.mxOutputStream;
469 else if ( rValue.Name == "GraphicRenderer" )
471 rValue.Value >>= rSettings.mxGraphicRenderer;
473 else if ( rValue.Name == "StatusIndicator" )
475 rValue.Value >>= rSettings.mxStatusIndicator;
477 else if ( rValue.Name == "InteractionHandler" )
479 rValue.Value >>= rSettings.mxInteractionHandler;
481 else if( rValue.Name == "Width" ) // for compatibility reasons, deprecated
483 rValue.Value >>= rSettings.mnWidth;
485 else if( rValue.Name == "Height" ) // for compatibility reasons, deprecated
487 rValue.Value >>= rSettings.mnHeight;
489 else if( rValue.Name == "ExportOnlyBackground" ) // for compatibility reasons, deprecated
491 rValue.Value >>= rSettings.mbExportOnlyBackground;
493 else if ( rValue.Name == "FilterData" )
495 rValue.Value >>= rSettings.maFilterData;
497 for( PropertyValue& rDataValue : rSettings.maFilterData )
499 if ( rDataValue.Name == "Translucent" )
501 if ( !( rDataValue.Value >>= rSettings.mbTranslucent ) ) // SJ: TODO: The GIF Transparency is stored as int32 in
502 { // configuration files, this has to be changed to boolean
503 sal_Int32 nTranslucent = 0;
504 if ( rDataValue.Value >>= nTranslucent )
505 rSettings.mbTranslucent = nTranslucent != 0;
508 else if ( rDataValue.Name == "PixelWidth" )
510 rDataValue.Value >>= rSettings.mnWidth;
512 else if ( rDataValue.Name == "PixelHeight" )
514 rDataValue.Value >>= rSettings.mnHeight;
516 else if( rDataValue.Name == "Width" ) // for compatibility reasons, deprecated
518 rDataValue.Value >>= rSettings.mnWidth;
519 rDataValue.Name = "PixelWidth";
521 else if( rDataValue.Name == "Height" ) // for compatibility reasons, deprecated
523 rDataValue.Value >>= rSettings.mnHeight;
524 rDataValue.Name = "PixelHeight";
526 else if ( rDataValue.Name == "ExportOnlyBackground" )
528 rDataValue.Value >>= rSettings.mbExportOnlyBackground;
530 else if ( rDataValue.Name == "HighContrast" )
532 rDataValue.Value >>= rSettings.mbUseHighContrast;
534 else if ( rDataValue.Name == "PageNumber" )
536 rDataValue.Value >>= mnPageNumber;
538 else if ( rDataValue.Name == "ScrollText" )
540 // #110496# Read flag solitary scroll text metafile
541 rDataValue.Value >>= rSettings.mbScrollText;
543 else if ( rDataValue.Name == "CurrentPage" )
545 Reference< XDrawPage > xPage;
546 rDataValue.Value >>= xPage;
547 if( xPage.is() )
549 SvxDrawPage* pUnoPage = comphelper::getUnoTunnelImplementation<SvxDrawPage>( xPage );
550 if( pUnoPage && pUnoPage->GetSdrPage() )
551 mpCurrentPage = pUnoPage->GetSdrPage();
554 else if ( rDataValue.Name == "ScaleXNumerator" )
556 sal_Int32 nVal = 1;
557 if( rDataValue.Value >>= nVal )
558 rSettings.maScaleX = Fraction( nVal, rSettings.maScaleX.GetDenominator() );
560 else if ( rDataValue.Name == "ScaleXDenominator" )
562 sal_Int32 nVal = 1;
563 if( rDataValue.Value >>= nVal )
564 rSettings.maScaleX = Fraction( rSettings.maScaleX.GetNumerator(), nVal );
566 else if ( rDataValue.Name == "ScaleYNumerator" )
568 sal_Int32 nVal = 1;
569 if( rDataValue.Value >>= nVal )
570 rSettings.maScaleY = Fraction( nVal, rSettings.maScaleY.GetDenominator() );
572 else if ( rDataValue.Name == "ScaleYDenominator" )
574 sal_Int32 nVal = 1;
575 if( rDataValue.Value >>= nVal )
576 rSettings.maScaleY = Fraction( rSettings.maScaleY.GetNumerator(), nVal );
578 else if (rDataValue.Name == "AntiAliasing")
580 bool bAntiAliasing;
581 if (rDataValue.Value >>= bAntiAliasing)
582 rSettings.meAntiAliasing = bAntiAliasing ? TRISTATE_TRUE : TRISTATE_FALSE;
588 // putting the StatusIndicator that we got from the MediaDescriptor into our local FilterData copy
589 if ( rSettings.mxStatusIndicator.is() )
591 int i = rSettings.maFilterData.getLength();
592 rSettings.maFilterData.realloc( i + 1 );
593 rSettings.maFilterData[ i ].Name = "StatusIndicator";
594 rSettings.maFilterData[ i ].Value <<= rSettings.mxStatusIndicator;
598 bool GraphicExporter::GetGraphic( ExportSettings const & rSettings, Graphic& aGraphic, bool bVectorType )
600 if( !mpDoc || !mpUnoPage )
601 return false;
603 SdrPage* pPage = mpUnoPage->GetSdrPage();
604 if( !pPage )
605 return false;
607 ScopedVclPtrInstance< VirtualDevice > aVDev;
608 const MapMode aMap( mpDoc->GetScaleUnit(), Point(), rSettings.maScaleX, rSettings.maScaleY );
610 SdrOutliner& rOutl=mpDoc->GetDrawOutliner();
611 maOldCalcFieldValueHdl = rOutl.GetCalcFieldValueHdl();
612 rOutl.SetCalcFieldValueHdl( LINK(this, GraphicExporter, CalcFieldValueHdl) );
613 rOutl.SetBackgroundColor( pPage->GetPageBackgroundColor() );
615 // #i102251#
616 const EEControlBits nOldCntrl(rOutl.GetControlWord());
617 EEControlBits nCntrl = nOldCntrl & ~EEControlBits::ONLINESPELLING;
618 rOutl.SetControlWord(nCntrl);
620 SdrObject* pTempBackgroundShape = nullptr;
621 std::vector< SdrObject* > aShapes;
622 bool bRet = true;
624 // export complete page?
625 if ( !mxShape.is() )
627 if( rSettings.mbExportOnlyBackground )
629 const SdrPageProperties* pCorrectProperties = pPage->getCorrectSdrPageProperties();
631 if(pCorrectProperties)
633 pTempBackgroundShape = new SdrRectObj(
634 *mpDoc,
635 tools::Rectangle(Point(0,0), pPage->GetSize()));
636 pTempBackgroundShape->SetMergedItemSet(pCorrectProperties->GetItemSet());
637 pTempBackgroundShape->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
638 pTempBackgroundShape->NbcSetStyleSheet(pCorrectProperties->GetStyleSheet(), true);
639 aShapes.push_back(pTempBackgroundShape);
642 else
644 const Size aSize( pPage->GetSize() );
646 // generate a bitmap to convert it to a pixel format.
647 // For gif pictures there can also be a vector format used (bTranslucent)
648 if ( !bVectorType && !rSettings.mbTranslucent )
650 tools::Long nWidthPix = 0;
651 tools::Long nHeightPix = 0;
652 if ( rSettings.mnWidth > 0 && rSettings.mnHeight > 0 )
654 nWidthPix = rSettings.mnWidth;
655 nHeightPix = rSettings.mnHeight;
657 else
659 const Size aSizePix( Application::GetDefaultDevice()->LogicToPixel( aSize, aMap ) );
660 if (aSizePix.Width() > MAX_EXT_PIX || aSizePix.Height() > MAX_EXT_PIX)
662 if (aSizePix.Width() > MAX_EXT_PIX)
663 nWidthPix = MAX_EXT_PIX;
664 else
665 nWidthPix = aSizePix.Width();
666 if (aSizePix.Height() > MAX_EXT_PIX)
667 nHeightPix = MAX_EXT_PIX;
668 else
669 nHeightPix = aSizePix.Height();
671 double fWidthDif = static_cast<double>(aSizePix.Width()) / nWidthPix;
672 double fHeightDif = static_cast<double>(aSizePix.Height()) / nHeightPix;
674 if (fWidthDif > fHeightDif)
675 nHeightPix = static_cast<tools::Long>(aSizePix.Height() / fWidthDif);
676 else
677 nWidthPix = static_cast<tools::Long>(aSizePix.Width() / fHeightDif);
679 else
681 nWidthPix = aSizePix.Width();
682 nHeightPix = aSizePix.Height();
686 std::unique_ptr<SdrView> xLocalView;
688 if (FmFormModel* pFormModel = dynamic_cast<FmFormModel*>(mpDoc))
690 xLocalView.reset(new FmFormView(*pFormModel, aVDev));
692 else
694 xLocalView.reset(new SdrView(*mpDoc, aVDev));
697 ScopedVclPtr<VirtualDevice> pVDev(CreatePageVDev( pPage, nWidthPix, nHeightPix ));
699 if( pVDev )
701 aGraphic = pVDev->GetBitmapEx( Point(), pVDev->GetOutputSize() );
702 aGraphic.SetPrefMapMode( aMap );
703 aGraphic.SetPrefSize( aSize );
706 // create a metafile to export a vector format
707 else
709 GDIMetaFile aMtf;
711 aVDev->SetMapMode( aMap );
712 if( rSettings.mbUseHighContrast )
713 aVDev->SetDrawMode( aVDev->GetDrawMode() | DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient );
714 aVDev->EnableOutput( false );
715 aMtf.Record( aVDev );
716 Size aNewSize;
718 // create a view
719 std::unique_ptr< SdrView > pView;
721 if (FmFormModel *pFormModel = dynamic_cast<FmFormModel*>(mpDoc))
723 pView.reset(new FmFormView(*pFormModel, aVDev));
725 else
727 pView.reset(new SdrView(*mpDoc, aVDev));
730 pView->SetBordVisible( false );
731 pView->SetPageVisible( false );
732 pView->ShowSdrPage( pPage );
734 // tdf#96922 completely deactivate EditView PageVisualization, including
735 // PageBackground (formerly 'wiese').
736 pView->SetPagePaintingAllowed(false);
738 const Point aNewOrg( pPage->GetLeftBorder(), pPage->GetUpperBorder() );
739 aNewSize = Size( aSize.Width() - pPage->GetLeftBorder() - pPage->GetRightBorder(),
740 aSize.Height() - pPage->GetUpperBorder() - pPage->GetLowerBorder() );
741 const tools::Rectangle aClipRect( aNewOrg, aNewSize );
742 MapMode aVMap( aMap );
744 aVDev->Push();
745 aVMap.SetOrigin( Point( -aNewOrg.X(), -aNewOrg.Y() ) );
746 aVDev->SetRelativeMapMode( aVMap );
747 aVDev->IntersectClipRegion( aClipRect );
749 // Use new StandardCheckVisisbilityRedirector
750 ImplExportCheckVisisbilityRedirector aRedirector( mpCurrentPage );
752 pView->CompleteRedraw(aVDev, vcl::Region(tools::Rectangle(aNewOrg, aNewSize)), &aRedirector);
754 aVDev->Pop();
756 aMtf.Stop();
757 aMtf.WindStart();
758 aMtf.SetPrefMapMode( aMap );
759 aMtf.SetPrefSize( aNewSize );
761 // AW: Here the current version was filtering out the MetaActionType::CLIPREGIONs
762 // from the metafile. I asked some other developers why this was done, but no
763 // one knew a direct reason. Since it's in for long time, it may be an old
764 // piece of code. MetaFiles save and load ClipRegions with polygons with preserving
765 // the polygons, so a resolution-independent roundtrip is supported. Removed this
766 // code since it destroys some MetaFiles where ClipRegions are used. Anyways,
767 // just filtering them out is a hack, at least the encapsulated content would need
768 // to be clipped geometrically.
769 aGraphic = Graphic(aMtf);
771 pView->HideSdrPage();
773 if( rSettings.mbTranslucent )
775 Size aOutSize;
776 aGraphic = GetBitmapFromMetaFile( aGraphic.GetGDIMetaFile(), false, CalcSize( rSettings.mnWidth, rSettings.mnHeight, aNewSize, aOutSize ) );
782 // export only single shape or shape collection
783 else
785 // build list of SdrObject
786 if( mxShapes.is() )
788 Reference< XShape > xShape;
789 const sal_Int32 nCount = mxShapes->getCount();
791 for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
793 mxShapes->getByIndex( nIndex ) >>= xShape;
794 SdrObject* pObj = GetSdrObjectFromXShape( xShape );
795 if( pObj )
796 aShapes.push_back( pObj );
799 else
801 // only one shape
802 SdrObject* pObj = GetSdrObjectFromXShape( mxShape );
803 if( pObj )
804 aShapes.push_back( pObj );
807 if( aShapes.empty() )
808 bRet = false;
811 if( bRet && !aShapes.empty() )
813 // special treatment for only one SdrGrafObj that has text
814 bool bSingleGraphic = false;
816 if( 1 == aShapes.size() )
818 if( !bVectorType )
820 if( auto pGrafObj = dynamic_cast<const SdrGrafObj*>(aShapes.front()) )
821 if (pGrafObj->HasText() )
823 aGraphic = pGrafObj->GetTransformedGraphic();
824 if ( aGraphic.GetType() == GraphicType::Bitmap )
826 Size aSizePixel( aGraphic.GetSizePixel() );
827 if( rSettings.mnWidth && rSettings.mnHeight &&
828 ( ( rSettings.mnWidth != aSizePixel.Width() ) ||
829 ( rSettings.mnHeight != aSizePixel.Height() ) ) )
831 BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
832 // export: use highest quality
833 aBmpEx.Scale( Size( rSettings.mnWidth, rSettings.mnHeight ), BmpScaleFlag::Lanczos );
834 aGraphic = aBmpEx;
837 // #118804# only accept for bitmap graphics, else the
838 // conversion to bitmap will happen anywhere without size control
839 // as evtl. defined in rSettings.mnWidth/mnHeight
840 bSingleGraphic = true;
844 else if( rSettings.mbScrollText )
846 SdrObject* pObj = aShapes.front();
847 auto pTextObj = dynamic_cast<SdrTextObj*>( pObj);
848 if( pTextObj && pTextObj->HasText() )
850 tools::Rectangle aScrollRectangle;
851 tools::Rectangle aPaintRectangle;
853 const std::unique_ptr< GDIMetaFile > pMtf(
854 pTextObj->GetTextScrollMetaFileAndRectangle(
855 aScrollRectangle, aPaintRectangle ) );
857 // take the larger one of the two rectangles (that
858 // should be the bound rect of the retrieved
859 // metafile)
860 tools::Rectangle aTextRect;
862 if( aScrollRectangle.IsInside( aPaintRectangle ) )
863 aTextRect = aScrollRectangle;
864 else
865 aTextRect = aPaintRectangle;
867 // setup pref size and mapmode
868 pMtf->SetPrefSize( aTextRect.GetSize() );
870 // set actual origin (mtf is at actual shape
871 // output position)
872 MapMode aLocalMapMode( aMap );
873 aLocalMapMode.SetOrigin(
874 Point( -aPaintRectangle.Left(),
875 -aPaintRectangle.Top() ) );
876 pMtf->SetPrefMapMode( aLocalMapMode );
878 pMtf->AddAction( new MetaCommentAction(
879 "XTEXT_SCROLLRECT", 0,
880 reinterpret_cast<sal_uInt8 const*>(&aScrollRectangle),
881 sizeof( tools::Rectangle ) ) );
882 pMtf->AddAction( new MetaCommentAction(
883 "XTEXT_PAINTRECT", 0,
884 reinterpret_cast<sal_uInt8 const*>(&aPaintRectangle),
885 sizeof( tools::Rectangle ) ) );
887 aGraphic = Graphic( *pMtf );
889 bSingleGraphic = true;
894 if( !bSingleGraphic )
896 // create a metafile for all shapes
897 ScopedVclPtrInstance< VirtualDevice > aOut;
899 // calculate bound rect for all shapes
900 tools::Rectangle aBound;
903 for( SdrObject* pObj : aShapes )
905 tools::Rectangle aR1(pObj->GetCurrentBoundRect());
906 if (aBound.IsEmpty())
907 aBound=aR1;
908 else
909 aBound.Union(aR1);
913 aOut->EnableOutput( false );
914 aOut->SetMapMode( aMap );
915 if( rSettings.mbUseHighContrast )
916 aOut->SetDrawMode( aOut->GetDrawMode() | DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient );
918 GDIMetaFile aMtf;
919 aMtf.Clear();
920 aMtf.Record( aOut );
922 MapMode aOutMap( aMap );
923 aOutMap.SetOrigin( Point( -aBound.Left(), -aBound.Top() ) );
924 aOut->SetRelativeMapMode( aOutMap );
926 sdr::contact::DisplayInfo aDisplayInfo;
928 if(mpCurrentPage)
930 if(mpCurrentPage->TRG_HasMasterPage() && pPage->IsMasterPage())
932 // MasterPage is processed as another page's SubContent
933 aDisplayInfo.SetProcessLayers(mpCurrentPage->TRG_GetMasterPageVisibleLayers());
934 aDisplayInfo.SetSubContentActive(true);
938 if(!aShapes.empty())
940 // more effective way to paint a vector of SdrObjects. Hand over the processed page
941 // to have it in the
942 sdr::contact::ObjectContactOfObjListPainter aMultiObjectPainter(*aOut, aShapes, mpCurrentPage);
943 ImplExportCheckVisisbilityRedirector aCheckVisibilityRedirector(mpCurrentPage);
944 aMultiObjectPainter.SetViewObjectContactRedirector(&aCheckVisibilityRedirector);
946 aMultiObjectPainter.ProcessDisplay(aDisplayInfo);
949 aMtf.Stop();
950 aMtf.WindStart();
952 const Size aExtSize( aOut->PixelToLogic( Size( 0, 0 ) ) );
953 Size aBoundSize( aBound.GetWidth() + ( aExtSize.Width() ),
954 aBound.GetHeight() + ( aExtSize.Height() ) );
956 aMtf.SetPrefMapMode( aMap );
957 aMtf.SetPrefSize( aBoundSize );
959 if( !bVectorType )
961 Size aOutSize;
962 aGraphic = GetBitmapFromMetaFile( aMtf, true, CalcSize( rSettings.mnWidth, rSettings.mnHeight, aBoundSize, aOutSize ) );
964 else
966 aGraphic = aMtf;
971 if(pTempBackgroundShape)
973 SdrObject::Free(pTempBackgroundShape);
976 rOutl.SetCalcFieldValueHdl( maOldCalcFieldValueHdl );
978 // #i102251#
979 rOutl.SetControlWord(nOldCntrl);
981 return bRet;
985 // XFilter
986 sal_Bool SAL_CALL GraphicExporter::filter( const Sequence< PropertyValue >& aDescriptor )
988 ::SolarMutexGuard aGuard;
990 if( maGraphic.IsNone() && nullptr == mpUnoPage )
991 return false;
993 if( maGraphic.IsNone() && ( nullptr == mpUnoPage->GetSdrPage() || nullptr == mpDoc ) )
994 return false;
996 GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
998 // get the arguments from the descriptor
999 ExportSettings aSettings(mpDoc);
1000 ParseSettings(aDescriptor, aSettings);
1002 const sal_uInt16 nFilter = !aSettings.maMediaType.isEmpty()
1003 ? rFilter.GetExportFormatNumberForMediaType( aSettings.maMediaType )
1004 : rFilter.GetExportFormatNumberForShortName( aSettings.maFilterName );
1005 bool bVectorType = !rFilter.IsExportPixelFormat( nFilter );
1007 // create the output stuff
1008 Graphic aGraphic = maGraphic;
1010 ErrCode nStatus = ERRCODE_NONE;
1011 if (maGraphic.IsNone())
1013 SvtOptionsDrawinglayer aOptions;
1014 bool bAntiAliasing = aOptions.IsAntiAliasing();
1015 AllSettings aAllSettings = Application::GetSettings();
1016 StyleSettings aStyleSettings = aAllSettings.GetStyleSettings();
1017 bool bUseFontAAFromSystem = aStyleSettings.GetUseFontAAFromSystem();
1018 if (aSettings.meAntiAliasing != TRISTATE_INDET)
1020 // This is safe to do globally as we own the solar mutex.
1021 aOptions.SetAntiAliasing(aSettings.meAntiAliasing == TRISTATE_TRUE);
1022 // Opt in to have AA affect font rendering as well.
1023 aStyleSettings.SetUseFontAAFromSystem(false);
1024 aAllSettings.SetStyleSettings(aStyleSettings);
1025 Application::SetSettings(aAllSettings);
1027 nStatus = GetGraphic( aSettings, aGraphic, bVectorType ) ? ERRCODE_NONE : ERRCODE_GRFILTER_FILTERERROR;
1028 if (aSettings.meAntiAliasing != TRISTATE_INDET)
1030 aOptions.SetAntiAliasing(bAntiAliasing);
1031 aStyleSettings.SetUseFontAAFromSystem(bUseFontAAFromSystem);
1032 aAllSettings.SetStyleSettings(aStyleSettings);
1033 Application::SetSettings(aAllSettings);
1037 if( nStatus == ERRCODE_NONE )
1039 // export graphic only if it has a size
1040 const Size aGraphSize( aGraphic.GetPrefSize() );
1041 if ( aGraphSize.IsEmpty() )
1043 nStatus = ERRCODE_GRFILTER_FILTERERROR;
1045 else
1047 // now we have a graphic, so export it
1048 if( aSettings.mxGraphicRenderer.is() )
1050 // render graphic directly into given renderer
1051 aSettings.mxGraphicRenderer->render( aGraphic.GetXGraphic() );
1053 else if( aSettings.mxOutputStream.is() )
1055 // TODO: Either utilize optional XSeekable functionality for the
1056 // SvOutputStream, or adapt the graphic filter to not seek anymore.
1057 SvMemoryStream aStream( 1024, 1024 );
1059 nStatus = rFilter.ExportGraphic( aGraphic,"", aStream, nFilter, &aSettings.maFilterData );
1061 // copy temp stream to XOutputStream
1062 SvOutputStream aOutputStream( aSettings.mxOutputStream );
1063 aStream.Seek(0);
1064 aOutputStream.WriteStream( aStream );
1066 else
1068 INetURLObject aURLObject( aSettings.maURL.Complete );
1069 DBG_ASSERT( aURLObject.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
1071 nStatus = XOutBitmap::ExportGraphic( aGraphic, aURLObject, rFilter, nFilter, &aSettings.maFilterData );
1076 if ( aSettings.mxInteractionHandler.is() && ( nStatus != ERRCODE_NONE ) )
1078 Any aInteraction;
1079 Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations(1);
1080 lContinuations[0] = new ::comphelper::OInteractionApprove();
1082 GraphicFilterRequest aErrorCode;
1083 aErrorCode.ErrCode = sal_uInt32(nStatus);
1084 aInteraction <<= aErrorCode;
1085 aSettings.mxInteractionHandler->handle( framework::InteractionRequest::CreateRequest( aInteraction, lContinuations ) );
1087 return nStatus == ERRCODE_NONE;
1090 void SAL_CALL GraphicExporter::cancel()
1094 // XExporter
1096 /** the source 'document' could be a XDrawPage, a XShape or a generic XShapes */
1097 void SAL_CALL GraphicExporter::setSourceDocument( const Reference< lang::XComponent >& xComponent )
1099 ::SolarMutexGuard aGuard;
1101 mxShapes = nullptr;
1102 mpUnoPage = nullptr;
1106 // any break inside this one loop while will throw an IllegalArgumentException
1109 mxPage.set( xComponent, UNO_QUERY );
1110 mxShapes.set( xComponent, UNO_QUERY );
1111 mxShape.set( xComponent, UNO_QUERY );
1113 // Step 1: try a generic XShapes
1114 if( !mxPage.is() && !mxShape.is() && mxShapes.is() )
1116 // we do not support empty shape collections
1117 if( 0 == mxShapes->getCount() )
1118 break;
1120 // get first shape to detect corresponding page and model
1121 mxShapes->getByIndex(0) >>= mxShape;
1123 else
1125 mxShapes = nullptr;
1128 // Step 2: try a shape
1129 if( mxShape.is() )
1131 if( nullptr == GetSdrObjectFromXShape( mxShape ) )
1133 // This is not a Draw shape, let's see if it's a Writer one.
1134 uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
1135 if (!xPropertySet.is())
1136 break;
1137 uno::Reference<graphic::XGraphic> xGraphic(
1138 xPropertySet->getPropertyValue("Graphic"), uno::UNO_QUERY);
1139 if (!xGraphic.is())
1140 break;
1142 maGraphic = Graphic(xGraphic);
1143 if (!maGraphic.IsNone())
1144 return;
1145 else
1146 break;
1149 // get page for this shape
1150 Reference< XChild > xChild( mxShape, UNO_QUERY );
1151 if( !xChild.is() )
1152 break;
1154 Reference< XInterface > xInt;
1157 xInt = xChild->getParent();
1158 mxPage.set( xInt, UNO_QUERY );
1159 if( !mxPage.is() )
1160 xChild.set( xInt, UNO_QUERY );
1162 while( !mxPage.is() && xChild.is() );
1164 if( !mxPage.is() )
1165 break;
1168 // Step 3: check the page
1169 if( !mxPage.is() )
1170 break;
1172 mpUnoPage = comphelper::getUnoTunnelImplementation<SvxDrawPage>( mxPage );
1174 if( nullptr == mpUnoPage || nullptr == mpUnoPage->GetSdrPage() )
1175 break;
1177 mpDoc = &mpUnoPage->GetSdrPage()->getSdrModelFromSdrPage();
1179 // Step 4: If we got a generic XShapes test all contained shapes
1180 // if they belong to the same XDrawPage
1182 if( mxShapes.is() )
1184 SdrPage* pPage = mpUnoPage->GetSdrPage();
1185 SdrObject* pObj;
1186 Reference< XShape > xShape;
1188 bool bOk = true;
1190 const sal_Int32 nCount = mxShapes->getCount();
1192 // test all but the first shape if they have the same page than
1193 // the first shape
1194 for( sal_Int32 nIndex = 1; bOk && ( nIndex < nCount ); nIndex++ )
1196 mxShapes->getByIndex( nIndex ) >>= xShape;
1197 pObj = GetSdrObjectFromXShape( xShape );
1198 bOk = pObj && pObj->getSdrPageFromSdrObject() == pPage;
1201 if( !bOk )
1202 break;
1205 // no errors so far
1206 return;
1208 while( false );
1210 catch( Exception& )
1214 throw IllegalArgumentException();
1217 // XServiceInfo
1218 OUString SAL_CALL GraphicExporter::getImplementationName( )
1220 return "com.sun.star.comp.Draw.GraphicExporter";
1223 sal_Bool SAL_CALL GraphicExporter::supportsService( const OUString& ServiceName )
1225 return cppu::supportsService(this, ServiceName);
1228 Sequence< OUString > SAL_CALL GraphicExporter::getSupportedServiceNames( )
1230 Sequence< OUString > aSupportedServiceNames { "com.sun.star.drawing.GraphicExportFilter" };
1231 return aSupportedServiceNames;
1234 // XMimeTypeInfo
1235 sal_Bool SAL_CALL GraphicExporter::supportsMimeType( const OUString& rMimeTypeName )
1237 GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
1238 sal_uInt16 nCount = rFilter.GetExportFormatCount();
1239 sal_uInt16 nFilter;
1240 for( nFilter = 0; nFilter < nCount; nFilter++ )
1242 if( rMimeTypeName == rFilter.GetExportFormatMediaType( nFilter ) )
1244 return true;
1248 return false;
1251 Sequence< OUString > SAL_CALL GraphicExporter::getSupportedMimeTypeNames( )
1253 GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
1254 sal_uInt16 nCount = rFilter.GetExportFormatCount();
1255 sal_uInt16 nFilter;
1256 sal_uInt16 nFound = 0;
1258 Sequence< OUString > aSeq( nCount );
1259 OUString* pStr = aSeq.getArray();
1261 for( nFilter = 0; nFilter < nCount; nFilter++ )
1263 OUString aMimeType( rFilter.GetExportFormatMediaType( nFilter ) );
1264 if( !aMimeType.isEmpty() )
1266 *pStr++ = aMimeType;
1267 nFound++;
1271 if( nFound < nCount )
1272 aSeq.realloc( nFound );
1274 return aSeq;
1279 Graphic SvxGetGraphicForShape( SdrObject& rShape )
1281 Graphic aGraphic;
1284 rtl::Reference< GraphicExporter > xExporter( new GraphicExporter() );
1285 Reference< XComponent > xComp( rShape.getUnoShape(), UNO_QUERY_THROW );
1286 xExporter->setSourceDocument( xComp );
1287 ExportSettings aSettings(&rShape.getSdrModelFromSdrObject());
1288 xExporter->GetGraphic( aSettings, aGraphic, true/*bVector*/ );
1290 catch( Exception& )
1292 TOOLS_WARN_EXCEPTION("svx", "");
1294 return aGraphic;
1297 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1298 com_sun_star_comp_Draw_GraphicExporter_get_implementation(
1299 css::uno::XComponentContext *,
1300 css::uno::Sequence<css::uno::Any> const &)
1302 return cppu::acquire(new GraphicExporter);
1305 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */