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

Reply via email to