diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2020-12-09 09:38:48 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2020-12-09 10:46:31 +0100 |
commit | ca67839234e78fe6bea21ec39906d1bd71d34d47 (patch) | |
tree | 2003f700fa05bd24bea1efc890e9549aa3507391 | |
parent | c81fea2e78d66c1978cb2340868c938ba9d6c9f1 (diff) |
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@collabora.com>
Tested-by: Jenkins
-rw-r--r-- | emfio/inc/emfreader.hxx | 2 | ||||
-rw-r--r-- | emfio/source/emfuno/xemfparser.cxx | 16 | ||||
-rw-r--r-- | emfio/source/reader/emfreader.cxx | 6 | ||||
-rw-r--r-- | include/vcl/vectorgraphicdata.hxx | 4 | ||||
-rw-r--r-- | include/vcl/wmf.hxx | 2 | ||||
-rw-r--r-- | vcl/qa/cppunit/GraphicTest.cxx | 26 | ||||
-rw-r--r-- | vcl/source/filter/graphicfilter.cxx | 2 | ||||
-rw-r--r-- | vcl/source/filter/wmf/wmf.cxx | 29 | ||||
-rw-r--r-- | vcl/source/gdi/vectorgraphicdata.cxx | 11 |
9 files changed, 96 insertions, 2 deletions
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)); } |