diff options
-rw-r--r-- | filter/source/svg/svgexport.cxx | 159 | ||||
-rw-r--r-- | filter/source/svg/svgfilter.hxx | 5 | ||||
-rw-r--r-- | filter/source/svg/svgwriter.cxx | 55 | ||||
-rw-r--r-- | filter/source/svg/svgwriter.hxx | 5 |
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 ); }; |