include/oox/export/drawingml.hxx | 8 +++-- include/oox/export/vmlexport.hxx | 6 ++- oox/source/export/drawingml.cxx | 31 ++++++++++++++----- oox/source/export/vmlexport.cxx | 10 +++--- sw/qa/extras/ooxmlexport/data/tdf118535.odt |binary sw/qa/extras/ooxmlexport/ooxmlexport16.cxx | 13 ++++++++ sw/source/filter/ww8/docxattributeoutput.cxx | 42 ++++++++++++++++++++------- sw/source/filter/ww8/docxattributeoutput.hxx | 11 +++---- sw/source/filter/ww8/docxexport.cxx | 4 -- 9 files changed, 88 insertions(+), 37 deletions(-)
New commits: commit 797fef38612fb2fd62d1f6591619b9361e526bca Author: Daniel Arato (NISZ) <arato.dan...@nisz.hu> AuthorDate: Tue Mar 9 14:11:11 2021 +0100 Commit: László Németh <nem...@numbertext.org> CommitDate: Fri Mar 26 13:07:57 2021 +0100 tdf#118535 DOCX export: save header image once Writer used to dump the same image file as many times as it was featured in different headers or footers in the document, bloating the .docx file size. This is countered by making all "relationships" in the header*.xml.rels files point to the same image. Change-Id: I44d72630289c721d58d8f7e208517df2f1fe621c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112656 Tested-by: László Németh <nem...@numbertext.org> Reviewed-by: László Németh <nem...@numbertext.org> diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx index 2cd17e6defb0..cfcad30fa257 100644 --- a/include/oox/export/drawingml.hxx +++ b/include/oox/export/drawingml.hxx @@ -125,8 +125,10 @@ public: virtual void WriteTextBox(css::uno::Reference<css::drawing::XShape> xShape) = 0; /// Look up the RelId of a graphic based on its checksum. virtual OUString FindRelId(BitmapChecksum nChecksum) = 0; - /// Store the RelId of a graphic based on its checksum. - virtual void CacheRelId(BitmapChecksum nChecksum, const OUString& rRelId) = 0; + /// Look up the filename of a graphic based on its checksum. + virtual OUString FindFileName(BitmapChecksum nChecksum) = 0; + /// Store the RelId and filename of a graphic based on its checksum. + virtual void CacheRelId(BitmapChecksum nChecksum, const OUString& rRelId, const OUString& rFileName) = 0; /// Get textbox which belongs to the shape. virtual css::uno::Reference<css::text::XTextFrame> GetUnoTextFrame( css::uno::Reference<css::drawing::XShape> xShape) = 0; @@ -192,7 +194,7 @@ public: void SetBackgroundDark(bool bIsDark) { mbIsBackgroundDark = bIsDark; } /// If bRelPathToMedia is true add "../" to image folder path while adding the image relationship - OUString WriteImage( const Graphic &rGraphic , bool bRelPathToMedia = false); + OUString WriteImage( const Graphic &rGraphic , bool bRelPathToMedia = false, OUString* pFileName = nullptr ); void WriteColor( ::Color nColor, sal_Int32 nAlpha = MAX_PERCENT ); void WriteColor( const OUString& sColorSchemeName, const css::uno::Sequence< css::beans::PropertyValue >& aTransformations, sal_Int32 nAlpha = MAX_PERCENT ); diff --git a/include/oox/export/vmlexport.hxx b/include/oox/export/vmlexport.hxx index dd5edc57c208..9a53a07652c8 100644 --- a/include/oox/export/vmlexport.hxx +++ b/include/oox/export/vmlexport.hxx @@ -67,8 +67,10 @@ public: virtual void WriteVMLTextBox(css::uno::Reference<css::drawing::XShape> xShape) = 0; /// Look up the RelId of a graphic based on its checksum. virtual OUString FindRelId(BitmapChecksum nChecksum) = 0; - /// Store the RelId of a graphic based on its checksum. - virtual void CacheRelId(BitmapChecksum nChecksum, const OUString& rRelId) = 0; + /// Look up the filename of a graphic based on its checksum. + virtual OUString FindFileName(BitmapChecksum nChecksum) = 0; + /// Store the RelId and filename of a graphic based on its checksum. + virtual void CacheRelId(BitmapChecksum nChecksum, const OUString& rRelId, const OUString& rFileName) = 0; protected: VMLTextExport() {} virtual ~VMLTextExport() {} diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index 67f26e71daea..32780296ce89 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -1162,7 +1162,7 @@ const char* DrawingML::GetRelationCompPrefix() const return "unknown"; } -OUString DrawingML::WriteImage( const Graphic& rGraphic , bool bRelPathToMedia ) +OUString DrawingML::WriteImage( const Graphic& rGraphic , bool bRelPathToMedia, OUString* pFileName ) { GfxLink aLink = rGraphic.GetGfxLink (); OUString sMediaType; @@ -1266,15 +1266,18 @@ OUString DrawingML::WriteImage( const Graphic& rGraphic , bool bRelPathToMedia ) sRelationCompPrefix = "../"; else sRelationCompPrefix = GetRelationCompPrefix(); + OUString sPath = OUStringBuffer() + .appendAscii( sRelationCompPrefix.getStr() ) + .appendAscii( sRelPathToMedia.getStr() ) + .append( static_cast<sal_Int32>(mnImageCounter ++) ) + .appendAscii( pExtension ) + .makeStringAndClear(); sRelId = mpFB->addRelation( mpFS->getOutputStream(), oox::getRelationship(Relationship::IMAGE), - OUStringBuffer() - .appendAscii( sRelationCompPrefix.getStr() ) - .appendAscii( sRelPathToMedia.getStr() ) - .append( static_cast<sal_Int32>(mnImageCounter ++) ) - .appendAscii( pExtension ) - .makeStringAndClear() ); + sPath ); + if (pFileName) + *pFileName = sPath; return sRelId; } @@ -1434,6 +1437,7 @@ OUString DrawingML::WriteXGraphicBlip(uno::Reference<beans::XPropertySet> const bool bRelPathToMedia) { OUString sRelId; + OUString sFileName; if (!rxGraphic.is()) return sRelId; @@ -1443,16 +1447,25 @@ OUString DrawingML::WriteXGraphicBlip(uno::Reference<beans::XPropertySet> const { BitmapChecksum nChecksum = aGraphic.GetChecksum(); sRelId = mpTextExport->FindRelId(nChecksum); + sFileName = mpTextExport->FindFileName(nChecksum); } if (sRelId.isEmpty()) { - sRelId = WriteImage(aGraphic, bRelPathToMedia); + sRelId = WriteImage(aGraphic, bRelPathToMedia, &sFileName); if (mpTextExport) { BitmapChecksum nChecksum = aGraphic.GetChecksum(); - mpTextExport->CacheRelId(nChecksum, sRelId); + mpTextExport->CacheRelId(nChecksum, sRelId, sFileName); } } + else + { + // Include the same relation again. This makes it possible to + // reuse an image across different headers. + sRelId = mpFB->addRelation( mpFS->getOutputStream(), + oox::getRelationship(Relationship::IMAGE), + sFileName ); + } mpFS->startElementNS(XML_a, XML_blip, FSNS(XML_r, XML_embed), sRelId); diff --git a/oox/source/export/vmlexport.cxx b/oox/source/export/vmlexport.cxx index 9c6b89ef7dd7..9f8df2279611 100644 --- a/oox/source/export/vmlexport.cxx +++ b/oox/source/export/vmlexport.cxx @@ -741,8 +741,9 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const tools::Rectangle& OUString aImageId = m_pTextExport->FindRelId(nChecksum); if (aImageId.isEmpty()) { - aImageId = m_pTextExport->GetDrawingML().WriteImage(aGraphic); - m_pTextExport->CacheRelId(nChecksum, aImageId); + OUString aFileName; + aImageId = m_pTextExport->GetDrawingML().WriteImage(aGraphic, false, &aFileName); + m_pTextExport->CacheRelId(nChecksum, aImageId, aFileName); } pAttrList->add(FSNS(XML_r, XML_id), OUStringToOString(aImageId, RTL_TEXTENCODING_UTF8)); @@ -763,8 +764,9 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const tools::Rectangle& OUString aImageId = m_pTextExport->FindRelId(nChecksum); if (aImageId.isEmpty()) { - aImageId = m_pTextExport->GetDrawingML().WriteImage(aGraphic); - m_pTextExport->CacheRelId(nChecksum, aImageId); + OUString aFileName; + aImageId = m_pTextExport->GetDrawingML().WriteImage(aGraphic, false, &aFileName); + m_pTextExport->CacheRelId(nChecksum, aImageId, aFileName); } pAttrList->add(FSNS(XML_r, XML_id), OUStringToOString(aImageId, RTL_TEXTENCODING_UTF8)); diff --git a/sw/qa/extras/ooxmlexport/data/tdf118535.odt b/sw/qa/extras/ooxmlexport/data/tdf118535.odt new file mode 100644 index 000000000000..146c6f471a18 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf118535.odt differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx index 28a2edb234bf..ac46467b87f7 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx @@ -18,6 +18,8 @@ #include <com/sun/star/text/XTextViewCursorSupplier.hpp> #include <com/sun/star/text/XTextTable.hpp> #include <com/sun/star/text/XTextTablesSupplier.hpp> +#include <com/sun/star/packages/zip/ZipFileAccess.hpp> +#include <comphelper/configuration.hxx> #include <editeng/escapementitem.hxx> #include <unotools/fltrcfg.hxx> @@ -224,6 +226,17 @@ DECLARE_OOXMLEXPORT_TEST(testTdf138953, "croppedAndRotated.odt") CPPUNIT_ASSERT_EQUAL(sal_Int32(8664), frameRect.Width); } +DECLARE_OOXMLEXPORT_TEST(testTdf118535, "tdf118535.odt") +{ + uno::Reference<packages::zip::XZipFileAccess2> xNameAccess = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory), maTempFile.GetURL()); + CPPUNIT_ASSERT_EQUAL(true, bool(xNameAccess->hasByName("word/media/image1.jpeg"))); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: false + // - Actual : true + // i.e. the embedded picture would have been saved twice. + CPPUNIT_ASSERT_EQUAL(false, bool(xNameAccess->hasByName("word/media/image2.jpeg"))); +} + DECLARE_OOXMLEXPORT_TEST(testTdf133473_shadowSize, "tdf133473.docx") { uno::Reference<drawing::XShape> xShape = getShape(1); diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index c0b0059d464a..46d19f82cec0 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -4893,15 +4893,25 @@ OUString DocxAttributeOutput::FindRelId(BitmapChecksum nChecksum) OUString aRet; if (!m_aSdrRelIdCache.empty() && m_aSdrRelIdCache.top().find(nChecksum) != m_aSdrRelIdCache.top().end()) - aRet = m_aSdrRelIdCache.top()[nChecksum]; + aRet = m_aSdrRelIdCache.top()[nChecksum].first; return aRet; } -void DocxAttributeOutput::CacheRelId(BitmapChecksum nChecksum, const OUString& rRelId) +OUString DocxAttributeOutput::FindFileName(BitmapChecksum nChecksum) +{ + OUString aRet; + + if (!m_aSdrRelIdCache.empty() && m_aSdrRelIdCache.top().find(nChecksum) != m_aSdrRelIdCache.top().end()) + aRet = m_aSdrRelIdCache.top()[nChecksum].second; + + return aRet; +} + +void DocxAttributeOutput::CacheRelId(BitmapChecksum nChecksum, const OUString& rRelId, const OUString& rFileName) { if (!m_aSdrRelIdCache.empty()) - m_aSdrRelIdCache.top()[nChecksum] = rRelId; + m_aSdrRelIdCache.top()[nChecksum] = std::pair(rRelId, rFileName); } uno::Reference<css::text::XTextFrame> DocxAttributeOutput::GetUnoTextFrame( @@ -4910,9 +4920,9 @@ uno::Reference<css::text::XTextFrame> DocxAttributeOutput::GetUnoTextFrame( return SwTextBoxHelper::getUnoTextFrame(xShape); } -OString DocxAttributeOutput::getExistingGraphicRelId(BitmapChecksum nChecksum) +std::pair<OString, OUString> DocxAttributeOutput::getExistingGraphicRelId(BitmapChecksum nChecksum) { - OString aResult; + std::pair<OString, OUString> aResult; if (m_aRelIdCache.empty()) return aResult; @@ -4927,10 +4937,10 @@ OString DocxAttributeOutput::getExistingGraphicRelId(BitmapChecksum nChecksum) return aResult; } -void DocxAttributeOutput::cacheGraphicRelId(BitmapChecksum nChecksum, OString const & rRelId) +void DocxAttributeOutput::cacheGraphicRelId(BitmapChecksum nChecksum, OString const & rRelId, OUString const & rFileName) { if (!m_aRelIdCache.empty()) - m_aRelIdCache.top().emplace(nChecksum, rRelId); + m_aRelIdCache.top().emplace(nChecksum, std::pair(rRelId, rFileName)); } void DocxAttributeOutput::FlyFrameGraphic( const SwGrfNode* pGrfNode, const Size& rSize, const SwFlyFrameFormat* pOLEFrameFormat, SwOLENode* pOLENode, const SdrObject* pSdrObj ) @@ -4979,17 +4989,29 @@ void DocxAttributeOutput::FlyFrameGraphic( const SwGrfNode* pGrfNode, const Size aGraphic = *pOLENode->GetGraphic(); BitmapChecksum aChecksum = aGraphic.GetChecksum(); - aRelId = getExistingGraphicRelId(aChecksum); + OUString aFileName; + std::tie(aRelId, aFileName) = getExistingGraphicRelId(aChecksum); + OUString aImageId; if (aRelId.isEmpty()) { // Not in cache, then need to write it. m_rDrawingML.SetFS( m_pSerializer ); // to be sure that we write to the right stream - OUString aImageId = m_rDrawingML.WriteImage(aGraphic); + aImageId = m_rDrawingML.WriteImage(aGraphic, false, &aFileName); + + aRelId = OUStringToOString( aImageId, RTL_TEXTENCODING_UTF8 ); + cacheGraphicRelId(aChecksum, aRelId, aFileName); + } + else + { + // Include the same relation again. This makes it possible to + // reuse an image across different headers. + aImageId = m_rDrawingML.GetFB()->addRelation( m_pSerializer->getOutputStream(), + oox::getRelationship(Relationship::IMAGE), + aFileName ); aRelId = OUStringToOString( aImageId, RTL_TEXTENCODING_UTF8 ); - cacheGraphicRelId(aChecksum, aRelId); } nImageType = XML_embed; diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 423396196153..565741bd0afe 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -960,14 +960,14 @@ private: // store hardcoded value which was set during import. sal_Int32 m_nParaBeforeSpacing,m_nParaAfterSpacing; - OString getExistingGraphicRelId(BitmapChecksum aChecksum); - void cacheGraphicRelId(BitmapChecksum nChecksum, OString const & rRelId); + std::pair<OString, OUString> getExistingGraphicRelId(BitmapChecksum aChecksum); + void cacheGraphicRelId(BitmapChecksum nChecksum, OString const & rRelId, OUString const & rFileName); /// RelId <-> Graphic* cache, so that in case of alternate content, the same graphic only gets written once. - std::stack< std::map<BitmapChecksum, OString> > m_aRelIdCache; + std::stack< std::map<BitmapChecksum, std::pair<OString, OUString>> > m_aRelIdCache; /// RelId <-> BitmapChecksum cache, similar to m_aRelIdCache, but used for non-Writer graphics, handled in oox. - std::stack< std::map<BitmapChecksum, OUString> > m_aSdrRelIdCache; + std::stack< std::map<BitmapChecksum, std::pair<OUString, OUString>> > m_aSdrRelIdCache; /// members to control the existence of grabbagged SDT properties in the paragraph sal_Int32 m_nParagraphSdtPrToken; @@ -1026,7 +1026,8 @@ public: /// DMLTextExport virtual void WriteTextBox(css::uno::Reference<css::drawing::XShape> xShape) override; virtual OUString FindRelId(BitmapChecksum nChecksum) override; - virtual void CacheRelId(BitmapChecksum nChecksum, const OUString& rRelId) override; + virtual OUString FindFileName(BitmapChecksum nChecksum) override; + virtual void CacheRelId(BitmapChecksum nChecksum, const OUString& rRelId, const OUString& rFileName) override; virtual css::uno::Reference<css::text::XTextFrame> GetUnoTextFrame( css::uno::Reference<css::drawing::XShape> xShape) override; virtual oox::drawingml::DrawingML& GetDrawingML() override; diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index 89fac4af6e0a..20a6f906e72d 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -818,15 +818,11 @@ void DocxExport::WriteHeaderFooter( const SwFormat* pFormat, bool bHeader, const SetFS( pFS ); { DocxTableExportContext aTableExportContext(*m_pAttrOutput); - //When the stream changes the cache which is maintained for the graphics in case of alternate content is not cleared. - //So clearing the alternate content graphic cache. - m_pAttrOutput->PushRelIdCache(); // do the work if (pFormat == nullptr) AttrOutput().EmptyParagraph(); else WriteHeaderFooterText(*pFormat, bHeader); - m_pAttrOutput->PopRelIdCache(); m_pAttrOutput->EndParaSdtBlock(); } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits