tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / svx / source / unodraw / UnoGraphicExporter.cxx
blobe2b6f7ad029bccca4da118e36880c2044e606412
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vector>
21 #include <com/sun/star/io/XOutputStream.hpp>
22 #include <com/sun/star/beans/XPropertySet.hpp>
23 #include <com/sun/star/container/XChild.hpp>
24 #include <com/sun/star/lang/XServiceInfo.hpp>
25 #include <com/sun/star/lang/XComponent.hpp>
26 #include <com/sun/star/drawing/XShape.hpp>
27 #include <com/sun/star/drawing/XDrawPage.hpp>
28 #include <com/sun/star/drawing/XGraphicExportFilter.hpp>
29 #include <com/sun/star/graphic/XGraphic.hpp>
30 #include <com/sun/star/graphic/XGraphicRenderer.hpp>
31 #include <com/sun/star/task/XStatusIndicator.hpp>
32 #include <com/sun/star/task/XInteractionHandler.hpp>
33 #include <com/sun/star/task/XInteractionContinuation.hpp>
34 #include <com/sun/star/uno/XComponentContext.hpp>
36 #include <boost/property_tree/json_parser/error.hpp>
37 #include <tools/debug.hxx>
38 #include <comphelper/diagnose_ex.hxx>
39 #include <tools/urlobj.hxx>
40 #include <comphelper/interaction.hxx>
41 #include <framework/interaction.hxx>
42 #include <com/sun/star/drawing/GraphicFilterRequest.hpp>
43 #include <com/sun/star/util/URL.hpp>
44 #include <cppuhelper/implbase.hxx>
45 #include <cppuhelper/supportsservice.hxx>
46 #include <vcl/metaact.hxx>
47 #include <vcl/svapp.hxx>
48 #include <vcl/virdev.hxx>
49 #include <svl/outstrm.hxx>
50 #include <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 <editeng/numitem.hxx>
55 #include <svx/svdograf.hxx>
56 #include <svx/xoutbmp.hxx>
57 #include <vcl/graphicfilter.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 <svtools/optionsdrawinglayer.hxx>
67 #include <comphelper/sequenceashashmap.hxx>
68 #include <comphelper/propertysequence.hxx>
69 #include <comphelper/sequence.hxx>
70 #include <UnoGraphicExporter.hxx>
71 #include <memory>
72 // #i102251#
73 #include <editeng/editstat.hxx>
75 #define MAX_EXT_PIX 2048
77 using namespace ::comphelper;
78 using namespace ::cppu;
79 using namespace ::com::sun::star;
80 using namespace ::com::sun::star::uno;
81 using namespace ::com::sun::star::util;
82 using namespace ::com::sun::star::container;
83 using namespace ::com::sun::star::drawing;
84 using namespace ::com::sun::star::lang;
85 using namespace ::com::sun::star::beans;
86 using namespace ::com::sun::star::task;
88 namespace {
90 struct ExportSettings
92 OUString maFilterName;
93 OUString maMediaType;
94 URL maURL;
95 css::uno::Reference< css::io::XOutputStream > mxOutputStream;
96 css::uno::Reference< css::graphic::XGraphicRenderer > mxGraphicRenderer;
97 css::uno::Reference< css::task::XStatusIndicator > mxStatusIndicator;
98 css::uno::Reference< css::task::XInteractionHandler > mxInteractionHandler;
100 sal_Int32 mnWidth;
101 sal_Int32 mnHeight;
102 bool mbExportOnlyBackground;
103 bool mbScrollText;
104 bool mbUseHighContrast;
105 bool mbTranslucent;
107 Sequence< PropertyValue > maFilterData;
109 Fraction maScaleX;
110 Fraction maScaleY;
112 TriState meAntiAliasing = TRISTATE_INDET;
114 explicit ExportSettings();
117 ExportSettings::ExportSettings()
118 : mnWidth( 0 )
119 ,mnHeight( 0 )
120 ,mbExportOnlyBackground( false )
121 ,mbScrollText( false )
122 ,mbUseHighContrast( false )
123 ,mbTranslucent( false )
124 ,maScaleX(1, 1)
125 ,maScaleY(1, 1)
129 /** implements a component to export shapes or pages to external graphic formats.
131 @implements com.sun.star.drawing.GraphicExportFilter
133 class GraphicExporter : public ::cppu::WeakImplHelper< XGraphicExportFilter, XServiceInfo >
135 public:
136 GraphicExporter();
138 // XFilter
139 virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& aDescriptor ) override;
140 virtual void SAL_CALL cancel( ) override;
142 // XExporter
143 virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) override;
145 // XServiceInfo
146 virtual OUString SAL_CALL getImplementationName( ) override;
147 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
148 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
150 // XMimeTypeInfo
151 virtual sal_Bool SAL_CALL supportsMimeType( const OUString& MimeTypeName ) override;
152 virtual Sequence< OUString > SAL_CALL getSupportedMimeTypeNames( ) override;
154 VclPtr<VirtualDevice> CreatePageVDev( SdrPage* pPage, tools::Long nWidthPixel, tools::Long nHeightPixel ) const;
156 DECL_LINK( CalcFieldValueHdl, EditFieldInfo*, void );
158 void ParseSettings( const Sequence< PropertyValue >& aDescriptor, ExportSettings& rSettings );
159 bool GetGraphic( ExportSettings const & rSettings, Graphic& aGraphic, bool bVectorType );
161 private:
162 Reference< XShape > mxShape;
163 Reference< XDrawPage > mxPage;
164 Reference< XShapes > mxShapes;
165 Graphic maGraphic;
167 SvxDrawPage* mpUnoPage;
169 Link<EditFieldInfo*,void> maOldCalcFieldValueHdl;
170 sal_Int32 mnPageNumber;
171 SdrPage* mpCurrentPage;
172 SdrModel* mpDoc;
175 Size* CalcSize( sal_Int32 nWidth, sal_Int32 nHeight, const Size& aBoundSize, Size& aOutSize )
177 if( (nWidth == 0) && (nHeight == 0) )
178 return nullptr;
180 if( (nWidth == 0) && (nHeight != 0) && (aBoundSize.Height() != 0) )
182 nWidth = ( nHeight * aBoundSize.Width() ) / aBoundSize.Height();
184 else if( (nWidth != 0) && (nHeight == 0) && (aBoundSize.Width() != 0) )
186 nHeight = ( nWidth * aBoundSize.Height() ) / aBoundSize.Width();
189 aOutSize.setWidth( nWidth );
190 aOutSize.setHeight( nHeight );
192 return &aOutSize;
195 class ImplExportCheckVisisbilityRedirector : public sdr::contact::ViewObjectContactRedirector
197 public:
198 explicit ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage );
200 virtual void createRedirectedPrimitive2DSequence(
201 const sdr::contact::ViewObjectContact& rOriginal,
202 const sdr::contact::DisplayInfo& rDisplayInfo,
203 drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) override;
205 private:
206 SdrPage* mpCurrentPage;
209 ImplExportCheckVisisbilityRedirector::ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage )
210 : mpCurrentPage( pCurrentPage )
214 void ImplExportCheckVisisbilityRedirector::createRedirectedPrimitive2DSequence(
215 const sdr::contact::ViewObjectContact& rOriginal,
216 const sdr::contact::DisplayInfo& rDisplayInfo,
217 drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor)
219 SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject();
221 if(pObject)
223 SdrPage* pPage = mpCurrentPage;
225 if(nullptr == pPage)
227 pPage = pObject->getSdrPageFromSdrObject();
230 if( (pPage == nullptr) || pPage->checkVisibility(rOriginal, rDisplayInfo, false) )
232 return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo, rVisitor);
235 return;
237 else
239 // not an object, maybe a page
240 sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo, rVisitor);
244 GraphicExporter::GraphicExporter()
245 : mpUnoPage( nullptr ), mnPageNumber(-1), mpCurrentPage(nullptr), mpDoc( nullptr )
249 IMPL_LINK(GraphicExporter, CalcFieldValueHdl, EditFieldInfo*, pInfo, void)
251 if( pInfo )
253 if( mpCurrentPage )
255 pInfo->SetSdrPage( mpCurrentPage );
257 else if( mnPageNumber != -1 )
259 const SvxFieldData* pField = pInfo->GetField().GetField();
260 if( dynamic_cast<const SvxPageField*>( pField) )
262 OUString aPageNumValue;
263 bool bUpper = false;
265 switch(mpDoc->GetPageNumType())
267 case css::style::NumberingType::CHARS_UPPER_LETTER:
268 aPageNumValue += OUStringChar( sal_Unicode((mnPageNumber - 1) % 26 + 'A') );
269 break;
270 case css::style::NumberingType::CHARS_LOWER_LETTER:
271 aPageNumValue += OUStringChar( sal_Unicode((mnPageNumber - 1) % 26 + 'a') );
272 break;
273 case css::style::NumberingType::ROMAN_UPPER:
274 bUpper = true;
275 [[fallthrough]];
276 case css::style::NumberingType::ROMAN_LOWER:
277 aPageNumValue += SvxNumberFormat::CreateRomanString(mnPageNumber, bUpper);
278 break;
279 case css::style::NumberingType::NUMBER_NONE:
280 aPageNumValue = " ";
281 break;
282 default:
283 aPageNumValue += OUString::number( mnPageNumber );
286 pInfo->SetRepresentation( aPageNumValue );
288 return;
293 maOldCalcFieldValueHdl.Call( pInfo );
295 if( pInfo && mpCurrentPage )
296 pInfo->SetSdrPage( nullptr );
299 /** creates a virtual device for the given page
301 @return the returned VirtualDevice is owned by the caller
303 VclPtr<VirtualDevice> GraphicExporter::CreatePageVDev( SdrPage* pPage, tools::Long nWidthPixel, tools::Long nHeightPixel ) const
305 VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create();
306 MapMode aMM( MapUnit::Map100thMM );
308 Point aPoint( 0, 0 );
309 Size aPageSize(pPage->GetSize());
311 // use scaling?
312 if( nWidthPixel != 0 )
314 const Fraction aFrac( nWidthPixel, pVDev->LogicToPixel( aPageSize, aMM ).Width() );
316 aMM.SetScaleX( aFrac );
318 if( nHeightPixel == 0 )
319 aMM.SetScaleY( aFrac );
322 if( nHeightPixel != 0 )
324 const Fraction aFrac( nHeightPixel, pVDev->LogicToPixel( aPageSize, aMM ).Height() );
326 if( nWidthPixel == 0 )
327 aMM.SetScaleX( aFrac );
329 aMM.SetScaleY( aFrac );
332 pVDev->SetMapMode( aMM );
333 bool bSuccess(false);
335 // #i122820# If available, use pixel size directly
336 if(nWidthPixel && nHeightPixel)
338 bSuccess = pVDev->SetOutputSizePixel(Size(nWidthPixel, nHeightPixel));
340 else
342 bSuccess = pVDev->SetOutputSize(aPageSize);
345 if(bSuccess)
347 SdrView aView(*mpDoc, pVDev);
349 aView.SetPageVisible( false );
350 aView.SetBordVisible( false );
351 aView.SetGridVisible( false );
352 aView.SetHlplVisible( false );
353 aView.SetGlueVisible( false );
354 aView.ShowSdrPage(pPage);
356 vcl::Region aRegion (tools::Rectangle( aPoint, aPageSize ) );
358 ImplExportCheckVisisbilityRedirector aRedirector( mpCurrentPage );
360 aView.CompleteRedraw(pVDev, aRegion, &aRedirector);
362 else
364 OSL_ENSURE(false, "Could not get a VirtualDevice of requested size (!)");
367 return pVDev;
370 void GraphicExporter::ParseSettings(const Sequence<PropertyValue>& rDescriptor,
371 ExportSettings& rSettings)
373 Sequence<PropertyValue> aDescriptor = rDescriptor;
374 if (aDescriptor.hasElements())
376 comphelper::SequenceAsHashMap aMap(aDescriptor);
377 Sequence<PropertyValue> aFilterData;
378 OUString aFilterOptions;
379 auto it = aMap.find(u"FilterData"_ustr);
380 if (it != aMap.end())
382 it->second >>= aFilterData;
384 it = aMap.find(u"FilterOptions"_ustr);
385 if (it != aMap.end())
387 it->second >>= aFilterOptions;
389 if (!aFilterData.hasElements() && !aFilterOptions.isEmpty())
391 // Allow setting filter data keys from the cmdline.
394 std::vector<PropertyValue> aData
395 = comphelper::JsonToPropertyValues(aFilterOptions.toUtf8());
396 aFilterData = comphelper::containerToSequence(aData);
398 catch (const boost::property_tree::json_parser::json_parser_error&)
400 // This wasn't a valid json; maybe came from import filter (tdf#162528)
402 if (aFilterData.hasElements())
404 aMap[u"FilterData"_ustr] <<= aFilterData;
405 aDescriptor = aMap.getAsConstPropertyValueList();
410 for( const PropertyValue& rValue : aDescriptor )
412 if ( rValue.Name == "FilterName" )
414 rValue.Value >>= rSettings.maFilterName;
416 else if ( rValue.Name == "MediaType" )
418 rValue.Value >>= rSettings.maMediaType;
420 else if ( rValue.Name == "URL" )
422 if( !( rValue.Value >>= rSettings.maURL ) )
424 rValue.Value >>= rSettings.maURL.Complete;
427 else if ( rValue.Name == "OutputStream" )
429 rValue.Value >>= rSettings.mxOutputStream;
431 else if ( rValue.Name == "GraphicRenderer" )
433 rValue.Value >>= rSettings.mxGraphicRenderer;
435 else if ( rValue.Name == "StatusIndicator" )
437 rValue.Value >>= rSettings.mxStatusIndicator;
439 else if ( rValue.Name == "InteractionHandler" )
441 rValue.Value >>= rSettings.mxInteractionHandler;
443 else if( rValue.Name == "Width" ) // for compatibility reasons, deprecated
445 rValue.Value >>= rSettings.mnWidth;
447 else if( rValue.Name == "Height" ) // for compatibility reasons, deprecated
449 rValue.Value >>= rSettings.mnHeight;
451 else if( rValue.Name == "ExportOnlyBackground" ) // for compatibility reasons, deprecated
453 rValue.Value >>= rSettings.mbExportOnlyBackground;
455 else if ( rValue.Name == "FilterData" )
457 rValue.Value >>= rSettings.maFilterData;
459 for( PropertyValue& rDataValue : asNonConstRange(rSettings.maFilterData) )
461 if ( rDataValue.Name == "Translucent" )
463 if ( !( rDataValue.Value >>= rSettings.mbTranslucent ) ) // SJ: TODO: The GIF Transparency is stored as int32 in
464 { // configuration files, this has to be changed to boolean
465 sal_Int32 nTranslucent = 0;
466 if ( rDataValue.Value >>= nTranslucent )
467 rSettings.mbTranslucent = nTranslucent != 0;
470 else if ( rDataValue.Name == "PixelWidth" )
472 rDataValue.Value >>= rSettings.mnWidth;
474 else if ( rDataValue.Name == "PixelHeight" )
476 rDataValue.Value >>= rSettings.mnHeight;
478 else if( rDataValue.Name == "Width" ) // for compatibility reasons, deprecated
480 rDataValue.Value >>= rSettings.mnWidth;
481 rDataValue.Name = "PixelWidth";
483 else if( rDataValue.Name == "Height" ) // for compatibility reasons, deprecated
485 rDataValue.Value >>= rSettings.mnHeight;
486 rDataValue.Name = "PixelHeight";
488 else if ( rDataValue.Name == "ExportOnlyBackground" )
490 rDataValue.Value >>= rSettings.mbExportOnlyBackground;
492 else if ( rDataValue.Name == "HighContrast" )
494 rDataValue.Value >>= rSettings.mbUseHighContrast;
496 else if ( rDataValue.Name == "PageNumber" )
498 rDataValue.Value >>= mnPageNumber;
500 else if ( rDataValue.Name == "ScrollText" )
502 // #110496# Read flag solitary scroll text metafile
503 rDataValue.Value >>= rSettings.mbScrollText;
505 else if ( rDataValue.Name == "CurrentPage" )
507 Reference< XDrawPage > xPage;
508 rDataValue.Value >>= xPage;
509 if( xPage.is() )
511 SvxDrawPage* pUnoPage = comphelper::getFromUnoTunnel<SvxDrawPage>( xPage );
512 if( pUnoPage && pUnoPage->GetSdrPage() )
513 mpCurrentPage = pUnoPage->GetSdrPage();
516 else if ( rDataValue.Name == "ScaleXNumerator" )
518 sal_Int32 nVal = 1;
519 if( rDataValue.Value >>= nVal )
520 rSettings.maScaleX = Fraction( nVal, rSettings.maScaleX.GetDenominator() );
522 else if ( rDataValue.Name == "ScaleXDenominator" )
524 sal_Int32 nVal = 1;
525 if( rDataValue.Value >>= nVal )
526 rSettings.maScaleX = Fraction( rSettings.maScaleX.GetNumerator(), nVal );
528 else if ( rDataValue.Name == "ScaleYNumerator" )
530 sal_Int32 nVal = 1;
531 if( rDataValue.Value >>= nVal )
532 rSettings.maScaleY = Fraction( nVal, rSettings.maScaleY.GetDenominator() );
534 else if ( rDataValue.Name == "ScaleYDenominator" )
536 sal_Int32 nVal = 1;
537 if( rDataValue.Value >>= nVal )
538 rSettings.maScaleY = Fraction( rSettings.maScaleY.GetNumerator(), nVal );
540 else if (rDataValue.Name == "AntiAliasing")
542 bool bAntiAliasing;
543 if (rDataValue.Value >>= bAntiAliasing)
544 rSettings.meAntiAliasing = bAntiAliasing ? TRISTATE_TRUE : TRISTATE_FALSE;
550 // putting the StatusIndicator that we got from the MediaDescriptor into our local FilterData copy
551 if ( rSettings.mxStatusIndicator.is() )
553 int i = rSettings.maFilterData.getLength();
554 rSettings.maFilterData.realloc( i + 1 );
555 auto pFilterData = rSettings.maFilterData.getArray();
556 pFilterData[ i ].Name = "StatusIndicator";
557 pFilterData[ i ].Value <<= rSettings.mxStatusIndicator;
561 bool GraphicExporter::GetGraphic( ExportSettings const & rSettings, Graphic& aGraphic, bool bVectorType )
563 if( !mpDoc || !mpUnoPage )
564 return false;
566 SdrPage* pPage = mpUnoPage->GetSdrPage();
567 if( !pPage )
568 return false;
570 ScopedVclPtrInstance< VirtualDevice > aVDev;
571 const MapMode aMap( mpDoc->GetScaleUnit(), Point(), rSettings.maScaleX, rSettings.maScaleY );
573 SdrOutliner& rOutl=mpDoc->GetDrawOutliner();
574 maOldCalcFieldValueHdl = rOutl.GetCalcFieldValueHdl();
575 rOutl.SetCalcFieldValueHdl( LINK(this, GraphicExporter, CalcFieldValueHdl) );
576 ::Color aOldBackColor(rOutl.GetBackgroundColor());
577 rOutl.SetBackgroundColor(pPage->GetPageBackgroundColor());
579 // #i102251#
580 const EEControlBits nOldCntrl(rOutl.GetControlWord());
581 EEControlBits nCntrl = nOldCntrl & ~EEControlBits::ONLINESPELLING;
582 rOutl.SetControlWord(nCntrl);
584 rtl::Reference<SdrObject> pTempBackgroundShape;
585 std::vector< SdrObject* > aShapes;
586 bool bRet = true;
588 // export complete page?
589 if ( !mxShape.is() )
591 if( rSettings.mbExportOnlyBackground )
593 const SdrPageProperties* pCorrectProperties = pPage->getCorrectSdrPageProperties();
595 if(pCorrectProperties)
597 pTempBackgroundShape = new SdrRectObj(
598 *mpDoc,
599 tools::Rectangle(Point(0,0), pPage->GetSize()));
600 pTempBackgroundShape->SetMergedItemSet(pCorrectProperties->GetItemSet());
601 pTempBackgroundShape->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
602 pTempBackgroundShape->NbcSetStyleSheet(pCorrectProperties->GetStyleSheet(), true);
603 aShapes.push_back(pTempBackgroundShape.get());
606 else
608 const Size aSize( pPage->GetSize() );
610 // generate a bitmap to convert it to a pixel format.
611 // For gif pictures there can also be a vector format used (bTranslucent)
612 if ( !bVectorType && !rSettings.mbTranslucent )
614 tools::Long nWidthPix = 0;
615 tools::Long nHeightPix = 0;
616 if ( rSettings.mnWidth > 0 && rSettings.mnHeight > 0 )
618 nWidthPix = rSettings.mnWidth;
619 nHeightPix = rSettings.mnHeight;
621 else
623 const Size aSizePix( Application::GetDefaultDevice()->LogicToPixel( aSize, aMap ) );
624 if (aSizePix.Width() > MAX_EXT_PIX || aSizePix.Height() > MAX_EXT_PIX)
626 if (aSizePix.Width() > MAX_EXT_PIX)
627 nWidthPix = MAX_EXT_PIX;
628 else
629 nWidthPix = aSizePix.Width();
630 if (aSizePix.Height() > MAX_EXT_PIX)
631 nHeightPix = MAX_EXT_PIX;
632 else
633 nHeightPix = aSizePix.Height();
635 double fWidthDif = static_cast<double>(aSizePix.Width()) / nWidthPix;
636 double fHeightDif = static_cast<double>(aSizePix.Height()) / nHeightPix;
638 if (fWidthDif > fHeightDif)
639 nHeightPix = static_cast<tools::Long>(aSizePix.Height() / fWidthDif);
640 else
641 nWidthPix = static_cast<tools::Long>(aSizePix.Width() / fHeightDif);
643 else
645 nWidthPix = aSizePix.Width();
646 nHeightPix = aSizePix.Height();
650 std::unique_ptr<SdrView> xLocalView;
652 if (FmFormModel* pFormModel = dynamic_cast<FmFormModel*>(mpDoc))
654 xLocalView.reset(new FmFormView(*pFormModel, aVDev));
656 else
658 xLocalView.reset(new SdrView(*mpDoc, aVDev));
661 ScopedVclPtr<VirtualDevice> pVDev(CreatePageVDev( pPage, nWidthPix, nHeightPix ));
663 if( pVDev )
665 aGraphic = pVDev->GetBitmapEx( Point(), pVDev->GetOutputSize() );
666 aGraphic.SetPrefMapMode( aMap );
667 aGraphic.SetPrefSize( aSize );
670 // create a metafile to export a vector format
671 else
673 GDIMetaFile aMtf;
675 aVDev->SetMapMode( aMap );
676 if( rSettings.mbUseHighContrast )
677 aVDev->SetDrawMode( aVDev->GetDrawMode() | DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient );
678 aVDev->EnableOutput( false );
679 aMtf.Record( aVDev );
680 Size aNewSize;
682 // create a view
683 std::unique_ptr< SdrView > pView;
685 if (FmFormModel *pFormModel = dynamic_cast<FmFormModel*>(mpDoc))
687 pView.reset(new FmFormView(*pFormModel, aVDev));
689 else
691 pView.reset(new SdrView(*mpDoc, aVDev));
694 pView->SetBordVisible( false );
695 pView->SetPageVisible( false );
696 pView->ShowSdrPage( pPage );
698 // tdf#96922 deactivate EditView PageVisualization, including PageBackground
699 // (formerly 'wiese'). Do *not* switch off MasterPageVisualizationAllowed, we
700 // want MasterPage content if a whole SdrPage is exported
701 pView->SetPageDecorationAllowed(false);
703 const Point aNewOrg( pPage->GetLeftBorder(), pPage->GetUpperBorder() );
704 aNewSize = Size( aSize.Width() - pPage->GetLeftBorder() - pPage->GetRightBorder(),
705 aSize.Height() - pPage->GetUpperBorder() - pPage->GetLowerBorder() );
706 const tools::Rectangle aClipRect( aNewOrg, aNewSize );
707 MapMode aVMap( aMap );
709 aVDev->Push();
710 aVMap.SetOrigin( Point( -aNewOrg.X(), -aNewOrg.Y() ) );
711 aVDev->SetRelativeMapMode( aVMap );
712 aVDev->IntersectClipRegion( aClipRect );
714 // Use new StandardCheckVisisbilityRedirector
715 ImplExportCheckVisisbilityRedirector aRedirector( mpCurrentPage );
717 pView->CompleteRedraw(aVDev, vcl::Region(tools::Rectangle(aNewOrg, aNewSize)), &aRedirector);
719 aVDev->Pop();
721 aMtf.Stop();
722 aMtf.WindStart();
723 aMtf.SetPrefMapMode( aMap );
724 aMtf.SetPrefSize( aNewSize );
726 // AW: Here the current version was filtering out the MetaActionType::CLIPREGIONs
727 // from the metafile. I asked some other developers why this was done, but no
728 // one knew a direct reason. Since it's in for long time, it may be an old
729 // piece of code. MetaFiles save and load ClipRegions with polygons with preserving
730 // the polygons, so a resolution-independent roundtrip is supported. Removed this
731 // code since it destroys some MetaFiles where ClipRegions are used. Anyways,
732 // just filtering them out is a hack, at least the encapsulated content would need
733 // to be clipped geometrically.
734 aGraphic = Graphic(aMtf);
736 pView->HideSdrPage();
738 if( rSettings.mbTranslucent )
740 Size aOutSize;
741 aGraphic = GetBitmapFromMetaFile( aGraphic.GetGDIMetaFile(), CalcSize( rSettings.mnWidth, rSettings.mnHeight, aNewSize, aOutSize ) );
747 // export only single shape or shape collection
748 else
750 // build list of SdrObject
751 if( mxShapes.is() )
753 Reference< XShape > xShape;
754 const sal_Int32 nCount = mxShapes->getCount();
756 for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
758 mxShapes->getByIndex( nIndex ) >>= xShape;
759 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xShape);
760 if( pObj )
761 aShapes.push_back( pObj );
764 else
766 // only one shape
767 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mxShape);
768 if( pObj )
769 aShapes.push_back( pObj );
772 if( aShapes.empty() )
773 bRet = false;
776 if( bRet && !aShapes.empty() )
778 // special treatment for only one SdrGrafObj that has text
779 bool bSingleGraphic = false;
781 if( 1 == aShapes.size() )
783 if( !bVectorType )
785 if( auto pGrafObj = dynamic_cast<const SdrGrafObj*>(aShapes.front()) )
786 if (pGrafObj->HasText() )
788 aGraphic = pGrafObj->GetTransformedGraphic();
789 if ( aGraphic.GetType() == GraphicType::Bitmap )
791 Size aSizePixel( aGraphic.GetSizePixel() );
792 if( rSettings.mnWidth && rSettings.mnHeight &&
793 ( ( rSettings.mnWidth != aSizePixel.Width() ) ||
794 ( rSettings.mnHeight != aSizePixel.Height() ) ) )
796 BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
797 // export: use highest quality
798 aBmpEx.Scale( Size( rSettings.mnWidth, rSettings.mnHeight ), BmpScaleFlag::Lanczos );
799 aGraphic = aBmpEx;
802 // #118804# only accept for bitmap graphics, else the
803 // conversion to bitmap will happen anywhere without size control
804 // as evtl. defined in rSettings.mnWidth/mnHeight
805 bSingleGraphic = true;
809 else if( rSettings.mbScrollText )
811 SdrObject* pObj = aShapes.front();
812 auto pTextObj = DynCastSdrTextObj( pObj);
813 if( pTextObj && pTextObj->HasText() )
815 tools::Rectangle aScrollRectangle;
816 tools::Rectangle aPaintRectangle;
818 const std::unique_ptr< GDIMetaFile > pMtf(
819 pTextObj->GetTextScrollMetaFileAndRectangle(
820 aScrollRectangle, aPaintRectangle ) );
822 // take the larger one of the two rectangles (that
823 // should be the bound rect of the retrieved
824 // metafile)
825 tools::Rectangle aTextRect;
827 if( aScrollRectangle.Contains( aPaintRectangle ) )
828 aTextRect = aScrollRectangle;
829 else
830 aTextRect = aPaintRectangle;
832 // setup pref size and mapmode
833 pMtf->SetPrefSize( aTextRect.GetSize() );
835 // set actual origin (mtf is at actual shape
836 // output position)
837 MapMode aLocalMapMode( aMap );
838 aLocalMapMode.SetOrigin(
839 Point( -aPaintRectangle.Left(),
840 -aPaintRectangle.Top() ) );
841 pMtf->SetPrefMapMode( aLocalMapMode );
843 pMtf->AddAction( new MetaCommentAction(
844 "XTEXT_SCROLLRECT"_ostr, 0,
845 reinterpret_cast<sal_uInt8 const*>(&aScrollRectangle),
846 sizeof( tools::Rectangle ) ) );
847 pMtf->AddAction( new MetaCommentAction(
848 "XTEXT_PAINTRECT"_ostr, 0,
849 reinterpret_cast<sal_uInt8 const*>(&aPaintRectangle),
850 sizeof( tools::Rectangle ) ) );
852 aGraphic = Graphic( *pMtf );
854 bSingleGraphic = true;
859 if( !bSingleGraphic )
861 // create a metafile for all shapes
862 ScopedVclPtrInstance< VirtualDevice > aOut;
864 // calculate bound rect for all shapes
865 // tdf#126319 I did not convert all rendering to primitives,
866 // that would be too much for this fix. But I did so for the
867 // range calculation to get a valid high quality range.
868 // Based on that the conversion is reliable. With the BoundRect
869 // fetched from the Metafile it was just not possible to get the
870 // examples from the task handled in a way to fit all cases -
871 // due to bad-quality range data from it.
872 basegfx::B2DRange aBound;
873 const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
876 for( SdrObject* pObj : aShapes )
878 drawinglayer::primitive2d::Primitive2DContainer aSequence;
879 pObj->GetViewContact().getViewIndependentPrimitive2DContainer(aSequence);
880 aBound.expand(aSequence.getB2DRange(aViewInformation2D));
884 aOut->EnableOutput( false );
885 aOut->SetMapMode( aMap );
886 if( rSettings.mbUseHighContrast )
887 aOut->SetDrawMode( aOut->GetDrawMode() | DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient );
889 GDIMetaFile aMtf;
890 aMtf.Clear();
891 aMtf.Record( aOut );
893 MapMode aOutMap( aMap );
894 const Size aOnePixelInMtf(
895 Application::GetDefaultDevice()->PixelToLogic(
896 Size(1, 1),
897 aMap));
898 const Size aHalfPixelInMtf(
899 (aOnePixelInMtf.getWidth() + 1) / 2,
900 (aOnePixelInMtf.getHeight() + 1) / 2);
902 // tdf#126319 Immediately add needed offset to create metafile,
903 // that avoids to do it later by Metafile::Move what would be expensive
904 aOutMap.SetOrigin(
905 Point(
906 basegfx::fround<tools::Long>(-aBound.getMinX() - aHalfPixelInMtf.getWidth()),
907 basegfx::fround<tools::Long>(-aBound.getMinY() - aHalfPixelInMtf.getHeight()) ) );
908 aOut->SetRelativeMapMode( aOutMap );
910 sdr::contact::DisplayInfo aDisplayInfo;
912 if(mpCurrentPage)
914 if(mpCurrentPage->TRG_HasMasterPage() && pPage->IsMasterPage())
916 // MasterPage is processed as another page's SubContent
917 aDisplayInfo.SetProcessLayers(mpCurrentPage->TRG_GetMasterPageVisibleLayers());
918 aDisplayInfo.SetSubContentActive(true);
922 if(!aShapes.empty())
924 // more effective way to paint a vector of SdrObjects. Hand over the processed page
925 // to have it in the
926 ImplExportCheckVisisbilityRedirector aCheckVisibilityRedirector(mpCurrentPage);
927 sdr::contact::ObjectContactOfObjListPainter aMultiObjectPainter(*aOut, std::move(aShapes), mpCurrentPage);
928 aMultiObjectPainter.SetViewObjectContactRedirector(&aCheckVisibilityRedirector);
930 aMultiObjectPainter.ProcessDisplay(aDisplayInfo);
933 aMtf.Stop();
934 aMtf.WindStart();
936 // tdf#126319 Immediately add needed size to target's PrefSize
937 // tdf#150102 Checked that in aBound is indeed the size - 1 (probably
938 // due to old integer stuff using Size()/Rectangle() and getWidth()/GetWidth()
939 // with the old one-less paradigm somewhere), so just correct to the
940 // correct size. Be aware that checking of tdf#126319 is needed, but
941 // looks good in my tests. Still: Changing the central UNO API Metafile
942 // export is always a risky thing, so it will have to show if this will
943 // not influence something else.
944 const Size aBoundSize(
945 basegfx::fround<tools::Long>(aBound.getWidth() + 1),
946 basegfx::fround<tools::Long>(aBound.getHeight() + 1));
947 aMtf.SetPrefMapMode( aMap );
948 aMtf.SetPrefSize( aBoundSize );
950 if( !bVectorType )
952 Size aOutSize;
953 aGraphic = GetBitmapFromMetaFile( aMtf, CalcSize( rSettings.mnWidth, rSettings.mnHeight, aBoundSize, aOutSize ) );
955 else
957 aGraphic = aMtf;
962 pTempBackgroundShape.clear();
964 rOutl.SetCalcFieldValueHdl( maOldCalcFieldValueHdl );
966 // #i102251#
967 rOutl.SetControlWord(nOldCntrl);
969 rOutl.SetBackgroundColor(aOldBackColor);
971 return bRet;
975 // XFilter
976 sal_Bool SAL_CALL GraphicExporter::filter( const Sequence< PropertyValue >& aDescriptor )
978 ::SolarMutexGuard aGuard;
980 if( maGraphic.IsNone() && nullptr == mpUnoPage )
981 return false;
983 if( maGraphic.IsNone() && ( nullptr == mpUnoPage->GetSdrPage() || nullptr == mpDoc ) )
984 return false;
986 GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
988 // get the arguments from the descriptor
989 ExportSettings aSettings;
990 ParseSettings(aDescriptor, aSettings);
992 const sal_uInt16 nFilter = !aSettings.maMediaType.isEmpty()
993 ? rFilter.GetExportFormatNumberForMediaType( aSettings.maMediaType )
994 : rFilter.GetExportFormatNumberForShortName( aSettings.maFilterName );
995 bool bVectorType = !rFilter.IsExportPixelFormat( nFilter );
997 // create the output stuff
998 Graphic aGraphic = maGraphic;
1000 ErrCode nStatus = ERRCODE_NONE;
1001 if (maGraphic.IsNone())
1003 bool bAntiAliasing = SvtOptionsDrawinglayer::IsAntiAliasing();
1004 AllSettings aAllSettings = Application::GetSettings();
1005 StyleSettings aStyleSettings = aAllSettings.GetStyleSettings();
1006 bool bUseFontAAFromSystem = aStyleSettings.GetUseFontAAFromSystem();
1007 bool bUseSubpixelAA = aStyleSettings.GetUseSubpixelAA();
1008 aStyleSettings.SetUseSubpixelAA(false);
1009 if (aSettings.meAntiAliasing != TRISTATE_INDET)
1011 // This is safe to do globally as we own the solar mutex.
1012 SvtOptionsDrawinglayer::SetAntiAliasing(aSettings.meAntiAliasing == TRISTATE_TRUE, /*bTemporary*/true);
1013 // Opt in to have AA affect font rendering as well.
1014 aStyleSettings.SetUseFontAAFromSystem(false);
1016 aAllSettings.SetStyleSettings(aStyleSettings);
1017 Application::SetSettings(aAllSettings);
1018 nStatus = GetGraphic( aSettings, aGraphic, bVectorType ) ? ERRCODE_NONE : ERRCODE_GRFILTER_FILTERERROR;
1019 if (aSettings.meAntiAliasing != TRISTATE_INDET)
1021 SvtOptionsDrawinglayer::SetAntiAliasing(bAntiAliasing, /*bTemporary*/true);
1022 aStyleSettings.SetUseFontAAFromSystem(bUseFontAAFromSystem);
1024 aStyleSettings.SetUseSubpixelAA(bUseSubpixelAA);
1025 aAllSettings.SetStyleSettings(aStyleSettings);
1026 Application::SetSettings(aAllSettings);
1029 if( nStatus == ERRCODE_NONE )
1031 // export graphic only if it has a size
1032 const Size aGraphSize( aGraphic.GetPrefSize() );
1033 if ( aGraphSize.IsEmpty() )
1035 nStatus = ERRCODE_GRFILTER_FILTERERROR;
1037 else
1039 // now we have a graphic, so export it
1040 if( aSettings.mxGraphicRenderer.is() )
1042 // render graphic directly into given renderer
1043 aSettings.mxGraphicRenderer->render( aGraphic.GetXGraphic() );
1045 else if( aSettings.mxOutputStream.is() )
1047 // TODO: Either utilize optional XSeekable functionality for the
1048 // SvOutputStream, or adapt the graphic filter to not seek anymore.
1049 SvMemoryStream aStream( 1024, 1024 );
1051 nStatus = rFilter.ExportGraphic( aGraphic, u"", aStream, nFilter, &aSettings.maFilterData );
1053 // copy temp stream to XOutputStream
1054 SvOutputStream aOutputStream( aSettings.mxOutputStream );
1055 aStream.Seek(0);
1056 aOutputStream.WriteStream( aStream );
1058 else
1060 INetURLObject aURLObject( aSettings.maURL.Complete );
1061 DBG_ASSERT( aURLObject.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
1063 nStatus = XOutBitmap::ExportGraphic( aGraphic, aURLObject, rFilter, nFilter, &aSettings.maFilterData );
1068 if ( aSettings.mxInteractionHandler.is() && ( nStatus != ERRCODE_NONE ) )
1070 Any aInteraction;
1071 Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations{
1072 new ::comphelper::OInteractionApprove()
1075 GraphicFilterRequest aErrorCode;
1076 aErrorCode.ErrCode = sal_uInt32(nStatus);
1077 aInteraction <<= aErrorCode;
1078 aSettings.mxInteractionHandler->handle( framework::InteractionRequest::CreateRequest( aInteraction, lContinuations ) );
1080 return nStatus == ERRCODE_NONE;
1083 void SAL_CALL GraphicExporter::cancel()
1087 // XExporter
1089 /** the source 'document' could be a XDrawPage, a XShape or a generic XShapes */
1090 void SAL_CALL GraphicExporter::setSourceDocument( const Reference< lang::XComponent >& xComponent )
1092 ::SolarMutexGuard aGuard;
1094 mxShapes = nullptr;
1095 mpUnoPage = nullptr;
1099 // any break inside this one loop while will throw an IllegalArgumentException
1102 mxPage.set( xComponent, UNO_QUERY );
1103 mxShapes.set( xComponent, UNO_QUERY );
1104 mxShape.set( xComponent, UNO_QUERY );
1106 // Step 1: try a generic XShapes
1107 if( !mxPage.is() && !mxShape.is() && mxShapes.is() )
1109 // we do not support empty shape collections
1110 if( 0 == mxShapes->getCount() )
1111 break;
1113 // get first shape to detect corresponding page and model
1114 mxShapes->getByIndex(0) >>= mxShape;
1116 else
1118 mxShapes = nullptr;
1121 // Step 2: try a shape
1122 if( mxShape.is() )
1124 if (nullptr == SdrObject::getSdrObjectFromXShape(mxShape))
1126 // This is not a Draw shape, let's see if it's a Writer one.
1127 uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
1128 if (!xPropertySet.is())
1129 break;
1130 uno::Reference<graphic::XGraphic> xGraphic(
1131 xPropertySet->getPropertyValue(u"Graphic"_ustr), uno::UNO_QUERY);
1132 if (!xGraphic.is())
1133 break;
1135 maGraphic = Graphic(xGraphic);
1136 if (!maGraphic.IsNone())
1137 return;
1138 else
1139 break;
1142 // get page for this shape
1143 Reference< XChild > xChild( mxShape, UNO_QUERY );
1144 if( !xChild.is() )
1145 break;
1147 Reference< XInterface > xInt;
1150 xInt = xChild->getParent();
1151 mxPage.set( xInt, UNO_QUERY );
1152 if( !mxPage.is() )
1153 xChild.set( xInt, UNO_QUERY );
1155 while( !mxPage.is() && xChild.is() );
1157 if( !mxPage.is() )
1158 break;
1161 // Step 3: check the page
1162 if( !mxPage.is() )
1163 break;
1165 mpUnoPage = comphelper::getFromUnoTunnel<SvxDrawPage>( mxPage );
1167 if( nullptr == mpUnoPage || nullptr == mpUnoPage->GetSdrPage() )
1168 break;
1170 mpDoc = &mpUnoPage->GetSdrPage()->getSdrModelFromSdrPage();
1172 // Step 4: If we got a generic XShapes test all contained shapes
1173 // if they belong to the same XDrawPage
1175 if( mxShapes.is() )
1177 SdrPage* pPage = mpUnoPage->GetSdrPage();
1178 SdrObject* pObj;
1179 Reference< XShape > xShape;
1181 bool bOk = true;
1183 const sal_Int32 nCount = mxShapes->getCount();
1185 // test all but the first shape if they have the same page than
1186 // the first shape
1187 for( sal_Int32 nIndex = 1; bOk && ( nIndex < nCount ); nIndex++ )
1189 mxShapes->getByIndex( nIndex ) >>= xShape;
1190 pObj = SdrObject::getSdrObjectFromXShape(xShape);
1191 bOk = pObj && pObj->getSdrPageFromSdrObject() == pPage;
1194 if( !bOk )
1195 break;
1198 // no errors so far
1199 return;
1201 while( false );
1203 catch( Exception& )
1207 throw IllegalArgumentException();
1210 // XServiceInfo
1211 OUString SAL_CALL GraphicExporter::getImplementationName( )
1213 return u"com.sun.star.comp.Draw.GraphicExporter"_ustr;
1216 sal_Bool SAL_CALL GraphicExporter::supportsService( const OUString& ServiceName )
1218 return cppu::supportsService(this, ServiceName);
1221 Sequence< OUString > SAL_CALL GraphicExporter::getSupportedServiceNames( )
1223 Sequence< OUString > aSupportedServiceNames { u"com.sun.star.drawing.GraphicExportFilter"_ustr };
1224 return aSupportedServiceNames;
1227 // XMimeTypeInfo
1228 sal_Bool SAL_CALL GraphicExporter::supportsMimeType( const OUString& rMimeTypeName )
1230 GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
1231 sal_uInt16 nCount = rFilter.GetExportFormatCount();
1232 sal_uInt16 nFilter;
1233 for( nFilter = 0; nFilter < nCount; nFilter++ )
1235 if( rMimeTypeName == rFilter.GetExportFormatMediaType( nFilter ) )
1237 return true;
1241 return false;
1244 Sequence< OUString > SAL_CALL GraphicExporter::getSupportedMimeTypeNames( )
1246 GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
1247 sal_uInt16 nCount = rFilter.GetExportFormatCount();
1248 sal_uInt16 nFilter;
1249 sal_uInt16 nFound = 0;
1251 Sequence< OUString > aSeq( nCount );
1252 OUString* pStr = aSeq.getArray();
1254 for( nFilter = 0; nFilter < nCount; nFilter++ )
1256 OUString aMimeType( rFilter.GetExportFormatMediaType( nFilter ) );
1257 if( !aMimeType.isEmpty() )
1259 *pStr++ = aMimeType;
1260 nFound++;
1264 if( nFound < nCount )
1265 aSeq.realloc( nFound );
1267 return aSeq;
1272 /** creates a bitmap that is optionally transparent from a metafile
1274 BitmapEx GetBitmapFromMetaFile(const GDIMetaFile& rMtf, const Size* pSize)
1276 // use new primitive conversion tooling
1277 basegfx::B2DRange aRange(basegfx::B2DPoint(0.0, 0.0));
1278 sal_uInt32 nMaximumQuadraticPixels;
1280 if (pSize)
1282 // use 100th mm for primitive bitmap converter tool, input is pixel
1283 // use a real OutDev to get the correct DPI, the static LogicToLogic assumes 72dpi which is wrong (!)
1284 const Size aSize100th(
1285 Application::GetDefaultDevice()->PixelToLogic(*pSize, MapMode(MapUnit::Map100thMM)));
1287 aRange.expand(basegfx::B2DPoint(aSize100th.Width(), aSize100th.Height()));
1289 // when explicitly pixels are requested from the GraphicExporter, use a *very* high limit
1290 // of 16gb (4096x4096 pixels)
1291 nMaximumQuadraticPixels = 4096 * 4096;
1293 else
1295 // use 100th mm for primitive bitmap converter tool
1296 const Size aSize100th(OutputDevice::LogicToLogic(rMtf.GetPrefSize(), rMtf.GetPrefMapMode(),
1297 MapMode(MapUnit::Map100thMM)));
1299 aRange.expand(basegfx::B2DPoint(aSize100th.Width(), aSize100th.Height()));
1301 // limit to 2048x2048 pixels, as in ImpGraphic::getBitmap (vcl/source/gdi/impgraph.cxx):
1302 nMaximumQuadraticPixels = 2048 * 2048;
1305 return convertMetafileToBitmapEx(rMtf, aRange, nMaximumQuadraticPixels);
1308 Graphic SvxGetGraphicForShape( SdrObject& rShape )
1310 Graphic aGraphic;
1313 rtl::Reference< GraphicExporter > xExporter( new GraphicExporter() );
1314 Reference< XComponent > xComp( rShape.getUnoShape(), UNO_QUERY_THROW );
1315 xExporter->setSourceDocument( xComp );
1316 ExportSettings aSettings;
1317 xExporter->GetGraphic( aSettings, aGraphic, true/*bVector*/ );
1319 catch( Exception& )
1321 TOOLS_WARN_EXCEPTION("svx", "");
1323 return aGraphic;
1326 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1327 com_sun_star_comp_Draw_GraphicExporter_get_implementation(
1328 css::uno::XComponentContext *,
1329 css::uno::Sequence<css::uno::Any> const &)
1331 return cppu::acquire(new GraphicExporter);
1334 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */