blob: 65341372b9c92c8a68ff0d65631aad504c14fd87 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"
#include <vector>
#include <vos/mutex.hxx>
#include <com/sun/star/io/XOutputStream.hpp>
#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/document/XFilter.hpp>
#include <com/sun/star/document/XExporter.hpp>
#include <com/sun/star/document/XMimeTypeInfo.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/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 <comphelper/interaction.hxx>
#include <framework/interaction.hxx>
#include <com/sun/star/drawing/GraphicFilterRequest.hpp>
#include <com/sun/star/util/URL.hpp>
#include <cppuhelper/implbase4.hxx>
#include <osl/diagnose.h>
#include <osl/mutex.hxx>
#include <vcl/metaact.hxx>
#include <vcl/svapp.hxx>
#include <vcl/virdev.hxx>
#include <svtools/FilterConfigItem.hxx>
#include <svl/outstrm.hxx>
#include <svx/sdr/contact/objectcontactofobjlistpainter.hxx>
#include <svx/sdr/contact/viewobjectcontact.hxx>
#include <svx/sdr/contact/viewcontact.hxx>
#include <svx/sdr/contact/displayinfo.hxx>
#include <svx/sdr/contact/viewcontactofsdrobj.hxx>
#include <editeng/numitem.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svdograf.hxx>
#include "svx/xoutbmp.hxx"
#include "svtools/filter.hxx"
#include "svx/unoapi.hxx"
#include <svx/svdpage.hxx>
#include <svx/svdmodel.hxx>
#include <svx/fmview.hxx>
#include <svx/fmmodel.hxx>
#include <svx/unopage.hxx>
#include <svx/pageitem.hxx>
#include <editeng/eeitem.hxx>
#include <svx/svdoutl.hxx>
#include <editeng/flditem.hxx>
#include "boost/scoped_ptr.hpp"
#define MAX_EXT_PIX 2048
using namespace ::comphelper;
using namespace ::osl;
using namespace ::vos;
using ::rtl::OUString;
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::document;
using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::task;
#include <svx/sdr/contact/viewobjectcontactredirector.hxx>
#include <svx/sdr/contact/viewobjectcontact.hxx>
#include <svx/sdr/contact/viewcontact.hxx>
// #i102251#
#include <editeng/editstat.hxx>
//////////////////////////////////////////////////////////////////////////////
namespace svx
{
struct ExportSettings
{
OUString maFilterName;
OUString maMediaType;
URL maURL;
com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > mxOutputStream;
com::sun::star::uno::Reference< com::sun::star::graphic::XGraphicRenderer > mxGraphicRenderer;
com::sun::star::uno::Reference< com::sun::star::task::XStatusIndicator > mxStatusIndicator;
com::sun::star::uno::Reference< com::sun::star::task::XInteractionHandler > mxInteractionHandler;
sal_Int32 mnWidth;
sal_Int32 mnHeight;
sal_Bool mbExportOnlyBackground;
sal_Bool mbVerboseComments;
sal_Bool mbScrollText;
sal_Bool mbUseHighContrast;
sal_Bool mbTranslucent;
Sequence< PropertyValue > maFilterData;
Fraction maScaleX;
Fraction maScaleY;
ExportSettings( SdrModel* pDoc );
};
ExportSettings::ExportSettings( SdrModel* pDoc )
: mnWidth( 0 )
, mnHeight( 0 )
, mbExportOnlyBackground( false )
, mbVerboseComments( false )
, mbScrollText( false )
, mbUseHighContrast( false )
, mbTranslucent( sal_False )
, maScaleX( 1, 1 )
, maScaleY( 1, 1 )
{
if( pDoc )
{
maScaleX = pDoc->GetScaleFraction();
maScaleY = pDoc->GetScaleFraction();
}
}
/** implements a component to export shapes or pages to external graphic formats.
@implements com.sun.star.drawing.GraphicExportFilter
*/
class GraphicExporter : public WeakImplHelper4< XFilter, XExporter, XServiceInfo, XMimeTypeInfo >
{
public:
GraphicExporter();
virtual ~GraphicExporter();
// XFilter
virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& aDescriptor ) throw(RuntimeException);
virtual void SAL_CALL cancel( ) throw(RuntimeException);
// XExporter
virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) throw(IllegalArgumentException, RuntimeException);
// XServiceInfo
virtual OUString SAL_CALL getImplementationName( ) throw(RuntimeException);
virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw(RuntimeException);
virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) throw(RuntimeException);
// XMimeTypeInfo
virtual sal_Bool SAL_CALL supportsMimeType( const ::rtl::OUString& MimeTypeName ) throw (RuntimeException);
virtual Sequence< OUString > SAL_CALL getSupportedMimeTypeNames( ) throw (RuntimeException);
VirtualDevice* CreatePageVDev( SdrPage* pPage, sal_uIntPtr nWidthPixel, sal_uIntPtr nHeightPixel ) const;
DECL_LINK( CalcFieldValueHdl, EditFieldInfo* );
void ParseSettings( const Sequence< PropertyValue >& aDescriptor, ExportSettings& rSettings );
bool GetGraphic( ExportSettings& rSettings, Graphic& aGraphic, sal_Bool bVectorType );
private:
Reference< XShape > mxShape;
Reference< XDrawPage > mxPage;
Reference< XShapes > mxShapes;
SvxDrawPage* mpUnoPage;
Link maOldCalcFieldValueHdl;
sal_Int32 mnPageNumber;
SdrPage* mpCurrentPage;
SdrModel* mpDoc;
};
SVX_DLLPUBLIC Reference< XInterface > SAL_CALL GraphicExporter_createInstance(const Reference< XMultiServiceFactory > & )
throw( Exception )
{
return (XWeak*)new GraphicExporter();
}
SVX_DLLPUBLIC Sequence< OUString > SAL_CALL GraphicExporter_getSupportedServiceNames()
throw()
{
Sequence< OUString > aSupportedServiceNames( 1 );
aSupportedServiceNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.GraphicExportFilter" ) );
return aSupportedServiceNames;
}
SVX_DLLPUBLIC OUString SAL_CALL GraphicExporter_getImplementationName()
throw()
{
return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Draw.GraphicExporter" ) );
}
/** creates a bitmap that is optionaly transparent from a metafile
*/
BitmapEx GetBitmapFromMetaFile( const GDIMetaFile& rMtf, sal_Bool bTransparent, const Size* pSize )
{
BitmapEx aBmpEx;
if(bTransparent)
{
// use new primitive conversion tooling
basegfx::B2DRange aRange(basegfx::B2DPoint(0.0, 0.0));
sal_uInt32 nMaximumQuadraticPixels(500000);
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(MAP_100TH_MM)));
aRange.expand(basegfx::B2DPoint(aSize100th.Width(), aSize100th.Height()));
// when explicitely pixels are requested from the GraphicExporter, use a *very* high limit
// of 16gb (4096x4096 pixels), else use the default for the converters
nMaximumQuadraticPixels = std::min(sal_uInt32(4096 * 4096), sal_uInt32(pSize->Width() * pSize->Height()));
}
else
{
// use 100th mm for primitive bitmap converter tool
const Size aSize100th(Application::GetDefaultDevice()->LogicToLogic(rMtf.GetPrefSize(), rMtf.GetPrefMapMode(), MapMode(MAP_100TH_MM)));
aRange.expand(basegfx::B2DPoint(aSize100th.Width(), aSize100th.Height()));
}
aBmpEx = convertMetafileToBitmapEx(rMtf, aRange, nMaximumQuadraticPixels);
}
else
{
const SvtOptionsDrawinglayer aDrawinglayerOpt;
Size aTargetSize(0, 0);
if(pSize)
{
// #122820# If a concrete target size in pixels is given, use it
aTargetSize = *pSize;
// get hairline and full bound rect to evtl. reduce given target pixel size when
// it is known that it will be expanded to get the right and bottom hairlines right
Rectangle aHairlineRect;
const Rectangle aRect(rMtf.GetBoundRect(*Application::GetDefaultDevice(), &aHairlineRect));
if(!aRect.IsEmpty() && !aHairlineRect.IsEmpty())
{
if(aRect.Right() == aHairlineRect.Right() || aRect.Bottom() == aHairlineRect.Bottom())
{
if(aTargetSize.Width())
{
aTargetSize.Width() -= 1;
}
if(aTargetSize.Height())
{
aTargetSize.Height() -= 1;
}
}
}
}
const GraphicConversionParameters aParameters(
aTargetSize,
true, // allow unlimited size
aDrawinglayerOpt.IsAntiAliasing(),
aDrawinglayerOpt.IsSnapHorVerLinesToDiscrete());
const Graphic aGraphic(rMtf);
aBmpEx = BitmapEx(aGraphic.GetBitmap(aParameters));
aBmpEx.SetPrefMapMode( rMtf.GetPrefMapMode() );
aBmpEx.SetPrefSize( rMtf.GetPrefSize() );
}
return aBmpEx;
}
Size* CalcSize( sal_Int32 nWidth, sal_Int32 nHeight, const Size& aBoundSize, Size& aOutSize )
{
if( (nWidth == 0) && (nHeight == 0) )
return NULL;
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.Width() = nWidth;
aOutSize.Height() = nHeight;
return &aOutSize;
}
}
class ImplExportCheckVisisbilityRedirector : public ::sdr::contact::ViewObjectContactRedirector
{
public:
ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage );
virtual ~ImplExportCheckVisisbilityRedirector();
virtual drawinglayer::primitive2d::Primitive2DSequence createRedirectedPrimitive2DSequence(
const sdr::contact::ViewObjectContact& rOriginal,
const sdr::contact::DisplayInfo& rDisplayInfo);
private:
SdrPage* mpCurrentPage;
};
ImplExportCheckVisisbilityRedirector::ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage )
: ViewObjectContactRedirector(), mpCurrentPage( pCurrentPage )
{
}
ImplExportCheckVisisbilityRedirector::~ImplExportCheckVisisbilityRedirector()
{
}
drawinglayer::primitive2d::Primitive2DSequence ImplExportCheckVisisbilityRedirector::createRedirectedPrimitive2DSequence(
const sdr::contact::ViewObjectContact& rOriginal,
const sdr::contact::DisplayInfo& rDisplayInfo)
{
SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject();
if(pObject)
{
SdrPage* pPage = mpCurrentPage;
if( pPage == 0 )
pPage = pObject->GetPage();
if( (pPage == 0) || pPage->checkVisibility(rOriginal, rDisplayInfo, false) )
{
return ::sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo);
}
return drawinglayer::primitive2d::Primitive2DSequence();
}
else
{
// not an object, maybe a page
return ::sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo);
}
}
using namespace ::svx;
GraphicExporter::GraphicExporter()
: mpUnoPage( NULL ), mnPageNumber(-1), mpCurrentPage(0), mpDoc( NULL )
{
}
GraphicExporter::~GraphicExporter()
{
}
IMPL_LINK(GraphicExporter, CalcFieldValueHdl, EditFieldInfo*, pInfo)
{
if( pInfo )
{
if( mpCurrentPage )
{
pInfo->SetSdrPage( mpCurrentPage );
}
else if( mnPageNumber != -1 )
{
const SvxFieldData* pField = pInfo->GetField().GetField();
if( pField && pField->ISA( SvxPageField ) )
{
String aPageNumValue;
sal_Bool bUpper = sal_False;
switch(mpDoc->GetPageNumType())
{
case SVX_CHARS_UPPER_LETTER:
aPageNumValue += (sal_Unicode)(char)((mnPageNumber - 1) % 26 + 'A');
break;
case SVX_CHARS_LOWER_LETTER:
aPageNumValue += (sal_Unicode)(char)((mnPageNumber - 1) % 26 + 'a');
break;
case SVX_ROMAN_UPPER:
bUpper = sal_True;
case SVX_ROMAN_LOWER:
aPageNumValue += SvxNumberFormat::CreateRomanString(mnPageNumber, bUpper);
break;
case SVX_NUMBER_NONE:
aPageNumValue.Erase();
aPageNumValue += sal_Unicode(' ');
break;
default:
aPageNumValue += String::CreateFromInt32( (sal_Int32)mnPageNumber );
}
pInfo->SetRepresentation( aPageNumValue );
return(0);
}
}
}
long nRet = maOldCalcFieldValueHdl.Call( pInfo );
if( pInfo && mpCurrentPage )
pInfo->SetSdrPage( 0 );
return nRet;
}
/** creates an virtual device for the given page
@return the returned VirtualDevice is owned by the caller
*/
VirtualDevice* GraphicExporter::CreatePageVDev( SdrPage* pPage, sal_uIntPtr nWidthPixel, sal_uIntPtr nHeightPixel ) const
{
VirtualDevice* pVDev = new VirtualDevice();
MapMode aMM( MAP_100TH_MM );
Point aPoint( 0, 0 );
Size aPageSize(pPage->GetSize());
// use scaling?
if( nWidthPixel )
{
const Fraction aFrac( (long) nWidthPixel, pVDev->LogicToPixel( aPageSize, aMM ).Width() );
aMM.SetScaleX( aFrac );
if( nHeightPixel == 0 )
aMM.SetScaleY( aFrac );
}
if( nHeightPixel )
{
const Fraction aFrac( (long) nHeightPixel, pVDev->LogicToPixel( aPageSize, aMM ).Height() );
if( nWidthPixel == 0 )
aMM.SetScaleX( aFrac );
aMM.SetScaleY( aFrac );
}
pVDev->SetMapMode( aMM );
bool bSuccess(false);
// #122820# If available, use pixel size directly
if(nWidthPixel && nHeightPixel)
{
bSuccess = pVDev->SetOutputSizePixel(Size(nWidthPixel, nHeightPixel));
}
else
{
bSuccess = pVDev->SetOutputSize(aPageSize);
}
if(bSuccess)
{
SdrView* pView = new SdrView(mpDoc, pVDev);
pView->SetPageVisible( sal_False );
pView->SetBordVisible( sal_False );
pView->SetGridVisible( sal_False );
pView->SetHlplVisible( sal_False );
pView->SetGlueVisible( sal_False );
pView->ShowSdrPage(pPage);
Region aRegion (Rectangle( aPoint, aPageSize ) );
ImplExportCheckVisisbilityRedirector aRedirector( mpCurrentPage );
pView->CompleteRedraw(pVDev, aRegion, &aRedirector);
delete pView;
}
else
{
OSL_ENSURE(false, "Could not get a VirtualDevice of requested size (!)");
}
return pVDev;
}
void GraphicExporter::ParseSettings( const Sequence< PropertyValue >& aDescriptor, ExportSettings& rSettings )
{
sal_Int32 nArgs = aDescriptor.getLength();
const PropertyValue* pValues = aDescriptor.getConstArray();
while( nArgs-- )
{
if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "FilterName" ) ) )
{
pValues->Value >>= rSettings.maFilterName;
}
else if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) )
{
pValues->Value >>= rSettings.maMediaType;
}
else if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "URL" ) ) )
{
if( !( pValues->Value >>= rSettings.maURL ) )
{
pValues->Value >>= rSettings.maURL.Complete;
}
}
else if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "OutputStream" ) ) )
{
pValues->Value >>= rSettings.mxOutputStream;
}
else if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "GraphicRenderer" ) ) )
{
pValues->Value >>= rSettings.mxGraphicRenderer;
}
else if ( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "StatusIndicator" ) ) )
{
pValues->Value >>= rSettings.mxStatusIndicator;
}
else if ( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "InteractionHandler" ) ) )
{
pValues->Value >>= rSettings.mxInteractionHandler;
}
else if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Width" ) ) ) // for compatibility reasons, deprecated
{
pValues->Value >>= rSettings.mnWidth;
}
else if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Height" ) ) ) // for compatibility reasons, deprecated
{
pValues->Value >>= rSettings.mnHeight;
}
else if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ExportOnlyBackground" ) ) ) // for compatibility reasons, deprecated
{
pValues->Value >>= rSettings.mbExportOnlyBackground;
}
else if ( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "FilterData" ) ) )
{
pValues->Value >>= rSettings.maFilterData;
sal_Int32 nFilterArgs = rSettings.maFilterData.getLength();
PropertyValue* pDataValues = rSettings.maFilterData.getArray();
while( nFilterArgs-- )
{
if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Translucent" ) ) )
{
if ( !( pDataValues->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 ( pDataValues->Value >>= nTranslucent )
rSettings.mbTranslucent = nTranslucent != 0;
}
}
else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "PixelWidth" ) ) )
{
pDataValues->Value >>= rSettings.mnWidth;
}
else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "PixelHeight" ) ) )
{
pDataValues->Value >>= rSettings.mnHeight;
}
else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Width" ) ) ) // for compatibility reasons, deprecated
{
pDataValues->Value >>= rSettings.mnWidth;
pDataValues->Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "PixelWidth" ) );
}
else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Height" ) ) ) // for compatibility reasons, deprecated
{
pDataValues->Value >>= rSettings.mnHeight;
pDataValues->Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "PixelHeight" ) );
}
else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ExportOnlyBackground" ) ) )
{
pDataValues->Value >>= rSettings.mbExportOnlyBackground;
}
else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "HighContrast" ) ) )
{
pDataValues->Value >>= rSettings.mbUseHighContrast;
}
else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "PageNumber" ) ) )
{
pDataValues->Value >>= mnPageNumber;
}
else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "VerboseComments" ) ) )
{
// #110496# Read flag for verbose metafile comments
pDataValues->Value >>= rSettings.mbVerboseComments;
}
else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScrollText" ) ) )
{
// #110496# Read flag solitary scroll text metafile
pDataValues->Value >>= rSettings.mbScrollText;
}
else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CurrentPage" ) ) )
{
Reference< XDrawPage > xPage;
pDataValues->Value >>= xPage;
if( xPage.is() )
{
SvxDrawPage* pUnoPage = SvxDrawPage::getImplementation( xPage );
if( pUnoPage && pUnoPage->GetSdrPage() )
mpCurrentPage = pUnoPage->GetSdrPage();
}
}
else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleXNumerator" ) ) )
{
sal_Int32 nVal = 1;
if( pDataValues->Value >>= nVal )
rSettings.maScaleX = Fraction( nVal, rSettings.maScaleX.GetDenominator() );
}
else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleXDenominator" ) ) )
{
sal_Int32 nVal = 1;
if( pDataValues->Value >>= nVal )
rSettings.maScaleX = Fraction( rSettings.maScaleX.GetNumerator(), nVal );
}
else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleYNumerator" ) ) )
{
sal_Int32 nVal = 1;
if( pDataValues->Value >>= nVal )
rSettings.maScaleY = Fraction( nVal, rSettings.maScaleY.GetDenominator() );
}
else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleYDenominator" ) ) )
{
sal_Int32 nVal = 1;
if( pDataValues->Value >>= nVal )
rSettings.maScaleY = Fraction( rSettings.maScaleY.GetNumerator(), nVal );
}
pDataValues++;
}
}
pValues++;
}
// putting the StatusIndicator that we got from the MediaDescriptor into our local FilterData copy
if ( rSettings.mxStatusIndicator.is() )
{
rtl::OUString sStatusIndicator( RTL_CONSTASCII_USTRINGPARAM( "StatusIndicator" ) );
int i = rSettings.maFilterData.getLength();
rSettings.maFilterData.realloc( i + 1 );
rSettings.maFilterData[ i ].Name = sStatusIndicator;
rSettings.maFilterData[ i ].Value <<= rSettings.mxStatusIndicator;
}
}
bool GraphicExporter::GetGraphic( ExportSettings& rSettings, Graphic& aGraphic, sal_Bool bVectorType )
{
if( !mpDoc || !mpUnoPage )
return false;
SdrPage* pPage = mpUnoPage->GetSdrPage();
if( !pPage )
return false;
VirtualDevice aVDev;
const MapMode aMap( mpDoc->GetScaleUnit(), Point(), rSettings.maScaleX, rSettings.maScaleY );
SdrOutliner& rOutl=mpDoc->GetDrawOutliner(NULL);
maOldCalcFieldValueHdl = rOutl.GetCalcFieldValueHdl();
rOutl.SetCalcFieldValueHdl( LINK(this, GraphicExporter, CalcFieldValueHdl) );
rOutl.SetBackgroundColor( pPage->GetPageBackgroundColor() );
// #i102251#
const sal_uInt32 nOldCntrl(rOutl.GetControlWord());
sal_uInt32 nCntrl = nOldCntrl & ~EE_CNTRL_ONLINESPELLING;
rOutl.SetControlWord(nCntrl);
SdrObject* pTempBackgroundShape = 0;
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(Rectangle(Point(0,0), pPage->GetSize()));
pTempBackgroundShape->SetMergedItemSet(pCorrectProperties->GetItemSet());
pTempBackgroundShape->SetMergedItem(XLineStyleItem(XLINE_NONE));
pTempBackgroundShape->NbcSetStyleSheet(pCorrectProperties->GetStyleSheet(), true);
aShapes.push_back(pTempBackgroundShape);
}
}
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 )
{
long nWidthPix = 0;
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 = aSizePix.Width() / nWidthPix;
double fHeightDif = aSizePix.Height() / nHeightPix;
if (fWidthDif > fHeightDif)
nHeightPix = static_cast<long>(aSizePix.Height() / fWidthDif);
else
nWidthPix = static_cast<long>(aSizePix.Width() / fHeightDif);
}
else
{
nWidthPix = aSizePix.Width();
nHeightPix = aSizePix.Height();
}
}
boost::scoped_ptr< SdrView > pLocalView;
if( PTR_CAST( FmFormModel, mpDoc ) )
{
pLocalView.reset( new FmFormView( PTR_CAST( FmFormModel, mpDoc ), &aVDev ) );
}
else
{
pLocalView.reset( new SdrView( mpDoc, &aVDev ) );
}
VirtualDevice* pVDev = CreatePageVDev( pPage, nWidthPix, nHeightPix );
if( pVDev )
{
aGraphic = pVDev->GetBitmap( Point(), pVDev->GetOutputSize() );
aGraphic.SetPrefMapMode( aMap );
aGraphic.SetPrefSize( aSize );
delete pVDev;
}
}
// create a metafile to export a vector format
else
{
GDIMetaFile aMtf;
aVDev.SetMapMode( aMap );
if( rSettings.mbUseHighContrast )
aVDev.SetDrawMode( aVDev.GetDrawMode() | DRAWMODE_SETTINGSLINE | DRAWMODE_SETTINGSFILL | DRAWMODE_SETTINGSTEXT | DRAWMODE_SETTINGSGRADIENT );
aVDev.EnableOutput( sal_False );
aMtf.Record( &aVDev );
Size aNewSize;
// create a view
SdrView* pView;
if( PTR_CAST( FmFormModel, mpDoc ) )
{
pView = new FmFormView( PTR_CAST( FmFormModel, mpDoc ), &aVDev );
}
else
{
pView = new SdrView( mpDoc, &aVDev );
}
pView->SetBordVisible( sal_False );
pView->SetPageVisible( sal_False );
pView->ShowSdrPage( pPage );
if ( pView && pPage )
{
pView->SetBordVisible( sal_False );
pView->SetPageVisible( sal_False );
pView->ShowSdrPage( pPage );
const Point aNewOrg( pPage->GetLftBorder(), pPage->GetUppBorder() );
aNewSize = Size( aSize.Width() - pPage->GetLftBorder() - pPage->GetRgtBorder(),
aSize.Height() - pPage->GetUppBorder() - pPage->GetLwrBorder() );
const 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, Region(Rectangle(Point(), aNewSize)), &aRedirector);
aVDev.Pop();
aMtf.Stop();
aMtf.WindStart();
aMtf.SetPrefMapMode( aMap );
aMtf.SetPrefSize( aNewSize );
// AW: Here the current version was filtering out the META_CLIPREGION_ACTIONs
// 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-indepent 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);
}
if ( pView )
{
pView->HideSdrPage();
delete pView;
}
if( rSettings.mbTranslucent )
{
Size aOutSize;
aGraphic = GetBitmapFromMetaFile( aGraphic.GetGDIMetaFile(), sal_True, 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 = GetSdrObjectFromXShape( xShape );
if( pObj )
aShapes.push_back( pObj );
}
}
else
{
// only one shape
SdrObject* pObj = 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
sal_Bool bSingleGraphic = sal_False;
if( 1 == aShapes.size() )
{
if( !bVectorType )
{
SdrObject* pObj = aShapes.front();
if( pObj && pObj->ISA( SdrGrafObj ) && !( (SdrGrafObj*) pObj )->HasText() )
{
aGraphic = ( (SdrGrafObj*) pObj )->GetTransformedGraphic();
if ( aGraphic.GetType() == GRAPHIC_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 ), BMP_SCALE_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 = sal_True;
}
}
}
else if( rSettings.mbScrollText )
{
SdrObject* pObj = aShapes.front();
if( pObj && pObj->ISA( SdrTextObj )
&& ( (SdrTextObj*) pObj )->HasText() )
{
Rectangle aScrollRectangle;
Rectangle aPaintRectangle;
const boost::scoped_ptr< GDIMetaFile > pMtf(
( (SdrTextObj*) pObj )->GetTextScrollMetaFileAndRectangle(
aScrollRectangle, aPaintRectangle ) );
// take the larger one of the two rectangles (that
// should be the bound rect of the retrieved
// metafile)
Rectangle aTextRect;
if( aScrollRectangle.IsInside( 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", 0,
reinterpret_cast<sal_uInt8 const*>(&aScrollRectangle),
sizeof( Rectangle ) ) );
pMtf->AddAction( new MetaCommentAction(
"XTEXT_PAINTRECT", 0,
reinterpret_cast<sal_uInt8 const*>(&aPaintRectangle),
sizeof( Rectangle ) ) );
aGraphic = Graphic( *pMtf );
bSingleGraphic = sal_True;
}
}
}
if( !bSingleGraphic )
{
// create a metafile for all shapes
VirtualDevice aOut;
// calculate bound rect for all shapes
Rectangle aBound;
{
std::vector< SdrObject* >::iterator aIter = aShapes.begin();
const std::vector< SdrObject* >::iterator aEnd = aShapes.end();
while( aIter != aEnd )
{
SdrObject* pObj = (*aIter++);
Rectangle aR1(pObj->GetCurrentBoundRect());
if (aBound.IsEmpty())
aBound=aR1;
else
aBound.Union(aR1);
}
}
aOut.EnableOutput( sal_False );
aOut.SetMapMode( aMap );
if( rSettings.mbUseHighContrast )
aOut.SetDrawMode( aVDev.GetDrawMode() | DRAWMODE_SETTINGSLINE | DRAWMODE_SETTINGSFILL | DRAWMODE_SETTINGSTEXT | DRAWMODE_SETTINGSGRADIENT );
GDIMetaFile aMtf;
aMtf.Clear();
aMtf.Record( &aOut );
MapMode aOutMap( aMap );
aOutMap.SetOrigin( Point( -aBound.TopLeft().X(), -aBound.TopLeft().Y() ) );
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
sdr::contact::ObjectContactOfObjListPainter aMultiObjectPainter(aOut, aShapes, mpCurrentPage);
ImplExportCheckVisisbilityRedirector aCheckVisibilityRedirector(mpCurrentPage);
aMultiObjectPainter.SetViewObjectContactRedirector(&aCheckVisibilityRedirector);
aMultiObjectPainter.ProcessDisplay(aDisplayInfo);
}
aMtf.Stop();
aMtf.WindStart();
const Size aExtSize( aOut.PixelToLogic( Size( 0, 0 ) ) );
Size aBoundSize( aBound.GetWidth() + ( aExtSize.Width() ),
aBound.GetHeight() + ( aExtSize.Height() ) );
aMtf.SetPrefMapMode( aMap );
aMtf.SetPrefSize( aBoundSize );
if( !bVectorType )
{
Size aOutSize;
aGraphic = GetBitmapFromMetaFile( aMtf, rSettings.mbTranslucent, CalcSize( rSettings.mnWidth, rSettings.mnHeight, aBoundSize, aOutSize ) );
}
else
{
aGraphic = aMtf;
}
}
}
if(pTempBackgroundShape)
{
SdrObject::Free(pTempBackgroundShape);
}
rOutl.SetCalcFieldValueHdl( maOldCalcFieldValueHdl );
// #i102251#
rOutl.SetControlWord(nOldCntrl);
return bRet;
}
// XFilter
sal_Bool SAL_CALL GraphicExporter::filter( const Sequence< PropertyValue >& aDescriptor )
throw(RuntimeException)
{
OGuard aGuard( Application::GetSolarMutex() );
if( NULL == mpUnoPage )
return sal_False;
GraphicFilter* pFilter = GraphicFilter::GetGraphicFilter();
if( NULL == pFilter || NULL == mpUnoPage->GetSdrPage() || NULL == mpDoc )
return sal_False;
// get the arguments from the descriptor
ExportSettings aSettings( mpDoc );
ParseSettings( aDescriptor, aSettings );
const sal_uInt16 nFilter = aSettings.maMediaType.getLength()
? pFilter->GetExportFormatNumberForMediaType( aSettings.maMediaType )
: pFilter->GetExportFormatNumberForShortName( aSettings.maFilterName );
sal_Bool bVectorType = !pFilter->IsExportPixelFormat( nFilter );
// create the output stuff
Graphic aGraphic;
sal_uInt16 nStatus = GetGraphic( aSettings, aGraphic, bVectorType ) ? GRFILTER_OK : GRFILTER_FILTERERROR;
if( nStatus == GRFILTER_OK )
{
// export graphic only if it has a size
const Size aGraphSize( aGraphic.GetPrefSize() );
if ( ( aGraphSize.Width() == 0 ) || ( aGraphSize.Height() == 0 ) )
{
nStatus = 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 = pFilter->ExportGraphic( aGraphic, String(), aStream, nFilter, &aSettings.maFilterData );
// copy temp stream to XOutputStream
SvOutputStream aOutputStream( aSettings.mxOutputStream );
aStream.Seek(0);
aOutputStream << aStream;
}
else
{
INetURLObject aURLObject( aSettings.maURL.Complete );
DBG_ASSERT( aURLObject.GetProtocol() != INET_PROT_NOT_VALID, "invalid URL" );
nStatus = XOutBitmap::ExportGraphic( aGraphic, aURLObject, *pFilter, nFilter, &aSettings.maFilterData );
}
}
}
if ( aSettings.mxInteractionHandler.is() && ( nStatus != GRFILTER_OK ) )
{
Any aInteraction;
Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionContinuation > > lContinuations(1);
::comphelper::OInteractionApprove* pApprove = new ::comphelper::OInteractionApprove();
lContinuations[0] = Reference< XInteractionContinuation >(static_cast< XInteractionContinuation* >(pApprove), UNO_QUERY);
GraphicFilterRequest aErrorCode;
aErrorCode.ErrCode = nStatus;
aInteraction <<= aErrorCode;
aSettings.mxInteractionHandler->handle( framework::InteractionRequest::CreateRequest( aInteraction, lContinuations ) );
}
return nStatus == GRFILTER_OK;
}
void SAL_CALL GraphicExporter::cancel()
throw(RuntimeException)
{
}
// XExporter
/** the source 'document' could be a XDrawPage, a XShape or a generic XShapes */
void SAL_CALL GraphicExporter::setSourceDocument( const Reference< lang::XComponent >& xComponent )
throw(IllegalArgumentException, RuntimeException)
{
OGuard aGuard( Application::GetSolarMutex() );
mxShapes = NULL;
mpUnoPage = NULL;
try
{
// any break inside this one loop while will throw a IllegalArgumentException
do
{
mxPage = Reference< XDrawPage >::query( xComponent );
mxShapes = Reference< XShapes >::query( xComponent );
mxShape = Reference< XShape >::query( xComponent );
// 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 = NULL;
}
// Step 2: try a shape
if( mxShape.is() )
{
if( NULL == GetSdrObjectFromXShape( mxShape ) )
break;
// get page for this shape
Reference< XChild > xChild( mxShape, UNO_QUERY );
if( !xChild.is() )
break;
Reference< XInterface > xInt;
do
{
xInt = xChild->getParent();
mxPage = Reference< XDrawPage >::query( xInt );
if( !mxPage.is() )
xChild = Reference< XChild >::query( xInt );
}
while( !mxPage.is() && xChild.is() );
if( !mxPage.is() )
break;
}
// Step 3: check the page
if( !mxPage.is() )
break;
mpUnoPage = SvxDrawPage::getImplementation( mxPage );
if( NULL == mpUnoPage || NULL == mpUnoPage->GetSdrPage() )
break;
mpDoc = mpUnoPage->GetSdrPage()->GetModel();
// 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;
sal_Bool bOk = sal_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 = GetSdrObjectFromXShape( xShape );
bOk = pObj && pObj->GetPage() == pPage;
}
if( !bOk )
break;
}
// no errors so far
return;
}
while( 0 );
}
catch( Exception& )
{
}
throw IllegalArgumentException();
}
// XServiceInfo
OUString SAL_CALL GraphicExporter::getImplementationName( )
throw(RuntimeException)
{
return GraphicExporter_getImplementationName();
}
sal_Bool SAL_CALL GraphicExporter::supportsService( const OUString& ServiceName )
throw(RuntimeException)
{
Sequence< OUString > aSeq( GraphicExporter_getSupportedServiceNames() );
sal_Int32 nArgs = aSeq.getLength();
const OUString* pService = aSeq.getConstArray();
while( nArgs-- )
if( *pService++ == ServiceName )
return sal_True;
return sal_False;
}
Sequence< OUString > SAL_CALL GraphicExporter::getSupportedServiceNames( )
throw(RuntimeException)
{
return GraphicExporter_getSupportedServiceNames();
}
// XMimeTypeInfo
sal_Bool SAL_CALL GraphicExporter::supportsMimeType( const OUString& MimeTypeName ) throw (RuntimeException)
{
const String aMimeTypeName( MimeTypeName );
GraphicFilter* pFilter = GraphicFilter::GetGraphicFilter();
sal_uInt16 nCount = pFilter->GetExportFormatCount();
sal_uInt16 nFilter;
for( nFilter = 0; nFilter < nCount; nFilter++ )
{
if( aMimeTypeName.Equals( pFilter->GetExportFormatMediaType( nFilter ) ) )
{
return sal_True;
}
}
return sal_False;
}
Sequence< OUString > SAL_CALL GraphicExporter::getSupportedMimeTypeNames( ) throw (RuntimeException)
{
GraphicFilter* pFilter = GraphicFilter::GetGraphicFilter();
sal_uInt16 nCount = pFilter->GetExportFormatCount();
sal_uInt16 nFilter;
sal_uInt16 nFound = 0;
Sequence< OUString > aSeq( nCount );
OUString* pStr = aSeq.getArray();
for( nFilter = 0; nFilter < nCount; nFilter++ )
{
OUString aMimeType( pFilter->GetExportFormatMediaType( nFilter ) );
if( aMimeType.getLength() )
{
*pStr++ = aMimeType;
nFound++;
}
}
if( nFound < nCount )
aSeq.realloc( nFound );
return aSeq;
}
Graphic SvxGetGraphicForShape( SdrObject& rShape, bool bVector )
{
Graphic aGraphic;
try
{
rtl::Reference< GraphicExporter > xExporter( new GraphicExporter() );
Reference< XComponent > xComp( rShape.getUnoShape(), UNO_QUERY_THROW );
xExporter->setSourceDocument( xComp );
ExportSettings aSettings( rShape.GetModel() );
xExporter->GetGraphic( aSettings, aGraphic, bVector );
}
catch( Exception& )
{
DBG_ERROR("SvxGetGraphicForShape(), exception caught!");
}
return aGraphic;
}