[Libreoffice-commits] core.git: emfio/inc emfio/source include/vcl vcl/qa vcl/source
Miklos Vajna (via logerrit)
logerrit at kemper.freedesktop.org
Wed Dec 9 09:47:09 UTC 2020
emfio/inc/emfreader.hxx | 2 ++
emfio/source/emfuno/xemfparser.cxx | 16 ++++++++++++++++
emfio/source/reader/emfreader.cxx | 6 ++++++
include/vcl/vectorgraphicdata.hxx | 4 ++++
include/vcl/wmf.hxx | 2 ++
vcl/qa/cppunit/GraphicTest.cxx | 26 ++++++++++++++++++++++++++
vcl/source/filter/graphicfilter.cxx | 2 +-
vcl/source/filter/wmf/wmf.cxx | 29 ++++++++++++++++++++++++++++-
vcl/source/gdi/vectorgraphicdata.cxx | 11 +++++++++++
9 files changed, 96 insertions(+), 2 deletions(-)
New commits:
commit ca67839234e78fe6bea21ec39906d1bd71d34d47
Author: Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Wed Dec 9 09:38:48 2020 +0100
Commit: Miklos Vajna <vmiklos at collabora.com>
CommitDate: Wed Dec 9 10:46:31 2020 +0100
vcl: improve EMF+ -> WMF conversion
We throw away EMF fallback info when parsing EMF+ data. This means that
the resulting GDIMetaFile (containing EMF+ data but no EMF fallback) is
tricky to export to WMF, where EMF+ comments are not allowed.
Improve the conversion result by re-parsing such EMF+ data with EMF+
disabled, and then converting the GDIMetaFile (containing EMF fallback
data) to WMF.
Change-Id: Ib2c0388f1344aef7f601ce9be59e4a8924e8085b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/107453
Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
Tested-by: Jenkins
diff --git a/emfio/inc/emfreader.hxx b/emfio/inc/emfreader.hxx
index 39d576b64aed..e580835fc083 100644
--- a/emfio/inc/emfreader.hxx
+++ b/emfio/inc/emfreader.hxx
@@ -35,6 +35,7 @@ namespace emfio
/// Another format is read already, can ignore actual EMF data.
bool mbReadOtherGraphicFormat = false;
basegfx::B2DTuple maSizeHint;
+ bool mbEnableEMFPlus = true;
bool ReadHeader();
// reads and converts the rectangle
@@ -49,6 +50,7 @@ namespace emfio
/// Parses EMR_COMMENT_MULTIFORMATS.
void ReadMultiformatsComment();
void SetSizeHint(const basegfx::B2DTuple& rSizeHint) { maSizeHint = rSizeHint; }
+ void SetEnableEMFPlus(bool bEnableEMFPlus) { mbEnableEMFPlus = bEnableEMFPlus; }
private:
template <class T> void ReadAndDrawPolyPolygon(sal_uInt32 nNextPos);
diff --git a/emfio/source/emfuno/xemfparser.cxx b/emfio/source/emfuno/xemfparser.cxx
index 8667ccf1faea..7788802c4e1c 100644
--- a/emfio/source/emfuno/xemfparser.cxx
+++ b/emfio/source/emfuno/xemfparser.cxx
@@ -33,6 +33,7 @@
#include <unotools/ucbstreamhelper.hxx>
#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
#include <sal/log.hxx>
+#include <comphelper/sequenceashashmap.hxx>
#include <wmfreader.hxx>
#include <emfreader.hxx>
@@ -87,6 +88,17 @@ namespace emfio::emfreader
{
WmfExternal aExternalHeader;
const bool bExternalHeaderUsed(aExternalHeader.setSequence(rProperties));
+ bool bEnableEMFPlus = true;
+ comphelper::SequenceAsHashMap aMap(rProperties);
+ auto it = aMap.find("EMFPlusEnable");
+ if (it != aMap.end())
+ {
+ bool bValue;
+ if (it->second >>= bValue)
+ {
+ bEnableEMFPlus = bValue;
+ }
+ }
// rough check - import and conv to primitive
GDIMetaFile aMtf;
@@ -110,6 +122,10 @@ namespace emfio::emfreader
// read and get possible failure/error, ReadEnhWMF returns success
emfio::EmfReader aReader(*pStream, aMtf);
aReader.SetSizeHint(maSizeHint);
+ if (!bEnableEMFPlus)
+ {
+ aReader.SetEnableEMFPlus(bEnableEMFPlus);
+ }
bReadError = !aReader.ReadEnhWMF();
}
else
diff --git a/emfio/source/reader/emfreader.cxx b/emfio/source/reader/emfreader.cxx
index 69916939fa26..ae00508380e1 100644
--- a/emfio/source/reader/emfreader.cxx
+++ b/emfio/source/reader/emfreader.cxx
@@ -803,6 +803,12 @@ namespace emfio
OUString aEMFPlusDisable;
rtl::Bootstrap::get("EMF_PLUS_DISABLE", aEMFPlusDisable);
bool bEnableEMFPlus = aEMFPlusDisable.isEmpty();
+ if (!mbEnableEMFPlus)
+ {
+ // EMF+ is enabled if neither the bootstrap variable, not the member variable disables
+ // it.
+ bEnableEMFPlus = mbEnableEMFPlus;
+ }
SAL_INFO("emfio", "EMF_PLUS_DISABLE is " << (bEnableEMFPlus ? "enabled" : "disabled"));
diff --git a/include/vcl/vectorgraphicdata.hxx b/include/vcl/vectorgraphicdata.hxx
index 0fdc9abbba42..1787d060e11b 100644
--- a/include/vcl/vectorgraphicdata.hxx
+++ b/include/vcl/vectorgraphicdata.hxx
@@ -77,6 +77,8 @@ private:
/// Useful for PDF, which is vector-based, but still rendered to a bitmap.
basegfx::B2DTuple maSizeHint;
+ bool mbEnableEMFPlus = true;
+
// on demand creators
void ensurePdfReplacement();
void ensureReplacement();
@@ -128,6 +130,8 @@ public:
const basegfx::B2DTuple& getSizeHint() const { return maSizeHint; }
+ void setEnableEMFPlus(bool bEnableEMFPlus) { mbEnableEMFPlus = bEnableEMFPlus; }
+
bool isPrimitiveSequenceCreated() const { return mbSequenceCreated; }
};
diff --git a/include/vcl/wmf.hxx b/include/vcl/wmf.hxx
index 26a1c734425d..4acc21465723 100644
--- a/include/vcl/wmf.hxx
+++ b/include/vcl/wmf.hxx
@@ -25,10 +25,12 @@
class FilterConfigItem;
class GDIMetaFile;
class SvStream;
+class Graphic;
VCL_DLLPUBLIC bool ReadWindowMetafile( SvStream& rStream, GDIMetaFile& rMTF );
VCL_DLLPUBLIC bool ConvertGDIMetaFileToWMF( const GDIMetaFile & rMTF, SvStream & rTargetStream, FilterConfigItem const * pConfigItem, bool bPlaceable = true );
+VCL_DLLPUBLIC bool ConvertGraphicToWMF( const Graphic & rGraphic, SvStream & rTargetStream, FilterConfigItem const * pConfigItem, bool bPlaceable = true );
bool ConvertGDIMetaFileToEMF(const GDIMetaFile & rMTF, SvStream & rTargetStream);
diff --git a/vcl/qa/cppunit/GraphicTest.cxx b/vcl/qa/cppunit/GraphicTest.cxx
index 479a3c91f836..d3671fe3c881 100644
--- a/vcl/qa/cppunit/GraphicTest.cxx
+++ b/vcl/qa/cppunit/GraphicTest.cxx
@@ -26,6 +26,7 @@
#include <unotools/ucbstreamhelper.hxx>
#include <unotools/tempfile.hxx>
#include <vcl/cvtgrf.hxx>
+#include <vcl/metaact.hxx>
#include <impgraph.hxx>
#include <graphic/GraphicFormatDetector.hxx>
@@ -335,6 +336,31 @@ void GraphicTest::testEmfToWmfConversion()
// - Actual : EMF
// i.e. EMF data was requested to be converted to WMF, but the output was still EMF.
CPPUNIT_ASSERT_EQUAL(OUString("WMF"), aDetector.msDetectedFormat);
+
+ // Import the WMF result and check for traces of EMF+ in it.
+ Graphic aWmfGraphic;
+ aGraphicStream.Seek(0);
+ CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, aGraphicFilter.ImportGraphic(aWmfGraphic, OUString(),
+ aGraphicStream, nFormat));
+ int nCommentCount = 0;
+ for (size_t i = 0; i < aWmfGraphic.GetGDIMetaFile().GetActionSize(); ++i)
+ {
+ MetaAction* pAction = aWmfGraphic.GetGDIMetaFile().GetAction(i);
+ if (pAction->GetType() == MetaActionType::COMMENT)
+ {
+ auto pComment = static_cast<MetaCommentAction*>(pAction);
+ if (pComment->GetComment().startsWith("EMF_PLUS"))
+ {
+ ++nCommentCount;
+ }
+ }
+ }
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected less or equal than: 4
+ // - Actual : 8
+ // i.e. even more EMF+ comments were left in the WMF output. The ideal would be to get this down
+ // to 0, though.
+ CPPUNIT_ASSERT_LESSEQUAL(4, nCommentCount);
}
void GraphicTest::testSwapping()
diff --git a/vcl/source/filter/graphicfilter.cxx b/vcl/source/filter/graphicfilter.cxx
index 4b4fa6c4582d..dd70545d3645 100644
--- a/vcl/source/filter/graphicfilter.cxx
+++ b/vcl/source/filter/graphicfilter.cxx
@@ -1985,7 +1985,7 @@ ErrCode GraphicFilter::ExportGraphic( const Graphic& rGraphic, const OUString& r
if (!bDone)
{
// #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
- if (!ConvertGDIMetaFileToWMF(aGraphic.GetGDIMetaFile(), rOStm, &aConfigItem))
+ if (!ConvertGraphicToWMF(aGraphic, rOStm, &aConfigItem))
nStatus = ERRCODE_GRFILTER_FORMATERROR;
if (rOStm.GetError())
diff --git a/vcl/source/filter/wmf/wmf.cxx b/vcl/source/filter/wmf/wmf.cxx
index 7818309ed6d1..8a04bc1d3025 100644
--- a/vcl/source/filter/wmf/wmf.cxx
+++ b/vcl/source/filter/wmf/wmf.cxx
@@ -23,6 +23,8 @@
#include <vcl/gdimetafiletools.hxx>
#include <vcl/graph.hxx>
+using namespace com::sun::star;
+
bool ReadWindowMetafile( SvStream& rStream, GDIMetaFile& rMTF )
{
// tdf#111484 Use new method to import Metafile. Take current StreamPos
@@ -80,7 +82,32 @@ bool ConvertGDIMetaFileToWMF( const GDIMetaFile & rMTF, SvStream & rTargetStream
clipMetafileContentAgainstOwnRegions(aGdiMetaFile);
}
- return aWMFWriter.WriteWMF( aGdiMetaFile, rTargetStream, pConfigItem, bPlaceable );
+ bool bRet = aWMFWriter.WriteWMF(aGdiMetaFile, rTargetStream, pConfigItem, bPlaceable);
+ return bRet;
+}
+
+bool ConvertGraphicToWMF(const Graphic& rGraphic, SvStream& rTargetStream,
+ FilterConfigItem const* pConfigItem, bool bPlaceable)
+{
+ GfxLink aLink = rGraphic.GetGfxLink();
+ if (aLink.IsEMF() && aLink.GetData() && aLink.GetDataSize())
+ {
+ // This may be an EMF+ file, converting that to WMF is better done by re-parsing EMF+ as EMF
+ // and converting that to WMF.
+ uno::Sequence<sal_Int8> aData(reinterpret_cast<const sal_Int8*>(aLink.GetData()),
+ aLink.GetDataSize());
+ auto aVectorGraphicData
+ = std::make_shared<VectorGraphicData>(aData, OUString(), VectorGraphicDataType::Emf);
+ aVectorGraphicData->setEnableEMFPlus(false);
+ Graphic aGraphic(aVectorGraphicData);
+ bool bRet = ConvertGDIMetaFileToWMF(aGraphic.GetGDIMetaFile(), rTargetStream, pConfigItem,
+ bPlaceable);
+ return bRet;
+ }
+
+ bool bRet = ConvertGDIMetaFileToWMF(rGraphic.GetGDIMetaFile(), rTargetStream, pConfigItem,
+ bPlaceable);
+ return bRet;
}
bool ConvertGDIMetaFileToEMF(const GDIMetaFile & rMTF, SvStream & rTargetStream)
diff --git a/vcl/source/gdi/vectorgraphicdata.cxx b/vcl/source/gdi/vectorgraphicdata.cxx
index 6d5dc6e87768..92d49e07de3e 100644
--- a/vcl/source/gdi/vectorgraphicdata.cxx
+++ b/vcl/source/gdi/vectorgraphicdata.cxx
@@ -34,6 +34,7 @@
#include <comphelper/seqstream.hxx>
#include <comphelper/sequence.hxx>
#include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
#include <vcl/svapp.hxx>
#include <vcl/outdev.hxx>
#include <vcl/wmfexternal.hxx>
@@ -221,6 +222,16 @@ void VectorGraphicData::ensureSequenceAndRange()
aSizeHint.Y = maSizeHint.getY();
xEmfParser->setSizeHint(aSizeHint);
+ if (!mbEnableEMFPlus)
+ {
+ auto aVector
+ = comphelper::sequenceToContainer<std::vector<beans::PropertyValue>>(
+ aSequence);
+ aVector.push_back(
+ comphelper::makePropertyValue("EMFPlusEnable", uno::makeAny(false)));
+ aSequence = comphelper::containerToSequence(aVector);
+ }
+
maSequence = comphelper::sequenceToContainer<std::deque<css::uno::Reference< css::graphic::XPrimitive2D >>>(xEmfParser->getDecomposition(myInputStream, maPath, aSequence));
}
More information about the Libreoffice-commits
mailing list