summaryrefslogtreecommitdiff
path: root/filter
diff options
context:
space:
mode:
authorMarco Cecchetti <marco.cecchetti@collabora.com>2021-01-22 19:31:26 +0100
committerAndras Timar <andras.timar@collabora.com>2021-03-06 21:58:48 +0100
commit3d008f3bcd19a74cff0781cbd9a3d173892553cf (patch)
tree0408f4f3cb98675d15571c65ab5eb94b52f3031f /filter
parentcc3b9c0bcc4a379efb99b273c426a5ecb2214d0f (diff)
filter: svg: js engine: support for bitmaps in slide background
When a slide background includes one or more bitmaps, they are exported only once. This avoid to export the same bitmap more than once when it is embedded in several backgound slides and to export only one bitmap for the tile style. Change-Id: Ia5b75f7805541486b76a81f86907e88ed9d4764a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/109835 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Reviewed-by: Marco Cecchetti <marco.cecchetti@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111842 Tested-by: Jenkins Reviewed-by: Andras Timar <andras.timar@collabora.com>
Diffstat (limited to 'filter')
-rw-r--r--filter/source/svg/svgexport.cxx161
-rw-r--r--filter/source/svg/svgfilter.hxx5
-rw-r--r--filter/source/svg/svgwriter.cxx54
-rw-r--r--filter/source/svg/svgwriter.hxx5
4 files changed, 198 insertions, 27 deletions
diff --git a/filter/source/svg/svgexport.cxx b/filter/source/svg/svgexport.cxx
index e35a42746216..4eb56a5a9ced 100644
--- a/filter/source/svg/svgexport.cxx
+++ b/filter/source/svg/svgexport.cxx
@@ -427,6 +427,12 @@ namespace
BitmapChecksum GetBitmapChecksum( const MetaAction* pAction )
{
+ if( !pAction )
+ {
+ OSL_FAIL( "GetBitmapChecksum: passed MetaAction pointer is null." );
+ return 0;
+ }
+
BitmapChecksum nChecksum = 0;
const MetaActionType nType = pAction->GetType();
@@ -435,19 +441,16 @@ BitmapChecksum GetBitmapChecksum( const MetaAction* pAction )
case MetaActionType::BMPSCALE:
{
const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction);
- if( pA )
- nChecksum = pA->GetBitmap().GetChecksum();
- else
- OSL_FAIL( "GetBitmapChecksum: MetaBmpScaleAction pointer is null." );
+ // The conversion to BitmapEx is needed since a Bitmap object is
+ // converted to BitmapEx before passing it to SVGActionWriter::ImplWriteBmp
+ // where the checksum is checked for matching.
+ nChecksum = BitmapEx( pA->GetBitmap() ).GetChecksum();
}
break;
case MetaActionType::BMPEXSCALE:
{
const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction);
- if( pA )
- nChecksum = pA->GetBitmapEx().GetChecksum();
- else
- OSL_FAIL( "GetBitmapChecksum: MetaBmpExScaleAction pointer is null." );
+ nChecksum = pA->GetBitmapEx().GetChecksum();
}
break;
default: break;
@@ -455,37 +458,95 @@ BitmapChecksum GetBitmapChecksum( const MetaAction* pAction )
return nChecksum;
}
-} // end anonymous namespace
+MetaAction* CreateMetaBitmapAction( const MetaAction* pAction, const Point& rPt, const Size& rSz )
+{
+ if( !pAction )
+ {
+ OSL_FAIL( "CreateMetaBitmapAction: passed MetaAction pointer is null." );
+ return nullptr;
+ }
+ MetaAction* pResAction = nullptr;
+ const MetaActionType nType = pAction->GetType();
+ switch( nType )
+ {
+ case MetaActionType::BMPSCALE:
+ {
+ const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction);
+ pResAction = new MetaBmpScaleAction( rPt, rSz, pA->GetBitmap() );
+ }
+ break;
+ case MetaActionType::BMPEXSCALE:
+ {
+ const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction);
+ pResAction = new MetaBmpExScaleAction( rPt, rSz, pA->GetBitmapEx() );
+ }
+ break;
+ default: break;
+ }
+ return pResAction;
+}
-static void MetaBitmapActionGetPoint( const MetaAction* pAction, Point& rPt )
+void MetaBitmapActionGetPoint( const MetaAction* pAction, Point& rPt )
{
+ if( !pAction )
+ {
+ OSL_FAIL( "MetaBitmapActionGetPoint: passed MetaAction pointer is null." );
+ return;
+ }
const MetaActionType nType = pAction->GetType();
switch( nType )
{
case MetaActionType::BMPSCALE:
{
const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction);
- if( pA )
- rPt = pA->GetPoint();
- else
- OSL_FAIL( "MetaBitmapActionGetPoint: MetaBmpScaleAction pointer is null." );
+ rPt = pA->GetPoint();
}
break;
case MetaActionType::BMPEXSCALE:
{
const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction);
- if( pA )
- rPt = pA->GetPoint();
- else
- OSL_FAIL( "MetaBitmapActionGetPoint: MetaBmpExScaleAction pointer is null." );
+ rPt = pA->GetPoint();
}
break;
default: break;
}
+}
+
+void MetaBitmapActionGetSize( const MetaAction* pAction, Size& rSz )
+{
+ if( !pAction )
+ {
+ OSL_FAIL( "MetaBitmapActionGetSize: passed MetaAction pointer is null." );
+ return;
+ }
+
+ const MetaActionType nType = pAction->GetType();
+ MapMode aSourceMode( MapUnit::MapPixel );
+ MapMode aTargetMode( MapUnit::Map100thMM );
+ switch( nType )
+ {
+ case MetaActionType::BMPSCALE:
+ {
+ const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction);
+ const Bitmap& rBitmap = pA->GetBitmap();
+ rSz = rBitmap.GetSizePixel();
+ }
+ break;
+ case MetaActionType::BMPEXSCALE:
+ {
+ const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction);
+ const BitmapEx& rBitmap = pA->GetBitmapEx();
+ rSz = rBitmap.GetSizePixel();
+ }
+ break;
+ default: break;
+ }
+ rSz = OutputDevice::LogicToLogic( rSz, aSourceMode, aTargetMode );
}
+} // end anonymous namespace
size_t HashBitmap::operator()( const ObjectRepresentation& rObjRep ) const
{
@@ -870,6 +931,8 @@ bool SVGFilter::implExportDocument()
implExportTextShapeIndex();
implEmbedBulletGlyphs();
implExportTextEmbeddedBitmaps();
+ implExportBackgroundBitmaps();
+ mpSVGWriter->SetEmbeddedBitmapRefs( &maBitmapActionMap );
}
// #i124608# export a given object selection, so no MasterPage export at all
@@ -1424,6 +1487,31 @@ void SVGFilter::implEmbedBulletGlyph( sal_Unicode cBullet, const OUString & sPat
}
+void SVGFilter::implExportBackgroundBitmaps()
+{
+ if (maBitmapActionMap.empty())
+ return;
+
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", "BackgroundBitmaps" );
+ SvXMLElementExport aDefsContainerElem( *mpSVGExport, XML_NAMESPACE_NONE, "defs", true, true );
+
+ OUString sId;
+ for( const auto& rItem : maBitmapActionMap )
+ {
+ BitmapChecksum nChecksum = rItem.first;
+ const GDIMetaFile& aEmbeddedBitmapMtf = *(rItem.second);
+ MetaAction* pBitmapAction = aEmbeddedBitmapMtf.GetAction( 0 );
+ if( pBitmapAction )
+ {
+ sId = "bitmap(" + OUString::number( nChecksum ) + ")";
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sId );
+
+ const Point aPos; // (0, 0)
+ const Size aSize = aEmbeddedBitmapMtf.GetPrefSize();
+ mpSVGWriter->WriteMetaFile( aPos, aSize, aEmbeddedBitmapMtf, 0xffffffff );
+ }
+ }
+}
/** SVGFilter::implExportTextEmbeddedBitmaps
We export bitmaps embedded into text shapes, such as those used by list
@@ -2073,10 +2161,8 @@ bool SVGFilter::implCreateObjects()
// implementation status:
// - hatch stroke color is set to 'none' so the hatch is not visible, why?
// - gradient look is not really awesome, too few colors are used;
- // - stretched bitmap, gradient and hatch are not exported only once
+ // - gradient and hatch are not exported only once
// and then referenced in case more than one slide uses them.
- // - tiled bitmap: an image element is exported for each tile,
- // this is really too expensive!
Reference< XPropertySet > xPropSet( xDrawPage, UNO_QUERY );
if( xPropSet.is() )
{
@@ -2086,8 +2172,7 @@ bool SVGFilter::implCreateObjects()
{
drawing::FillStyle aFillStyle;
bool assigned = ( xBackground->getPropertyValue( "FillStyle" ) >>= aFillStyle );
- if( assigned && aFillStyle != drawing::FillStyle_NONE
- && aFillStyle != drawing::FillStyle_BITMAP )
+ if( assigned && aFillStyle != drawing::FillStyle_NONE )
{
implCreateObjectsFromBackground( xDrawPage );
}
@@ -2269,10 +2354,38 @@ void SVGFilter::implCreateObjectsFromBackground( const Reference< css::drawing::
xExporter->filter( aDescriptor );
aMtf.Read( *aFile.GetStream( StreamMode::READ ) );
+ MetaAction* pAction;
+ sal_uLong nCount = aMtf.GetActionSize();
+ for( sal_uLong nCurAction = 0; nCurAction < nCount; ++nCurAction )
+ {
+ pAction = aMtf.GetAction( nCurAction );
+ const MetaActionType nType = pAction->GetType();
+
+ if( nType == MetaActionType::BMPSCALE || nType == MetaActionType::BMPEXSCALE )
+ {
+ BitmapChecksum nChecksum = GetBitmapChecksum( pAction );
+ if( maBitmapActionMap.find( nChecksum ) == maBitmapActionMap.end() )
+ {
+ Point aPos; // (0, 0)
+ Size aSize;
+ MetaBitmapActionGetSize( pAction, aSize );
+ MetaAction* pBitmapAction = CreateMetaBitmapAction( pAction, aPos, aSize );
+ if( pBitmapAction )
+ {
+ GDIMetaFile* pEmbeddedBitmapMtf = new GDIMetaFile();
+ pEmbeddedBitmapMtf->AddAction( pBitmapAction );
+ pEmbeddedBitmapMtf->SetPrefSize( aSize );
+ pEmbeddedBitmapMtf->SetPrefMapMode( MapMode(MapUnit::Map100thMM) );
+
+ maBitmapActionMap[ nChecksum ].reset( pEmbeddedBitmapMtf );
+ }
+ }
+ }
+ }
+
(*mpObjects)[ rxDrawPage ] = ObjectRepresentation( rxDrawPage, aMtf );
}
-
OUString SVGFilter::implGetClassFromShape( const Reference< css::drawing::XShape >& rxShape )
{
OUString aRet;
diff --git a/filter/source/svg/svgfilter.hxx b/filter/source/svg/svgfilter.hxx
index b761e1768e9c..9f612440ebdf 100644
--- a/filter/source/svg/svgfilter.hxx
+++ b/filter/source/svg/svgfilter.hxx
@@ -153,6 +153,9 @@ struct EqualityBitmap
const ObjectRepresentation& rObjRep2 ) const;
};
+// This must match the same type definition in svgwriter.hxx
+typedef std::unordered_map< BitmapChecksum, std::unique_ptr< GDIMetaFile > > MetaBitmapActionMap;
+
class SVGFontExport;
class SVGActionWriter;
class EditFieldInfo;
@@ -210,6 +213,7 @@ private:
mTextShapeIdListMap;
MetaBitmapActionSet mEmbeddedBitmapActionSet;
ObjectMap mEmbeddedBitmapActionMap;
+ MetaBitmapActionMap maBitmapActionMap;
std::vector< Reference< css::drawing::XDrawPage > > mMasterPageTargets;
Link<EditFieldInfo*,void> maOldFieldHdl;
@@ -229,6 +233,7 @@ private:
void implEmbedBulletGlyphs();
void implEmbedBulletGlyph( sal_Unicode cBullet, const OUString & sPathData );
void implExportTextEmbeddedBitmaps();
+ void implExportBackgroundBitmaps();
void implGenerateScript();
bool implExportDocument();
diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index 9cfdf5e14250..0b08de921549 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -1501,7 +1501,12 @@ void SVGTextWriter::implWriteEmbeddedBitmaps()
case MetaActionType::BMPSCALE:
{
const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction);
- nChecksum = pA->GetBitmap().GetChecksum();
+ // The conversion to BitmapEx is needed since at the point
+ // where the bitmap is actually exported a Bitmap object is
+ // converted to BitmapEx before computing the checksum used
+ // to generate the <image> element id.
+ // (See GetBitmapChecksum in svgexport.cxx)
+ nChecksum = BitmapEx( pA->GetBitmap() ).GetChecksum();
aPt = pA->GetPoint();
aSz = pA->GetSize();
}
@@ -1773,7 +1778,8 @@ SVGActionWriter::SVGActionWriter( SVGExport& rExport, SVGFontExport& rFontExport
maTextWriter(rExport, maAttributeWriter, *this),
mpVDev(VclPtr<VirtualDevice>::Create()),
mbClipAttrChanged( false ),
- mbIsPlaceholderShape( false )
+ mbIsPlaceholderShape( false ),
+ mpEmbeddedBitmapsMap( nullptr )
{
mpVDev->EnableOutput( false );
maTargetMapMode = MapMode(MapUnit::Map100thMM);
@@ -1917,7 +1923,6 @@ OUString SVGActionWriter::GetPathString( const tools::PolyPolygon& rPolyPoly, bo
return aPathData.makeStringAndClear();
}
-
BitmapChecksum SVGActionWriter::GetChecksum( const MetaAction* pAction )
{
GDIMetaFile aMtf;
@@ -1926,6 +1931,13 @@ BitmapChecksum SVGActionWriter::GetChecksum( const MetaAction* pAction )
return aMtf.GetChecksum();
}
+void SVGActionWriter::SetEmbeddedBitmapRefs( const MetaBitmapActionMap* pEmbeddedBitmapsMap )
+{
+ if (pEmbeddedBitmapsMap)
+ mpEmbeddedBitmapsMap = pEmbeddedBitmapsMap;
+ else
+ OSL_FAIL( "SVGActionWriter::SetEmbeddedBitmapRefs: passed pointer is null" );
+}
void SVGActionWriter::ImplWriteLine( const Point& rPt1, const Point& rPt2,
const Color* pLineColor )
@@ -2816,6 +2828,42 @@ void SVGActionWriter::ImplWriteBmp( const BitmapEx& rBmpEx,
{
if( !rBmpEx )
return;
+ if( mpEmbeddedBitmapsMap && !mpEmbeddedBitmapsMap->empty())
+ {
+ BitmapChecksum nChecksum = rBmpEx.GetChecksum();
+ if( mpEmbeddedBitmapsMap->find( nChecksum ) != mpEmbeddedBitmapsMap->end() )
+ {
+ // <use transform="translate(?) scale(?)" xlink:ref="?" >
+ OUString sTransform;
+
+ Point aPoint;
+ ImplMap( rPt, aPoint );
+ if( aPoint.X() != 0 || aPoint.Y() != 0 )
+ sTransform = "translate(" + OUString::number( aPoint.X() ) + ", " + OUString::number( aPoint.Y() ) + ")";
+
+ Size aSize;
+ ImplMap( rSz, aSize );
+
+ MapMode aSourceMode( MapUnit::MapPixel );
+ Size aPrefSize = OutputDevice::LogicToLogic( rSrcSz, aSourceMode, maTargetMapMode );
+ Fraction aFractionX( aSize.Width(), aPrefSize.Width() );
+ Fraction aFractionY( aSize.Height(), aPrefSize.Height() );
+ double scaleX = rtl_math_round( double(aFractionX), 3, rtl_math_RoundingMode::rtl_math_RoundingMode_Corrected );
+ double scaleY = rtl_math_round( double(aFractionY), 3, rtl_math_RoundingMode::rtl_math_RoundingMode_Corrected );
+ if( !rtl_math_approxEqual( scaleX, 1.0 ) || !rtl_math_approxEqual( scaleY, 1.0 ) )
+ sTransform += " scale(" + OUString::number( double(aFractionX) ) + ", " + OUString::number( double(aFractionY) ) + ")";
+
+ if( !sTransform.isEmpty() )
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTransform, sTransform );
+
+ // referenced bitmap template
+ OUString sRefId = "#bitmap(" + OUString::number( nChecksum ) + ")";
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, sRefId );
+
+ SvXMLElementExport aRefElem( mrExport, XML_NAMESPACE_NONE, "use", true, true );
+ return;
+ }
+ }
BitmapEx aBmpEx( rBmpEx );
const tools::Rectangle aBmpRect( Point(), rBmpEx.GetSizePixel() );
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index b7d03d3ee8c6..1fa351f10382 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -57,6 +57,8 @@ using namespace ::com::sun::star::xml::sax;
#define SVGWRITER_WRITE_TEXT 0x00000002
#define SVGWRITER_NO_SHAPE_COMMENTS 0x01000000
+// This must match the same type definition in svgexport.hxx
+typedef std::unordered_map< BitmapChecksum, std::unique_ptr< GDIMetaFile > > MetaBitmapActionMap;
struct SVGState
{
@@ -315,6 +317,7 @@ private:
MapMode maTargetMapMode;
bool mbClipAttrChanged;
bool mbIsPlaceholderShape;
+ const MetaBitmapActionMap* mpEmbeddedBitmapsMap;
tools::Long ImplMap( sal_Int32 nVal ) const;
@@ -370,6 +373,8 @@ public:
const OUString* pElementId = nullptr,
const Reference< css::drawing::XShape >* pXShape = nullptr,
const GDIMetaFile* pTextEmbeddedBitmapMtf = nullptr );
+
+ void SetEmbeddedBitmapRefs( const MetaBitmapActionMap* pEmbeddedBitmapsMap );
void StartMask(const Point& rDestPt, const Size& rDestSize, const Gradient& rGradient,
sal_uInt32 nWriteFlags, OUString* pTextStyle = nullptr);
};