summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Cecchetti <marco.cecchetti@collabora.com>2021-01-22 19:31:26 +0100
committerMarco Cecchetti <marco.cecchetti@collabora.com>2021-01-26 12:33:22 +0100
commit87a3bbbf9088da4afae97d8209ddc7eae1979a07 (patch)
tree5c2756a14be8662e361b5d9383f186db85cc4b3e
parent7ea4ee17da49f4ddce1d4444b02557482c755b12 (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>
-rw-r--r--filter/source/svg/svgexport.cxx159
-rw-r--r--filter/source/svg/svgfilter.hxx5
-rw-r--r--filter/source/svg/svgwriter.cxx55
-rw-r--r--filter/source/svg/svgwriter.hxx5
4 files changed, 198 insertions, 26 deletions
diff --git a/filter/source/svg/svgexport.cxx b/filter/source/svg/svgexport.cxx
index 896d0ef4179f..d791780d408d 100644
--- a/filter/source/svg/svgexport.cxx
+++ b/filter/source/svg/svgexport.cxx
@@ -421,6 +421,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();
@@ -429,19 +435,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;
@@ -449,37 +452,95 @@ BitmapChecksum GetBitmapChecksum( const MetaAction* pAction )
return nChecksum;
}
-} // end anonymous namespace
+static 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 )
{
+ 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;
}
+}
+
+static 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
{
@@ -872,6 +933,8 @@ bool SVGFilter::implExportDocument()
implExportTextShapeIndex();
implEmbedBulletGlyphs();
implExportTextEmbeddedBitmaps();
+ implExportBackgroundBitmaps();
+ mpSVGWriter->SetEmbeddedBitmapRefs( &maBitmapActionMap );
}
// #i124608# export a given object selection, so no MasterPage export at all
@@ -1427,6 +1490,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
@@ -2081,10 +2169,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() )
{
@@ -2094,8 +2180,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 );
}
@@ -2277,10 +2362,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 c4b31eef77a7..530981efd266 100644
--- a/filter/source/svg/svgfilter.hxx
+++ b/filter/source/svg/svgfilter.hxx
@@ -163,6 +163,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;
@@ -221,6 +224,7 @@ private:
UOStringMap mTextShapeIdListMap;
MetaBitmapActionSet mEmbeddedBitmapActionSet;
ObjectMap mEmbeddedBitmapActionMap;
+ MetaBitmapActionMap maBitmapActionMap;
std::vector< Reference< css::drawing::XDrawPage > > mMasterPageTargets;
Link<EditFieldInfo*,void> maOldFieldHdl;
@@ -240,6 +244,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 7ad9fbe74666..653be99b0444 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -1471,7 +1471,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();
}
@@ -1738,7 +1743,8 @@ SVGActionWriter::SVGActionWriter( SVGExport& rExport, SVGFontExport& rFontExport
maAttributeWriter( rExport, rFontExport, mrCurrentState ),
maTextWriter( rExport, maAttributeWriter ),
mbClipAttrChanged( false ),
- mbIsPlaceholderShape( false )
+ mbIsPlaceholderShape( false ),
+ mpEmbeddedBitmapsMap( nullptr )
{
mpVDev = VclPtr<VirtualDevice>::Create();
mpVDev->EnableOutput( false );
@@ -1881,7 +1887,6 @@ OUString SVGActionWriter::GetPathString( const tools::PolyPolygon& rPolyPoly, bo
return aPathData.makeStringAndClear();
}
-
BitmapChecksum SVGActionWriter::GetChecksum( const MetaAction* pAction )
{
GDIMetaFile aMtf;
@@ -1890,6 +1895,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 )
@@ -2751,6 +2763,43 @@ void SVGActionWriter::ImplWriteBmp( const BitmapEx& rBmpEx,
{
if( !!rBmpEx )
{
+ 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() );
const tools::Rectangle aSrcRect( rSrcPt, rSrcSz );
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index eeaf840807fb..ba8037d1ea91 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -77,6 +77,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
{
@@ -333,6 +335,7 @@ private:
MapMode maTargetMapMode;
bool mbClipAttrChanged;
bool mbIsPlaceholderShape;
+ const MetaBitmapActionMap* mpEmbeddedBitmapsMap;
long ImplMap( sal_Int32 nVal ) const;
@@ -388,6 +391,8 @@ public:
const OUString* pElementId = nullptr,
const Reference< css::drawing::XShape >* pXShape = nullptr,
const GDIMetaFile* pTextEmbeddedBitmapMtf = nullptr );
+
+ void SetEmbeddedBitmapRefs( const MetaBitmapActionMap* pEmbeddedBitmapsMap );
};