1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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 <comphelper/diagnose_ex.hxx>
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/svdpage.hxx>
58 #include <svx/svdmodel.hxx>
59 #include <svx/fmview.hxx>
60 #include <svx/fmmodel.hxx>
61 #include <svx/unopage.hxx>
62 #include <svx/svdoutl.hxx>
63 #include <svx/xlineit0.hxx>
64 #include <editeng/flditem.hxx>
65 #include <svtools/optionsdrawinglayer.hxx>
66 #include <comphelper/sequenceashashmap.hxx>
67 #include <comphelper/propertysequence.hxx>
68 #include <comphelper/sequence.hxx>
69 #include "UnoGraphicExporter.hxx"
72 #define MAX_EXT_PIX 2048
74 using namespace ::comphelper
;
75 using namespace ::cppu
;
76 using namespace ::com::sun::star
;
77 using namespace ::com::sun::star::uno
;
78 using namespace ::com::sun::star::util
;
79 using namespace ::com::sun::star::container
;
80 using namespace ::com::sun::star::drawing
;
81 using namespace ::com::sun::star::lang
;
82 using namespace ::com::sun::star::document
;
83 using namespace ::com::sun::star::beans
;
84 using namespace ::com::sun::star::task
;
87 #include <editeng/editstat.hxx>
93 OUString maFilterName
;
96 css::uno::Reference
< css::io::XOutputStream
> mxOutputStream
;
97 css::uno::Reference
< css::graphic::XGraphicRenderer
> mxGraphicRenderer
;
98 css::uno::Reference
< css::task::XStatusIndicator
> mxStatusIndicator
;
99 css::uno::Reference
< css::task::XInteractionHandler
> mxInteractionHandler
;
103 bool mbExportOnlyBackground
;
105 bool mbUseHighContrast
;
108 Sequence
< PropertyValue
> maFilterData
;
113 TriState meAntiAliasing
= TRISTATE_INDET
;
115 explicit ExportSettings();
118 ExportSettings::ExportSettings()
121 ,mbExportOnlyBackground( false )
122 ,mbScrollText( false )
123 ,mbUseHighContrast( false )
124 ,mbTranslucent( false )
130 /** implements a component to export shapes or pages to external graphic formats.
132 @implements com.sun.star.drawing.GraphicExportFilter
134 class GraphicExporter
: public WeakImplHelper
< XGraphicExportFilter
, XServiceInfo
>
140 virtual sal_Bool SAL_CALL
filter( const Sequence
< PropertyValue
>& aDescriptor
) override
;
141 virtual void SAL_CALL
cancel( ) override
;
144 virtual void SAL_CALL
setSourceDocument( const Reference
< XComponent
>& xDoc
) override
;
147 virtual OUString SAL_CALL
getImplementationName( ) override
;
148 virtual sal_Bool SAL_CALL
supportsService( const OUString
& ServiceName
) override
;
149 virtual Sequence
< OUString
> SAL_CALL
getSupportedServiceNames( ) override
;
152 virtual sal_Bool SAL_CALL
supportsMimeType( const OUString
& MimeTypeName
) override
;
153 virtual Sequence
< OUString
> SAL_CALL
getSupportedMimeTypeNames( ) override
;
155 VclPtr
<VirtualDevice
> CreatePageVDev( SdrPage
* pPage
, tools::Long nWidthPixel
, tools::Long nHeightPixel
) const;
157 DECL_LINK( CalcFieldValueHdl
, EditFieldInfo
*, void );
159 void ParseSettings( const Sequence
< PropertyValue
>& aDescriptor
, ExportSettings
& rSettings
);
160 bool GetGraphic( ExportSettings
const & rSettings
, Graphic
& aGraphic
, bool bVectorType
);
163 Reference
< XShape
> mxShape
;
164 Reference
< XDrawPage
> mxPage
;
165 Reference
< XShapes
> mxShapes
;
168 SvxDrawPage
* mpUnoPage
;
170 Link
<EditFieldInfo
*,void> maOldCalcFieldValueHdl
;
171 sal_Int32 mnPageNumber
;
172 SdrPage
* mpCurrentPage
;
176 /** creates a bitmap that is optionally transparent from a metafile
178 BitmapEx
GetBitmapFromMetaFile( const GDIMetaFile
& rMtf
, const Size
* pSize
)
180 // use new primitive conversion tooling
181 basegfx::B2DRange
aRange(basegfx::B2DPoint(0.0, 0.0));
182 sal_uInt32
nMaximumQuadraticPixels(500000);
186 // use 100th mm for primitive bitmap converter tool, input is pixel
187 // use a real OutDev to get the correct DPI, the static LogicToLogic assumes 72dpi which is wrong (!)
188 const Size
aSize100th(Application::GetDefaultDevice()->PixelToLogic(*pSize
, MapMode(MapUnit::Map100thMM
)));
190 aRange
.expand(basegfx::B2DPoint(aSize100th
.Width(), aSize100th
.Height()));
192 // when explicitly pixels are requested from the GraphicExporter, use a *very* high limit
193 // of 16gb (4096x4096 pixels), else use the default for the converters
194 nMaximumQuadraticPixels
= std::min(sal_uInt32(4096 * 4096), sal_uInt32(pSize
->Width() * pSize
->Height()));
198 // use 100th mm for primitive bitmap converter tool
199 const Size
aSize100th(OutputDevice::LogicToLogic(rMtf
.GetPrefSize(), rMtf
.GetPrefMapMode(), MapMode(MapUnit::Map100thMM
)));
201 aRange
.expand(basegfx::B2DPoint(aSize100th
.Width(), aSize100th
.Height()));
204 return convertMetafileToBitmapEx(rMtf
, aRange
, nMaximumQuadraticPixels
);
207 Size
* CalcSize( sal_Int32 nWidth
, sal_Int32 nHeight
, const Size
& aBoundSize
, Size
& aOutSize
)
209 if( (nWidth
== 0) && (nHeight
== 0) )
212 if( (nWidth
== 0) && (nHeight
!= 0) && (aBoundSize
.Height() != 0) )
214 nWidth
= ( nHeight
* aBoundSize
.Width() ) / aBoundSize
.Height();
216 else if( (nWidth
!= 0) && (nHeight
== 0) && (aBoundSize
.Width() != 0) )
218 nHeight
= ( nWidth
* aBoundSize
.Height() ) / aBoundSize
.Width();
221 aOutSize
.setWidth( nWidth
);
222 aOutSize
.setHeight( nHeight
);
227 class ImplExportCheckVisisbilityRedirector
: public sdr::contact::ViewObjectContactRedirector
230 explicit ImplExportCheckVisisbilityRedirector( SdrPage
* pCurrentPage
);
232 virtual void createRedirectedPrimitive2DSequence(
233 const sdr::contact::ViewObjectContact
& rOriginal
,
234 const sdr::contact::DisplayInfo
& rDisplayInfo
,
235 drawinglayer::primitive2d::Primitive2DDecompositionVisitor
& rVisitor
) override
;
238 SdrPage
* mpCurrentPage
;
241 ImplExportCheckVisisbilityRedirector::ImplExportCheckVisisbilityRedirector( SdrPage
* pCurrentPage
)
242 : mpCurrentPage( pCurrentPage
)
246 void ImplExportCheckVisisbilityRedirector::createRedirectedPrimitive2DSequence(
247 const sdr::contact::ViewObjectContact
& rOriginal
,
248 const sdr::contact::DisplayInfo
& rDisplayInfo
,
249 drawinglayer::primitive2d::Primitive2DDecompositionVisitor
& rVisitor
)
251 SdrObject
* pObject
= rOriginal
.GetViewContact().TryToGetSdrObject();
255 SdrPage
* pPage
= mpCurrentPage
;
259 pPage
= pObject
->getSdrPageFromSdrObject();
262 if( (pPage
== nullptr) || pPage
->checkVisibility(rOriginal
, rDisplayInfo
, false) )
264 return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal
, rDisplayInfo
, rVisitor
);
271 // not an object, maybe a page
272 sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal
, rDisplayInfo
, rVisitor
);
276 GraphicExporter::GraphicExporter()
277 : mpUnoPage( nullptr ), mnPageNumber(-1), mpCurrentPage(nullptr), mpDoc( nullptr )
281 IMPL_LINK(GraphicExporter
, CalcFieldValueHdl
, EditFieldInfo
*, pInfo
, void)
287 pInfo
->SetSdrPage( mpCurrentPage
);
289 else if( mnPageNumber
!= -1 )
291 const SvxFieldData
* pField
= pInfo
->GetField().GetField();
292 if( dynamic_cast<const SvxPageField
*>( pField
) )
294 OUString aPageNumValue
;
297 switch(mpDoc
->GetPageNumType())
299 case css::style::NumberingType::CHARS_UPPER_LETTER
:
300 aPageNumValue
+= OUStringChar( sal_Unicode((mnPageNumber
- 1) % 26 + 'A') );
302 case css::style::NumberingType::CHARS_LOWER_LETTER
:
303 aPageNumValue
+= OUStringChar( sal_Unicode((mnPageNumber
- 1) % 26 + 'a') );
305 case css::style::NumberingType::ROMAN_UPPER
:
308 case css::style::NumberingType::ROMAN_LOWER
:
309 aPageNumValue
+= SvxNumberFormat::CreateRomanString(mnPageNumber
, bUpper
);
311 case css::style::NumberingType::NUMBER_NONE
:
315 aPageNumValue
+= OUString::number( mnPageNumber
);
318 pInfo
->SetRepresentation( aPageNumValue
);
325 maOldCalcFieldValueHdl
.Call( pInfo
);
327 if( pInfo
&& mpCurrentPage
)
328 pInfo
->SetSdrPage( nullptr );
331 /** creates a virtual device for the given page
333 @return the returned VirtualDevice is owned by the caller
335 VclPtr
<VirtualDevice
> GraphicExporter::CreatePageVDev( SdrPage
* pPage
, tools::Long nWidthPixel
, tools::Long nHeightPixel
) const
337 VclPtr
<VirtualDevice
> pVDev
= VclPtr
<VirtualDevice
>::Create();
338 MapMode
aMM( MapUnit::Map100thMM
);
340 Point
aPoint( 0, 0 );
341 Size
aPageSize(pPage
->GetSize());
344 if( nWidthPixel
!= 0 )
346 const Fraction
aFrac( nWidthPixel
, pVDev
->LogicToPixel( aPageSize
, aMM
).Width() );
348 aMM
.SetScaleX( aFrac
);
350 if( nHeightPixel
== 0 )
351 aMM
.SetScaleY( aFrac
);
354 if( nHeightPixel
!= 0 )
356 const Fraction
aFrac( nHeightPixel
, pVDev
->LogicToPixel( aPageSize
, aMM
).Height() );
358 if( nWidthPixel
== 0 )
359 aMM
.SetScaleX( aFrac
);
361 aMM
.SetScaleY( aFrac
);
364 pVDev
->SetMapMode( aMM
);
365 bool bSuccess(false);
367 // #i122820# If available, use pixel size directly
368 if(nWidthPixel
&& nHeightPixel
)
370 bSuccess
= pVDev
->SetOutputSizePixel(Size(nWidthPixel
, nHeightPixel
));
374 bSuccess
= pVDev
->SetOutputSize(aPageSize
);
379 SdrView
aView(*mpDoc
, pVDev
);
381 aView
.SetPageVisible( false );
382 aView
.SetBordVisible( false );
383 aView
.SetGridVisible( false );
384 aView
.SetHlplVisible( false );
385 aView
.SetGlueVisible( false );
386 aView
.ShowSdrPage(pPage
);
388 vcl::Region
aRegion (tools::Rectangle( aPoint
, aPageSize
) );
390 ImplExportCheckVisisbilityRedirector
aRedirector( mpCurrentPage
);
392 aView
.CompleteRedraw(pVDev
, aRegion
, &aRedirector
);
396 OSL_ENSURE(false, "Could not get a VirtualDevice of requested size (!)");
402 void GraphicExporter::ParseSettings(const Sequence
<PropertyValue
>& rDescriptor
,
403 ExportSettings
& rSettings
)
405 Sequence
<PropertyValue
> aDescriptor
= rDescriptor
;
406 if (aDescriptor
.hasElements())
408 comphelper::SequenceAsHashMap
aMap(aDescriptor
);
409 Sequence
<PropertyValue
> aFilterData
;
410 OUString aFilterOptions
;
411 auto it
= aMap
.find("FilterData");
412 if (it
!= aMap
.end())
414 it
->second
>>= aFilterData
;
416 it
= aMap
.find("FilterOptions");
417 if (it
!= aMap
.end())
419 it
->second
>>= aFilterOptions
;
421 if (!aFilterData
.hasElements() && !aFilterOptions
.isEmpty())
423 // Allow setting filter data keys from the cmdline.
424 std::vector
<PropertyValue
> aData
425 = comphelper::JsonToPropertyValues(aFilterOptions
.toUtf8());
426 aFilterData
= comphelper::containerToSequence(aData
);
427 if (aFilterData
.hasElements())
429 aMap
["FilterData"] <<= aFilterData
;
430 aDescriptor
= aMap
.getAsConstPropertyValueList();
435 for( const PropertyValue
& rValue
: aDescriptor
)
437 if ( rValue
.Name
== "FilterName" )
439 rValue
.Value
>>= rSettings
.maFilterName
;
441 else if ( rValue
.Name
== "MediaType" )
443 rValue
.Value
>>= rSettings
.maMediaType
;
445 else if ( rValue
.Name
== "URL" )
447 if( !( rValue
.Value
>>= rSettings
.maURL
) )
449 rValue
.Value
>>= rSettings
.maURL
.Complete
;
452 else if ( rValue
.Name
== "OutputStream" )
454 rValue
.Value
>>= rSettings
.mxOutputStream
;
456 else if ( rValue
.Name
== "GraphicRenderer" )
458 rValue
.Value
>>= rSettings
.mxGraphicRenderer
;
460 else if ( rValue
.Name
== "StatusIndicator" )
462 rValue
.Value
>>= rSettings
.mxStatusIndicator
;
464 else if ( rValue
.Name
== "InteractionHandler" )
466 rValue
.Value
>>= rSettings
.mxInteractionHandler
;
468 else if( rValue
.Name
== "Width" ) // for compatibility reasons, deprecated
470 rValue
.Value
>>= rSettings
.mnWidth
;
472 else if( rValue
.Name
== "Height" ) // for compatibility reasons, deprecated
474 rValue
.Value
>>= rSettings
.mnHeight
;
476 else if( rValue
.Name
== "ExportOnlyBackground" ) // for compatibility reasons, deprecated
478 rValue
.Value
>>= rSettings
.mbExportOnlyBackground
;
480 else if ( rValue
.Name
== "FilterData" )
482 rValue
.Value
>>= rSettings
.maFilterData
;
484 for( PropertyValue
& rDataValue
: asNonConstRange(rSettings
.maFilterData
) )
486 if ( rDataValue
.Name
== "Translucent" )
488 if ( !( rDataValue
.Value
>>= rSettings
.mbTranslucent
) ) // SJ: TODO: The GIF Transparency is stored as int32 in
489 { // configuration files, this has to be changed to boolean
490 sal_Int32 nTranslucent
= 0;
491 if ( rDataValue
.Value
>>= nTranslucent
)
492 rSettings
.mbTranslucent
= nTranslucent
!= 0;
495 else if ( rDataValue
.Name
== "PixelWidth" )
497 rDataValue
.Value
>>= rSettings
.mnWidth
;
499 else if ( rDataValue
.Name
== "PixelHeight" )
501 rDataValue
.Value
>>= rSettings
.mnHeight
;
503 else if( rDataValue
.Name
== "Width" ) // for compatibility reasons, deprecated
505 rDataValue
.Value
>>= rSettings
.mnWidth
;
506 rDataValue
.Name
= "PixelWidth";
508 else if( rDataValue
.Name
== "Height" ) // for compatibility reasons, deprecated
510 rDataValue
.Value
>>= rSettings
.mnHeight
;
511 rDataValue
.Name
= "PixelHeight";
513 else if ( rDataValue
.Name
== "ExportOnlyBackground" )
515 rDataValue
.Value
>>= rSettings
.mbExportOnlyBackground
;
517 else if ( rDataValue
.Name
== "HighContrast" )
519 rDataValue
.Value
>>= rSettings
.mbUseHighContrast
;
521 else if ( rDataValue
.Name
== "PageNumber" )
523 rDataValue
.Value
>>= mnPageNumber
;
525 else if ( rDataValue
.Name
== "ScrollText" )
527 // #110496# Read flag solitary scroll text metafile
528 rDataValue
.Value
>>= rSettings
.mbScrollText
;
530 else if ( rDataValue
.Name
== "CurrentPage" )
532 Reference
< XDrawPage
> xPage
;
533 rDataValue
.Value
>>= xPage
;
536 SvxDrawPage
* pUnoPage
= comphelper::getFromUnoTunnel
<SvxDrawPage
>( xPage
);
537 if( pUnoPage
&& pUnoPage
->GetSdrPage() )
538 mpCurrentPage
= pUnoPage
->GetSdrPage();
541 else if ( rDataValue
.Name
== "ScaleXNumerator" )
544 if( rDataValue
.Value
>>= nVal
)
545 rSettings
.maScaleX
= Fraction( nVal
, rSettings
.maScaleX
.GetDenominator() );
547 else if ( rDataValue
.Name
== "ScaleXDenominator" )
550 if( rDataValue
.Value
>>= nVal
)
551 rSettings
.maScaleX
= Fraction( rSettings
.maScaleX
.GetNumerator(), nVal
);
553 else if ( rDataValue
.Name
== "ScaleYNumerator" )
556 if( rDataValue
.Value
>>= nVal
)
557 rSettings
.maScaleY
= Fraction( nVal
, rSettings
.maScaleY
.GetDenominator() );
559 else if ( rDataValue
.Name
== "ScaleYDenominator" )
562 if( rDataValue
.Value
>>= nVal
)
563 rSettings
.maScaleY
= Fraction( rSettings
.maScaleY
.GetNumerator(), nVal
);
565 else if (rDataValue
.Name
== "AntiAliasing")
568 if (rDataValue
.Value
>>= bAntiAliasing
)
569 rSettings
.meAntiAliasing
= bAntiAliasing
? TRISTATE_TRUE
: TRISTATE_FALSE
;
575 // putting the StatusIndicator that we got from the MediaDescriptor into our local FilterData copy
576 if ( rSettings
.mxStatusIndicator
.is() )
578 int i
= rSettings
.maFilterData
.getLength();
579 rSettings
.maFilterData
.realloc( i
+ 1 );
580 auto pFilterData
= rSettings
.maFilterData
.getArray();
581 pFilterData
[ i
].Name
= "StatusIndicator";
582 pFilterData
[ i
].Value
<<= rSettings
.mxStatusIndicator
;
586 bool GraphicExporter::GetGraphic( ExportSettings
const & rSettings
, Graphic
& aGraphic
, bool bVectorType
)
588 if( !mpDoc
|| !mpUnoPage
)
591 SdrPage
* pPage
= mpUnoPage
->GetSdrPage();
595 ScopedVclPtrInstance
< VirtualDevice
> aVDev
;
596 const MapMode
aMap( mpDoc
->GetScaleUnit(), Point(), rSettings
.maScaleX
, rSettings
.maScaleY
);
598 SdrOutliner
& rOutl
=mpDoc
->GetDrawOutliner();
599 maOldCalcFieldValueHdl
= rOutl
.GetCalcFieldValueHdl();
600 rOutl
.SetCalcFieldValueHdl( LINK(this, GraphicExporter
, CalcFieldValueHdl
) );
601 rOutl
.SetBackgroundColor( pPage
->GetPageBackgroundColor() );
604 const EEControlBits
nOldCntrl(rOutl
.GetControlWord());
605 EEControlBits nCntrl
= nOldCntrl
& ~EEControlBits::ONLINESPELLING
;
606 rOutl
.SetControlWord(nCntrl
);
608 rtl::Reference
<SdrObject
> pTempBackgroundShape
;
609 std::vector
< SdrObject
* > aShapes
;
612 // export complete page?
615 if( rSettings
.mbExportOnlyBackground
)
617 const SdrPageProperties
* pCorrectProperties
= pPage
->getCorrectSdrPageProperties();
619 if(pCorrectProperties
)
621 pTempBackgroundShape
= new SdrRectObj(
623 tools::Rectangle(Point(0,0), pPage
->GetSize()));
624 pTempBackgroundShape
->SetMergedItemSet(pCorrectProperties
->GetItemSet());
625 pTempBackgroundShape
->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE
));
626 pTempBackgroundShape
->NbcSetStyleSheet(pCorrectProperties
->GetStyleSheet(), true);
627 aShapes
.push_back(pTempBackgroundShape
.get());
632 const Size
aSize( pPage
->GetSize() );
634 // generate a bitmap to convert it to a pixel format.
635 // For gif pictures there can also be a vector format used (bTranslucent)
636 if ( !bVectorType
&& !rSettings
.mbTranslucent
)
638 tools::Long nWidthPix
= 0;
639 tools::Long nHeightPix
= 0;
640 if ( rSettings
.mnWidth
> 0 && rSettings
.mnHeight
> 0 )
642 nWidthPix
= rSettings
.mnWidth
;
643 nHeightPix
= rSettings
.mnHeight
;
647 const Size
aSizePix( Application::GetDefaultDevice()->LogicToPixel( aSize
, aMap
) );
648 if (aSizePix
.Width() > MAX_EXT_PIX
|| aSizePix
.Height() > MAX_EXT_PIX
)
650 if (aSizePix
.Width() > MAX_EXT_PIX
)
651 nWidthPix
= MAX_EXT_PIX
;
653 nWidthPix
= aSizePix
.Width();
654 if (aSizePix
.Height() > MAX_EXT_PIX
)
655 nHeightPix
= MAX_EXT_PIX
;
657 nHeightPix
= aSizePix
.Height();
659 double fWidthDif
= static_cast<double>(aSizePix
.Width()) / nWidthPix
;
660 double fHeightDif
= static_cast<double>(aSizePix
.Height()) / nHeightPix
;
662 if (fWidthDif
> fHeightDif
)
663 nHeightPix
= static_cast<tools::Long
>(aSizePix
.Height() / fWidthDif
);
665 nWidthPix
= static_cast<tools::Long
>(aSizePix
.Width() / fHeightDif
);
669 nWidthPix
= aSizePix
.Width();
670 nHeightPix
= aSizePix
.Height();
674 std::unique_ptr
<SdrView
> xLocalView
;
676 if (FmFormModel
* pFormModel
= dynamic_cast<FmFormModel
*>(mpDoc
))
678 xLocalView
.reset(new FmFormView(*pFormModel
, aVDev
));
682 xLocalView
.reset(new SdrView(*mpDoc
, aVDev
));
685 ScopedVclPtr
<VirtualDevice
> pVDev(CreatePageVDev( pPage
, nWidthPix
, nHeightPix
));
689 aGraphic
= pVDev
->GetBitmapEx( Point(), pVDev
->GetOutputSize() );
690 aGraphic
.SetPrefMapMode( aMap
);
691 aGraphic
.SetPrefSize( aSize
);
694 // create a metafile to export a vector format
699 aVDev
->SetMapMode( aMap
);
700 if( rSettings
.mbUseHighContrast
)
701 aVDev
->SetDrawMode( aVDev
->GetDrawMode() | DrawModeFlags::SettingsLine
| DrawModeFlags::SettingsFill
| DrawModeFlags::SettingsText
| DrawModeFlags::SettingsGradient
);
702 aVDev
->EnableOutput( false );
703 aMtf
.Record( aVDev
);
707 std::unique_ptr
< SdrView
> pView
;
709 if (FmFormModel
*pFormModel
= dynamic_cast<FmFormModel
*>(mpDoc
))
711 pView
.reset(new FmFormView(*pFormModel
, aVDev
));
715 pView
.reset(new SdrView(*mpDoc
, aVDev
));
718 pView
->SetBordVisible( false );
719 pView
->SetPageVisible( false );
720 pView
->ShowSdrPage( pPage
);
722 // tdf#96922 completely deactivate EditView PageVisualization, including
723 // PageBackground (formerly 'wiese').
724 pView
->SetPagePaintingAllowed(false);
726 const Point
aNewOrg( pPage
->GetLeftBorder(), pPage
->GetUpperBorder() );
727 aNewSize
= Size( aSize
.Width() - pPage
->GetLeftBorder() - pPage
->GetRightBorder(),
728 aSize
.Height() - pPage
->GetUpperBorder() - pPage
->GetLowerBorder() );
729 const tools::Rectangle
aClipRect( aNewOrg
, aNewSize
);
730 MapMode
aVMap( aMap
);
733 aVMap
.SetOrigin( Point( -aNewOrg
.X(), -aNewOrg
.Y() ) );
734 aVDev
->SetRelativeMapMode( aVMap
);
735 aVDev
->IntersectClipRegion( aClipRect
);
737 // Use new StandardCheckVisisbilityRedirector
738 ImplExportCheckVisisbilityRedirector
aRedirector( mpCurrentPage
);
740 pView
->CompleteRedraw(aVDev
, vcl::Region(tools::Rectangle(aNewOrg
, aNewSize
)), &aRedirector
);
746 aMtf
.SetPrefMapMode( aMap
);
747 aMtf
.SetPrefSize( aNewSize
);
749 // AW: Here the current version was filtering out the MetaActionType::CLIPREGIONs
750 // from the metafile. I asked some other developers why this was done, but no
751 // one knew a direct reason. Since it's in for long time, it may be an old
752 // piece of code. MetaFiles save and load ClipRegions with polygons with preserving
753 // the polygons, so a resolution-independent roundtrip is supported. Removed this
754 // code since it destroys some MetaFiles where ClipRegions are used. Anyways,
755 // just filtering them out is a hack, at least the encapsulated content would need
756 // to be clipped geometrically.
757 aGraphic
= Graphic(aMtf
);
759 pView
->HideSdrPage();
761 if( rSettings
.mbTranslucent
)
764 aGraphic
= GetBitmapFromMetaFile( aGraphic
.GetGDIMetaFile(), CalcSize( rSettings
.mnWidth
, rSettings
.mnHeight
, aNewSize
, aOutSize
) );
770 // export only single shape or shape collection
773 // build list of SdrObject
776 Reference
< XShape
> xShape
;
777 const sal_Int32 nCount
= mxShapes
->getCount();
779 for( sal_Int32 nIndex
= 0; nIndex
< nCount
; nIndex
++ )
781 mxShapes
->getByIndex( nIndex
) >>= xShape
;
782 SdrObject
* pObj
= SdrObject::getSdrObjectFromXShape(xShape
);
784 aShapes
.push_back( pObj
);
790 SdrObject
* pObj
= SdrObject::getSdrObjectFromXShape(mxShape
);
792 aShapes
.push_back( pObj
);
795 if( aShapes
.empty() )
799 if( bRet
&& !aShapes
.empty() )
801 // special treatment for only one SdrGrafObj that has text
802 bool bSingleGraphic
= false;
804 if( 1 == aShapes
.size() )
808 if( auto pGrafObj
= dynamic_cast<const SdrGrafObj
*>(aShapes
.front()) )
809 if (pGrafObj
->HasText() )
811 aGraphic
= pGrafObj
->GetTransformedGraphic();
812 if ( aGraphic
.GetType() == GraphicType::Bitmap
)
814 Size
aSizePixel( aGraphic
.GetSizePixel() );
815 if( rSettings
.mnWidth
&& rSettings
.mnHeight
&&
816 ( ( rSettings
.mnWidth
!= aSizePixel
.Width() ) ||
817 ( rSettings
.mnHeight
!= aSizePixel
.Height() ) ) )
819 BitmapEx
aBmpEx( aGraphic
.GetBitmapEx() );
820 // export: use highest quality
821 aBmpEx
.Scale( Size( rSettings
.mnWidth
, rSettings
.mnHeight
), BmpScaleFlag::Lanczos
);
825 // #118804# only accept for bitmap graphics, else the
826 // conversion to bitmap will happen anywhere without size control
827 // as evtl. defined in rSettings.mnWidth/mnHeight
828 bSingleGraphic
= true;
832 else if( rSettings
.mbScrollText
)
834 SdrObject
* pObj
= aShapes
.front();
835 auto pTextObj
= DynCastSdrTextObj( pObj
);
836 if( pTextObj
&& pTextObj
->HasText() )
838 tools::Rectangle aScrollRectangle
;
839 tools::Rectangle aPaintRectangle
;
841 const std::unique_ptr
< GDIMetaFile
> pMtf(
842 pTextObj
->GetTextScrollMetaFileAndRectangle(
843 aScrollRectangle
, aPaintRectangle
) );
845 // take the larger one of the two rectangles (that
846 // should be the bound rect of the retrieved
848 tools::Rectangle aTextRect
;
850 if( aScrollRectangle
.Contains( aPaintRectangle
) )
851 aTextRect
= aScrollRectangle
;
853 aTextRect
= aPaintRectangle
;
855 // setup pref size and mapmode
856 pMtf
->SetPrefSize( aTextRect
.GetSize() );
858 // set actual origin (mtf is at actual shape
860 MapMode
aLocalMapMode( aMap
);
861 aLocalMapMode
.SetOrigin(
862 Point( -aPaintRectangle
.Left(),
863 -aPaintRectangle
.Top() ) );
864 pMtf
->SetPrefMapMode( aLocalMapMode
);
866 pMtf
->AddAction( new MetaCommentAction(
867 "XTEXT_SCROLLRECT", 0,
868 reinterpret_cast<sal_uInt8
const*>(&aScrollRectangle
),
869 sizeof( tools::Rectangle
) ) );
870 pMtf
->AddAction( new MetaCommentAction(
871 "XTEXT_PAINTRECT", 0,
872 reinterpret_cast<sal_uInt8
const*>(&aPaintRectangle
),
873 sizeof( tools::Rectangle
) ) );
875 aGraphic
= Graphic( *pMtf
);
877 bSingleGraphic
= true;
882 if( !bSingleGraphic
)
884 // create a metafile for all shapes
885 ScopedVclPtrInstance
< VirtualDevice
> aOut
;
887 // calculate bound rect for all shapes
888 // tdf#126319 I did not convert all rendering to primities,
889 // that would be to much for this fix. But I did so for the
890 // range calculation to get a valid high quality range.
891 // Based on that the conversion is reliable. With the BoundRect
892 // fetched from the Metafile it was just not possible to get the
893 // examples from the task handled in a way to fit all cases -
894 // due to bad-quality range data from it.
895 basegfx::B2DRange aBound
;
896 const drawinglayer::geometry::ViewInformation2D aViewInformation2D
;
899 for( SdrObject
* pObj
: aShapes
)
901 drawinglayer::primitive2d::Primitive2DContainer aSequence
;
902 pObj
->GetViewContact().getViewIndependentPrimitive2DContainer(aSequence
);
903 aBound
.expand(aSequence
.getB2DRange(aViewInformation2D
));
907 aOut
->EnableOutput( false );
908 aOut
->SetMapMode( aMap
);
909 if( rSettings
.mbUseHighContrast
)
910 aOut
->SetDrawMode( aOut
->GetDrawMode() | DrawModeFlags::SettingsLine
| DrawModeFlags::SettingsFill
| DrawModeFlags::SettingsText
| DrawModeFlags::SettingsGradient
);
916 MapMode
aOutMap( aMap
);
917 const Size
aOnePixelInMtf(
918 Application::GetDefaultDevice()->PixelToLogic(
921 const Size
aHalfPixelInMtf(
922 (aOnePixelInMtf
.getWidth() + 1) / 2,
923 (aOnePixelInMtf
.getHeight() + 1) / 2);
925 // tdf#126319 Immediately add needed offset to create metafile,
926 // that avoids to do it later by Metafile::Move what would be expensive
929 basegfx::fround(-aBound
.getMinX() - aHalfPixelInMtf
.getWidth()),
930 basegfx::fround(-aBound
.getMinY() - aHalfPixelInMtf
.getHeight()) ) );
931 aOut
->SetRelativeMapMode( aOutMap
);
933 sdr::contact::DisplayInfo aDisplayInfo
;
937 if(mpCurrentPage
->TRG_HasMasterPage() && pPage
->IsMasterPage())
939 // MasterPage is processed as another page's SubContent
940 aDisplayInfo
.SetProcessLayers(mpCurrentPage
->TRG_GetMasterPageVisibleLayers());
941 aDisplayInfo
.SetSubContentActive(true);
947 // more effective way to paint a vector of SdrObjects. Hand over the processed page
949 ImplExportCheckVisisbilityRedirector
aCheckVisibilityRedirector(mpCurrentPage
);
950 sdr::contact::ObjectContactOfObjListPainter
aMultiObjectPainter(*aOut
, std::move(aShapes
), mpCurrentPage
);
951 aMultiObjectPainter
.SetViewObjectContactRedirector(&aCheckVisibilityRedirector
);
953 aMultiObjectPainter
.ProcessDisplay(aDisplayInfo
);
959 // tdf#126319 Immediately add needed size to target's PrefSize
960 // tdf#150102 Checked that in aBound is indeed the size - 1 (probably
961 // due to old integer stuff using Size()/Rectangle() and getWidth()/GetWidth()
962 // with the old one-less paradigm somewhere), so just correct to the
963 // correct size. Be aware that checking of tdf#126319 is needed, but
964 // looks good in my tests. Still: Changing the central UNO API Metafile
965 // export is always a risky thing, so it will have to show if this will
966 // not influence something else.
967 const Size
aBoundSize(
968 basegfx::fround(aBound
.getWidth() + 1),
969 basegfx::fround(aBound
.getHeight() + 1));
970 aMtf
.SetPrefMapMode( aMap
);
971 aMtf
.SetPrefSize( aBoundSize
);
976 aGraphic
= GetBitmapFromMetaFile( aMtf
, CalcSize( rSettings
.mnWidth
, rSettings
.mnHeight
, aBoundSize
, aOutSize
) );
985 pTempBackgroundShape
.clear();
987 rOutl
.SetCalcFieldValueHdl( maOldCalcFieldValueHdl
);
990 rOutl
.SetControlWord(nOldCntrl
);
997 sal_Bool SAL_CALL
GraphicExporter::filter( const Sequence
< PropertyValue
>& aDescriptor
)
999 ::SolarMutexGuard aGuard
;
1001 if( maGraphic
.IsNone() && nullptr == mpUnoPage
)
1004 if( maGraphic
.IsNone() && ( nullptr == mpUnoPage
->GetSdrPage() || nullptr == mpDoc
) )
1007 GraphicFilter
&rFilter
= GraphicFilter::GetGraphicFilter();
1009 // get the arguments from the descriptor
1010 ExportSettings aSettings
;
1011 ParseSettings(aDescriptor
, aSettings
);
1013 const sal_uInt16 nFilter
= !aSettings
.maMediaType
.isEmpty()
1014 ? rFilter
.GetExportFormatNumberForMediaType( aSettings
.maMediaType
)
1015 : rFilter
.GetExportFormatNumberForShortName( aSettings
.maFilterName
);
1016 bool bVectorType
= !rFilter
.IsExportPixelFormat( nFilter
);
1018 // create the output stuff
1019 Graphic aGraphic
= maGraphic
;
1021 ErrCode nStatus
= ERRCODE_NONE
;
1022 if (maGraphic
.IsNone())
1024 bool bAntiAliasing
= SvtOptionsDrawinglayer::IsAntiAliasing();
1025 AllSettings aAllSettings
= Application::GetSettings();
1026 StyleSettings aStyleSettings
= aAllSettings
.GetStyleSettings();
1027 bool bUseFontAAFromSystem
= aStyleSettings
.GetUseFontAAFromSystem();
1028 if (aSettings
.meAntiAliasing
!= TRISTATE_INDET
)
1030 // This is safe to do globally as we own the solar mutex.
1031 SvtOptionsDrawinglayer::SetAntiAliasing(aSettings
.meAntiAliasing
== TRISTATE_TRUE
, /*bTemporary*/true);
1032 // Opt in to have AA affect font rendering as well.
1033 aStyleSettings
.SetUseFontAAFromSystem(false);
1034 aAllSettings
.SetStyleSettings(aStyleSettings
);
1035 Application::SetSettings(aAllSettings
);
1037 nStatus
= GetGraphic( aSettings
, aGraphic
, bVectorType
) ? ERRCODE_NONE
: ERRCODE_GRFILTER_FILTERERROR
;
1038 if (aSettings
.meAntiAliasing
!= TRISTATE_INDET
)
1040 SvtOptionsDrawinglayer::SetAntiAliasing(bAntiAliasing
, /*bTemporary*/true);
1041 aStyleSettings
.SetUseFontAAFromSystem(bUseFontAAFromSystem
);
1042 aAllSettings
.SetStyleSettings(aStyleSettings
);
1043 Application::SetSettings(aAllSettings
);
1047 if( nStatus
== ERRCODE_NONE
)
1049 // export graphic only if it has a size
1050 const Size
aGraphSize( aGraphic
.GetPrefSize() );
1051 if ( aGraphSize
.IsEmpty() )
1053 nStatus
= ERRCODE_GRFILTER_FILTERERROR
;
1057 // now we have a graphic, so export it
1058 if( aSettings
.mxGraphicRenderer
.is() )
1060 // render graphic directly into given renderer
1061 aSettings
.mxGraphicRenderer
->render( aGraphic
.GetXGraphic() );
1063 else if( aSettings
.mxOutputStream
.is() )
1065 // TODO: Either utilize optional XSeekable functionality for the
1066 // SvOutputStream, or adapt the graphic filter to not seek anymore.
1067 SvMemoryStream
aStream( 1024, 1024 );
1069 nStatus
= rFilter
.ExportGraphic( aGraphic
, u
"", aStream
, nFilter
, &aSettings
.maFilterData
);
1071 // copy temp stream to XOutputStream
1072 SvOutputStream
aOutputStream( aSettings
.mxOutputStream
);
1074 aOutputStream
.WriteStream( aStream
);
1078 INetURLObject
aURLObject( aSettings
.maURL
.Complete
);
1079 DBG_ASSERT( aURLObject
.GetProtocol() != INetProtocol::NotValid
, "invalid URL" );
1081 nStatus
= XOutBitmap::ExportGraphic( aGraphic
, aURLObject
, rFilter
, nFilter
, &aSettings
.maFilterData
);
1086 if ( aSettings
.mxInteractionHandler
.is() && ( nStatus
!= ERRCODE_NONE
) )
1089 Sequence
< css::uno::Reference
< css::task::XInteractionContinuation
> > lContinuations
{
1090 new ::comphelper::OInteractionApprove()
1093 GraphicFilterRequest aErrorCode
;
1094 aErrorCode
.ErrCode
= sal_uInt32(nStatus
);
1095 aInteraction
<<= aErrorCode
;
1096 aSettings
.mxInteractionHandler
->handle( framework::InteractionRequest::CreateRequest( aInteraction
, lContinuations
) );
1098 return nStatus
== ERRCODE_NONE
;
1101 void SAL_CALL
GraphicExporter::cancel()
1107 /** the source 'document' could be a XDrawPage, a XShape or a generic XShapes */
1108 void SAL_CALL
GraphicExporter::setSourceDocument( const Reference
< lang::XComponent
>& xComponent
)
1110 ::SolarMutexGuard aGuard
;
1113 mpUnoPage
= nullptr;
1117 // any break inside this one loop while will throw an IllegalArgumentException
1120 mxPage
.set( xComponent
, UNO_QUERY
);
1121 mxShapes
.set( xComponent
, UNO_QUERY
);
1122 mxShape
.set( xComponent
, UNO_QUERY
);
1124 // Step 1: try a generic XShapes
1125 if( !mxPage
.is() && !mxShape
.is() && mxShapes
.is() )
1127 // we do not support empty shape collections
1128 if( 0 == mxShapes
->getCount() )
1131 // get first shape to detect corresponding page and model
1132 mxShapes
->getByIndex(0) >>= mxShape
;
1139 // Step 2: try a shape
1142 if (nullptr == SdrObject::getSdrObjectFromXShape(mxShape
))
1144 // This is not a Draw shape, let's see if it's a Writer one.
1145 uno::Reference
<beans::XPropertySet
> xPropertySet(mxShape
, uno::UNO_QUERY
);
1146 if (!xPropertySet
.is())
1148 uno::Reference
<graphic::XGraphic
> xGraphic(
1149 xPropertySet
->getPropertyValue("Graphic"), uno::UNO_QUERY
);
1153 maGraphic
= Graphic(xGraphic
);
1154 if (!maGraphic
.IsNone())
1160 // get page for this shape
1161 Reference
< XChild
> xChild( mxShape
, UNO_QUERY
);
1165 Reference
< XInterface
> xInt
;
1168 xInt
= xChild
->getParent();
1169 mxPage
.set( xInt
, UNO_QUERY
);
1171 xChild
.set( xInt
, UNO_QUERY
);
1173 while( !mxPage
.is() && xChild
.is() );
1179 // Step 3: check the page
1183 mpUnoPage
= comphelper::getFromUnoTunnel
<SvxDrawPage
>( mxPage
);
1185 if( nullptr == mpUnoPage
|| nullptr == mpUnoPage
->GetSdrPage() )
1188 mpDoc
= &mpUnoPage
->GetSdrPage()->getSdrModelFromSdrPage();
1190 // Step 4: If we got a generic XShapes test all contained shapes
1191 // if they belong to the same XDrawPage
1195 SdrPage
* pPage
= mpUnoPage
->GetSdrPage();
1197 Reference
< XShape
> xShape
;
1201 const sal_Int32 nCount
= mxShapes
->getCount();
1203 // test all but the first shape if they have the same page than
1205 for( sal_Int32 nIndex
= 1; bOk
&& ( nIndex
< nCount
); nIndex
++ )
1207 mxShapes
->getByIndex( nIndex
) >>= xShape
;
1208 pObj
= SdrObject::getSdrObjectFromXShape(xShape
);
1209 bOk
= pObj
&& pObj
->getSdrPageFromSdrObject() == pPage
;
1225 throw IllegalArgumentException();
1229 OUString SAL_CALL
GraphicExporter::getImplementationName( )
1231 return "com.sun.star.comp.Draw.GraphicExporter";
1234 sal_Bool SAL_CALL
GraphicExporter::supportsService( const OUString
& ServiceName
)
1236 return cppu::supportsService(this, ServiceName
);
1239 Sequence
< OUString
> SAL_CALL
GraphicExporter::getSupportedServiceNames( )
1241 Sequence
< OUString
> aSupportedServiceNames
{ "com.sun.star.drawing.GraphicExportFilter" };
1242 return aSupportedServiceNames
;
1246 sal_Bool SAL_CALL
GraphicExporter::supportsMimeType( const OUString
& rMimeTypeName
)
1248 GraphicFilter
&rFilter
= GraphicFilter::GetGraphicFilter();
1249 sal_uInt16 nCount
= rFilter
.GetExportFormatCount();
1251 for( nFilter
= 0; nFilter
< nCount
; nFilter
++ )
1253 if( rMimeTypeName
== rFilter
.GetExportFormatMediaType( nFilter
) )
1262 Sequence
< OUString
> SAL_CALL
GraphicExporter::getSupportedMimeTypeNames( )
1264 GraphicFilter
&rFilter
= GraphicFilter::GetGraphicFilter();
1265 sal_uInt16 nCount
= rFilter
.GetExportFormatCount();
1267 sal_uInt16 nFound
= 0;
1269 Sequence
< OUString
> aSeq( nCount
);
1270 OUString
* pStr
= aSeq
.getArray();
1272 for( nFilter
= 0; nFilter
< nCount
; nFilter
++ )
1274 OUString
aMimeType( rFilter
.GetExportFormatMediaType( nFilter
) );
1275 if( !aMimeType
.isEmpty() )
1277 *pStr
++ = aMimeType
;
1282 if( nFound
< nCount
)
1283 aSeq
.realloc( nFound
);
1290 Graphic
SvxGetGraphicForShape( SdrObject
& rShape
)
1295 rtl::Reference
< GraphicExporter
> xExporter( new GraphicExporter() );
1296 Reference
< XComponent
> xComp( rShape
.getUnoShape(), UNO_QUERY_THROW
);
1297 xExporter
->setSourceDocument( xComp
);
1298 ExportSettings aSettings
;
1299 xExporter
->GetGraphic( aSettings
, aGraphic
, true/*bVector*/ );
1303 TOOLS_WARN_EXCEPTION("svx", "");
1308 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
1309 com_sun_star_comp_Draw_GraphicExporter_get_implementation(
1310 css::uno::XComponentContext
*,
1311 css::uno::Sequence
<css::uno::Any
> const &)
1313 return cppu::acquire(new GraphicExporter
);
1316 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */