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 <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"
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
;
84 #include <editeng/editstat.hxx>
90 OUString maFilterName
;
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
;
100 bool mbExportOnlyBackground
;
102 bool mbUseHighContrast
;
105 Sequence
< PropertyValue
> maFilterData
;
110 TriState meAntiAliasing
= TRISTATE_INDET
;
112 explicit ExportSettings(const SdrModel
* pSdrModel
);
115 ExportSettings::ExportSettings(const SdrModel
* pSdrModel
)
118 ,mbExportOnlyBackground( false )
119 ,mbScrollText( false )
120 ,mbUseHighContrast( false )
121 ,mbTranslucent( false )
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
>
142 virtual sal_Bool SAL_CALL
filter( const Sequence
< PropertyValue
>& aDescriptor
) override
;
143 virtual void SAL_CALL
cancel( ) override
;
146 virtual void SAL_CALL
setSourceDocument( const Reference
< XComponent
>& xDoc
) override
;
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
;
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
);
165 Reference
< XShape
> mxShape
;
166 Reference
< XDrawPage
> mxPage
;
167 Reference
< XShapes
> mxShapes
;
170 SvxDrawPage
* mpUnoPage
;
172 Link
<EditFieldInfo
*,void> maOldCalcFieldValueHdl
;
173 sal_Int32 mnPageNumber
;
174 SdrPage
* mpCurrentPage
;
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);
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()));
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
));
213 GDIMetaFile
aMtf(rMtf
);
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(
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
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
243 aRect
.getWidth() + (bHairlineBR
? aOnePixelInMtf
.getWidth() : 0) + aHalfPixelInMtf
.getWidth(),
244 aRect
.getHeight() + (bHairlineBR
? aOnePixelInMtf
.getHeight() : 0) + aHalfPixelInMtf
.getHeight()));
247 return convertMetafileToBitmapEx(aMtf
, aRange
, nMaximumQuadraticPixels
);
253 Size
* CalcSize( sal_Int32 nWidth
, sal_Int32 nHeight
, const Size
& aBoundSize
, Size
& aOutSize
)
255 if( (nWidth
== 0) && (nHeight
== 0) )
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
);
273 class ImplExportCheckVisisbilityRedirector
: public sdr::contact::ViewObjectContactRedirector
276 explicit ImplExportCheckVisisbilityRedirector( SdrPage
* pCurrentPage
);
278 virtual drawinglayer::primitive2d::Primitive2DContainer
createRedirectedPrimitive2DSequence(
279 const sdr::contact::ViewObjectContact
& rOriginal
,
280 const sdr::contact::DisplayInfo
& rDisplayInfo
) override
;
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();
299 SdrPage
* pPage
= mpCurrentPage
;
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();
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)
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
;
341 switch(mpDoc
->GetPageNumType())
343 case css::style::NumberingType::CHARS_UPPER_LETTER
:
344 aPageNumValue
+= OUStringChar( sal_Unicode((mnPageNumber
- 1) % 26 + 'A') );
346 case css::style::NumberingType::CHARS_LOWER_LETTER
:
347 aPageNumValue
+= OUStringChar( sal_Unicode((mnPageNumber
- 1) % 26 + 'a') );
349 case css::style::NumberingType::ROMAN_UPPER
:
352 case css::style::NumberingType::ROMAN_LOWER
:
353 aPageNumValue
+= SvxNumberFormat::CreateRomanString(mnPageNumber
, bUpper
);
355 case css::style::NumberingType::NUMBER_NONE
:
359 aPageNumValue
+= OUString::number( mnPageNumber
);
362 pInfo
->SetRepresentation( aPageNumValue
);
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());
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
));
418 bSuccess
= pVDev
->SetOutputSize(aPageSize
);
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
);
440 OSL_ENSURE(false, "Could not get a VirtualDevice of requested size (!)");
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
;
549 SvxDrawPage
* pUnoPage
= comphelper::getUnoTunnelImplementation
<SvxDrawPage
>( xPage
);
550 if( pUnoPage
&& pUnoPage
->GetSdrPage() )
551 mpCurrentPage
= pUnoPage
->GetSdrPage();
554 else if ( rDataValue
.Name
== "ScaleXNumerator" )
557 if( rDataValue
.Value
>>= nVal
)
558 rSettings
.maScaleX
= Fraction( nVal
, rSettings
.maScaleX
.GetDenominator() );
560 else if ( rDataValue
.Name
== "ScaleXDenominator" )
563 if( rDataValue
.Value
>>= nVal
)
564 rSettings
.maScaleX
= Fraction( rSettings
.maScaleX
.GetNumerator(), nVal
);
566 else if ( rDataValue
.Name
== "ScaleYNumerator" )
569 if( rDataValue
.Value
>>= nVal
)
570 rSettings
.maScaleY
= Fraction( nVal
, rSettings
.maScaleY
.GetDenominator() );
572 else if ( rDataValue
.Name
== "ScaleYDenominator" )
575 if( rDataValue
.Value
>>= nVal
)
576 rSettings
.maScaleY
= Fraction( rSettings
.maScaleY
.GetNumerator(), nVal
);
578 else if (rDataValue
.Name
== "AntiAliasing")
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
)
603 SdrPage
* pPage
= mpUnoPage
->GetSdrPage();
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() );
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
;
624 // export complete page?
627 if( rSettings
.mbExportOnlyBackground
)
629 const SdrPageProperties
* pCorrectProperties
= pPage
->getCorrectSdrPageProperties();
631 if(pCorrectProperties
)
633 pTempBackgroundShape
= new SdrRectObj(
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
);
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
;
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
;
665 nWidthPix
= aSizePix
.Width();
666 if (aSizePix
.Height() > MAX_EXT_PIX
)
667 nHeightPix
= MAX_EXT_PIX
;
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
);
677 nWidthPix
= static_cast<tools::Long
>(aSizePix
.Width() / fHeightDif
);
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
));
694 xLocalView
.reset(new SdrView(*mpDoc
, aVDev
));
697 ScopedVclPtr
<VirtualDevice
> pVDev(CreatePageVDev( pPage
, nWidthPix
, nHeightPix
));
701 aGraphic
= pVDev
->GetBitmapEx( Point(), pVDev
->GetOutputSize() );
702 aGraphic
.SetPrefMapMode( aMap
);
703 aGraphic
.SetPrefSize( aSize
);
706 // create a metafile to export a vector format
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
);
719 std::unique_ptr
< SdrView
> pView
;
721 if (FmFormModel
*pFormModel
= dynamic_cast<FmFormModel
*>(mpDoc
))
723 pView
.reset(new FmFormView(*pFormModel
, aVDev
));
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
);
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
);
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
)
776 aGraphic
= GetBitmapFromMetaFile( aGraphic
.GetGDIMetaFile(), false, CalcSize( rSettings
.mnWidth
, rSettings
.mnHeight
, aNewSize
, aOutSize
) );
782 // export only single shape or shape collection
785 // build list of SdrObject
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
);
796 aShapes
.push_back( pObj
);
802 SdrObject
* pObj
= GetSdrObjectFromXShape( mxShape
);
804 aShapes
.push_back( pObj
);
807 if( aShapes
.empty() )
811 if( bRet
&& !aShapes
.empty() )
813 // special treatment for only one SdrGrafObj that has text
814 bool bSingleGraphic
= false;
816 if( 1 == aShapes
.size() )
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
);
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
860 tools::Rectangle aTextRect
;
862 if( aScrollRectangle
.IsInside( aPaintRectangle
) )
863 aTextRect
= aScrollRectangle
;
865 aTextRect
= aPaintRectangle
;
867 // setup pref size and mapmode
868 pMtf
->SetPrefSize( aTextRect
.GetSize() );
870 // set actual origin (mtf is at actual shape
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())
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
);
922 MapMode
aOutMap( aMap
);
923 aOutMap
.SetOrigin( Point( -aBound
.Left(), -aBound
.Top() ) );
924 aOut
->SetRelativeMapMode( aOutMap
);
926 sdr::contact::DisplayInfo aDisplayInfo
;
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);
940 // more effective way to paint a vector of SdrObjects. Hand over the processed page
942 sdr::contact::ObjectContactOfObjListPainter
aMultiObjectPainter(*aOut
, aShapes
, mpCurrentPage
);
943 ImplExportCheckVisisbilityRedirector
aCheckVisibilityRedirector(mpCurrentPage
);
944 aMultiObjectPainter
.SetViewObjectContactRedirector(&aCheckVisibilityRedirector
);
946 aMultiObjectPainter
.ProcessDisplay(aDisplayInfo
);
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
);
962 aGraphic
= GetBitmapFromMetaFile( aMtf
, true, CalcSize( rSettings
.mnWidth
, rSettings
.mnHeight
, aBoundSize
, aOutSize
) );
971 if(pTempBackgroundShape
)
973 SdrObject::Free(pTempBackgroundShape
);
976 rOutl
.SetCalcFieldValueHdl( maOldCalcFieldValueHdl
);
979 rOutl
.SetControlWord(nOldCntrl
);
986 sal_Bool SAL_CALL
GraphicExporter::filter( const Sequence
< PropertyValue
>& aDescriptor
)
988 ::SolarMutexGuard aGuard
;
990 if( maGraphic
.IsNone() && nullptr == mpUnoPage
)
993 if( maGraphic
.IsNone() && ( nullptr == mpUnoPage
->GetSdrPage() || nullptr == mpDoc
) )
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
;
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
);
1064 aOutputStream
.WriteStream( aStream
);
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
) )
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()
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
;
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() )
1120 // get first shape to detect corresponding page and model
1121 mxShapes
->getByIndex(0) >>= mxShape
;
1128 // Step 2: try a shape
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())
1137 uno::Reference
<graphic::XGraphic
> xGraphic(
1138 xPropertySet
->getPropertyValue("Graphic"), uno::UNO_QUERY
);
1142 maGraphic
= Graphic(xGraphic
);
1143 if (!maGraphic
.IsNone())
1149 // get page for this shape
1150 Reference
< XChild
> xChild( mxShape
, UNO_QUERY
);
1154 Reference
< XInterface
> xInt
;
1157 xInt
= xChild
->getParent();
1158 mxPage
.set( xInt
, UNO_QUERY
);
1160 xChild
.set( xInt
, UNO_QUERY
);
1162 while( !mxPage
.is() && xChild
.is() );
1168 // Step 3: check the page
1172 mpUnoPage
= comphelper::getUnoTunnelImplementation
<SvxDrawPage
>( mxPage
);
1174 if( nullptr == mpUnoPage
|| nullptr == mpUnoPage
->GetSdrPage() )
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
1184 SdrPage
* pPage
= mpUnoPage
->GetSdrPage();
1186 Reference
< XShape
> xShape
;
1190 const sal_Int32 nCount
= mxShapes
->getCount();
1192 // test all but the first shape if they have the same page than
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
;
1214 throw IllegalArgumentException();
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
;
1235 sal_Bool SAL_CALL
GraphicExporter::supportsMimeType( const OUString
& rMimeTypeName
)
1237 GraphicFilter
&rFilter
= GraphicFilter::GetGraphicFilter();
1238 sal_uInt16 nCount
= rFilter
.GetExportFormatCount();
1240 for( nFilter
= 0; nFilter
< nCount
; nFilter
++ )
1242 if( rMimeTypeName
== rFilter
.GetExportFormatMediaType( nFilter
) )
1251 Sequence
< OUString
> SAL_CALL
GraphicExporter::getSupportedMimeTypeNames( )
1253 GraphicFilter
&rFilter
= GraphicFilter::GetGraphicFilter();
1254 sal_uInt16 nCount
= rFilter
.GetExportFormatCount();
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
;
1271 if( nFound
< nCount
)
1272 aSeq
.realloc( nFound
);
1279 Graphic
SvxGetGraphicForShape( SdrObject
& rShape
)
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*/ );
1292 TOOLS_WARN_EXCEPTION("svx", "");
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: */