Kaydet (Commit) 76abcd5f authored tarafından Miklos Vajna's avatar Miklos Vajna

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/55430Reviewed-by: 's avatarMiklos Vajna <vmiklos@collabora.co.uk>
Tested-by: Jenkins
üst efa1d0df
......@@ -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;
}
}
}
......
......@@ -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);
}
}
......
......@@ -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")
......
......@@ -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.
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;
}
......
......@@ -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: */
......@@ -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
......
......@@ -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)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment