Bump version to 6.4.7.2.M8
[LibreOffice.git] / svx / source / unodraw / UnoGraphicExporter.cxx
blob4480fd53354020ac34c922645ecce74a209931f1
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/urlobj.hxx>
38 #include <comphelper/interaction.hxx>
39 #include <framework/interaction.hxx>
40 #include <com/sun/star/drawing/GraphicFilterRequest.hpp>
41 #include <com/sun/star/util/URL.hpp>
42 #include <cppuhelper/implbase.hxx>
43 #include <cppuhelper/supportsservice.hxx>
44 #include <osl/diagnose.h>
45 #include <vcl/metaact.hxx>
46 #include <vcl/svapp.hxx>
47 #include <vcl/virdev.hxx>
48 #include <vcl/FilterConfigItem.hxx>
49 #include <svl/outstrm.hxx>
50 #include <svx/sdr/contact/objectcontactofobjlistpainter.hxx>
51 #include <svx/sdr/contact/viewobjectcontact.hxx>
52 #include <svx/sdr/contact/viewcontact.hxx>
53 #include <svx/sdr/contact/displayinfo.hxx>
54 #include <svx/sdr/contact/viewcontactofsdrobj.hxx>
55 #include <editeng/numitem.hxx>
56 #include <svx/svdpagv.hxx>
57 #include <svx/svdograf.hxx>
58 #include <svx/xoutbmp.hxx>
59 #include <vcl/graphicfilter.hxx>
60 #include <svx/unoapi.hxx>
61 #include <svx/svdpage.hxx>
62 #include <svx/svdmodel.hxx>
63 #include <svx/fmview.hxx>
64 #include <svx/fmmodel.hxx>
65 #include <svx/unopage.hxx>
66 #include <svx/pageitem.hxx>
67 #include <editeng/eeitem.hxx>
68 #include <svx/svdoutl.hxx>
69 #include <svx/xlineit0.hxx>
70 #include <editeng/flditem.hxx>
71 #include "UnoGraphicExporter.hxx"
72 #include <memory>
74 #define MAX_EXT_PIX 2048
76 using namespace ::comphelper;
77 using namespace ::cppu;
78 using namespace ::com::sun::star;
79 using namespace ::com::sun::star::uno;
80 using namespace ::com::sun::star::util;
81 using namespace ::com::sun::star::container;
82 using namespace ::com::sun::star::drawing;
83 using namespace ::com::sun::star::lang;
84 using namespace ::com::sun::star::document;
85 using namespace ::com::sun::star::beans;
86 using namespace ::com::sun::star::task;
88 // #i102251#
89 #include <editeng/editstat.hxx>
91 namespace {
93 struct ExportSettings
95 OUString maFilterName;
96 OUString maMediaType;
97 URL maURL;
98 css::uno::Reference< css::io::XOutputStream > mxOutputStream;
99 css::uno::Reference< css::graphic::XGraphicRenderer > mxGraphicRenderer;
100 css::uno::Reference< css::task::XStatusIndicator > mxStatusIndicator;
101 css::uno::Reference< css::task::XInteractionHandler > mxInteractionHandler;
103 sal_Int32 mnWidth;
104 sal_Int32 mnHeight;
105 bool mbExportOnlyBackground;
106 bool mbScrollText;
107 bool mbUseHighContrast;
108 bool mbTranslucent;
110 Sequence< PropertyValue > maFilterData;
112 Fraction maScaleX;
113 Fraction maScaleY;
115 TriState meAntiAliasing = TRISTATE_INDET;
117 explicit ExportSettings(const SdrModel* pSdrModel);
120 ExportSettings::ExportSettings(const SdrModel* pSdrModel)
121 : mnWidth( 0 )
122 ,mnHeight( 0 )
123 ,mbExportOnlyBackground( false )
124 ,mbScrollText( false )
125 ,mbUseHighContrast( false )
126 ,mbTranslucent( false )
127 ,maScaleX( 1, 1 )
128 ,maScaleY( 1, 1 )
130 if (pSdrModel)
132 maScaleX = pSdrModel->GetScaleFraction();
133 maScaleY = pSdrModel->GetScaleFraction();
137 /** implements a component to export shapes or pages to external graphic formats.
139 @implements com.sun.star.drawing.GraphicExportFilter
141 class GraphicExporter : public WeakImplHelper< XGraphicExportFilter, XServiceInfo >
143 public:
144 GraphicExporter();
146 // XFilter
147 virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& aDescriptor ) override;
148 virtual void SAL_CALL cancel( ) override;
150 // XExporter
151 virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) override;
153 // XServiceInfo
154 virtual OUString SAL_CALL getImplementationName( ) override;
155 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
156 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
158 // XMimeTypeInfo
159 virtual sal_Bool SAL_CALL supportsMimeType( const OUString& MimeTypeName ) override;
160 virtual Sequence< OUString > SAL_CALL getSupportedMimeTypeNames( ) override;
162 VclPtr<VirtualDevice> CreatePageVDev( SdrPage* pPage, sal_uIntPtr nWidthPixel, sal_uIntPtr nHeightPixel ) const;
164 DECL_LINK( CalcFieldValueHdl, EditFieldInfo*, void );
166 void ParseSettings( const Sequence< PropertyValue >& aDescriptor, ExportSettings& rSettings );
167 bool GetGraphic( ExportSettings const & rSettings, Graphic& aGraphic, bool bVectorType );
169 private:
170 Reference< XShape > mxShape;
171 Reference< XDrawPage > mxPage;
172 Reference< XShapes > mxShapes;
173 Graphic maGraphic;
175 SvxDrawPage* mpUnoPage;
177 Link<EditFieldInfo*,void> maOldCalcFieldValueHdl;
178 sal_Int32 mnPageNumber;
179 SdrPage* mpCurrentPage;
180 SdrModel* mpDoc;
183 /** creates a bitmap that is optionally transparent from a metafile
185 BitmapEx GetBitmapFromMetaFile( const GDIMetaFile& rMtf,bool bIsSelection, const Size* pSize )
187 // use new primitive conversion tooling
188 basegfx::B2DRange aRange(basegfx::B2DPoint(0.0, 0.0));
189 sal_uInt32 nMaximumQuadraticPixels(500000);
191 if(pSize)
193 // use 100th mm for primitive bitmap converter tool, input is pixel
194 // use a real OutDev to get the correct DPI, the static LogicToLogic assumes 72dpi which is wrong (!)
195 const Size aSize100th(Application::GetDefaultDevice()->PixelToLogic(*pSize, MapMode(MapUnit::Map100thMM)));
197 aRange.expand(basegfx::B2DPoint(aSize100th.Width(), aSize100th.Height()));
199 // when explicitly pixels are requested from the GraphicExporter, use a *very* high limit
200 // of 16gb (4096x4096 pixels), else use the default for the converters
201 nMaximumQuadraticPixels = std::min(sal_uInt32(4096 * 4096), sal_uInt32(pSize->Width() * pSize->Height()));
203 else
205 // use 100th mm for primitive bitmap converter tool
206 const Size aSize100th(OutputDevice::LogicToLogic(rMtf.GetPrefSize(), rMtf.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)));
208 aRange.expand(basegfx::B2DPoint(aSize100th.Width(), aSize100th.Height()));
211 // get hairline and full bound rect to evtl. correct logic size by the
212 // equivalent of one pixel to make those visible at right and bottom
213 tools::Rectangle aHairlineRect;
214 const tools::Rectangle aRect(rMtf.GetBoundRect(*Application::GetDefaultDevice(), &aHairlineRect));
216 if(!aRect.IsEmpty())
218 GDIMetaFile aMtf(rMtf);
220 if (bIsSelection)
222 // tdf#105998 Correct the Metafile using information from it's real sizes measured
223 // using rMtf.GetBoundRect above and a copy
224 const Size aOnePixelInMtf(
225 Application::GetDefaultDevice()->PixelToLogic(
226 Size(1, 1),
227 rMtf.GetPrefMapMode()));
228 const Size aHalfPixelInMtf(
229 (aOnePixelInMtf.getWidth() + 1) / 2,
230 (aOnePixelInMtf.getHeight() + 1) / 2);
231 const bool bHairlineBR(
232 !aHairlineRect.IsEmpty() && (aRect.Right() == aHairlineRect.Right() || aRect.Bottom() == aHairlineRect.Bottom()));
234 // Move the content to (0,0), usually TopLeft ist slightly
235 // negative. For better visualization, add a half pixel, too
236 aMtf.Move(
237 aHalfPixelInMtf.getWidth() - aRect.Left(),
238 aHalfPixelInMtf.getHeight() - aRect.Top());
240 // Do not Scale, but set the PrefSize. Some levels deeper the
241 // MetafilePrimitive will add a mapping to the decomposition
242 // (and possibly a clipping) to map the graphic content to
243 // a unit coordinate system.
244 // Size is the measured size plus one pixel if needed (bHairlineBR)
245 // and the moved half pixwel from above
246 aMtf.SetPrefSize(
247 Size(
248 aRect.getWidth() + (bHairlineBR ? aOnePixelInMtf.getWidth() : 0) + aHalfPixelInMtf.getWidth(),
249 aRect.getHeight() + (bHairlineBR ? aOnePixelInMtf.getHeight() : 0) + aHalfPixelInMtf.getHeight()));
252 return convertMetafileToBitmapEx(aMtf, aRange, nMaximumQuadraticPixels);
255 return BitmapEx();
258 Size* CalcSize( sal_Int32 nWidth, sal_Int32 nHeight, const Size& aBoundSize, Size& aOutSize )
260 if( (nWidth == 0) && (nHeight == 0) )
261 return nullptr;
263 if( (nWidth == 0) && (nHeight != 0) && (aBoundSize.Height() != 0) )
265 nWidth = ( nHeight * aBoundSize.Width() ) / aBoundSize.Height();
267 else if( (nWidth != 0) && (nHeight == 0) && (aBoundSize.Width() != 0) )
269 nHeight = ( nWidth * aBoundSize.Height() ) / aBoundSize.Width();
272 aOutSize.setWidth( nWidth );
273 aOutSize.setHeight( nHeight );
275 return &aOutSize;
278 class ImplExportCheckVisisbilityRedirector : public sdr::contact::ViewObjectContactRedirector
280 public:
281 explicit ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage );
283 virtual drawinglayer::primitive2d::Primitive2DContainer createRedirectedPrimitive2DSequence(
284 const sdr::contact::ViewObjectContact& rOriginal,
285 const sdr::contact::DisplayInfo& rDisplayInfo) override;
287 private:
288 SdrPage* const mpCurrentPage;
291 ImplExportCheckVisisbilityRedirector::ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage )
292 : ViewObjectContactRedirector(), mpCurrentPage( pCurrentPage )
296 drawinglayer::primitive2d::Primitive2DContainer ImplExportCheckVisisbilityRedirector::createRedirectedPrimitive2DSequence(
297 const sdr::contact::ViewObjectContact& rOriginal,
298 const sdr::contact::DisplayInfo& rDisplayInfo)
300 SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject();
302 if(pObject)
304 SdrPage* pPage = mpCurrentPage;
306 if(nullptr == pPage)
308 pPage = pObject->getSdrPageFromSdrObject();
311 if( (pPage == nullptr) || pPage->checkVisibility(rOriginal, rDisplayInfo, false) )
313 return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo);
316 return drawinglayer::primitive2d::Primitive2DContainer();
318 else
320 // not an object, maybe a page
321 return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo);
325 GraphicExporter::GraphicExporter()
326 : mpUnoPage( nullptr ), mnPageNumber(-1), mpCurrentPage(nullptr), mpDoc( nullptr )
330 IMPL_LINK(GraphicExporter, CalcFieldValueHdl, EditFieldInfo*, pInfo, void)
332 if( pInfo )
334 if( mpCurrentPage )
336 pInfo->SetSdrPage( mpCurrentPage );
338 else if( mnPageNumber != -1 )
340 const SvxFieldData* pField = pInfo->GetField().GetField();
341 if( dynamic_cast<const SvxPageField*>( pField) )
343 OUString aPageNumValue;
344 bool bUpper = false;
346 switch(mpDoc->GetPageNumType())
348 case css::style::NumberingType::CHARS_UPPER_LETTER:
349 aPageNumValue += OUStringChar( sal_Unicode((mnPageNumber - 1) % 26 + 'A') );
350 break;
351 case css::style::NumberingType::CHARS_LOWER_LETTER:
352 aPageNumValue += OUStringChar( sal_Unicode((mnPageNumber - 1) % 26 + 'a') );
353 break;
354 case css::style::NumberingType::ROMAN_UPPER:
355 bUpper = true;
356 [[fallthrough]];
357 case css::style::NumberingType::ROMAN_LOWER:
358 aPageNumValue += SvxNumberFormat::CreateRomanString(mnPageNumber, bUpper);
359 break;
360 case css::style::NumberingType::NUMBER_NONE:
361 aPageNumValue = " ";
362 break;
363 default:
364 aPageNumValue += OUString::number( mnPageNumber );
367 pInfo->SetRepresentation( aPageNumValue );
369 return;
374 maOldCalcFieldValueHdl.Call( pInfo );
376 if( pInfo && mpCurrentPage )
377 pInfo->SetSdrPage( nullptr );
380 /** creates a virtual device for the given page
382 @return the returned VirtualDevice is owned by the caller
384 VclPtr<VirtualDevice> GraphicExporter::CreatePageVDev( SdrPage* pPage, sal_uIntPtr nWidthPixel, sal_uIntPtr nHeightPixel ) const
386 VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create();
387 MapMode aMM( MapUnit::Map100thMM );
389 Point aPoint( 0, 0 );
390 Size aPageSize(pPage->GetSize());
392 // use scaling?
393 if( nWidthPixel )
395 const Fraction aFrac( static_cast<long>(nWidthPixel), pVDev->LogicToPixel( aPageSize, aMM ).Width() );
397 aMM.SetScaleX( aFrac );
399 if( nHeightPixel == 0 )
400 aMM.SetScaleY( aFrac );
403 if( nHeightPixel )
405 const Fraction aFrac( static_cast<long>(nHeightPixel), pVDev->LogicToPixel( aPageSize, aMM ).Height() );
407 if( nWidthPixel == 0 )
408 aMM.SetScaleX( aFrac );
410 aMM.SetScaleY( aFrac );
413 pVDev->SetMapMode( aMM );
414 bool bSuccess(false);
416 // #i122820# If available, use pixel size directly
417 if(nWidthPixel && nHeightPixel)
419 bSuccess = pVDev->SetOutputSizePixel(Size(nWidthPixel, nHeightPixel));
421 else
423 bSuccess = pVDev->SetOutputSize(aPageSize);
426 if(bSuccess)
428 std::unique_ptr<SdrView> pView(new SdrView(*mpDoc, pVDev));
430 pView->SetPageVisible( false );
431 pView->SetBordVisible( false );
432 pView->SetGridVisible( false );
433 pView->SetHlplVisible( false );
434 pView->SetGlueVisible( false );
435 pView->ShowSdrPage(pPage);
437 vcl::Region aRegion (tools::Rectangle( aPoint, aPageSize ) );
439 ImplExportCheckVisisbilityRedirector aRedirector( mpCurrentPage );
441 pView->CompleteRedraw(pVDev, aRegion, &aRedirector);
443 else
445 OSL_ENSURE(false, "Could not get a VirtualDevice of requested size (!)");
448 return pVDev;
451 void GraphicExporter::ParseSettings( const Sequence< PropertyValue >& aDescriptor, ExportSettings& rSettings )
453 for( const PropertyValue& rValue : aDescriptor )
455 if ( rValue.Name == "FilterName" )
457 rValue.Value >>= rSettings.maFilterName;
459 else if ( rValue.Name == "MediaType" )
461 rValue.Value >>= rSettings.maMediaType;
463 else if ( rValue.Name == "URL" )
465 if( !( rValue.Value >>= rSettings.maURL ) )
467 rValue.Value >>= rSettings.maURL.Complete;
470 else if ( rValue.Name == "OutputStream" )
472 rValue.Value >>= rSettings.mxOutputStream;
474 else if ( rValue.Name == "GraphicRenderer" )
476 rValue.Value >>= rSettings.mxGraphicRenderer;
478 else if ( rValue.Name == "StatusIndicator" )
480 rValue.Value >>= rSettings.mxStatusIndicator;
482 else if ( rValue.Name == "InteractionHandler" )
484 rValue.Value >>= rSettings.mxInteractionHandler;
486 else if( rValue.Name == "Width" ) // for compatibility reasons, deprecated
488 rValue.Value >>= rSettings.mnWidth;
490 else if( rValue.Name == "Height" ) // for compatibility reasons, deprecated
492 rValue.Value >>= rSettings.mnHeight;
494 else if( rValue.Name == "ExportOnlyBackground" ) // for compatibility reasons, deprecated
496 rValue.Value >>= rSettings.mbExportOnlyBackground;
498 else if ( rValue.Name == "FilterData" )
500 rValue.Value >>= rSettings.maFilterData;
502 for( PropertyValue& rDataValue : rSettings.maFilterData )
504 if ( rDataValue.Name == "Translucent" )
506 if ( !( rDataValue.Value >>= rSettings.mbTranslucent ) ) // SJ: TODO: The GIF Transparency is stored as int32 in
507 { // configuration files, this has to be changed to boolean
508 sal_Int32 nTranslucent = 0;
509 if ( rDataValue.Value >>= nTranslucent )
510 rSettings.mbTranslucent = nTranslucent != 0;
513 else if ( rDataValue.Name == "PixelWidth" )
515 rDataValue.Value >>= rSettings.mnWidth;
517 else if ( rDataValue.Name == "PixelHeight" )
519 rDataValue.Value >>= rSettings.mnHeight;
521 else if( rDataValue.Name == "Width" ) // for compatibility reasons, deprecated
523 rDataValue.Value >>= rSettings.mnWidth;
524 rDataValue.Name = "PixelWidth";
526 else if( rDataValue.Name == "Height" ) // for compatibility reasons, deprecated
528 rDataValue.Value >>= rSettings.mnHeight;
529 rDataValue.Name = "PixelHeight";
531 else if ( rDataValue.Name == "ExportOnlyBackground" )
533 rDataValue.Value >>= rSettings.mbExportOnlyBackground;
535 else if ( rDataValue.Name == "HighContrast" )
537 rDataValue.Value >>= rSettings.mbUseHighContrast;
539 else if ( rDataValue.Name == "PageNumber" )
541 rDataValue.Value >>= mnPageNumber;
543 else if ( rDataValue.Name == "ScrollText" )
545 // #110496# Read flag solitary scroll text metafile
546 rDataValue.Value >>= rSettings.mbScrollText;
548 else if ( rDataValue.Name == "CurrentPage" )
550 Reference< XDrawPage > xPage;
551 rDataValue.Value >>= xPage;
552 if( xPage.is() )
554 SvxDrawPage* pUnoPage = comphelper::getUnoTunnelImplementation<SvxDrawPage>( xPage );
555 if( pUnoPage && pUnoPage->GetSdrPage() )
556 mpCurrentPage = pUnoPage->GetSdrPage();
559 else if ( rDataValue.Name == "ScaleXNumerator" )
561 sal_Int32 nVal = 1;
562 if( rDataValue.Value >>= nVal )
563 rSettings.maScaleX = Fraction( nVal, rSettings.maScaleX.GetDenominator() );
565 else if ( rDataValue.Name == "ScaleXDenominator" )
567 sal_Int32 nVal = 1;
568 if( rDataValue.Value >>= nVal )
569 rSettings.maScaleX = Fraction( rSettings.maScaleX.GetNumerator(), nVal );
571 else if ( rDataValue.Name == "ScaleYNumerator" )
573 sal_Int32 nVal = 1;
574 if( rDataValue.Value >>= nVal )
575 rSettings.maScaleY = Fraction( nVal, rSettings.maScaleY.GetDenominator() );
577 else if ( rDataValue.Name == "ScaleYDenominator" )
579 sal_Int32 nVal = 1;
580 if( rDataValue.Value >>= nVal )
581 rSettings.maScaleY = Fraction( rSettings.maScaleY.GetNumerator(), nVal );
583 else if (rDataValue.Name == "AntiAliasing")
585 bool bAntiAliasing;
586 if (rDataValue.Value >>= bAntiAliasing)
587 rSettings.meAntiAliasing = bAntiAliasing ? TRISTATE_TRUE : TRISTATE_FALSE;
593 // putting the StatusIndicator that we got from the MediaDescriptor into our local FilterData copy
594 if ( rSettings.mxStatusIndicator.is() )
596 int i = rSettings.maFilterData.getLength();
597 rSettings.maFilterData.realloc( i + 1 );
598 rSettings.maFilterData[ i ].Name = "StatusIndicator";
599 rSettings.maFilterData[ i ].Value <<= rSettings.mxStatusIndicator;
603 bool GraphicExporter::GetGraphic( ExportSettings const & rSettings, Graphic& aGraphic, bool bVectorType )
605 if( !mpDoc || !mpUnoPage )
606 return false;
608 SdrPage* pPage = mpUnoPage->GetSdrPage();
609 if( !pPage )
610 return false;
612 ScopedVclPtrInstance< VirtualDevice > aVDev;
613 const MapMode aMap( mpDoc->GetScaleUnit(), Point(), rSettings.maScaleX, rSettings.maScaleY );
615 SdrOutliner& rOutl=mpDoc->GetDrawOutliner();
616 maOldCalcFieldValueHdl = rOutl.GetCalcFieldValueHdl();
617 rOutl.SetCalcFieldValueHdl( LINK(this, GraphicExporter, CalcFieldValueHdl) );
618 rOutl.SetBackgroundColor( pPage->GetPageBackgroundColor() );
620 // #i102251#
621 const EEControlBits nOldCntrl(rOutl.GetControlWord());
622 EEControlBits nCntrl = nOldCntrl & ~EEControlBits::ONLINESPELLING;
623 rOutl.SetControlWord(nCntrl);
625 SdrObject* pTempBackgroundShape = nullptr;
626 std::vector< SdrObject* > aShapes;
627 bool bRet = true;
629 // export complete page?
630 if ( !mxShape.is() )
632 if( rSettings.mbExportOnlyBackground )
634 const SdrPageProperties* pCorrectProperties = pPage->getCorrectSdrPageProperties();
636 if(pCorrectProperties)
638 pTempBackgroundShape = new SdrRectObj(
639 *mpDoc,
640 tools::Rectangle(Point(0,0), pPage->GetSize()));
641 pTempBackgroundShape->SetMergedItemSet(pCorrectProperties->GetItemSet());
642 pTempBackgroundShape->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
643 pTempBackgroundShape->NbcSetStyleSheet(pCorrectProperties->GetStyleSheet(), true);
644 aShapes.push_back(pTempBackgroundShape);
647 else
649 const Size aSize( pPage->GetSize() );
651 // generate a bitmap to convert it to a pixel format.
652 // For gif pictures there can also be a vector format used (bTranslucent)
653 if ( !bVectorType && !rSettings.mbTranslucent )
655 long nWidthPix = 0;
656 long nHeightPix = 0;
657 if ( rSettings.mnWidth > 0 && rSettings.mnHeight > 0 )
659 nWidthPix = rSettings.mnWidth;
660 nHeightPix = rSettings.mnHeight;
662 else
664 const Size aSizePix( Application::GetDefaultDevice()->LogicToPixel( aSize, aMap ) );
665 if (aSizePix.Width() > MAX_EXT_PIX || aSizePix.Height() > MAX_EXT_PIX)
667 if (aSizePix.Width() > MAX_EXT_PIX)
668 nWidthPix = MAX_EXT_PIX;
669 else
670 nWidthPix = aSizePix.Width();
671 if (aSizePix.Height() > MAX_EXT_PIX)
672 nHeightPix = MAX_EXT_PIX;
673 else
674 nHeightPix = aSizePix.Height();
676 double fWidthDif = static_cast<double>(aSizePix.Width()) / nWidthPix;
677 double fHeightDif = static_cast<double>(aSizePix.Height()) / nHeightPix;
679 if (fWidthDif > fHeightDif)
680 nHeightPix = static_cast<long>(aSizePix.Height() / fWidthDif);
681 else
682 nWidthPix = static_cast<long>(aSizePix.Width() / fHeightDif);
684 else
686 nWidthPix = aSizePix.Width();
687 nHeightPix = aSizePix.Height();
691 std::unique_ptr<SdrView> xLocalView;
693 if (FmFormModel* pFormModel = dynamic_cast<FmFormModel*>(mpDoc))
695 xLocalView.reset(new FmFormView(*pFormModel, aVDev));
697 else
699 xLocalView.reset(new SdrView(*mpDoc, aVDev));
702 ScopedVclPtr<VirtualDevice> pVDev(CreatePageVDev( pPage, nWidthPix, nHeightPix ));
704 if( pVDev )
706 aGraphic = pVDev->GetBitmapEx( Point(), pVDev->GetOutputSize() );
707 aGraphic.SetPrefMapMode( aMap );
708 aGraphic.SetPrefSize( aSize );
711 // create a metafile to export a vector format
712 else
714 GDIMetaFile aMtf;
716 aVDev->SetMapMode( aMap );
717 if( rSettings.mbUseHighContrast )
718 aVDev->SetDrawMode( aVDev->GetDrawMode() | DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient );
719 aVDev->EnableOutput( false );
720 aMtf.Record( aVDev );
721 Size aNewSize;
723 // create a view
724 std::unique_ptr< SdrView > pView;
726 if (FmFormModel *pFormModel = dynamic_cast<FmFormModel*>(mpDoc))
728 pView.reset(new FmFormView(*pFormModel, aVDev));
730 else
732 pView.reset(new SdrView(*mpDoc, aVDev));
735 pView->SetBordVisible( false );
736 pView->SetPageVisible( false );
737 pView->ShowSdrPage( pPage );
739 // tdf#96922 completely deactivate EditView PageVisualization, including
740 // PageBackground (formerly 'wiese').
741 pView->SetPagePaintingAllowed(false);
743 const Point aNewOrg( pPage->GetLeftBorder(), pPage->GetUpperBorder() );
744 aNewSize = Size( aSize.Width() - pPage->GetLeftBorder() - pPage->GetRightBorder(),
745 aSize.Height() - pPage->GetUpperBorder() - pPage->GetLowerBorder() );
746 const tools::Rectangle aClipRect( aNewOrg, aNewSize );
747 MapMode aVMap( aMap );
749 aVDev->Push();
750 aVMap.SetOrigin( Point( -aNewOrg.X(), -aNewOrg.Y() ) );
751 aVDev->SetRelativeMapMode( aVMap );
752 aVDev->IntersectClipRegion( aClipRect );
754 // Use new StandardCheckVisisbilityRedirector
755 ImplExportCheckVisisbilityRedirector aRedirector( mpCurrentPage );
757 pView->CompleteRedraw(aVDev, vcl::Region(tools::Rectangle(aNewOrg, aNewSize)), &aRedirector);
759 aVDev->Pop();
761 aMtf.Stop();
762 aMtf.WindStart();
763 aMtf.SetPrefMapMode( aMap );
764 aMtf.SetPrefSize( aNewSize );
766 // AW: Here the current version was filtering out the MetaActionType::CLIPREGIONs
767 // from the metafile. I asked some other developers why this was done, but no
768 // one knew a direct reason. Since it's in for long time, it may be an old
769 // piece of code. MetaFiles save and load ClipRegions with polygons with preserving
770 // the polygons, so a resolution-independent roundtrip is supported. Removed this
771 // code since it destroys some MetaFiles where ClipRegions are used. Anyways,
772 // just filtering them out is a hack, at least the encapsulated content would need
773 // to be clipped geometrically.
774 aGraphic = Graphic(aMtf);
776 pView->HideSdrPage();
778 if( rSettings.mbTranslucent )
780 Size aOutSize;
781 aGraphic = GetBitmapFromMetaFile( aGraphic.GetGDIMetaFile(), false, CalcSize( rSettings.mnWidth, rSettings.mnHeight, aNewSize, aOutSize ) );
787 // export only single shape or shape collection
788 else
790 // build list of SdrObject
791 if( mxShapes.is() )
793 Reference< XShape > xShape;
794 const sal_Int32 nCount = mxShapes->getCount();
796 for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
798 mxShapes->getByIndex( nIndex ) >>= xShape;
799 SdrObject* pObj = GetSdrObjectFromXShape( xShape );
800 if( pObj )
801 aShapes.push_back( pObj );
804 else
806 // only one shape
807 SdrObject* pObj = GetSdrObjectFromXShape( mxShape );
808 if( pObj )
809 aShapes.push_back( pObj );
812 if( aShapes.empty() )
813 bRet = false;
816 if( bRet && !aShapes.empty() )
818 // special treatment for only one SdrGrafObj that has text
819 bool bSingleGraphic = false;
821 if( 1 == aShapes.size() )
823 if( !bVectorType )
825 SdrObject* pObj = aShapes.front();
826 if( dynamic_cast<const SdrGrafObj*>( pObj) && !static_cast<SdrGrafObj*>(pObj)->HasText() )
828 aGraphic = static_cast<SdrGrafObj*>(pObj)->GetTransformedGraphic();
829 if ( aGraphic.GetType() == GraphicType::Bitmap )
831 Size aSizePixel( aGraphic.GetSizePixel() );
832 if( rSettings.mnWidth && rSettings.mnHeight &&
833 ( ( rSettings.mnWidth != aSizePixel.Width() ) ||
834 ( rSettings.mnHeight != aSizePixel.Height() ) ) )
836 BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
837 // export: use highest quality
838 aBmpEx.Scale( Size( rSettings.mnWidth, rSettings.mnHeight ), BmpScaleFlag::Lanczos );
839 aGraphic = aBmpEx;
842 // #118804# only accept for bitmap graphics, else the
843 // conversion to bitmap will happen anywhere without size control
844 // as evtl. defined in rSettings.mnWidth/mnHeight
845 bSingleGraphic = true;
849 else if( rSettings.mbScrollText )
851 SdrObject* pObj = aShapes.front();
852 if( dynamic_cast<const SdrTextObj*>( pObj)
853 && static_cast<SdrTextObj*>(pObj)->HasText() )
855 tools::Rectangle aScrollRectangle;
856 tools::Rectangle aPaintRectangle;
858 const std::unique_ptr< GDIMetaFile > pMtf(
859 static_cast<SdrTextObj*>(pObj)->GetTextScrollMetaFileAndRectangle(
860 aScrollRectangle, aPaintRectangle ) );
862 // take the larger one of the two rectangles (that
863 // should be the bound rect of the retrieved
864 // metafile)
865 tools::Rectangle aTextRect;
867 if( aScrollRectangle.IsInside( aPaintRectangle ) )
868 aTextRect = aScrollRectangle;
869 else
870 aTextRect = aPaintRectangle;
872 // setup pref size and mapmode
873 pMtf->SetPrefSize( aTextRect.GetSize() );
875 // set actual origin (mtf is at actual shape
876 // output position)
877 MapMode aLocalMapMode( aMap );
878 aLocalMapMode.SetOrigin(
879 Point( -aPaintRectangle.Left(),
880 -aPaintRectangle.Top() ) );
881 pMtf->SetPrefMapMode( aLocalMapMode );
883 pMtf->AddAction( new MetaCommentAction(
884 "XTEXT_SCROLLRECT", 0,
885 reinterpret_cast<sal_uInt8 const*>(&aScrollRectangle),
886 sizeof( tools::Rectangle ) ) );
887 pMtf->AddAction( new MetaCommentAction(
888 "XTEXT_PAINTRECT", 0,
889 reinterpret_cast<sal_uInt8 const*>(&aPaintRectangle),
890 sizeof( tools::Rectangle ) ) );
892 aGraphic = Graphic( *pMtf );
894 bSingleGraphic = true;
899 if( !bSingleGraphic )
901 // create a metafile for all shapes
902 ScopedVclPtrInstance< VirtualDevice > aOut;
904 // calculate bound rect for all shapes
905 tools::Rectangle aBound;
908 for( SdrObject* pObj : aShapes )
910 tools::Rectangle aR1(pObj->GetCurrentBoundRect());
911 if (aBound.IsEmpty())
912 aBound=aR1;
913 else
914 aBound.Union(aR1);
918 aOut->EnableOutput( false );
919 aOut->SetMapMode( aMap );
920 if( rSettings.mbUseHighContrast )
921 aOut->SetDrawMode( aOut->GetDrawMode() | DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient );
923 GDIMetaFile aMtf;
924 aMtf.Clear();
925 aMtf.Record( aOut );
927 MapMode aOutMap( aMap );
928 aOutMap.SetOrigin( Point( -aBound.TopLeft().X(), -aBound.TopLeft().Y() ) );
929 aOut->SetRelativeMapMode( aOutMap );
931 sdr::contact::DisplayInfo aDisplayInfo;
933 if(mpCurrentPage)
935 if(mpCurrentPage->TRG_HasMasterPage() && pPage->IsMasterPage())
937 // MasterPage is processed as another page's SubContent
938 aDisplayInfo.SetProcessLayers(mpCurrentPage->TRG_GetMasterPageVisibleLayers());
939 aDisplayInfo.SetSubContentActive(true);
943 if(!aShapes.empty())
945 // more effective way to paint a vector of SdrObjects. Hand over the processed page
946 // to have it in the
947 sdr::contact::ObjectContactOfObjListPainter aMultiObjectPainter(*aOut, aShapes, mpCurrentPage);
948 ImplExportCheckVisisbilityRedirector aCheckVisibilityRedirector(mpCurrentPage);
949 aMultiObjectPainter.SetViewObjectContactRedirector(&aCheckVisibilityRedirector);
951 aMultiObjectPainter.ProcessDisplay(aDisplayInfo);
954 aMtf.Stop();
955 aMtf.WindStart();
957 const Size aExtSize( aOut->PixelToLogic( Size( 0, 0 ) ) );
958 Size aBoundSize( aBound.GetWidth() + ( aExtSize.Width() ),
959 aBound.GetHeight() + ( aExtSize.Height() ) );
961 aMtf.SetPrefMapMode( aMap );
962 aMtf.SetPrefSize( aBoundSize );
964 if( !bVectorType )
966 Size aOutSize;
967 aGraphic = GetBitmapFromMetaFile( aMtf, true, CalcSize( rSettings.mnWidth, rSettings.mnHeight, aBoundSize, aOutSize ) );
969 else
971 aGraphic = aMtf;
976 if(pTempBackgroundShape)
978 SdrObject::Free(pTempBackgroundShape);
981 rOutl.SetCalcFieldValueHdl( maOldCalcFieldValueHdl );
983 // #i102251#
984 rOutl.SetControlWord(nOldCntrl);
986 return bRet;
990 // XFilter
991 sal_Bool SAL_CALL GraphicExporter::filter( const Sequence< PropertyValue >& aDescriptor )
993 ::SolarMutexGuard aGuard;
995 if( maGraphic.IsNone() && nullptr == mpUnoPage )
996 return false;
998 if( maGraphic.IsNone() && ( nullptr == mpUnoPage->GetSdrPage() || nullptr == mpDoc ) )
999 return false;
1001 GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
1003 // get the arguments from the descriptor
1004 ExportSettings aSettings(mpDoc);
1005 ParseSettings(aDescriptor, aSettings);
1007 const sal_uInt16 nFilter = !aSettings.maMediaType.isEmpty()
1008 ? rFilter.GetExportFormatNumberForMediaType( aSettings.maMediaType )
1009 : rFilter.GetExportFormatNumberForShortName( aSettings.maFilterName );
1010 bool bVectorType = !rFilter.IsExportPixelFormat( nFilter );
1012 // create the output stuff
1013 Graphic aGraphic = maGraphic;
1015 ErrCode nStatus = ERRCODE_NONE;
1016 if (maGraphic.IsNone())
1018 SvtOptionsDrawinglayer aOptions;
1019 bool bAntiAliasing = aOptions.IsAntiAliasing();
1020 AllSettings aAllSettings = Application::GetSettings();
1021 StyleSettings aStyleSettings = aAllSettings.GetStyleSettings();
1022 bool bUseFontAAFromSystem = aStyleSettings.GetUseFontAAFromSystem();
1023 if (aSettings.meAntiAliasing != TRISTATE_INDET)
1025 // This is safe to do globally as we own the solar mutex.
1026 aOptions.SetAntiAliasing(aSettings.meAntiAliasing == TRISTATE_TRUE);
1027 // Opt in to have AA affect font rendering as well.
1028 aStyleSettings.SetUseFontAAFromSystem(false);
1029 aAllSettings.SetStyleSettings(aStyleSettings);
1030 Application::SetSettings(aAllSettings);
1032 nStatus = GetGraphic( aSettings, aGraphic, bVectorType ) ? ERRCODE_NONE : ERRCODE_GRFILTER_FILTERERROR;
1033 if (aSettings.meAntiAliasing != TRISTATE_INDET)
1035 aOptions.SetAntiAliasing(bAntiAliasing);
1036 aStyleSettings.SetUseFontAAFromSystem(bUseFontAAFromSystem);
1037 aAllSettings.SetStyleSettings(aStyleSettings);
1038 Application::SetSettings(aAllSettings);
1042 if( nStatus == ERRCODE_NONE )
1044 // export graphic only if it has a size
1045 const Size aGraphSize( aGraphic.GetPrefSize() );
1046 if ( ( aGraphSize.Width() == 0 ) || ( aGraphSize.Height() == 0 ) )
1048 nStatus = ERRCODE_GRFILTER_FILTERERROR;
1050 else
1052 // now we have a graphic, so export it
1053 if( aSettings.mxGraphicRenderer.is() )
1055 // render graphic directly into given renderer
1056 aSettings.mxGraphicRenderer->render( aGraphic.GetXGraphic() );
1058 else if( aSettings.mxOutputStream.is() )
1060 // TODO: Either utilize optional XSeekable functionality for the
1061 // SvOutputStream, or adapt the graphic filter to not seek anymore.
1062 SvMemoryStream aStream( 1024, 1024 );
1064 nStatus = rFilter.ExportGraphic( aGraphic,"", aStream, nFilter, &aSettings.maFilterData );
1066 // copy temp stream to XOutputStream
1067 SvOutputStream aOutputStream( aSettings.mxOutputStream );
1068 aStream.Seek(0);
1069 aOutputStream.WriteStream( aStream );
1071 else
1073 INetURLObject aURLObject( aSettings.maURL.Complete );
1074 DBG_ASSERT( aURLObject.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
1076 nStatus = XOutBitmap::ExportGraphic( aGraphic, aURLObject, rFilter, nFilter, &aSettings.maFilterData );
1081 if ( aSettings.mxInteractionHandler.is() && ( nStatus != ERRCODE_NONE ) )
1083 Any aInteraction;
1084 Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations(1);
1085 ::comphelper::OInteractionApprove* pApprove = new ::comphelper::OInteractionApprove();
1086 lContinuations[0].set(static_cast< XInteractionContinuation* >(pApprove), UNO_QUERY);
1088 GraphicFilterRequest aErrorCode;
1089 aErrorCode.ErrCode = sal_uInt32(nStatus);
1090 aInteraction <<= aErrorCode;
1091 aSettings.mxInteractionHandler->handle( framework::InteractionRequest::CreateRequest( aInteraction, lContinuations ) );
1093 return nStatus == ERRCODE_NONE;
1096 void SAL_CALL GraphicExporter::cancel()
1100 // XExporter
1102 /** the source 'document' could be a XDrawPage, a XShape or a generic XShapes */
1103 void SAL_CALL GraphicExporter::setSourceDocument( const Reference< lang::XComponent >& xComponent )
1105 ::SolarMutexGuard aGuard;
1107 mxShapes = nullptr;
1108 mpUnoPage = nullptr;
1112 // any break inside this one loop while will throw an IllegalArgumentException
1115 mxPage.set( xComponent, UNO_QUERY );
1116 mxShapes.set( xComponent, UNO_QUERY );
1117 mxShape.set( xComponent, UNO_QUERY );
1119 // Step 1: try a generic XShapes
1120 if( !mxPage.is() && !mxShape.is() && mxShapes.is() )
1122 // we do not support empty shape collections
1123 if( 0 == mxShapes->getCount() )
1124 break;
1126 // get first shape to detect corresponding page and model
1127 mxShapes->getByIndex(0) >>= mxShape;
1129 else
1131 mxShapes = nullptr;
1134 // Step 2: try a shape
1135 if( mxShape.is() )
1137 if( nullptr == GetSdrObjectFromXShape( mxShape ) )
1139 // This is not a Draw shape, let's see if it's a Writer one.
1140 uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
1141 if (!xPropertySet.is())
1142 break;
1143 uno::Reference<graphic::XGraphic> xGraphic(
1144 xPropertySet->getPropertyValue("Graphic"), uno::UNO_QUERY);
1145 if (!xGraphic.is())
1146 break;
1148 maGraphic = Graphic(xGraphic);
1149 if (!maGraphic.IsNone())
1150 return;
1151 else
1152 break;
1155 // get page for this shape
1156 Reference< XChild > xChild( mxShape, UNO_QUERY );
1157 if( !xChild.is() )
1158 break;
1160 Reference< XInterface > xInt;
1163 xInt = xChild->getParent();
1164 mxPage.set( xInt, UNO_QUERY );
1165 if( !mxPage.is() )
1166 xChild.set( xInt, UNO_QUERY );
1168 while( !mxPage.is() && xChild.is() );
1170 if( !mxPage.is() )
1171 break;
1174 // Step 3: check the page
1175 if( !mxPage.is() )
1176 break;
1178 mpUnoPage = comphelper::getUnoTunnelImplementation<SvxDrawPage>( mxPage );
1180 if( nullptr == mpUnoPage || nullptr == mpUnoPage->GetSdrPage() )
1181 break;
1183 mpDoc = &mpUnoPage->GetSdrPage()->getSdrModelFromSdrPage();
1185 // Step 4: If we got a generic XShapes test all contained shapes
1186 // if they belong to the same XDrawPage
1188 if( mxShapes.is() )
1190 SdrPage* pPage = mpUnoPage->GetSdrPage();
1191 SdrObject* pObj;
1192 Reference< XShape > xShape;
1194 bool bOk = true;
1196 const sal_Int32 nCount = mxShapes->getCount();
1198 // test all but the first shape if they have the same page than
1199 // the first shape
1200 for( sal_Int32 nIndex = 1; bOk && ( nIndex < nCount ); nIndex++ )
1202 mxShapes->getByIndex( nIndex ) >>= xShape;
1203 pObj = GetSdrObjectFromXShape( xShape );
1204 bOk = pObj && pObj->getSdrPageFromSdrObject() == pPage;
1207 if( !bOk )
1208 break;
1211 // no errors so far
1212 return;
1214 while( false );
1216 catch( Exception& )
1220 throw IllegalArgumentException();
1223 // XServiceInfo
1224 OUString SAL_CALL GraphicExporter::getImplementationName( )
1226 return "com.sun.star.comp.Draw.GraphicExporter";
1229 sal_Bool SAL_CALL GraphicExporter::supportsService( const OUString& ServiceName )
1231 return cppu::supportsService(this, ServiceName);
1234 Sequence< OUString > SAL_CALL GraphicExporter::getSupportedServiceNames( )
1236 Sequence< OUString > aSupportedServiceNames { "com.sun.star.drawing.GraphicExportFilter" };
1237 return aSupportedServiceNames;
1240 // XMimeTypeInfo
1241 sal_Bool SAL_CALL GraphicExporter::supportsMimeType( const OUString& rMimeTypeName )
1243 GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
1244 sal_uInt16 nCount = rFilter.GetExportFormatCount();
1245 sal_uInt16 nFilter;
1246 for( nFilter = 0; nFilter < nCount; nFilter++ )
1248 if( rMimeTypeName == rFilter.GetExportFormatMediaType( nFilter ) )
1250 return true;
1254 return false;
1257 Sequence< OUString > SAL_CALL GraphicExporter::getSupportedMimeTypeNames( )
1259 GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
1260 sal_uInt16 nCount = rFilter.GetExportFormatCount();
1261 sal_uInt16 nFilter;
1262 sal_uInt16 nFound = 0;
1264 Sequence< OUString > aSeq( nCount );
1265 OUString* pStr = aSeq.getArray();
1267 for( nFilter = 0; nFilter < nCount; nFilter++ )
1269 OUString aMimeType( rFilter.GetExportFormatMediaType( nFilter ) );
1270 if( !aMimeType.isEmpty() )
1272 *pStr++ = aMimeType;
1273 nFound++;
1277 if( nFound < nCount )
1278 aSeq.realloc( nFound );
1280 return aSeq;
1285 Graphic SvxGetGraphicForShape( SdrObject& rShape )
1287 Graphic aGraphic;
1290 rtl::Reference< GraphicExporter > xExporter( new GraphicExporter() );
1291 Reference< XComponent > xComp( rShape.getUnoShape(), UNO_QUERY_THROW );
1292 xExporter->setSourceDocument( xComp );
1293 ExportSettings aSettings(&rShape.getSdrModelFromSdrObject());
1294 xExporter->GetGraphic( aSettings, aGraphic, true/*bVector*/ );
1296 catch( Exception& )
1298 OSL_FAIL("SvxGetGraphicForShape(), exception caught!");
1300 return aGraphic;
1303 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1304 com_sun_star_comp_Draw_GraphicExporter_get_implementation(
1305 css::uno::XComponentContext *,
1306 css::uno::Sequence<css::uno::Any> const &)
1308 return cppu::acquire(new GraphicExporter);
1311 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */