[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-6.4' - filter/source

Marco Cecchetti (via logerrit) logerrit at kemper.freedesktop.org
Tue Jan 26 11:34:09 UTC 2021


 filter/source/svg/svgexport.cxx |  159 ++++++++++++++++++++++++++++++++++------
 filter/source/svg/svgfilter.hxx |    5 +
 filter/source/svg/svgwriter.cxx |   55 +++++++++++++
 filter/source/svg/svgwriter.hxx |    5 +
 4 files changed, 198 insertions(+), 26 deletions(-)

New commits:
commit 87a3bbbf9088da4afae97d8209ddc7eae1979a07
Author:     Marco Cecchetti <marco.cecchetti at collabora.com>
AuthorDate: Fri Jan 22 19:31:26 2021 +0100
Commit:     Marco Cecchetti <marco.cecchetti at collabora.com>
CommitDate: Tue Jan 26 12:33:22 2021 +0100

    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 at gmail.com>
    Reviewed-by: Marco Cecchetti <marco.cecchetti at collabora.com>

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 );
 };
 
 


More information about the Libreoffice-commits mailing list