sw/qa/extras/htmlexport/htmlexport.cxx | 32 +++++++++++++ sw/source/filter/html/htmlflywriter.cxx | 76 ++++++++++++++++++++------------ sw/source/filter/html/htmlplug.cxx | 5 +- sw/source/filter/html/wrthtml.hxx | 3 - 4 files changed, 86 insertions(+), 30 deletions(-)
New commits: commit 3fe661041aadbfd945a20afe2310a19f5e76976e Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Jun 1 14:50:01 2021 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue Jun 1 16:13:11 2021 +0200 sw XHTML / reqif export: write PNG fallback for non-PNG images - split up OutHTML_Image, so it's possible to write <object type="image/jpeg"> <object type="image/png"/> </object> - write PNG inside the original image - disable this when the original format is PNG already Change-Id: I3ad40089ee2b02b8850823dd536c58ac59af37f2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116544 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx index 9ace986366f3..275896ed7ccb 100644 --- a/sw/qa/extras/htmlexport/htmlexport.cxx +++ b/sw/qa/extras/htmlexport/htmlexport.cxx @@ -1558,6 +1558,38 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifEmbedPNGDirectly) assertXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object", "type", "image/png"); } +CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifEmbedJPGDirectly) +{ + // Given a document with an image: + loadURL("private:factory/swriter", nullptr); + OUString aImageURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "reqif-ole-img.jpg"; + uno::Sequence<beans::PropertyValue> aArgs = { + comphelper::makePropertyValue("FileName", aImageURL), + }; + dispatchCommand(mxComponent, ".uno:InsertGraphic", aArgs); + + // When exporting to XHTML: + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + uno::Sequence<beans::PropertyValue> aStoreProperties = { + comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")), + comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")), + }; + xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties); + + // Then make sure the JPG is embedded directly, without an RTF wrapper: + SvMemoryStream aStream; + HtmlExportTest::wrapFragment(maTempFile, aStream); + xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + CPPUNIT_ASSERT(pXmlDoc); + assertXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object", "type", "image/jpeg"); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: image/jpeg + // - Actual : image/png + // i.e. first the original JPG data was lost, then the inner PNG fallback was missing. + assertXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object/reqif-xhtml:object", "type", + "image/png"); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/html/htmlflywriter.cxx b/sw/source/filter/html/htmlflywriter.cxx index 09dfa97a5220..a050c9c2056b 100644 --- a/sw/source/filter/html/htmlflywriter.cxx +++ b/sw/source/filter/html/htmlflywriter.cxx @@ -137,7 +137,7 @@ static Writer& OutHTML_FrameFormatAsDivOrSpan( Writer& rWrt, static Writer& OutHTML_FrameFormatAsImage( Writer& rWrt, const SwFrameFormat& rFormat ); static Writer& OutHTML_FrameFormatGrfNode( Writer& rWrt, const SwFrameFormat& rFormat, - bool bInCntnr ); + bool bInCntnr, bool bPNGFallback ); static Writer& OutHTML_FrameFormatAsMarquee( Writer& rWrt, const SwFrameFormat& rFrameFormat, const SdrObject& rSdrObj ); @@ -467,7 +467,7 @@ void SwHTMLWriter::OutFrameFormat( AllHtmlFlags nMode, const SwFrameFormat& rFra OutHTML_FrameFormatTableNode( *this, rFrameFormat ); break; case HtmlOut::GraphicNode: // OK - OutHTML_FrameFormatGrfNode( *this, rFrameFormat, !aContainerStr.isEmpty() ); + OutHTML_FrameFormatGrfNode( *this, rFrameFormat, !aContainerStr.isEmpty(), /*bPNGFallback=*/true ); break; case HtmlOut::OleNode: // OK OutHTML_FrameFormatOLENode( *this, rFrameFormat, !aContainerStr.isEmpty() ); @@ -1192,7 +1192,7 @@ OUString lclWriteOutImap(SwHTMLWriter& rHTMLWrt, const SfxItemSet& rItemSet, con } -Writer& OutHTML_Image( Writer& rWrt, const SwFrameFormat &rFrameFormat, +Writer& OutHTML_ImageStart( HtmlWriter& rHtml, Writer& rWrt, const SwFrameFormat &rFrameFormat, const OUString& rGraphicURL, Graphic const & rGraphic, const OUString& rAlternateText, const Size &rRealSize, HtmlFrmOpts nFrameOpts, @@ -1228,8 +1228,6 @@ Writer& OutHTML_Image( Writer& rWrt, const SwFrameFormat &rFrameFormat, if( rHTMLWrt.m_bLFPossible ) rHTMLWrt.OutNewLine( true ); - HtmlWriter aHtml(rWrt.Strm(), rHTMLWrt.maNamespace); - // <a name=...></a>...<img ...> if( pMarkType && !rFrameFormat.GetName().isEmpty() ) { @@ -1260,22 +1258,22 @@ Writer& OutHTML_Image( Writer& rWrt, const SwFrameFormat &rFrameFormat, if( !aMapURL.isEmpty() || !aName.isEmpty() || !aTarget.isEmpty() || bEvents ) { - aHtml.start(OOO_STRING_SVTOOLS_HTML_anchor); + rHtml.start(OOO_STRING_SVTOOLS_HTML_anchor); // Output "href" element if a link or macro exists if( !aMapURL.isEmpty() || bEvents ) { - aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_href, OUStringToOString(rHTMLWrt.convertHyperlinkHRefValue(aMapURL), RTL_TEXTENCODING_UTF8)); + rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_href, OUStringToOString(rHTMLWrt.convertHyperlinkHRefValue(aMapURL), RTL_TEXTENCODING_UTF8)); } if( !aName.isEmpty() ) { - aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_name, OUStringToOString(aName, RTL_TEXTENCODING_UTF8)); + rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_name, OUStringToOString(aName, RTL_TEXTENCODING_UTF8)); } if( !aTarget.isEmpty() ) { - aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_target, OUStringToOString(aTarget, RTL_TEXTENCODING_UTF8)); + rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_target, OUStringToOString(aTarget, RTL_TEXTENCODING_UTF8)); } if( pMacItem ) @@ -1283,7 +1281,7 @@ Writer& OutHTML_Image( Writer& rWrt, const SwFrameFormat &rFrameFormat, const SvxMacroTableDtor& rMacTable = pMacItem->GetMacroTable(); if (!rMacTable.empty()) { - HtmlWriterHelper::applyEvents(aHtml, rMacTable, aAnchorEventTable, rHTMLWrt.m_bCfgStarBasic); + HtmlWriterHelper::applyEvents(rHtml, rMacTable, aAnchorEventTable, rHTMLWrt.m_bCfgStarBasic); } } } @@ -1349,8 +1347,8 @@ Writer& OutHTML_Image( Writer& rWrt, const SwFrameFormat &rFrameFormat, if( pColBorderLine ) { - aHtml.start(OOO_STRING_SVTOOLS_HTML_font); - HtmlWriterHelper::applyColor(aHtml, OOO_STRING_SVTOOLS_HTML_O_color, pColBorderLine->GetColor()); + rHtml.start(OOO_STRING_SVTOOLS_HTML_font); + HtmlWriterHelper::applyColor(rHtml, OOO_STRING_SVTOOLS_HTML_O_color, pColBorderLine->GetColor()); } } @@ -1358,7 +1356,7 @@ Writer& OutHTML_Image( Writer& rWrt, const SwFrameFormat &rFrameFormat, if (bReplacement) // Write replacement graphic of OLE object as <object>. aTag = OOO_STRING_SVTOOLS_HTML_object; - aHtml.start(aTag); + rHtml.start(aTag); OStringBuffer sBuffer; if(rHTMLWrt.mbEmbedImages) @@ -1369,7 +1367,7 @@ Writer& OutHTML_Image( Writer& rWrt, const SwFrameFormat &rFrameFormat, sBuffer.append(OOO_STRING_SVTOOLS_HTML_O_data); sBuffer.append(":"); sBuffer.append(OUStringToOString(aGraphicInBase64, RTL_TEXTENCODING_UTF8)); - aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_src, sBuffer.makeStringAndClear().getStr()); + rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_src, sBuffer.makeStringAndClear().getStr()); } else rHTMLWrt.m_nWarn = WARN_SWG_POOR_LOAD; @@ -1380,14 +1378,14 @@ Writer& OutHTML_Image( Writer& rWrt, const SwFrameFormat &rFrameFormat, OString aAttribute(OOO_STRING_SVTOOLS_HTML_O_src); if (bReplacement) aAttribute = OOO_STRING_SVTOOLS_HTML_O_data; - aHtml.attribute(aAttribute, sBuffer.makeStringAndClear().getStr()); + rHtml.attribute(aAttribute, sBuffer.makeStringAndClear().getStr()); } if (bReplacement) { // Handle XHTML type attribute for OLE replacement images. if (!rMimeType.isEmpty()) - aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_type, rMimeType.toUtf8()); + rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_type, rMimeType.toUtf8()); } // Events @@ -1396,28 +1394,28 @@ Writer& OutHTML_Image( Writer& rWrt, const SwFrameFormat &rFrameFormat, const SvxMacroTableDtor& rMacTable = static_cast<const SvxMacroItem *>(pItem)->GetMacroTable(); if (!rMacTable.empty()) { - HtmlWriterHelper::applyEvents(aHtml, rMacTable, aImageEventTable, rHTMLWrt.m_bCfgStarBasic); + HtmlWriterHelper::applyEvents(rHtml, rMacTable, aImageEventTable, rHTMLWrt.m_bCfgStarBasic); } } // alt, align, width, height, hspace, vspace - rHTMLWrt.writeFrameFormatOptions(aHtml, rFrameFormat, rAlternateText, nFrameOpts); + rHTMLWrt.writeFrameFormatOptions(rHtml, rFrameFormat, rAlternateText, nFrameOpts); if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) ) rHTMLWrt.OutCSS1_FrameFormatOptions( rFrameFormat, nFrameOpts ); if ((nFrameOpts & HtmlFrmOpts::Border) && !bReplacement) { - aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_border, nBorderWidth); + rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_border, nBorderWidth); } if( pURLItem && pURLItem->IsServerMap() ) { - aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_ismap); + rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_ismap); } if( !aIMapName.isEmpty() ) { - aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_usemap, OUString("#" + aIMapName)); + rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_usemap, OUString("#" + aIMapName)); } if (bReplacement) @@ -1426,12 +1424,18 @@ Writer& OutHTML_Image( Writer& rWrt, const SwFrameFormat &rFrameFormat, // "alt" attribute. if (rAlternateText.isEmpty()) // Empty alternate text is not valid. - aHtml.characters(" "); + rHtml.characters(" "); else - aHtml.characters(rAlternateText.toUtf8()); + rHtml.characters(rAlternateText.toUtf8()); } - aHtml.flushStack(); + return rHTMLWrt; +} + +Writer& OutHTML_ImageEnd( HtmlWriter& rHtml, Writer& rWrt ) +{ + SwHTMLWriter& rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt); + rHtml.flushStack(); if( !rHTMLWrt.m_aINetFormats.empty() ) { @@ -1763,17 +1767,20 @@ static Writer & OutHTML_FrameFormatAsImage( Writer& rWrt, const SwFrameFormat& r URIHelper::GetMaybeFileHdl() ); } - OutHTML_Image( rWrt, rFrameFormat, GraphicURL, aGraphic, rFrameFormat.GetName(), aSz, + HtmlWriter aHtml(rWrt.Strm(), rHTMLWrt.maNamespace); + OutHTML_ImageStart( aHtml, rWrt, rFrameFormat, GraphicURL, aGraphic, rFrameFormat.GetName(), aSz, HtmlFrmOpts::GenImgMask, "frame", aIMap.GetIMapObjectCount() ? &aIMap : nullptr ); + OutHTML_ImageEnd(aHtml, rWrt); return rWrt; } static Writer& OutHTML_FrameFormatGrfNode( Writer& rWrt, const SwFrameFormat& rFrameFormat, - bool bInCntnr ) + bool bInCntnr, bool bPNGFallback ) { SwHTMLWriter& rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt); + bool bWritePNGFallback = !rHTMLWrt.m_bExportImagesAsOLE && bPNGFallback; if (rHTMLWrt.mbSkipImages) return rWrt; @@ -1824,10 +1831,12 @@ static Writer& OutHTML_FrameFormatGrfNode( Writer& rWrt, const SwFrameFormat& rF OUString aFilterName(""); - if (rHTMLWrt.mbReqIF) + if (rHTMLWrt.mbReqIF && !bWritePNGFallback) { // Writing image without fallback PNG in ReqIF mode: force PNG // output. + // But don't force it when writing the original format and we'll write PNG inside + // that. aFilterName = "PNG"; nFlags &= ~XOutFlags::UseNativeIfPossible; nFlags &= ~XOutFlags::UseGifIfSensible; @@ -1890,9 +1899,20 @@ static Writer& OutHTML_FrameFormatGrfNode( Writer& rWrt, const SwFrameFormat& rF rHTMLWrt.OutNewLine(); } - OutHTML_Image( rWrt, rFrameFormat, aGraphicURL, aGraphic, pGrfNd->GetTitle(), + HtmlWriter aHtml(rWrt.Strm(), rHTMLWrt.maNamespace); + OutHTML_ImageStart( aHtml, rWrt, rFrameFormat, aGraphicURL, aGraphic, pGrfNd->GetTitle(), pGrfNd->GetTwipSize(), nFrameFlags, "graphic", nullptr, aMimeType ); + GfxLink aLink = aGraphic.GetGfxLink(); + if (bWritePNGFallback && aLink.GetType() != GfxLinkType::NativePng) + { + // Not OLE mode, outer format is not PNG: write inner PNG. + OutHTML_FrameFormatGrfNode( rWrt, rFrameFormat, + bInCntnr, /*bPNGFallback=*/false ); + } + + OutHTML_ImageEnd(aHtml, rWrt); + if (rHTMLWrt.mbReqIF && rHTMLWrt.m_bExportImagesAsOLE) rWrt.Strm().WriteOString(OString("</" + rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object ">")); diff --git a/sw/source/filter/html/htmlplug.cxx b/sw/source/filter/html/htmlplug.cxx index 5ce2ab50d90b..166c91931731 100644 --- a/sw/source/filter/html/htmlplug.cxx +++ b/sw/source/filter/html/htmlplug.cxx @@ -79,6 +79,7 @@ #include <o3tl/safeint.hxx> #include <osl/file.hxx> #include <comphelper/propertyvalue.hxx> +#include <svtools/HtmlWriter.hxx> using namespace com::sun::star; @@ -1655,9 +1656,11 @@ Writer& OutHTML_FrameFormatOLENodeGrf( Writer& rWrt, const SwFrameFormat& rFrame : HtmlFrmOpts::GenImgMask; if (bObjectOpened) nFlags |= HtmlFrmOpts::Replacement; - OutHTML_Image( rWrt, rFrameFormat, aGraphicURL, aGraphic, + HtmlWriter aHtml(rWrt.Strm(), rHTMLWrt.maNamespace); + OutHTML_ImageStart( aHtml, rWrt, rFrameFormat, aGraphicURL, aGraphic, pOLENd->GetTitle(), pOLENd->GetTwipSize(), nFlags, "ole", nullptr, aMimeType ); + OutHTML_ImageEnd(aHtml, rWrt); if (bObjectOpened) // Close native data. diff --git a/sw/source/filter/html/wrthtml.hxx b/sw/source/filter/html/wrthtml.hxx index 3e23616f6b21..8d6d1751e5a3 100644 --- a/sw/source/filter/html/wrthtml.hxx +++ b/sw/source/filter/html/wrthtml.hxx @@ -666,13 +666,14 @@ Writer& OutHTML_DrawFrameFormatAsMarquee( Writer& rWrt, const SwDrawFrameFormat& Writer& OutHTML_HeaderFooter( Writer& rWrt, const SwFrameFormat& rFrameFormat, bool bHeader ); -Writer& OutHTML_Image( Writer&, const SwFrameFormat& rFormat, +Writer& OutHTML_ImageStart( HtmlWriter& rHtml, Writer&, const SwFrameFormat& rFormat, const OUString& rGraphicURL, Graphic const & rGraphic, const OUString& rAlternateText, const Size& rRealSize, HtmlFrmOpts nFrameOpts, const char *pMarkType, const ImageMap *pGenImgMap, const OUString& rMimeType = OUString() ); +Writer& OutHTML_ImageEnd( HtmlWriter& rHtml, Writer& ); Writer& OutHTML_BulletImage( Writer& rWrt, const char *pTag, const SvxBrushItem* pBrush, _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits