summaryrefslogtreecommitdiff
path: root/filter
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-02-05 15:24:32 +0100
commitc3954cda3a0332ec185159ae9f292f9caeb13ee8 (patch)
tree0e3b7973116cd19731c70d99f28a849d05258fa6 /filter
parent73f807f8b1f558b509012b89d73bb497722bcaad (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/+/110478
Diffstat (limited to 'filter')
-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 094dfe2a884d..a2357b605b18 100644
--- a/filter/source/svg/svgexport.cxx
+++ b/filter/source/svg/svgexport.cxx
@@ -419,6 +419,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();
@@ -427,19 +433,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;
@@ -447,37 +450,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
{
@@ -882,6 +943,8 @@ bool SVGFilter::implExportDocument()
implExportTextShapeIndex();
implEmbedBulletGlyphs();
implExportTextEmbeddedBitmaps();
+ implExportBackgroundBitmaps();
+ mpSVGWriter->SetEmbeddedBitmapRefs( &maBitmapActionMap );
}
// #i124608# export a given object selection, so no MasterPage export at all
@@ -1441,6 +1504,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
@@ -2098,10 +2186,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() )
{
@@ -2111,8 +2197,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 );
}
@@ -2294,10 +2379,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 683f3f1591f2..64dc619dc739 100644
--- a/filter/source/svg/svgfilter.hxx
+++ b/filter/source/svg/svgfilter.hxx
@@ -171,6 +171,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;
@@ -230,6 +233,7 @@ private:
UOStringMap mTextShapeIdListMap;
MetaBitmapActionSet mEmbeddedBitmapActionSet;
ObjectMap mEmbeddedBitmapActionMap;
+ MetaBitmapActionMap maBitmapActionMap;
std::vector< Reference< css::drawing::XDrawPage > > mMasterPageTargets;
Link<EditFieldInfo*,void> maOldFieldHdl;
@@ -249,6 +253,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 71f3581b7a15..4f4bea2dc98b 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -1473,7 +1473,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();
}
@@ -1740,7 +1745,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 );
@@ -1883,7 +1889,6 @@ OUString SVGActionWriter::GetPathString( const tools::PolyPolygon& rPolyPoly, bo
return aPathData.makeStringAndClear();
}
-
BitmapChecksum SVGActionWriter::GetChecksum( const MetaAction* pAction )
{
GDIMetaFile aMtf;
@@ -1892,6 +1897,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 )
@@ -2753,6 +2765,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 541a39eaa843..c5725d63e491 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 );
};