filter/source/msfilter/rtfutil.cxx | 16 +++++++ include/filter/msfilter/rtfutil.hxx | 3 + sw/qa/extras/htmlexport/htmlexport.cxx | 14 ++++-- sw/source/filter/html/htmlflywriter.cxx | 44 ++++++++++++++++++- sw/source/filter/html/htmlreqifreader.cxx | 64 ++++++++++++++++++++++++++++ sw/source/filter/html/htmlreqifreader.hxx | 9 +++ sw/source/filter/ww8/rtfattributeoutput.cxx | 20 -------- 7 files changed, 147 insertions(+), 23 deletions(-)
New commits: commit 76abcd5f912f1a9e6f86ffc2a489ba7dba1aac56 Author: Miklos Vajna <vmik...@collabora.co.uk> Date: Thu Jun 7 16:49:58 2018 +0200 sw HTML export: use PNG fallback + RTF native data for all images for ReqIF ReqIF says the image should be either PNG or has a PNG fallback and then it can be something else. We used to convert images to PNG to avoid writing any native data, but results in data loss. So instead: 1) Write the original image as an RTF fragment, so it's not lost. 2) Some ReqIF parsers expect an RTF fragment even for PNG, so make sure we always write the RTF fragment, even if that means a small duplication. Change-Id: Ida0fcaa58d56b9e11f81992307505599807353b5 Reviewed-on: https://gerrit.libreoffice.org/55430 Reviewed-by: Miklos Vajna <vmik...@collabora.co.uk> Tested-by: Jenkins diff --git a/filter/source/msfilter/rtfutil.cxx b/filter/source/msfilter/rtfutil.cxx index ad2031d5536f..4ff71330b85c 100644 --- a/filter/source/msfilter/rtfutil.cxx +++ b/filter/source/msfilter/rtfutil.cxx @@ -285,6 +285,22 @@ bool ExtractOLE2FromObjdata(const OString& rObjdata, SvStream& rOle2) return true; } + +bool StripMetafileHeader(const sal_uInt8*& rpGraphicAry, sal_uInt64& rSize) +{ + if (rpGraphicAry && (rSize > 0x22)) + { + if ((rpGraphicAry[0] == 0xd7) && (rpGraphicAry[1] == 0xcd) && (rpGraphicAry[2] == 0xc6) + && (rpGraphicAry[3] == 0x9a)) + { + // we have to get rid of the metafileheader + rpGraphicAry += 22; + rSize -= 22; + return true; + } + } + return false; +} } } diff --git a/include/filter/msfilter/rtfutil.hxx b/include/filter/msfilter/rtfutil.hxx index 1cadaa94bd50..58aa4d54addf 100644 --- a/include/filter/msfilter/rtfutil.hxx +++ b/include/filter/msfilter/rtfutil.hxx @@ -70,6 +70,9 @@ MSFILTER_DLLPUBLIC OString WriteHex(const sal_uInt8* pData, sal_uInt32 nSize, * Extract OLE2 data from an \objdata hex dump. */ MSFILTER_DLLPUBLIC bool ExtractOLE2FromObjdata(const OString& rObjdata, SvStream& rOle2); + +/// Strips the header of a WMF file. +MSFILTER_DLLPUBLIC bool StripMetafileHeader(const sal_uInt8*& rpGraphicAry, sal_uInt64& rSize); } } diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx index e3ca80a0430d..8cb60396691d 100644 --- a/sw/qa/extras/htmlexport/htmlexport.cxx +++ b/sw/qa/extras/htmlexport/htmlexport.cxx @@ -434,11 +434,15 @@ DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testReqIfPngImg, "reqif-png-img.xhtml") uno::Reference<container::XNamed> xShape(getShape(1), uno::UNO_QUERY); CPPUNIT_ASSERT(xShape.is()); - // This was Object1, PNG without fallback was imported as OLE object. - CPPUNIT_ASSERT_EQUAL(OUString("Image1"), xShape->getName()); - if (!mbExported) + { + // Imported PNG image is not an object. + CPPUNIT_ASSERT_EQUAL(OUString("Image1"), xShape->getName()); return; + } + + // All images are exported as objects in ReqIF mode. + CPPUNIT_ASSERT_EQUAL(OUString("Object1"), xShape->getName()); // This was <img>, not <object>, which is not valid in the reqif-xhtml // subset. @@ -449,6 +453,10 @@ DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testReqIfPngImg, "reqif-png-img.xhtml") pStream->Seek(0); OString aStream(read_uInt8s_ToOString(*pStream, nLength)); CPPUNIT_ASSERT(aStream.indexOf("<reqif-xhtml:object") != -1); + + // Make sure that both RTF and PNG versions are written. + CPPUNIT_ASSERT(aStream.indexOf("text/rtf") != -1); + CPPUNIT_ASSERT(aStream.indexOf("image/png") != -1); } DECLARE_HTMLEXPORT_TEST(testReqIfJpgImg, "reqif-jpg-img.xhtml") diff --git a/sw/source/filter/html/htmlflywriter.cxx b/sw/source/filter/html/htmlflywriter.cxx index 8a2653608589..42a45951ed81 100644 --- a/sw/source/filter/html/htmlflywriter.cxx +++ b/sw/source/filter/html/htmlflywriter.cxx @@ -64,6 +64,7 @@ #include "css1kywd.hxx" #include "htmlatr.hxx" #include "htmlfly.hxx" +#include "htmlreqifreader.hxx" using namespace css; @@ -1425,10 +1426,16 @@ Writer& OutHTML_Image( Writer& rWrt, const SwFrameFormat &rFrameFormat, aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_usemap, "#" + aIMapName); } - if (bReplacement && !rAlternateText.isEmpty()) + if (bReplacement) + { // XHTML object replacement image's alternate text doesn't use the // "alt" attribute. - aHtml.characters(rAlternateText.toUtf8()); + if (rAlternateText.isEmpty()) + // Empty alternate text is not valid. + aHtml.characters(" "); + else + aHtml.characters(rAlternateText.toUtf8()); + } aHtml.flushStack(); @@ -1855,9 +1862,42 @@ static Writer& OutHTML_FrameFormatGrfNode( Writer& rWrt, const SwFrameFormat& rF uno::Reference<beans::XPropertySet> xGraphic(aGraphic.GetXGraphic(), uno::UNO_QUERY); if (xGraphic.is() && aMimeType.isEmpty()) xGraphic->getPropertyValue("MimeType") >>= aMimeType; + + if (rHTMLWrt.mbReqIF) + { + // Write the original image as an RTF fragment. + OUString aFileName; + if (rHTMLWrt.GetOrigFileName()) + aFileName = *rHTMLWrt.GetOrigFileName(); + INetURLObject aURL(aFileName); + OUString aName(aURL.getBase()); + aName += "_"; + aName += aURL.getExtension(); + aName += "_"; + aName += OUString::number(aGraphic.GetChecksum(), 16); + aURL.setBase(aName); + aURL.setExtension("ole"); + aFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); + + SvFileStream aOutStream(aFileName, StreamMode::WRITE); + if (!SwReqIfReader::WrapGraphicInRtf(aGraphic, pGrfNd->GetTwipSize(), aOutStream)) + SAL_WARN("sw.html", "SwReqIfReader::WrapGraphicInRtf() failed"); + + // Refer to this data. + aFileName = URIHelper::simpleNormalizedMakeRelative(rWrt.GetBaseURL(), aFileName); + rWrt.Strm().WriteOString("<" + rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object); + rWrt.Strm().WriteOString(" data=\"" + aFileName.toUtf8() + "\""); + rWrt.Strm().WriteOString(" type=\"text/rtf\""); + rWrt.Strm().WriteOString(">"); + rHTMLWrt.OutNewLine(); + } + OutHTML_Image( rWrt, rFrameFormat, aGraphicURL, aGraphic, pGrfNd->GetTitle(), pGrfNd->GetTwipSize(), nFrameFlags, "graphic", nullptr, aMimeType ); + if (rHTMLWrt.mbReqIF) + rWrt.Strm().WriteOString("</" + rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object ">"); + return rWrt; } diff --git a/sw/source/filter/html/htmlreqifreader.cxx b/sw/source/filter/html/htmlreqifreader.cxx index fcfff80358bf..234d15aa3964 100644 --- a/sw/source/filter/html/htmlreqifreader.cxx +++ b/sw/source/filter/html/htmlreqifreader.cxx @@ -209,6 +209,70 @@ bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf) return true; } + +bool WrapGraphicInRtf(const Graphic& rGraphic, const Size& rLogicSize, SvStream& rRtf) +{ + rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_PICT); + + GfxLink aLink = rGraphic.GetGfxLink(); + const sal_uInt8* pGraphicAry = aLink.GetData(); + sal_uInt64 nSize = aLink.GetDataSize(); + OString aBlipType; + bool bIsWMF = false; + switch (aLink.GetType()) + { + case GfxLinkType::NativeBmp: + aBlipType = OOO_STRING_SVTOOLS_RTF_WBITMAP; + break; + case GfxLinkType::NativeJpg: + aBlipType = OOO_STRING_SVTOOLS_RTF_JPEGBLIP; + break; + case GfxLinkType::NativePng: + aBlipType = OOO_STRING_SVTOOLS_RTF_PNGBLIP; + break; + case GfxLinkType::NativeWmf: + if (aLink.IsEMF()) + aBlipType = OOO_STRING_SVTOOLS_RTF_EMFBLIP; + else + { + aBlipType = OOO_STRING_SVTOOLS_RTF_WMETAFILE; + bIsWMF = true; + } + break; + default: + break; + } + + if (aBlipType.isEmpty()) + return false; + + rRtf.WriteOString(aBlipType); + + Size aMapped(rGraphic.GetPrefSize()); + rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICW); + rRtf.WriteOString(OString::number(aMapped.Width())); + rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICH); + rRtf.WriteOString(OString::number(aMapped.Height())); + + rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICWGOAL); + rRtf.WriteOString(OString::number(rLogicSize.Width())); + rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICHGOAL); + rRtf.WriteOString(OString::number(rLogicSize.Height())); + + if (bIsWMF) + { + rRtf.WriteOString(OString::number(8)); + msfilter::rtfutil::StripMetafileHeader(pGraphicAry, nSize); + } + rRtf.WriteOString(SAL_NEWLINE_STRING); + + msfilter::rtfutil::WriteHex(pGraphicAry, nSize, &rRtf); + rRtf.WriteOString(SAL_NEWLINE_STRING); + + // End pict. + rRtf.WriteCharPtr("}"); + return true; +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/html/htmlreqifreader.hxx b/sw/source/filter/html/htmlreqifreader.hxx index 84d470ce4db1..3b24a4f28311 100644 --- a/sw/source/filter/html/htmlreqifreader.hxx +++ b/sw/source/filter/html/htmlreqifreader.hxx @@ -9,6 +9,8 @@ #ifndef INCLUDED_SW_SOURCE_FILTER_HTML_HTMLREQIFREADER_HXX #define INCLUDED_SW_SOURCE_FILTER_HTML_HTMLREQIFREADER_HXX +class Graphic; +class Size; class SvStream; namespace SwReqIfReader @@ -22,6 +24,13 @@ bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle, bool& bOwnFormat); /// Wraps an OLE2 container binary in an RTF fragment. bool WrapOleInRtf(SvStream& rOle, SvStream& rRtf); + +/** + * Wraps an image in an RTF fragment. + * + * @param rLogicSize the size used in the document model (not pixel size) + */ +bool WrapGraphicInRtf(const Graphic& rGraphic, const Size& rLogicSize, SvStream& rRtf); } #endif // INCLUDED_SW_SOURCE_FILTER_HTML_HTMLREQIFREADER_HXX diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx index f5459efe4062..8aca7d56ede5 100644 --- a/sw/source/filter/ww8/rtfattributeoutput.cxx +++ b/sw/source/filter/ww8/rtfattributeoutput.cxx @@ -3682,22 +3682,6 @@ void RtfAttributeOutput::FontPitchType(FontPitch ePitch) const m_rExport.OutULong(nVal); } -static bool StripMetafileHeader(const sal_uInt8*& rpGraphicAry, unsigned long& rSize) -{ - if (rpGraphicAry && (rSize > 0x22)) - { - if ((rpGraphicAry[0] == 0xd7) && (rpGraphicAry[1] == 0xcd) && (rpGraphicAry[2] == 0xc6) - && (rpGraphicAry[3] == 0x9a)) - { - // we have to get rid of the metafileheader - rpGraphicAry += 22; - rSize -= 22; - return true; - } - } - return false; -} - static void lcl_AppendSP(OStringBuffer& rBuffer, const char cName[], const OUString& rValue, const RtfExport& rExport) { @@ -3712,7 +3696,7 @@ static void lcl_AppendSP(OStringBuffer& rBuffer, const char cName[], const OUStr static OString ExportPICT(const SwFlyFrameFormat* pFlyFrameFormat, const Size& rOrig, const Size& rRendered, const Size& rMapped, const SwCropGrf& rCr, - const char* pBLIPType, const sal_uInt8* pGraphicAry, unsigned long nSize, + const char* pBLIPType, const sal_uInt8* pGraphicAry, sal_uInt64 nSize, const RtfExport& rExport, SvStream* pStream = nullptr, bool bWritePicProp = true, const SwAttrSet* pAttrSet = nullptr) { @@ -3784,7 +3768,7 @@ static OString ExportPICT(const SwFlyFrameFormat* pFlyFrameFormat, const Size& r if (bIsWMF) { aRet.append(sal_Int32(8)); - StripMetafileHeader(pGraphicAry, nSize); + msfilter::rtfutil::StripMetafileHeader(pGraphicAry, nSize); } aRet.append(SAL_NEWLINE_STRING); if (pStream) _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits