From aea8043bc5f5187498fa450505d6de9d6986e2a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=BCnde=20T=C3=B3th?= Date: Tue, 22 Mar 2022 09:47:57 +0100 Subject: [PATCH] tdf#74670 tdf#91286 PPTX XLSX export: save image once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Impress and Calc used to dump the same image file as many times as it was featured in the document, resulting redundant, sometimes huge documents. Note: using only checksum to recognize image duplication is a regression, because checksum collision results image loss. This is a very unlikely event, and the following commits have got the same problem. The solution is comparing the images with the same checksum byte for byte. See also commit b484e9814c66d8d51cea974390963a6944bc9d73 "tdf#83227 oox: reuse RelId in DML/VML export for the same graphic" and commit 797fef38612fb2fd62d1f6591619b9361e526bca "tdf#118535 DOCX export: save header image once". Change-Id: I9f233d521941381746634cf4f9b5991da0dadda9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131928 Tested-by: László Németh Reviewed-by: László Németh --- include/oox/export/drawingml.hxx | 8 +- oox/source/export/drawingml.cxx | 207 +++++++++++++---------- sc/qa/unit/data/ods/tdf91286.ods | Bin 0 -> 10152 bytes sc/qa/unit/subsequent_export_test2.cxx | 26 +++ sc/source/filter/excel/xestream.cxx | 4 + sd/qa/unit/data/odp/tdf74670.odp | Bin 0 -> 11786 bytes sd/qa/unit/export-tests-ooxml3.cxx | 26 +++ sd/source/filter/eppt/pptx-epptooxml.cxx | 2 + 8 files changed, 182 insertions(+), 91 deletions(-) create mode 100644 sc/qa/unit/data/ods/tdf91286.ods create mode 100644 sd/qa/unit/data/odp/tdf74670.odp diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx index fb125dd647ad..9a7f744520c8 100644 --- a/include/oox/export/drawingml.hxx +++ b/include/oox/export/drawingml.hxx @@ -21,7 +21,9 @@ #define INCLUDED_OOX_EXPORT_DRAWINGML_HXX #include +#include #include +#include #include #include @@ -41,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -150,6 +153,7 @@ private: static std::map maWdpCache; static sal_Int32 mnDrawingMLCount; static sal_Int32 mnVmlCount; + static std::stack> maExportGraphics; /// To specify where write eg. the images to (like 'ppt', or 'word' - according to the OPC). DocumentType meDocumentType; @@ -342,9 +346,11 @@ public: sal_Int32 getBulletMarginIndentation (const css::uno::Reference< css::beans::XPropertySet >& rXPropSet,sal_Int16 nLevel, std::u16string_view propName); static void ResetCounters(); - static void ResetMlCounters(); + static void PushExportGraphics(); + static void PopExportGraphics(); + static sal_Int32 getNewDrawingUniqueId() { return ++mnDrawingMLCount; } static sal_Int32 getNewVMLUniqueId() { return ++mnVmlCount; } diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index a790a643abc0..a99a0474a458 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -111,7 +111,6 @@ #include #include #include -#include #include #include #include @@ -237,6 +236,7 @@ int DrawingML::mnWdpImageCounter = 1; std::map DrawingML::maWdpCache; sal_Int32 DrawingML::mnDrawingMLCount = 0; sal_Int32 DrawingML::mnVmlCount = 0; +std::stack> DrawingML::maExportGraphics; sal_Int16 DrawingML::GetScriptType(const OUString& rStr) { @@ -275,6 +275,16 @@ void DrawingML::ResetMlCounters() mnVmlCount = 0; } +void DrawingML::PushExportGraphics() +{ + maExportGraphics.emplace(); +} + +void DrawingML::PopExportGraphics() +{ + maExportGraphics.pop(); +} + bool DrawingML::GetProperty( const Reference< XPropertySet >& rXPropertySet, const OUString& aName ) { try @@ -1264,113 +1274,130 @@ const char* DrawingML::GetRelationCompPrefix() const OUString DrawingML::WriteImage( const Graphic& rGraphic , bool bRelPathToMedia, OUString* pFileName ) { GfxLink aLink = rGraphic.GetGfxLink (); + BitmapChecksum aChecksum = rGraphic.GetChecksum(); OUString sMediaType; const char* pExtension = ""; OUString sRelId; + OUString sPath; - SvMemoryStream aStream; - const void* aData = aLink.GetData(); - std::size_t nDataSize = aLink.GetDataSize(); - - switch ( aLink.GetType() ) + // tdf#74670 tdf#91286 Save image only once (this is no problem for DOCX) + if (GetDocumentType() != DOCUMENT_DOCX && !maExportGraphics.empty()) { - case GfxLinkType::NativeGif: - sMediaType = "image/gif"; - pExtension = ".gif"; - break; + auto aIterator = maExportGraphics.top().find(aChecksum); + if (aIterator != maExportGraphics.top().end()) + sPath = aIterator->second; + } - // #i15508# added BMP type for better exports - // export not yet active, so adding for reference (not checked) - case GfxLinkType::NativeBmp: - sMediaType = "image/bmp"; - pExtension = ".bmp"; - break; + if (sPath.isEmpty()) + { + SvMemoryStream aStream; + const void* aData = aLink.GetData(); + std::size_t nDataSize = aLink.GetDataSize(); - case GfxLinkType::NativeJpg: - sMediaType = "image/jpeg"; - pExtension = ".jpeg"; - break; - case GfxLinkType::NativePng: - sMediaType = "image/png"; - pExtension = ".png"; - break; - case GfxLinkType::NativeTif: - sMediaType = "image/tiff"; - pExtension = ".tif"; - break; - case GfxLinkType::NativeWmf: - sMediaType = "image/x-wmf"; - pExtension = ".wmf"; - break; - case GfxLinkType::NativeMet: - sMediaType = "image/x-met"; - pExtension = ".met"; - break; - case GfxLinkType::NativePct: - sMediaType = "image/x-pict"; - pExtension = ".pct"; - break; - case GfxLinkType::NativeMov: - sMediaType = "application/movie"; - pExtension = ".MOV"; - break; - default: + switch (aLink.GetType()) { - GraphicType aType = rGraphic.GetType(); - if ( aType == GraphicType::Bitmap || aType == GraphicType::GdiMetafile) + case GfxLinkType::NativeGif: + sMediaType = "image/gif"; + pExtension = ".gif"; + break; + + // #i15508# added BMP type for better exports + // export not yet active, so adding for reference (not checked) + case GfxLinkType::NativeBmp: + sMediaType = "image/bmp"; + pExtension = ".bmp"; + break; + + case GfxLinkType::NativeJpg: + sMediaType = "image/jpeg"; + pExtension = ".jpeg"; + break; + case GfxLinkType::NativePng: + sMediaType = "image/png"; + pExtension = ".png"; + break; + case GfxLinkType::NativeTif: + sMediaType = "image/tiff"; + pExtension = ".tif"; + break; + case GfxLinkType::NativeWmf: + sMediaType = "image/x-wmf"; + pExtension = ".wmf"; + break; + case GfxLinkType::NativeMet: + sMediaType = "image/x-met"; + pExtension = ".met"; + break; + case GfxLinkType::NativePct: + sMediaType = "image/x-pict"; + pExtension = ".pct"; + break; + case GfxLinkType::NativeMov: + sMediaType = "application/movie"; + pExtension = ".MOV"; + break; + default: { - if ( aType == GraphicType::Bitmap ) + GraphicType aType = rGraphic.GetType(); + if (aType == GraphicType::Bitmap || aType == GraphicType::GdiMetafile) { - (void)GraphicConverter::Export( aStream, rGraphic, ConvertDataFormat::PNG ); - sMediaType = "image/png"; - pExtension = ".png"; + if (aType == GraphicType::Bitmap) + { + (void)GraphicConverter::Export(aStream, rGraphic, ConvertDataFormat::PNG); + sMediaType = "image/png"; + pExtension = ".png"; + } + else + { + (void)GraphicConverter::Export(aStream, rGraphic, ConvertDataFormat::EMF); + sMediaType = "image/x-emf"; + pExtension = ".emf"; + } } else { - (void)GraphicConverter::Export( aStream, rGraphic, ConvertDataFormat::EMF ); - sMediaType = "image/x-emf"; - pExtension = ".emf"; + SAL_WARN("oox.shape", "unhandled graphic type " << static_cast(aType)); + /*Earlier, even in case of unhandled graphic types we were + proceeding to write the image, which would eventually + write an empty image with a zero size, and return a valid + relationID, which is incorrect. + */ + return sRelId; } - } - else - { - SAL_WARN("oox.shape", "unhandled graphic type " << static_cast(aType) ); - /*Earlier, even in case of unhandled graphic types we were - proceeding to write the image, which would eventually - write an empty image with a zero size, and return a valid - relationID, which is incorrect. - */ - return sRelId; - } - aData = aStream.GetData(); - nDataSize = aStream.GetEndOfData(); - break; + aData = aStream.GetData(); + nDataSize = aStream.GetEndOfData(); + break; + } } + + Reference xOutStream = mpFB->openFragmentStream( + OUStringBuffer() + .appendAscii(GetComponentDir()) + .append("/media/image" + OUString::number(mnImageCounter)) + .appendAscii(pExtension) + .makeStringAndClear(), + sMediaType); + xOutStream->writeBytes(Sequence(static_cast(aData), nDataSize)); + xOutStream->closeOutput(); + + const OString sRelPathToMedia = "media/image"; + OString sRelationCompPrefix; + if (bRelPathToMedia) + sRelationCompPrefix = "../"; + else + sRelationCompPrefix = GetRelationCompPrefix(); + sPath = OUStringBuffer() + .appendAscii(sRelationCompPrefix.getStr()) + .appendAscii(sRelPathToMedia.getStr()) + .append(static_cast(mnImageCounter++)) + .appendAscii(pExtension) + .makeStringAndClear(); + + if (GetDocumentType() != DOCUMENT_DOCX && !maExportGraphics.empty()) + maExportGraphics.top()[aChecksum] = sPath; } - Reference< XOutputStream > xOutStream = mpFB->openFragmentStream( OUStringBuffer() - .appendAscii( GetComponentDir() ) - .append( "/media/image" + - OUString::number(mnImageCounter) ) - .appendAscii( pExtension ) - .makeStringAndClear(), - sMediaType ); - xOutStream->writeBytes( Sequence< sal_Int8 >( static_cast(aData), nDataSize ) ); - xOutStream->closeOutput(); - - const OString sRelPathToMedia = "media/image"; - OString sRelationCompPrefix; - if ( bRelPathToMedia ) - sRelationCompPrefix = "../"; - else - sRelationCompPrefix = GetRelationCompPrefix(); - OUString sPath = OUStringBuffer() - .appendAscii( sRelationCompPrefix.getStr() ) - .appendAscii( sRelPathToMedia.getStr() ) - .append( static_cast(mnImageCounter ++) ) - .appendAscii( pExtension ) - .makeStringAndClear(); sRelId = mpFB->addRelation( mpFS->getOutputStream(), oox::getRelationship(Relationship::IMAGE), sPath ); diff --git a/sc/qa/unit/data/ods/tdf91286.ods b/sc/qa/unit/data/ods/tdf91286.ods new file mode 100644 index 0000000000000000000000000000000000000000..8bc260584e1061417a85fa70a46d6ce5170e545a GIT binary patch literal 10152 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 QfCu~g1UuJ0Q(fo&A9CV@v;Y7A literal 0 HcmV?d00001 diff --git a/sc/qa/unit/subsequent_export_test2.cxx b/sc/qa/unit/subsequent_export_test2.cxx index 4d22a2ffdbc6..ee3c14117307 100644 --- a/sc/qa/unit/subsequent_export_test2.cxx +++ b/sc/qa/unit/subsequent_export_test2.cxx @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -186,6 +187,7 @@ public: void testTdf130104_XLSXIndent(); void testWholeRowBold(); void testXlsxRowsOrder(); + void testTdf91286(); CPPUNIT_TEST_SUITE(ScExportTest2); @@ -305,6 +307,7 @@ public: CPPUNIT_TEST(testTdf130104_XLSXIndent); CPPUNIT_TEST(testWholeRowBold); CPPUNIT_TEST(testXlsxRowsOrder); + CPPUNIT_TEST(testTdf91286); CPPUNIT_TEST_SUITE_END(); @@ -3110,6 +3113,29 @@ void ScExportTest2::testXlsxRowsOrder() xDocSh->DoClose(); } +void ScExportTest2::testTdf91286() +{ + ScDocShellRef xDocSh = loadDoc(u"tdf91286.", FORMAT_ODS); + CPPUNIT_ASSERT(xDocSh.is()); + std::shared_ptr pTemp = exportTo(*xDocSh, FORMAT_XLSX); + xDocSh->DoClose(); + + Reference xNameAccess + = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory), + pTemp->GetURL()); + const Sequence aNames(xNameAccess->getElementNames()); + int nImageFiles = 0; + for (const auto& rElementName : aNames) + if (rElementName.startsWith("xl/media/image")) + nImageFiles++; + + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 2 + // i.e. the embedded picture would have been saved twice. + CPPUNIT_ASSERT_EQUAL(1, nImageFiles); +} + CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest2); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sc/source/filter/excel/xestream.cxx b/sc/source/filter/excel/xestream.cxx index 08048e922111..b94959292891 100644 --- a/sc/source/filter/excel/xestream.cxx +++ b/sc/source/filter/excel/xestream.cxx @@ -1023,6 +1023,7 @@ bool XclExpXmlStream::exportDocument() // Instead, write via XOutputStream instance. tools::SvRef rStorage = static_cast(nullptr); drawingml::DrawingML::ResetMlCounters(); + drawingml::DrawingML::PushExportGraphics(); XclExpRootData aData( EXC_BIFF8, *pShell->GetMedium (), rStorage, rDoc, @@ -1124,6 +1125,9 @@ bool XclExpXmlStream::exportDocument() if (xStatusIndicator.is()) xStatusIndicator->end(); mpRoot = nullptr; + + drawingml::DrawingML::PopExportGraphics(); + return true; } diff --git a/sd/qa/unit/data/odp/tdf74670.odp b/sd/qa/unit/data/odp/tdf74670.odp new file mode 100644 index 0000000000000000000000000000000000000000..98e223eb0725b48bedd125786ff3cd3f0a63f8c8 GIT binary patch literal 11786 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 literal 0 HcmV?d00001 diff --git a/sd/qa/unit/export-tests-ooxml3.cxx b/sd/qa/unit/export-tests-ooxml3.cxx index 776d436b7edf..3f4bec336ef1 100644 --- a/sd/qa/unit/export-tests-ooxml3.cxx +++ b/sd/qa/unit/export-tests-ooxml3.cxx @@ -106,6 +106,7 @@ public: void testTdf147121(); void testTdf140912_PicturePlaceholder(); void testEnhancedPathViewBox(); + void testTdf74670(); CPPUNIT_TEST_SUITE(SdOOXMLExportTest3); @@ -182,6 +183,7 @@ public: CPPUNIT_TEST(testTdf147121); CPPUNIT_TEST(testTdf140912_PicturePlaceholder); CPPUNIT_TEST(testEnhancedPathViewBox); + CPPUNIT_TEST(testTdf74670); CPPUNIT_TEST_SUITE_END(); virtual void registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx) override @@ -1893,6 +1895,30 @@ void SdOOXMLExportTest3::testEnhancedPathViewBox() CPPUNIT_ASSERT_EQUAL(sal_Int32(2045), aBoundRectangle.Width); } +void SdOOXMLExportTest3::testTdf74670() +{ + ::sd::DrawDocShellRef xDocShRef + = loadURL(m_directories.getURLFromSrc(u"/sd/qa/unit/data/odp/tdf74670.odp"), ODP); + utl::TempFile tmpfile; + xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tmpfile); + xDocShRef->DoClose(); + + uno::Reference xNameAccess + = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory), + tmpfile.GetURL()); + const uno::Sequence aNames(xNameAccess->getElementNames()); + int nImageFiles = 0; + for (const auto& rElementName : aNames) + if (rElementName.startsWith("ppt/media/image")) + nImageFiles++; + + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 2 + // i.e. the embedded picture would have been saved twice. + CPPUNIT_ASSERT_EQUAL(1, nImageFiles); +} + CPPUNIT_TEST_SUITE_REGISTRATION(SdOOXMLExportTest3); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sd/source/filter/eppt/pptx-epptooxml.cxx b/sd/source/filter/eppt/pptx-epptooxml.cxx index 07be6521d678..8823cbd00d53 100644 --- a/sd/source/filter/eppt/pptx-epptooxml.cxx +++ b/sd/source/filter/eppt/pptx-epptooxml.cxx @@ -428,6 +428,7 @@ bool PowerPointExport::importDocument() noexcept bool PowerPointExport::exportDocument() { DrawingML::ResetCounters(); + DrawingML::PushExportGraphics(); maShapeMap.clear(); mXModel = getModel(); @@ -504,6 +505,7 @@ bool PowerPointExport::exportDocument() commitStorage(); + DrawingML::PopExportGraphics(); maShapeMap.clear(); maAuthors.clear(); maRelId.clear();