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/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"
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
;
89 #include <editeng/editstat.hxx>
95 OUString maFilterName
;
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
;
105 bool mbExportOnlyBackground
;
107 bool mbUseHighContrast
;
110 Sequence
< PropertyValue
> maFilterData
;
115 TriState meAntiAliasing
= TRISTATE_INDET
;
117 explicit ExportSettings(const SdrModel
* pSdrModel
);
120 ExportSettings::ExportSettings(const SdrModel
* pSdrModel
)
123 ,mbExportOnlyBackground( false )
124 ,mbScrollText( false )
125 ,mbUseHighContrast( false )
126 ,mbTranslucent( false )
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
>
147 virtual sal_Bool SAL_CALL
filter( const Sequence
< PropertyValue
>& aDescriptor
) override
;
148 virtual void SAL_CALL
cancel( ) override
;
151 virtual void SAL_CALL
setSourceDocument( const Reference
< XComponent
>& xDoc
) override
;
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
;
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
);
170 Reference
< XShape
> mxShape
;
171 Reference
< XDrawPage
> mxPage
;
172 Reference
< XShapes
> mxShapes
;
175 SvxDrawPage
* mpUnoPage
;
177 Link
<EditFieldInfo
*,void> maOldCalcFieldValueHdl
;
178 sal_Int32 mnPageNumber
;
179 SdrPage
* mpCurrentPage
;
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);
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()));
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
));
218 GDIMetaFile
aMtf(rMtf
);
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(
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
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
248 aRect
.getWidth() + (bHairlineBR
? aOnePixelInMtf
.getWidth() : 0) + aHalfPixelInMtf
.getWidth(),
249 aRect
.getHeight() + (bHairlineBR
? aOnePixelInMtf
.getHeight() : 0) + aHalfPixelInMtf
.getHeight()));
252 return convertMetafileToBitmapEx(aMtf
, aRange
, nMaximumQuadraticPixels
);
258 Size
* CalcSize( sal_Int32 nWidth
, sal_Int32 nHeight
, const Size
& aBoundSize
, Size
& aOutSize
)
260 if( (nWidth
== 0) && (nHeight
== 0) )
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
);
278 class ImplExportCheckVisisbilityRedirector
: public sdr::contact::ViewObjectContactRedirector
281 explicit ImplExportCheckVisisbilityRedirector( SdrPage
* pCurrentPage
);
283 virtual drawinglayer::primitive2d::Primitive2DContainer
createRedirectedPrimitive2DSequence(
284 const sdr::contact::ViewObjectContact
& rOriginal
,
285 const sdr::contact::DisplayInfo
& rDisplayInfo
) override
;
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();
304 SdrPage
* pPage
= mpCurrentPage
;
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();
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)
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
;
346 switch(mpDoc
->GetPageNumType())
348 case css::style::NumberingType::CHARS_UPPER_LETTER
:
349 aPageNumValue
+= OUStringChar( sal_Unicode((mnPageNumber
- 1) % 26 + 'A') );
351 case css::style::NumberingType::CHARS_LOWER_LETTER
:
352 aPageNumValue
+= OUStringChar( sal_Unicode((mnPageNumber
- 1) % 26 + 'a') );
354 case css::style::NumberingType::ROMAN_UPPER
:
357 case css::style::NumberingType::ROMAN_LOWER
:
358 aPageNumValue
+= SvxNumberFormat::CreateRomanString(mnPageNumber
, bUpper
);
360 case css::style::NumberingType::NUMBER_NONE
:
364 aPageNumValue
+= OUString::number( mnPageNumber
);
367 pInfo
->SetRepresentation( aPageNumValue
);
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());
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
);
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
));
423 bSuccess
= pVDev
->SetOutputSize(aPageSize
);
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
);
445 OSL_ENSURE(false, "Could not get a VirtualDevice of requested size (!)");
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
;
554 SvxDrawPage
* pUnoPage
= comphelper::getUnoTunnelImplementation
<SvxDrawPage
>( xPage
);
555 if( pUnoPage
&& pUnoPage
->GetSdrPage() )
556 mpCurrentPage
= pUnoPage
->GetSdrPage();
559 else if ( rDataValue
.Name
== "ScaleXNumerator" )
562 if( rDataValue
.Value
>>= nVal
)
563 rSettings
.maScaleX
= Fraction( nVal
, rSettings
.maScaleX
.GetDenominator() );
565 else if ( rDataValue
.Name
== "ScaleXDenominator" )
568 if( rDataValue
.Value
>>= nVal
)
569 rSettings
.maScaleX
= Fraction( rSettings
.maScaleX
.GetNumerator(), nVal
);
571 else if ( rDataValue
.Name
== "ScaleYNumerator" )
574 if( rDataValue
.Value
>>= nVal
)
575 rSettings
.maScaleY
= Fraction( nVal
, rSettings
.maScaleY
.GetDenominator() );
577 else if ( rDataValue
.Name
== "ScaleYDenominator" )
580 if( rDataValue
.Value
>>= nVal
)
581 rSettings
.maScaleY
= Fraction( rSettings
.maScaleY
.GetNumerator(), nVal
);
583 else if (rDataValue
.Name
== "AntiAliasing")
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
)
608 SdrPage
* pPage
= mpUnoPage
->GetSdrPage();
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() );
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
;
629 // export complete page?
632 if( rSettings
.mbExportOnlyBackground
)
634 const SdrPageProperties
* pCorrectProperties
= pPage
->getCorrectSdrPageProperties();
636 if(pCorrectProperties
)
638 pTempBackgroundShape
= new SdrRectObj(
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
);
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
)
657 if ( rSettings
.mnWidth
> 0 && rSettings
.mnHeight
> 0 )
659 nWidthPix
= rSettings
.mnWidth
;
660 nHeightPix
= rSettings
.mnHeight
;
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
;
670 nWidthPix
= aSizePix
.Width();
671 if (aSizePix
.Height() > MAX_EXT_PIX
)
672 nHeightPix
= MAX_EXT_PIX
;
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
);
682 nWidthPix
= static_cast<long>(aSizePix
.Width() / fHeightDif
);
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
));
699 xLocalView
.reset(new SdrView(*mpDoc
, aVDev
));
702 ScopedVclPtr
<VirtualDevice
> pVDev(CreatePageVDev( pPage
, nWidthPix
, nHeightPix
));
706 aGraphic
= pVDev
->GetBitmapEx( Point(), pVDev
->GetOutputSize() );
707 aGraphic
.SetPrefMapMode( aMap
);
708 aGraphic
.SetPrefSize( aSize
);
711 // create a metafile to export a vector format
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
);
724 std::unique_ptr
< SdrView
> pView
;
726 if (FmFormModel
*pFormModel
= dynamic_cast<FmFormModel
*>(mpDoc
))
728 pView
.reset(new FmFormView(*pFormModel
, aVDev
));
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
);
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
);
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
)
781 aGraphic
= GetBitmapFromMetaFile( aGraphic
.GetGDIMetaFile(), false, CalcSize( rSettings
.mnWidth
, rSettings
.mnHeight
, aNewSize
, aOutSize
) );
787 // export only single shape or shape collection
790 // build list of SdrObject
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
);
801 aShapes
.push_back( pObj
);
807 SdrObject
* pObj
= GetSdrObjectFromXShape( mxShape
);
809 aShapes
.push_back( pObj
);
812 if( aShapes
.empty() )
816 if( bRet
&& !aShapes
.empty() )
818 // special treatment for only one SdrGrafObj that has text
819 bool bSingleGraphic
= false;
821 if( 1 == aShapes
.size() )
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
);
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
865 tools::Rectangle aTextRect
;
867 if( aScrollRectangle
.IsInside( aPaintRectangle
) )
868 aTextRect
= aScrollRectangle
;
870 aTextRect
= aPaintRectangle
;
872 // setup pref size and mapmode
873 pMtf
->SetPrefSize( aTextRect
.GetSize() );
875 // set actual origin (mtf is at actual shape
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())
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
);
927 MapMode
aOutMap( aMap
);
928 aOutMap
.SetOrigin( Point( -aBound
.TopLeft().X(), -aBound
.TopLeft().Y() ) );
929 aOut
->SetRelativeMapMode( aOutMap
);
931 sdr::contact::DisplayInfo aDisplayInfo
;
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);
945 // more effective way to paint a vector of SdrObjects. Hand over the processed page
947 sdr::contact::ObjectContactOfObjListPainter
aMultiObjectPainter(*aOut
, aShapes
, mpCurrentPage
);
948 ImplExportCheckVisisbilityRedirector
aCheckVisibilityRedirector(mpCurrentPage
);
949 aMultiObjectPainter
.SetViewObjectContactRedirector(&aCheckVisibilityRedirector
);
951 aMultiObjectPainter
.ProcessDisplay(aDisplayInfo
);
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
);
967 aGraphic
= GetBitmapFromMetaFile( aMtf
, true, CalcSize( rSettings
.mnWidth
, rSettings
.mnHeight
, aBoundSize
, aOutSize
) );
976 if(pTempBackgroundShape
)
978 SdrObject::Free(pTempBackgroundShape
);
981 rOutl
.SetCalcFieldValueHdl( maOldCalcFieldValueHdl
);
984 rOutl
.SetControlWord(nOldCntrl
);
991 sal_Bool SAL_CALL
GraphicExporter::filter( const Sequence
< PropertyValue
>& aDescriptor
)
993 ::SolarMutexGuard aGuard
;
995 if( maGraphic
.IsNone() && nullptr == mpUnoPage
)
998 if( maGraphic
.IsNone() && ( nullptr == mpUnoPage
->GetSdrPage() || nullptr == mpDoc
) )
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
;
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
);
1069 aOutputStream
.WriteStream( aStream
);
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
) )
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()
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
;
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() )
1126 // get first shape to detect corresponding page and model
1127 mxShapes
->getByIndex(0) >>= mxShape
;
1134 // Step 2: try a shape
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())
1143 uno::Reference
<graphic::XGraphic
> xGraphic(
1144 xPropertySet
->getPropertyValue("Graphic"), uno::UNO_QUERY
);
1148 maGraphic
= Graphic(xGraphic
);
1149 if (!maGraphic
.IsNone())
1155 // get page for this shape
1156 Reference
< XChild
> xChild( mxShape
, UNO_QUERY
);
1160 Reference
< XInterface
> xInt
;
1163 xInt
= xChild
->getParent();
1164 mxPage
.set( xInt
, UNO_QUERY
);
1166 xChild
.set( xInt
, UNO_QUERY
);
1168 while( !mxPage
.is() && xChild
.is() );
1174 // Step 3: check the page
1178 mpUnoPage
= comphelper::getUnoTunnelImplementation
<SvxDrawPage
>( mxPage
);
1180 if( nullptr == mpUnoPage
|| nullptr == mpUnoPage
->GetSdrPage() )
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
1190 SdrPage
* pPage
= mpUnoPage
->GetSdrPage();
1192 Reference
< XShape
> xShape
;
1196 const sal_Int32 nCount
= mxShapes
->getCount();
1198 // test all but the first shape if they have the same page than
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
;
1220 throw IllegalArgumentException();
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
;
1241 sal_Bool SAL_CALL
GraphicExporter::supportsMimeType( const OUString
& rMimeTypeName
)
1243 GraphicFilter
&rFilter
= GraphicFilter::GetGraphicFilter();
1244 sal_uInt16 nCount
= rFilter
.GetExportFormatCount();
1246 for( nFilter
= 0; nFilter
< nCount
; nFilter
++ )
1248 if( rMimeTypeName
== rFilter
.GetExportFormatMediaType( nFilter
) )
1257 Sequence
< OUString
> SAL_CALL
GraphicExporter::getSupportedMimeTypeNames( )
1259 GraphicFilter
&rFilter
= GraphicFilter::GetGraphicFilter();
1260 sal_uInt16 nCount
= rFilter
.GetExportFormatCount();
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
;
1277 if( nFound
< nCount
)
1278 aSeq
.realloc( nFound
);
1285 Graphic
SvxGetGraphicForShape( SdrObject
& rShape
)
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*/ );
1298 OSL_FAIL("SvxGetGraphicForShape(), exception caught!");
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: */