1334 lines
48 KiB
C++
1334 lines
48 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <vector>
|
|
#include <com/sun/star/io/XOutputStream.hpp>
|
|
#include <com/sun/star/beans/XPropertySet.hpp>
|
|
#include <com/sun/star/container/XChild.hpp>
|
|
#include <com/sun/star/lang/XServiceInfo.hpp>
|
|
#include <com/sun/star/lang/XComponent.hpp>
|
|
#include <com/sun/star/drawing/XShape.hpp>
|
|
#include <com/sun/star/drawing/XDrawPage.hpp>
|
|
#include <com/sun/star/drawing/XGraphicExportFilter.hpp>
|
|
#include <com/sun/star/graphic/XGraphic.hpp>
|
|
#include <com/sun/star/graphic/XGraphicRenderer.hpp>
|
|
#include <com/sun/star/task/XStatusIndicator.hpp>
|
|
#include <com/sun/star/task/XInteractionHandler.hpp>
|
|
#include <com/sun/star/task/XInteractionContinuation.hpp>
|
|
#include <com/sun/star/uno/XComponentContext.hpp>
|
|
|
|
#include <boost/property_tree/json_parser/error.hpp>
|
|
#include <tools/debug.hxx>
|
|
#include <comphelper/diagnose_ex.hxx>
|
|
#include <tools/urlobj.hxx>
|
|
#include <comphelper/interaction.hxx>
|
|
#include <framework/interaction.hxx>
|
|
#include <com/sun/star/drawing/GraphicFilterRequest.hpp>
|
|
#include <com/sun/star/util/URL.hpp>
|
|
#include <cppuhelper/implbase.hxx>
|
|
#include <cppuhelper/supportsservice.hxx>
|
|
#include <vcl/metaact.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/virdev.hxx>
|
|
#include <svl/outstrm.hxx>
|
|
#include <sdr/contact/objectcontactofobjlistpainter.hxx>
|
|
#include <svx/sdr/contact/viewobjectcontact.hxx>
|
|
#include <svx/sdr/contact/viewcontact.hxx>
|
|
#include <svx/sdr/contact/displayinfo.hxx>
|
|
#include <editeng/numitem.hxx>
|
|
#include <svx/svdograf.hxx>
|
|
#include <svx/xoutbmp.hxx>
|
|
#include <vcl/graphicfilter.hxx>
|
|
#include <svx/svdpage.hxx>
|
|
#include <svx/svdmodel.hxx>
|
|
#include <svx/fmview.hxx>
|
|
#include <svx/fmmodel.hxx>
|
|
#include <svx/unopage.hxx>
|
|
#include <svx/svdoutl.hxx>
|
|
#include <svx/xlineit0.hxx>
|
|
#include <editeng/flditem.hxx>
|
|
#include <svtools/optionsdrawinglayer.hxx>
|
|
#include <comphelper/sequenceashashmap.hxx>
|
|
#include <comphelper/propertysequence.hxx>
|
|
#include <comphelper/sequence.hxx>
|
|
#include <UnoGraphicExporter.hxx>
|
|
#include <memory>
|
|
// #i102251#
|
|
#include <editeng/editstat.hxx>
|
|
|
|
#define MAX_EXT_PIX 2048
|
|
|
|
using namespace ::comphelper;
|
|
using namespace ::cppu;
|
|
using namespace ::com::sun::star;
|
|
using namespace ::com::sun::star::uno;
|
|
using namespace ::com::sun::star::util;
|
|
using namespace ::com::sun::star::container;
|
|
using namespace ::com::sun::star::drawing;
|
|
using namespace ::com::sun::star::lang;
|
|
using namespace ::com::sun::star::beans;
|
|
using namespace ::com::sun::star::task;
|
|
|
|
namespace {
|
|
|
|
struct ExportSettings
|
|
{
|
|
OUString maFilterName;
|
|
OUString maMediaType;
|
|
URL maURL;
|
|
css::uno::Reference< css::io::XOutputStream > mxOutputStream;
|
|
css::uno::Reference< css::graphic::XGraphicRenderer > mxGraphicRenderer;
|
|
css::uno::Reference< css::task::XStatusIndicator > mxStatusIndicator;
|
|
css::uno::Reference< css::task::XInteractionHandler > mxInteractionHandler;
|
|
|
|
sal_Int32 mnWidth;
|
|
sal_Int32 mnHeight;
|
|
bool mbExportOnlyBackground;
|
|
bool mbScrollText;
|
|
bool mbUseHighContrast;
|
|
bool mbTranslucent;
|
|
|
|
Sequence< PropertyValue > maFilterData;
|
|
|
|
Fraction maScaleX;
|
|
Fraction maScaleY;
|
|
|
|
TriState meAntiAliasing = TRISTATE_INDET;
|
|
|
|
explicit ExportSettings();
|
|
};
|
|
|
|
ExportSettings::ExportSettings()
|
|
: mnWidth( 0 )
|
|
,mnHeight( 0 )
|
|
,mbExportOnlyBackground( false )
|
|
,mbScrollText( false )
|
|
,mbUseHighContrast( false )
|
|
,mbTranslucent( false )
|
|
,maScaleX(1, 1)
|
|
,maScaleY(1, 1)
|
|
{
|
|
}
|
|
|
|
/** implements a component to export shapes or pages to external graphic formats.
|
|
|
|
@implements com.sun.star.drawing.GraphicExportFilter
|
|
*/
|
|
class GraphicExporter : public ::cppu::WeakImplHelper< XGraphicExportFilter, XServiceInfo >
|
|
{
|
|
public:
|
|
GraphicExporter();
|
|
|
|
// XFilter
|
|
virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& aDescriptor ) override;
|
|
virtual void SAL_CALL cancel( ) override;
|
|
|
|
// XExporter
|
|
virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) override;
|
|
|
|
// XServiceInfo
|
|
virtual OUString SAL_CALL getImplementationName( ) override;
|
|
virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
|
|
virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
|
|
|
|
// XMimeTypeInfo
|
|
virtual sal_Bool SAL_CALL supportsMimeType( const OUString& MimeTypeName ) override;
|
|
virtual Sequence< OUString > SAL_CALL getSupportedMimeTypeNames( ) override;
|
|
|
|
VclPtr<VirtualDevice> CreatePageVDev( SdrPage* pPage, tools::Long nWidthPixel, tools::Long nHeightPixel ) const;
|
|
|
|
DECL_LINK( CalcFieldValueHdl, EditFieldInfo*, void );
|
|
|
|
void ParseSettings( const Sequence< PropertyValue >& aDescriptor, ExportSettings& rSettings );
|
|
bool GetGraphic( ExportSettings const & rSettings, Graphic& aGraphic, bool bVectorType );
|
|
|
|
private:
|
|
Reference< XShape > mxShape;
|
|
Reference< XDrawPage > mxPage;
|
|
Reference< XShapes > mxShapes;
|
|
Graphic maGraphic;
|
|
|
|
SvxDrawPage* mpUnoPage;
|
|
|
|
Link<EditFieldInfo*,void> maOldCalcFieldValueHdl;
|
|
sal_Int32 mnPageNumber;
|
|
SdrPage* mpCurrentPage;
|
|
SdrModel* mpDoc;
|
|
};
|
|
|
|
Size* CalcSize( sal_Int32 nWidth, sal_Int32 nHeight, const Size& aBoundSize, Size& aOutSize )
|
|
{
|
|
if( (nWidth == 0) && (nHeight == 0) )
|
|
return nullptr;
|
|
|
|
if( (nWidth == 0) && (nHeight != 0) && (aBoundSize.Height() != 0) )
|
|
{
|
|
nWidth = ( nHeight * aBoundSize.Width() ) / aBoundSize.Height();
|
|
}
|
|
else if( (nWidth != 0) && (nHeight == 0) && (aBoundSize.Width() != 0) )
|
|
{
|
|
nHeight = ( nWidth * aBoundSize.Height() ) / aBoundSize.Width();
|
|
}
|
|
|
|
aOutSize.setWidth( nWidth );
|
|
aOutSize.setHeight( nHeight );
|
|
|
|
return &aOutSize;
|
|
}
|
|
|
|
class ImplExportCheckVisisbilityRedirector : public sdr::contact::ViewObjectContactRedirector
|
|
{
|
|
public:
|
|
explicit ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage );
|
|
|
|
virtual void createRedirectedPrimitive2DSequence(
|
|
const sdr::contact::ViewObjectContact& rOriginal,
|
|
const sdr::contact::DisplayInfo& rDisplayInfo,
|
|
drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) override;
|
|
|
|
private:
|
|
SdrPage* mpCurrentPage;
|
|
};
|
|
|
|
ImplExportCheckVisisbilityRedirector::ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage )
|
|
: mpCurrentPage( pCurrentPage )
|
|
{
|
|
}
|
|
|
|
void ImplExportCheckVisisbilityRedirector::createRedirectedPrimitive2DSequence(
|
|
const sdr::contact::ViewObjectContact& rOriginal,
|
|
const sdr::contact::DisplayInfo& rDisplayInfo,
|
|
drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor)
|
|
{
|
|
SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject();
|
|
|
|
if(pObject)
|
|
{
|
|
SdrPage* pPage = mpCurrentPage;
|
|
|
|
if(nullptr == pPage)
|
|
{
|
|
pPage = pObject->getSdrPageFromSdrObject();
|
|
}
|
|
|
|
if( (pPage == nullptr) || pPage->checkVisibility(rOriginal, rDisplayInfo, false) )
|
|
{
|
|
return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo, rVisitor);
|
|
}
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// not an object, maybe a page
|
|
sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo, rVisitor);
|
|
}
|
|
}
|
|
|
|
GraphicExporter::GraphicExporter()
|
|
: mpUnoPage( nullptr ), mnPageNumber(-1), mpCurrentPage(nullptr), mpDoc( nullptr )
|
|
{
|
|
}
|
|
|
|
IMPL_LINK(GraphicExporter, CalcFieldValueHdl, EditFieldInfo*, pInfo, void)
|
|
{
|
|
if( pInfo )
|
|
{
|
|
if( mpCurrentPage )
|
|
{
|
|
pInfo->SetSdrPage( mpCurrentPage );
|
|
}
|
|
else if( mnPageNumber != -1 )
|
|
{
|
|
const SvxFieldData* pField = pInfo->GetField().GetField();
|
|
if( dynamic_cast<const SvxPageField*>( pField) )
|
|
{
|
|
OUString aPageNumValue;
|
|
bool bUpper = false;
|
|
|
|
switch(mpDoc->GetPageNumType())
|
|
{
|
|
case css::style::NumberingType::CHARS_UPPER_LETTER:
|
|
aPageNumValue += OUStringChar( sal_Unicode((mnPageNumber - 1) % 26 + 'A') );
|
|
break;
|
|
case css::style::NumberingType::CHARS_LOWER_LETTER:
|
|
aPageNumValue += OUStringChar( sal_Unicode((mnPageNumber - 1) % 26 + 'a') );
|
|
break;
|
|
case css::style::NumberingType::ROMAN_UPPER:
|
|
bUpper = true;
|
|
[[fallthrough]];
|
|
case css::style::NumberingType::ROMAN_LOWER:
|
|
aPageNumValue += SvxNumberFormat::CreateRomanString(mnPageNumber, bUpper);
|
|
break;
|
|
case css::style::NumberingType::NUMBER_NONE:
|
|
aPageNumValue = " ";
|
|
break;
|
|
default:
|
|
aPageNumValue += OUString::number( mnPageNumber );
|
|
}
|
|
|
|
pInfo->SetRepresentation( aPageNumValue );
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
maOldCalcFieldValueHdl.Call( pInfo );
|
|
|
|
if( pInfo && mpCurrentPage )
|
|
pInfo->SetSdrPage( nullptr );
|
|
}
|
|
|
|
/** creates a virtual device for the given page
|
|
|
|
@return the returned VirtualDevice is owned by the caller
|
|
*/
|
|
VclPtr<VirtualDevice> GraphicExporter::CreatePageVDev( SdrPage* pPage, tools::Long nWidthPixel, tools::Long nHeightPixel ) const
|
|
{
|
|
VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create();
|
|
MapMode aMM( MapUnit::Map100thMM );
|
|
|
|
Point aPoint( 0, 0 );
|
|
Size aPageSize(pPage->GetSize());
|
|
|
|
// use scaling?
|
|
if( nWidthPixel != 0 )
|
|
{
|
|
const Fraction aFrac( nWidthPixel, pVDev->LogicToPixel( aPageSize, aMM ).Width() );
|
|
|
|
aMM.SetScaleX( aFrac );
|
|
|
|
if( nHeightPixel == 0 )
|
|
aMM.SetScaleY( aFrac );
|
|
}
|
|
|
|
if( nHeightPixel != 0 )
|
|
{
|
|
const Fraction aFrac( nHeightPixel, pVDev->LogicToPixel( aPageSize, aMM ).Height() );
|
|
|
|
if( nWidthPixel == 0 )
|
|
aMM.SetScaleX( aFrac );
|
|
|
|
aMM.SetScaleY( aFrac );
|
|
}
|
|
|
|
pVDev->SetMapMode( aMM );
|
|
bool bSuccess(false);
|
|
|
|
// #i122820# If available, use pixel size directly
|
|
if(nWidthPixel && nHeightPixel)
|
|
{
|
|
bSuccess = pVDev->SetOutputSizePixel(Size(nWidthPixel, nHeightPixel));
|
|
}
|
|
else
|
|
{
|
|
bSuccess = pVDev->SetOutputSize(aPageSize);
|
|
}
|
|
|
|
if(bSuccess)
|
|
{
|
|
SdrView aView(*mpDoc, pVDev);
|
|
|
|
aView.SetPageVisible( false );
|
|
aView.SetBordVisible( false );
|
|
aView.SetGridVisible( false );
|
|
aView.SetHlplVisible( false );
|
|
aView.SetGlueVisible( false );
|
|
aView.ShowSdrPage(pPage);
|
|
|
|
vcl::Region aRegion (tools::Rectangle( aPoint, aPageSize ) );
|
|
|
|
ImplExportCheckVisisbilityRedirector aRedirector( mpCurrentPage );
|
|
|
|
aView.CompleteRedraw(pVDev, aRegion, &aRedirector);
|
|
}
|
|
else
|
|
{
|
|
OSL_ENSURE(false, "Could not get a VirtualDevice of requested size (!)");
|
|
}
|
|
|
|
return pVDev;
|
|
}
|
|
|
|
void GraphicExporter::ParseSettings(const Sequence<PropertyValue>& rDescriptor,
|
|
ExportSettings& rSettings)
|
|
{
|
|
Sequence<PropertyValue> aDescriptor = rDescriptor;
|
|
if (aDescriptor.hasElements())
|
|
{
|
|
comphelper::SequenceAsHashMap aMap(aDescriptor);
|
|
Sequence<PropertyValue> aFilterData;
|
|
OUString aFilterOptions;
|
|
auto it = aMap.find(u"FilterData"_ustr);
|
|
if (it != aMap.end())
|
|
{
|
|
it->second >>= aFilterData;
|
|
}
|
|
it = aMap.find(u"FilterOptions"_ustr);
|
|
if (it != aMap.end())
|
|
{
|
|
it->second >>= aFilterOptions;
|
|
}
|
|
if (!aFilterData.hasElements() && !aFilterOptions.isEmpty())
|
|
{
|
|
// Allow setting filter data keys from the cmdline.
|
|
try
|
|
{
|
|
std::vector<PropertyValue> aData
|
|
= comphelper::JsonToPropertyValues(aFilterOptions.toUtf8());
|
|
aFilterData = comphelper::containerToSequence(aData);
|
|
}
|
|
catch (const boost::property_tree::json_parser::json_parser_error&)
|
|
{
|
|
// This wasn't a valid json; maybe came from import filter (tdf#162528)
|
|
}
|
|
if (aFilterData.hasElements())
|
|
{
|
|
aMap[u"FilterData"_ustr] <<= aFilterData;
|
|
aDescriptor = aMap.getAsConstPropertyValueList();
|
|
}
|
|
}
|
|
}
|
|
|
|
for( const PropertyValue& rValue : aDescriptor )
|
|
{
|
|
if ( rValue.Name == "FilterName" )
|
|
{
|
|
rValue.Value >>= rSettings.maFilterName;
|
|
}
|
|
else if ( rValue.Name == "MediaType" )
|
|
{
|
|
rValue.Value >>= rSettings.maMediaType;
|
|
}
|
|
else if ( rValue.Name == "URL" )
|
|
{
|
|
if( !( rValue.Value >>= rSettings.maURL ) )
|
|
{
|
|
rValue.Value >>= rSettings.maURL.Complete;
|
|
}
|
|
}
|
|
else if ( rValue.Name == "OutputStream" )
|
|
{
|
|
rValue.Value >>= rSettings.mxOutputStream;
|
|
}
|
|
else if ( rValue.Name == "GraphicRenderer" )
|
|
{
|
|
rValue.Value >>= rSettings.mxGraphicRenderer;
|
|
}
|
|
else if ( rValue.Name == "StatusIndicator" )
|
|
{
|
|
rValue.Value >>= rSettings.mxStatusIndicator;
|
|
}
|
|
else if ( rValue.Name == "InteractionHandler" )
|
|
{
|
|
rValue.Value >>= rSettings.mxInteractionHandler;
|
|
}
|
|
else if( rValue.Name == "Width" ) // for compatibility reasons, deprecated
|
|
{
|
|
rValue.Value >>= rSettings.mnWidth;
|
|
}
|
|
else if( rValue.Name == "Height" ) // for compatibility reasons, deprecated
|
|
{
|
|
rValue.Value >>= rSettings.mnHeight;
|
|
}
|
|
else if( rValue.Name == "ExportOnlyBackground" ) // for compatibility reasons, deprecated
|
|
{
|
|
rValue.Value >>= rSettings.mbExportOnlyBackground;
|
|
}
|
|
else if ( rValue.Name == "FilterData" )
|
|
{
|
|
rValue.Value >>= rSettings.maFilterData;
|
|
|
|
for( PropertyValue& rDataValue : asNonConstRange(rSettings.maFilterData) )
|
|
{
|
|
if ( rDataValue.Name == "Translucent" )
|
|
{
|
|
if ( !( rDataValue.Value >>= rSettings.mbTranslucent ) ) // SJ: TODO: The GIF Transparency is stored as int32 in
|
|
{ // configuration files, this has to be changed to boolean
|
|
sal_Int32 nTranslucent = 0;
|
|
if ( rDataValue.Value >>= nTranslucent )
|
|
rSettings.mbTranslucent = nTranslucent != 0;
|
|
}
|
|
}
|
|
else if ( rDataValue.Name == "PixelWidth" )
|
|
{
|
|
rDataValue.Value >>= rSettings.mnWidth;
|
|
}
|
|
else if ( rDataValue.Name == "PixelHeight" )
|
|
{
|
|
rDataValue.Value >>= rSettings.mnHeight;
|
|
}
|
|
else if( rDataValue.Name == "Width" ) // for compatibility reasons, deprecated
|
|
{
|
|
rDataValue.Value >>= rSettings.mnWidth;
|
|
rDataValue.Name = "PixelWidth";
|
|
}
|
|
else if( rDataValue.Name == "Height" ) // for compatibility reasons, deprecated
|
|
{
|
|
rDataValue.Value >>= rSettings.mnHeight;
|
|
rDataValue.Name = "PixelHeight";
|
|
}
|
|
else if ( rDataValue.Name == "ExportOnlyBackground" )
|
|
{
|
|
rDataValue.Value >>= rSettings.mbExportOnlyBackground;
|
|
}
|
|
else if ( rDataValue.Name == "HighContrast" )
|
|
{
|
|
rDataValue.Value >>= rSettings.mbUseHighContrast;
|
|
}
|
|
else if ( rDataValue.Name == "PageNumber" )
|
|
{
|
|
rDataValue.Value >>= mnPageNumber;
|
|
}
|
|
else if ( rDataValue.Name == "ScrollText" )
|
|
{
|
|
// #110496# Read flag solitary scroll text metafile
|
|
rDataValue.Value >>= rSettings.mbScrollText;
|
|
}
|
|
else if ( rDataValue.Name == "CurrentPage" )
|
|
{
|
|
Reference< XDrawPage > xPage;
|
|
rDataValue.Value >>= xPage;
|
|
if( xPage.is() )
|
|
{
|
|
SvxDrawPage* pUnoPage = comphelper::getFromUnoTunnel<SvxDrawPage>( xPage );
|
|
if( pUnoPage && pUnoPage->GetSdrPage() )
|
|
mpCurrentPage = pUnoPage->GetSdrPage();
|
|
}
|
|
}
|
|
else if ( rDataValue.Name == "ScaleXNumerator" )
|
|
{
|
|
sal_Int32 nVal = 1;
|
|
if( rDataValue.Value >>= nVal )
|
|
rSettings.maScaleX = Fraction( nVal, rSettings.maScaleX.GetDenominator() );
|
|
}
|
|
else if ( rDataValue.Name == "ScaleXDenominator" )
|
|
{
|
|
sal_Int32 nVal = 1;
|
|
if( rDataValue.Value >>= nVal )
|
|
rSettings.maScaleX = Fraction( rSettings.maScaleX.GetNumerator(), nVal );
|
|
}
|
|
else if ( rDataValue.Name == "ScaleYNumerator" )
|
|
{
|
|
sal_Int32 nVal = 1;
|
|
if( rDataValue.Value >>= nVal )
|
|
rSettings.maScaleY = Fraction( nVal, rSettings.maScaleY.GetDenominator() );
|
|
}
|
|
else if ( rDataValue.Name == "ScaleYDenominator" )
|
|
{
|
|
sal_Int32 nVal = 1;
|
|
if( rDataValue.Value >>= nVal )
|
|
rSettings.maScaleY = Fraction( rSettings.maScaleY.GetNumerator(), nVal );
|
|
}
|
|
else if (rDataValue.Name == "AntiAliasing")
|
|
{
|
|
bool bAntiAliasing;
|
|
if (rDataValue.Value >>= bAntiAliasing)
|
|
rSettings.meAntiAliasing = bAntiAliasing ? TRISTATE_TRUE : TRISTATE_FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// putting the StatusIndicator that we got from the MediaDescriptor into our local FilterData copy
|
|
if ( rSettings.mxStatusIndicator.is() )
|
|
{
|
|
int i = rSettings.maFilterData.getLength();
|
|
rSettings.maFilterData.realloc( i + 1 );
|
|
auto pFilterData = rSettings.maFilterData.getArray();
|
|
pFilterData[ i ].Name = "StatusIndicator";
|
|
pFilterData[ i ].Value <<= rSettings.mxStatusIndicator;
|
|
}
|
|
}
|
|
|
|
bool GraphicExporter::GetGraphic( ExportSettings const & rSettings, Graphic& aGraphic, bool bVectorType )
|
|
{
|
|
if( !mpDoc || !mpUnoPage )
|
|
return false;
|
|
|
|
SdrPage* pPage = mpUnoPage->GetSdrPage();
|
|
if( !pPage )
|
|
return false;
|
|
|
|
ScopedVclPtrInstance< VirtualDevice > aVDev;
|
|
const MapMode aMap( mpDoc->GetScaleUnit(), Point(), rSettings.maScaleX, rSettings.maScaleY );
|
|
|
|
SdrOutliner& rOutl=mpDoc->GetDrawOutliner();
|
|
maOldCalcFieldValueHdl = rOutl.GetCalcFieldValueHdl();
|
|
rOutl.SetCalcFieldValueHdl( LINK(this, GraphicExporter, CalcFieldValueHdl) );
|
|
::Color aOldBackColor(rOutl.GetBackgroundColor());
|
|
rOutl.SetBackgroundColor(pPage->GetPageBackgroundColor());
|
|
|
|
// #i102251#
|
|
const EEControlBits nOldCntrl(rOutl.GetControlWord());
|
|
EEControlBits nCntrl = nOldCntrl & ~EEControlBits::ONLINESPELLING;
|
|
rOutl.SetControlWord(nCntrl);
|
|
|
|
rtl::Reference<SdrObject> pTempBackgroundShape;
|
|
std::vector< SdrObject* > aShapes;
|
|
bool bRet = true;
|
|
|
|
// export complete page?
|
|
if ( !mxShape.is() )
|
|
{
|
|
if( rSettings.mbExportOnlyBackground )
|
|
{
|
|
const SdrPageProperties* pCorrectProperties = pPage->getCorrectSdrPageProperties();
|
|
|
|
if(pCorrectProperties)
|
|
{
|
|
pTempBackgroundShape = new SdrRectObj(
|
|
*mpDoc,
|
|
tools::Rectangle(Point(0,0), pPage->GetSize()));
|
|
pTempBackgroundShape->SetMergedItemSet(pCorrectProperties->GetItemSet());
|
|
pTempBackgroundShape->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
|
|
pTempBackgroundShape->NbcSetStyleSheet(pCorrectProperties->GetStyleSheet(), true);
|
|
aShapes.push_back(pTempBackgroundShape.get());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const Size aSize( pPage->GetSize() );
|
|
|
|
// generate a bitmap to convert it to a pixel format.
|
|
// For gif pictures there can also be a vector format used (bTranslucent)
|
|
if ( !bVectorType && !rSettings.mbTranslucent )
|
|
{
|
|
tools::Long nWidthPix = 0;
|
|
tools::Long nHeightPix = 0;
|
|
if ( rSettings.mnWidth > 0 && rSettings.mnHeight > 0 )
|
|
{
|
|
nWidthPix = rSettings.mnWidth;
|
|
nHeightPix = rSettings.mnHeight;
|
|
}
|
|
else
|
|
{
|
|
const Size aSizePix( Application::GetDefaultDevice()->LogicToPixel( aSize, aMap ) );
|
|
if (aSizePix.Width() > MAX_EXT_PIX || aSizePix.Height() > MAX_EXT_PIX)
|
|
{
|
|
if (aSizePix.Width() > MAX_EXT_PIX)
|
|
nWidthPix = MAX_EXT_PIX;
|
|
else
|
|
nWidthPix = aSizePix.Width();
|
|
if (aSizePix.Height() > MAX_EXT_PIX)
|
|
nHeightPix = MAX_EXT_PIX;
|
|
else
|
|
nHeightPix = aSizePix.Height();
|
|
|
|
double fWidthDif = static_cast<double>(aSizePix.Width()) / nWidthPix;
|
|
double fHeightDif = static_cast<double>(aSizePix.Height()) / nHeightPix;
|
|
|
|
if (fWidthDif > fHeightDif)
|
|
nHeightPix = static_cast<tools::Long>(aSizePix.Height() / fWidthDif);
|
|
else
|
|
nWidthPix = static_cast<tools::Long>(aSizePix.Width() / fHeightDif);
|
|
}
|
|
else
|
|
{
|
|
nWidthPix = aSizePix.Width();
|
|
nHeightPix = aSizePix.Height();
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<SdrView> xLocalView;
|
|
|
|
if (FmFormModel* pFormModel = dynamic_cast<FmFormModel*>(mpDoc))
|
|
{
|
|
xLocalView.reset(new FmFormView(*pFormModel, aVDev));
|
|
}
|
|
else
|
|
{
|
|
xLocalView.reset(new SdrView(*mpDoc, aVDev));
|
|
}
|
|
|
|
ScopedVclPtr<VirtualDevice> pVDev(CreatePageVDev( pPage, nWidthPix, nHeightPix ));
|
|
|
|
if( pVDev )
|
|
{
|
|
aGraphic = pVDev->GetBitmapEx( Point(), pVDev->GetOutputSize() );
|
|
aGraphic.SetPrefMapMode( aMap );
|
|
aGraphic.SetPrefSize( aSize );
|
|
}
|
|
}
|
|
// create a metafile to export a vector format
|
|
else
|
|
{
|
|
GDIMetaFile aMtf;
|
|
|
|
aVDev->SetMapMode( aMap );
|
|
if( rSettings.mbUseHighContrast )
|
|
aVDev->SetDrawMode( aVDev->GetDrawMode() | DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient );
|
|
aVDev->EnableOutput( false );
|
|
aMtf.Record( aVDev );
|
|
Size aNewSize;
|
|
|
|
// create a view
|
|
std::unique_ptr< SdrView > pView;
|
|
|
|
if (FmFormModel *pFormModel = dynamic_cast<FmFormModel*>(mpDoc))
|
|
{
|
|
pView.reset(new FmFormView(*pFormModel, aVDev));
|
|
}
|
|
else
|
|
{
|
|
pView.reset(new SdrView(*mpDoc, aVDev));
|
|
}
|
|
|
|
pView->SetBordVisible( false );
|
|
pView->SetPageVisible( false );
|
|
pView->ShowSdrPage( pPage );
|
|
|
|
// tdf#96922 deactivate EditView PageVisualization, including PageBackground
|
|
// (formerly 'wiese'). Do *not* switch off MasterPageVisualizationAllowed, we
|
|
// want MasterPage content if a whole SdrPage is exported
|
|
pView->SetPageDecorationAllowed(false);
|
|
|
|
const Point aNewOrg( pPage->GetLeftBorder(), pPage->GetUpperBorder() );
|
|
aNewSize = Size( aSize.Width() - pPage->GetLeftBorder() - pPage->GetRightBorder(),
|
|
aSize.Height() - pPage->GetUpperBorder() - pPage->GetLowerBorder() );
|
|
const tools::Rectangle aClipRect( aNewOrg, aNewSize );
|
|
MapMode aVMap( aMap );
|
|
|
|
aVDev->Push();
|
|
aVMap.SetOrigin( Point( -aNewOrg.X(), -aNewOrg.Y() ) );
|
|
aVDev->SetRelativeMapMode( aVMap );
|
|
aVDev->IntersectClipRegion( aClipRect );
|
|
|
|
// Use new StandardCheckVisisbilityRedirector
|
|
ImplExportCheckVisisbilityRedirector aRedirector( mpCurrentPage );
|
|
|
|
pView->CompleteRedraw(aVDev, vcl::Region(tools::Rectangle(aNewOrg, aNewSize)), &aRedirector);
|
|
|
|
aVDev->Pop();
|
|
|
|
aMtf.Stop();
|
|
aMtf.WindStart();
|
|
aMtf.SetPrefMapMode( aMap );
|
|
aMtf.SetPrefSize( aNewSize );
|
|
|
|
// AW: Here the current version was filtering out the MetaActionType::CLIPREGIONs
|
|
// from the metafile. I asked some other developers why this was done, but no
|
|
// one knew a direct reason. Since it's in for long time, it may be an old
|
|
// piece of code. MetaFiles save and load ClipRegions with polygons with preserving
|
|
// the polygons, so a resolution-independent roundtrip is supported. Removed this
|
|
// code since it destroys some MetaFiles where ClipRegions are used. Anyways,
|
|
// just filtering them out is a hack, at least the encapsulated content would need
|
|
// to be clipped geometrically.
|
|
aGraphic = Graphic(aMtf);
|
|
|
|
pView->HideSdrPage();
|
|
|
|
if( rSettings.mbTranslucent )
|
|
{
|
|
Size aOutSize;
|
|
aGraphic = GetBitmapFromMetaFile( aGraphic.GetGDIMetaFile(), CalcSize( rSettings.mnWidth, rSettings.mnHeight, aNewSize, aOutSize ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// export only single shape or shape collection
|
|
else
|
|
{
|
|
// build list of SdrObject
|
|
if( mxShapes.is() )
|
|
{
|
|
Reference< XShape > xShape;
|
|
const sal_Int32 nCount = mxShapes->getCount();
|
|
|
|
for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
|
|
{
|
|
mxShapes->getByIndex( nIndex ) >>= xShape;
|
|
SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xShape);
|
|
if( pObj )
|
|
aShapes.push_back( pObj );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// only one shape
|
|
SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mxShape);
|
|
if( pObj )
|
|
aShapes.push_back( pObj );
|
|
}
|
|
|
|
if( aShapes.empty() )
|
|
bRet = false;
|
|
}
|
|
|
|
if( bRet && !aShapes.empty() )
|
|
{
|
|
// special treatment for only one SdrGrafObj that has text
|
|
bool bSingleGraphic = false;
|
|
|
|
if( 1 == aShapes.size() )
|
|
{
|
|
if( !bVectorType )
|
|
{
|
|
if( auto pGrafObj = dynamic_cast<const SdrGrafObj*>(aShapes.front()) )
|
|
if (pGrafObj->HasText() )
|
|
{
|
|
aGraphic = pGrafObj->GetTransformedGraphic();
|
|
if ( aGraphic.GetType() == GraphicType::Bitmap )
|
|
{
|
|
Size aSizePixel( aGraphic.GetSizePixel() );
|
|
if( rSettings.mnWidth && rSettings.mnHeight &&
|
|
( ( rSettings.mnWidth != aSizePixel.Width() ) ||
|
|
( rSettings.mnHeight != aSizePixel.Height() ) ) )
|
|
{
|
|
BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
|
|
// export: use highest quality
|
|
aBmpEx.Scale( Size( rSettings.mnWidth, rSettings.mnHeight ), BmpScaleFlag::Lanczos );
|
|
aGraphic = aBmpEx;
|
|
}
|
|
|
|
// #118804# only accept for bitmap graphics, else the
|
|
// conversion to bitmap will happen anywhere without size control
|
|
// as evtl. defined in rSettings.mnWidth/mnHeight
|
|
bSingleGraphic = true;
|
|
}
|
|
}
|
|
}
|
|
else if( rSettings.mbScrollText )
|
|
{
|
|
SdrObject* pObj = aShapes.front();
|
|
auto pTextObj = DynCastSdrTextObj( pObj);
|
|
if( pTextObj && pTextObj->HasText() )
|
|
{
|
|
tools::Rectangle aScrollRectangle;
|
|
tools::Rectangle aPaintRectangle;
|
|
|
|
const std::unique_ptr< GDIMetaFile > pMtf(
|
|
pTextObj->GetTextScrollMetaFileAndRectangle(
|
|
aScrollRectangle, aPaintRectangle ) );
|
|
|
|
// take the larger one of the two rectangles (that
|
|
// should be the bound rect of the retrieved
|
|
// metafile)
|
|
tools::Rectangle aTextRect;
|
|
|
|
if( aScrollRectangle.Contains( aPaintRectangle ) )
|
|
aTextRect = aScrollRectangle;
|
|
else
|
|
aTextRect = aPaintRectangle;
|
|
|
|
// setup pref size and mapmode
|
|
pMtf->SetPrefSize( aTextRect.GetSize() );
|
|
|
|
// set actual origin (mtf is at actual shape
|
|
// output position)
|
|
MapMode aLocalMapMode( aMap );
|
|
aLocalMapMode.SetOrigin(
|
|
Point( -aPaintRectangle.Left(),
|
|
-aPaintRectangle.Top() ) );
|
|
pMtf->SetPrefMapMode( aLocalMapMode );
|
|
|
|
pMtf->AddAction( new MetaCommentAction(
|
|
"XTEXT_SCROLLRECT"_ostr, 0,
|
|
reinterpret_cast<sal_uInt8 const*>(&aScrollRectangle),
|
|
sizeof( tools::Rectangle ) ) );
|
|
pMtf->AddAction( new MetaCommentAction(
|
|
"XTEXT_PAINTRECT"_ostr, 0,
|
|
reinterpret_cast<sal_uInt8 const*>(&aPaintRectangle),
|
|
sizeof( tools::Rectangle ) ) );
|
|
|
|
aGraphic = Graphic( *pMtf );
|
|
|
|
bSingleGraphic = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !bSingleGraphic )
|
|
{
|
|
// create a metafile for all shapes
|
|
ScopedVclPtrInstance< VirtualDevice > aOut;
|
|
|
|
// calculate bound rect for all shapes
|
|
// tdf#126319 I did not convert all rendering to primitives,
|
|
// that would be too much for this fix. But I did so for the
|
|
// range calculation to get a valid high quality range.
|
|
// Based on that the conversion is reliable. With the BoundRect
|
|
// fetched from the Metafile it was just not possible to get the
|
|
// examples from the task handled in a way to fit all cases -
|
|
// due to bad-quality range data from it.
|
|
basegfx::B2DRange aBound;
|
|
const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
|
|
|
|
{
|
|
for( SdrObject* pObj : aShapes )
|
|
{
|
|
drawinglayer::primitive2d::Primitive2DContainer aSequence;
|
|
pObj->GetViewContact().getViewIndependentPrimitive2DContainer(aSequence);
|
|
aBound.expand(aSequence.getB2DRange(aViewInformation2D));
|
|
}
|
|
}
|
|
|
|
aOut->EnableOutput( false );
|
|
aOut->SetMapMode( aMap );
|
|
if( rSettings.mbUseHighContrast )
|
|
aOut->SetDrawMode( aOut->GetDrawMode() | DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient );
|
|
|
|
GDIMetaFile aMtf;
|
|
aMtf.Clear();
|
|
aMtf.Record( aOut );
|
|
|
|
MapMode aOutMap( aMap );
|
|
const Size aOnePixelInMtf(
|
|
Application::GetDefaultDevice()->PixelToLogic(
|
|
Size(1, 1),
|
|
aMap));
|
|
const Size aHalfPixelInMtf(
|
|
(aOnePixelInMtf.getWidth() + 1) / 2,
|
|
(aOnePixelInMtf.getHeight() + 1) / 2);
|
|
|
|
// tdf#126319 Immediately add needed offset to create metafile,
|
|
// that avoids to do it later by Metafile::Move what would be expensive
|
|
aOutMap.SetOrigin(
|
|
Point(
|
|
basegfx::fround<tools::Long>(-aBound.getMinX() - aHalfPixelInMtf.getWidth()),
|
|
basegfx::fround<tools::Long>(-aBound.getMinY() - aHalfPixelInMtf.getHeight()) ) );
|
|
aOut->SetRelativeMapMode( aOutMap );
|
|
|
|
sdr::contact::DisplayInfo aDisplayInfo;
|
|
|
|
if(mpCurrentPage)
|
|
{
|
|
if(mpCurrentPage->TRG_HasMasterPage() && pPage->IsMasterPage())
|
|
{
|
|
// MasterPage is processed as another page's SubContent
|
|
aDisplayInfo.SetProcessLayers(mpCurrentPage->TRG_GetMasterPageVisibleLayers());
|
|
aDisplayInfo.SetSubContentActive(true);
|
|
}
|
|
}
|
|
|
|
if(!aShapes.empty())
|
|
{
|
|
// more effective way to paint a vector of SdrObjects. Hand over the processed page
|
|
// to have it in the
|
|
ImplExportCheckVisisbilityRedirector aCheckVisibilityRedirector(mpCurrentPage);
|
|
sdr::contact::ObjectContactOfObjListPainter aMultiObjectPainter(*aOut, std::move(aShapes), mpCurrentPage);
|
|
aMultiObjectPainter.SetViewObjectContactRedirector(&aCheckVisibilityRedirector);
|
|
|
|
aMultiObjectPainter.ProcessDisplay(aDisplayInfo);
|
|
}
|
|
|
|
aMtf.Stop();
|
|
aMtf.WindStart();
|
|
|
|
// tdf#126319 Immediately add needed size to target's PrefSize
|
|
// tdf#150102 Checked that in aBound is indeed the size - 1 (probably
|
|
// due to old integer stuff using Size()/Rectangle() and getWidth()/GetWidth()
|
|
// with the old one-less paradigm somewhere), so just correct to the
|
|
// correct size. Be aware that checking of tdf#126319 is needed, but
|
|
// looks good in my tests. Still: Changing the central UNO API Metafile
|
|
// export is always a risky thing, so it will have to show if this will
|
|
// not influence something else.
|
|
const Size aBoundSize(
|
|
basegfx::fround<tools::Long>(aBound.getWidth() + 1),
|
|
basegfx::fround<tools::Long>(aBound.getHeight() + 1));
|
|
aMtf.SetPrefMapMode( aMap );
|
|
aMtf.SetPrefSize( aBoundSize );
|
|
|
|
if( !bVectorType )
|
|
{
|
|
Size aOutSize;
|
|
aGraphic = GetBitmapFromMetaFile( aMtf, CalcSize( rSettings.mnWidth, rSettings.mnHeight, aBoundSize, aOutSize ) );
|
|
}
|
|
else
|
|
{
|
|
aGraphic = aMtf;
|
|
}
|
|
}
|
|
}
|
|
|
|
pTempBackgroundShape.clear();
|
|
|
|
rOutl.SetCalcFieldValueHdl( maOldCalcFieldValueHdl );
|
|
|
|
// #i102251#
|
|
rOutl.SetControlWord(nOldCntrl);
|
|
|
|
rOutl.SetBackgroundColor(aOldBackColor);
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
// XFilter
|
|
sal_Bool SAL_CALL GraphicExporter::filter( const Sequence< PropertyValue >& aDescriptor )
|
|
{
|
|
::SolarMutexGuard aGuard;
|
|
|
|
if( maGraphic.IsNone() && nullptr == mpUnoPage )
|
|
return false;
|
|
|
|
if( maGraphic.IsNone() && ( nullptr == mpUnoPage->GetSdrPage() || nullptr == mpDoc ) )
|
|
return false;
|
|
|
|
GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
|
|
|
|
// get the arguments from the descriptor
|
|
ExportSettings aSettings;
|
|
ParseSettings(aDescriptor, aSettings);
|
|
|
|
const sal_uInt16 nFilter = !aSettings.maMediaType.isEmpty()
|
|
? rFilter.GetExportFormatNumberForMediaType( aSettings.maMediaType )
|
|
: rFilter.GetExportFormatNumberForShortName( aSettings.maFilterName );
|
|
bool bVectorType = !rFilter.IsExportPixelFormat( nFilter );
|
|
|
|
// create the output stuff
|
|
Graphic aGraphic = maGraphic;
|
|
|
|
ErrCode nStatus = ERRCODE_NONE;
|
|
if (maGraphic.IsNone())
|
|
{
|
|
bool bAntiAliasing = SvtOptionsDrawinglayer::IsAntiAliasing();
|
|
AllSettings aAllSettings = Application::GetSettings();
|
|
StyleSettings aStyleSettings = aAllSettings.GetStyleSettings();
|
|
bool bUseFontAAFromSystem = aStyleSettings.GetUseFontAAFromSystem();
|
|
bool bUseSubpixelAA = aStyleSettings.GetUseSubpixelAA();
|
|
aStyleSettings.SetUseSubpixelAA(false);
|
|
if (aSettings.meAntiAliasing != TRISTATE_INDET)
|
|
{
|
|
// This is safe to do globally as we own the solar mutex.
|
|
SvtOptionsDrawinglayer::SetAntiAliasing(aSettings.meAntiAliasing == TRISTATE_TRUE, /*bTemporary*/true);
|
|
// Opt in to have AA affect font rendering as well.
|
|
aStyleSettings.SetUseFontAAFromSystem(false);
|
|
}
|
|
aAllSettings.SetStyleSettings(aStyleSettings);
|
|
Application::SetSettings(aAllSettings, /*bTemporary*/true);
|
|
nStatus = GetGraphic( aSettings, aGraphic, bVectorType ) ? ERRCODE_NONE : ERRCODE_GRFILTER_FILTERERROR;
|
|
if (aSettings.meAntiAliasing != TRISTATE_INDET)
|
|
{
|
|
SvtOptionsDrawinglayer::SetAntiAliasing(bAntiAliasing, /*bTemporary*/true);
|
|
aStyleSettings.SetUseFontAAFromSystem(bUseFontAAFromSystem);
|
|
}
|
|
aStyleSettings.SetUseSubpixelAA(bUseSubpixelAA);
|
|
aAllSettings.SetStyleSettings(aStyleSettings);
|
|
Application::SetSettings(aAllSettings, /*bTemporary*/true);
|
|
}
|
|
|
|
if( nStatus == ERRCODE_NONE )
|
|
{
|
|
// export graphic only if it has a size
|
|
const Size aGraphSize( aGraphic.GetPrefSize() );
|
|
if ( aGraphSize.IsEmpty() )
|
|
{
|
|
nStatus = ERRCODE_GRFILTER_FILTERERROR;
|
|
}
|
|
else
|
|
{
|
|
// now we have a graphic, so export it
|
|
if( aSettings.mxGraphicRenderer.is() )
|
|
{
|
|
// render graphic directly into given renderer
|
|
aSettings.mxGraphicRenderer->render( aGraphic.GetXGraphic() );
|
|
}
|
|
else if( aSettings.mxOutputStream.is() )
|
|
{
|
|
// TODO: Either utilize optional XSeekable functionality for the
|
|
// SvOutputStream, or adapt the graphic filter to not seek anymore.
|
|
SvMemoryStream aStream( 1024, 1024 );
|
|
|
|
nStatus = rFilter.ExportGraphic( aGraphic, u"", aStream, nFilter, &aSettings.maFilterData );
|
|
|
|
// copy temp stream to XOutputStream
|
|
SvOutputStream aOutputStream( aSettings.mxOutputStream );
|
|
aStream.Seek(0);
|
|
aOutputStream.WriteStream( aStream );
|
|
}
|
|
else
|
|
{
|
|
INetURLObject aURLObject( aSettings.maURL.Complete );
|
|
DBG_ASSERT( aURLObject.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
|
|
|
|
nStatus = XOutBitmap::ExportGraphic( aGraphic, aURLObject, rFilter, nFilter, &aSettings.maFilterData );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( aSettings.mxInteractionHandler.is() && ( nStatus != ERRCODE_NONE ) )
|
|
{
|
|
Any aInteraction;
|
|
Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations{
|
|
new ::comphelper::OInteractionApprove()
|
|
};
|
|
|
|
GraphicFilterRequest aErrorCode;
|
|
aErrorCode.ErrCode = sal_uInt32(nStatus);
|
|
aInteraction <<= aErrorCode;
|
|
aSettings.mxInteractionHandler->handle( framework::InteractionRequest::CreateRequest( aInteraction, lContinuations ) );
|
|
}
|
|
return nStatus == ERRCODE_NONE;
|
|
}
|
|
|
|
void SAL_CALL GraphicExporter::cancel()
|
|
{
|
|
}
|
|
|
|
// XExporter
|
|
|
|
/** the source 'document' could be a XDrawPage, a XShape or a generic XShapes */
|
|
void SAL_CALL GraphicExporter::setSourceDocument( const Reference< lang::XComponent >& xComponent )
|
|
{
|
|
::SolarMutexGuard aGuard;
|
|
|
|
mxShapes = nullptr;
|
|
mpUnoPage = nullptr;
|
|
|
|
try
|
|
{
|
|
// any break inside this one loop while will throw an IllegalArgumentException
|
|
do
|
|
{
|
|
mxPage.set( xComponent, UNO_QUERY );
|
|
mxShapes.set( xComponent, UNO_QUERY );
|
|
mxShape.set( xComponent, UNO_QUERY );
|
|
|
|
// Step 1: try a generic XShapes
|
|
if( !mxPage.is() && !mxShape.is() && mxShapes.is() )
|
|
{
|
|
// we do not support empty shape collections
|
|
if( 0 == mxShapes->getCount() )
|
|
break;
|
|
|
|
// get first shape to detect corresponding page and model
|
|
mxShapes->getByIndex(0) >>= mxShape;
|
|
}
|
|
else
|
|
{
|
|
mxShapes = nullptr;
|
|
}
|
|
|
|
// Step 2: try a shape
|
|
if( mxShape.is() )
|
|
{
|
|
if (nullptr == SdrObject::getSdrObjectFromXShape(mxShape))
|
|
{
|
|
// This is not a Draw shape, let's see if it's a Writer one.
|
|
uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
|
|
if (!xPropertySet.is())
|
|
break;
|
|
uno::Reference<graphic::XGraphic> xGraphic(
|
|
xPropertySet->getPropertyValue(u"Graphic"_ustr), uno::UNO_QUERY);
|
|
if (!xGraphic.is())
|
|
break;
|
|
|
|
maGraphic = Graphic(xGraphic);
|
|
if (!maGraphic.IsNone())
|
|
return;
|
|
else
|
|
break;
|
|
}
|
|
|
|
// get page for this shape
|
|
Reference< XChild > xChild( mxShape, UNO_QUERY );
|
|
if( !xChild.is() )
|
|
break;
|
|
|
|
Reference< XInterface > xInt;
|
|
do
|
|
{
|
|
xInt = xChild->getParent();
|
|
mxPage.set( xInt, UNO_QUERY );
|
|
if( !mxPage.is() )
|
|
xChild.set( xInt, UNO_QUERY );
|
|
}
|
|
while( !mxPage.is() && xChild.is() );
|
|
|
|
if( !mxPage.is() )
|
|
break;
|
|
}
|
|
|
|
// Step 3: check the page
|
|
if( !mxPage.is() )
|
|
break;
|
|
|
|
mpUnoPage = comphelper::getFromUnoTunnel<SvxDrawPage>( mxPage );
|
|
|
|
if( nullptr == mpUnoPage || nullptr == mpUnoPage->GetSdrPage() )
|
|
break;
|
|
|
|
mpDoc = &mpUnoPage->GetSdrPage()->getSdrModelFromSdrPage();
|
|
|
|
// Step 4: If we got a generic XShapes test all contained shapes
|
|
// if they belong to the same XDrawPage
|
|
|
|
if( mxShapes.is() )
|
|
{
|
|
SdrPage* pPage = mpUnoPage->GetSdrPage();
|
|
SdrObject* pObj;
|
|
Reference< XShape > xShape;
|
|
|
|
bool bOk = true;
|
|
|
|
const sal_Int32 nCount = mxShapes->getCount();
|
|
|
|
// test all but the first shape if they have the same page than
|
|
// the first shape
|
|
for( sal_Int32 nIndex = 1; bOk && ( nIndex < nCount ); nIndex++ )
|
|
{
|
|
mxShapes->getByIndex( nIndex ) >>= xShape;
|
|
pObj = SdrObject::getSdrObjectFromXShape(xShape);
|
|
bOk = pObj && pObj->getSdrPageFromSdrObject() == pPage;
|
|
}
|
|
|
|
if( !bOk )
|
|
break;
|
|
}
|
|
|
|
// no errors so far
|
|
return;
|
|
}
|
|
while( false );
|
|
}
|
|
catch( Exception& )
|
|
{
|
|
}
|
|
|
|
throw IllegalArgumentException();
|
|
}
|
|
|
|
// XServiceInfo
|
|
OUString SAL_CALL GraphicExporter::getImplementationName( )
|
|
{
|
|
return u"com.sun.star.comp.Draw.GraphicExporter"_ustr;
|
|
}
|
|
|
|
sal_Bool SAL_CALL GraphicExporter::supportsService( const OUString& ServiceName )
|
|
{
|
|
return cppu::supportsService(this, ServiceName);
|
|
}
|
|
|
|
Sequence< OUString > SAL_CALL GraphicExporter::getSupportedServiceNames( )
|
|
{
|
|
Sequence< OUString > aSupportedServiceNames { u"com.sun.star.drawing.GraphicExportFilter"_ustr };
|
|
return aSupportedServiceNames;
|
|
}
|
|
|
|
// XMimeTypeInfo
|
|
sal_Bool SAL_CALL GraphicExporter::supportsMimeType( const OUString& rMimeTypeName )
|
|
{
|
|
GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
|
|
sal_uInt16 nCount = rFilter.GetExportFormatCount();
|
|
sal_uInt16 nFilter;
|
|
for( nFilter = 0; nFilter < nCount; nFilter++ )
|
|
{
|
|
if( rMimeTypeName == rFilter.GetExportFormatMediaType( nFilter ) )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
Sequence< OUString > SAL_CALL GraphicExporter::getSupportedMimeTypeNames( )
|
|
{
|
|
GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
|
|
sal_uInt16 nCount = rFilter.GetExportFormatCount();
|
|
sal_uInt16 nFilter;
|
|
sal_uInt16 nFound = 0;
|
|
|
|
Sequence< OUString > aSeq( nCount );
|
|
OUString* pStr = aSeq.getArray();
|
|
|
|
for( nFilter = 0; nFilter < nCount; nFilter++ )
|
|
{
|
|
OUString aMimeType( rFilter.GetExportFormatMediaType( nFilter ) );
|
|
if( !aMimeType.isEmpty() )
|
|
{
|
|
*pStr++ = aMimeType;
|
|
nFound++;
|
|
}
|
|
}
|
|
|
|
if( nFound < nCount )
|
|
aSeq.realloc( nFound );
|
|
|
|
return aSeq;
|
|
}
|
|
|
|
}
|
|
|
|
/** creates a bitmap that is optionally transparent from a metafile
|
|
*/
|
|
BitmapEx GetBitmapFromMetaFile(const GDIMetaFile& rMtf, const Size* pSize)
|
|
{
|
|
// use new primitive conversion tooling
|
|
basegfx::B2DRange aRange(basegfx::B2DPoint(0.0, 0.0));
|
|
sal_uInt32 nMaximumQuadraticPixels;
|
|
|
|
if (pSize)
|
|
{
|
|
// use 100th mm for primitive bitmap converter tool, input is pixel
|
|
// use a real OutDev to get the correct DPI, the static LogicToLogic assumes 72dpi which is wrong (!)
|
|
const Size aSize100th(
|
|
Application::GetDefaultDevice()->PixelToLogic(*pSize, MapMode(MapUnit::Map100thMM)));
|
|
|
|
aRange.expand(basegfx::B2DPoint(aSize100th.Width(), aSize100th.Height()));
|
|
|
|
// when explicitly pixels are requested from the GraphicExporter, use a *very* high limit
|
|
// of 16gb (4096x4096 pixels)
|
|
nMaximumQuadraticPixels = 4096 * 4096;
|
|
}
|
|
else
|
|
{
|
|
// use 100th mm for primitive bitmap converter tool
|
|
const Size aSize100th(OutputDevice::LogicToLogic(rMtf.GetPrefSize(), rMtf.GetPrefMapMode(),
|
|
MapMode(MapUnit::Map100thMM)));
|
|
|
|
aRange.expand(basegfx::B2DPoint(aSize100th.Width(), aSize100th.Height()));
|
|
|
|
// limit to 2048x2048 pixels, as in ImpGraphic::getBitmap (vcl/source/gdi/impgraph.cxx):
|
|
nMaximumQuadraticPixels = 2048 * 2048;
|
|
}
|
|
|
|
return convertMetafileToBitmapEx(rMtf, aRange, nMaximumQuadraticPixels);
|
|
}
|
|
|
|
Graphic SvxGetGraphicForShape( SdrObject& rShape )
|
|
{
|
|
Graphic aGraphic;
|
|
try
|
|
{
|
|
rtl::Reference< GraphicExporter > xExporter( new GraphicExporter() );
|
|
Reference< XComponent > xComp( rShape.getUnoShape(), UNO_QUERY_THROW );
|
|
xExporter->setSourceDocument( xComp );
|
|
ExportSettings aSettings;
|
|
xExporter->GetGraphic( aSettings, aGraphic, true/*bVector*/ );
|
|
}
|
|
catch( Exception& )
|
|
{
|
|
TOOLS_WARN_EXCEPTION("svx", "");
|
|
}
|
|
return aGraphic;
|
|
}
|
|
|
|
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
|
|
com_sun_star_comp_Draw_GraphicExporter_get_implementation(
|
|
css::uno::XComponentContext *,
|
|
css::uno::Sequence<css::uno::Any> const &)
|
|
{
|
|
return cppu::acquire(new GraphicExporter);
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|