diff options
-rw-r--r-- | emfio/CppunitTest_emfio_emf_test.mk | 15 | ||||
-rw-r--r-- | emfio/inc/emfreader.hxx | 2 | ||||
-rw-r--r-- | emfio/qa/cppunit/emf/EmfImportTest.cxx | 57 | ||||
-rw-r--r-- | emfio/qa/cppunit/emf/data/pdf-in-emf.pptx | bin | 0 -> 35443 bytes | |||
-rw-r--r-- | emfio/source/emfuno/xemfparser.cxx | 15 | ||||
-rw-r--r-- | emfio/source/reader/emfreader.cxx | 4 | ||||
-rw-r--r-- | include/vcl/pdfread.hxx | 2 | ||||
-rw-r--r-- | include/vcl/vectorgraphicdata.hxx | 10 | ||||
-rw-r--r-- | offapi/com/sun/star/graphic/XEmfParser.idl | 8 | ||||
-rw-r--r-- | svx/source/sdr/properties/defaultproperties.cxx | 16 | ||||
-rw-r--r-- | vcl/source/filter/ipdf/pdfread.cxx | 21 | ||||
-rw-r--r-- | vcl/source/gdi/vectorgraphicdata.cxx | 12 |
12 files changed, 140 insertions, 22 deletions
diff --git a/emfio/CppunitTest_emfio_emf_test.mk b/emfio/CppunitTest_emfio_emf_test.mk index 123e4b3549bd..5b32187b7ea8 100644 --- a/emfio/CppunitTest_emfio_emf_test.mk +++ b/emfio/CppunitTest_emfio_emf_test.mk @@ -38,20 +38,7 @@ $(eval $(call gb_CppunitTest_use_libraries,emfio_emf,\ $(eval $(call gb_CppunitTest_use_ure,emfio_emf)) $(eval $(call gb_CppunitTest_use_vcl,emfio_emf)) -$(eval $(call gb_CppunitTest_use_components,emfio_emf,\ - configmgr/source/configmgr \ - dtrans/util/mcnttype \ - emfio/emfio \ - framework/util/fwk \ - i18npool/util/i18npool \ - package/source/xstor/xstor \ - package/util/package2 \ - toolkit/util/tk \ - sfx2/util/sfx \ - ucb/source/core/ucb1 \ - ucb/source/ucp/file/ucpfile1 \ - unotools/util/utl \ -)) +$(eval $(call gb_CppunitTest_use_rdb,emfio_emf,services)) $(eval $(call gb_CppunitTest_use_configuration,emfio_emf)) diff --git a/emfio/inc/emfreader.hxx b/emfio/inc/emfreader.hxx index ec2c5273f650..39d576b64aed 100644 --- a/emfio/inc/emfreader.hxx +++ b/emfio/inc/emfreader.hxx @@ -34,6 +34,7 @@ namespace emfio bool mbEMFPlusDualMode : 1; /// Another format is read already, can ignore actual EMF data. bool mbReadOtherGraphicFormat = false; + basegfx::B2DTuple maSizeHint; bool ReadHeader(); // reads and converts the rectangle @@ -47,6 +48,7 @@ namespace emfio void ReadGDIComment(sal_uInt32 nCommentId); /// Parses EMR_COMMENT_MULTIFORMATS. void ReadMultiformatsComment(); + void SetSizeHint(const basegfx::B2DTuple& rSizeHint) { maSizeHint = rSizeHint; } private: template <class T> void ReadAndDrawPolyPolygon(sal_uInt32 nNextPos); diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx index ca42b307211b..9d3364693530 100644 --- a/emfio/qa/cppunit/emf/EmfImportTest.cxx +++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx @@ -12,6 +12,12 @@ #include <test/bootstrapfixture.hxx> #include <test/xmltesttools.hxx> +#include <unotest/macros_test.hxx> + +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> #include <comphelper/seqstream.hxx> #include <comphelper/sequence.hxx> @@ -26,14 +32,17 @@ namespace { +using namespace css; using namespace css::uno; using namespace css::io; using namespace css::graphic; using drawinglayer::primitive2d::Primitive2DSequence; using drawinglayer::primitive2d::Primitive2DContainer; -class Test : public test::BootstrapFixture, public XmlTestTools +class Test : public test::BootstrapFixture, public XmlTestTools, public unotest::MacrosTest { + uno::Reference<lang::XComponent> mxComponent; + void checkRectPrimitive(Primitive2DSequence const & rPrimitive); void testWorking(); @@ -41,19 +50,40 @@ class Test : public test::BootstrapFixture, public XmlTestTools void TestDrawStringTransparent(); void TestDrawLine(); void TestLinearGradient(); + void TestPdfInEmf(); Primitive2DSequence parseEmf(const OUString& aSource); public: + void setUp() override; + void tearDown() override; + uno::Reference<lang::XComponent>& getComponent() { return mxComponent; } + CPPUNIT_TEST_SUITE(Test); CPPUNIT_TEST(testWorking); CPPUNIT_TEST(TestDrawString); CPPUNIT_TEST(TestDrawStringTransparent); CPPUNIT_TEST(TestDrawLine); CPPUNIT_TEST(TestLinearGradient); + CPPUNIT_TEST(TestPdfInEmf); CPPUNIT_TEST_SUITE_END(); }; +void Test::setUp() +{ + test::BootstrapFixture::setUp(); + + mxDesktop.set(frame::Desktop::create(mxComponentContext)); +} + +void Test::tearDown() +{ + if (mxComponent.is()) + mxComponent->dispose(); + + test::BootstrapFixture::tearDown(); +} + Primitive2DSequence Test::parseEmf(const OUString& aSource) { const Reference<XEmfParser> xEmfParser = EmfTools::create(m_xContext); @@ -190,6 +220,31 @@ void Test::TestLinearGradient() assertXPath(pDocument, "/primitive2D/metafile/transform/mask/svglineargradient[2]/polypolygon", "path", "m7615.75822989746 0.216110019646294h7615.75822989746v7610.21611001965h-7615.75822989746z"); } +void Test::TestPdfInEmf() +{ + // Load a PPTX file, which has a shape, with a bitmap fill, which is an EMF, containing a PDF. + OUString aURL = m_directories.getURLFromSrc("emfio/qa/cppunit/emf/data/pdf-in-emf.pptx"); + getComponent() = loadFromDesktop(aURL); + + // Get the EMF. + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + uno::Reference<graphic::XGraphic> xGraphic; + xShape->getPropertyValue("FillBitmap") >>= xGraphic; + Graphic aGraphic(xGraphic); + + // Check the size hint of the EMF, which influences the bitmap generated from the PDF. + const std::shared_ptr<VectorGraphicData>& pVectorGraphicData = aGraphic.getVectorGraphicData(); + + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 14321 + // - Actual : 0 + // i.e. there was no size hint, the shape with 14cm height had a bitmap-from-PDF fill, the PDF + // height was only 5cm, so it looked blurry. + CPPUNIT_ASSERT_EQUAL(14321.0, pVectorGraphicData->getSizeHint().getY()); +} + CPPUNIT_TEST_SUITE_REGISTRATION(Test); } diff --git a/emfio/qa/cppunit/emf/data/pdf-in-emf.pptx b/emfio/qa/cppunit/emf/data/pdf-in-emf.pptx Binary files differnew file mode 100644 index 000000000000..61b2af28c8b3 --- /dev/null +++ b/emfio/qa/cppunit/emf/data/pdf-in-emf.pptx diff --git a/emfio/source/emfuno/xemfparser.cxx b/emfio/source/emfuno/xemfparser.cxx index 717f2dad7cfb..0c623d7659aa 100644 --- a/emfio/source/emfuno/xemfparser.cxx +++ b/emfio/source/emfuno/xemfparser.cxx @@ -32,6 +32,7 @@ #include <basegfx/matrix/b2dhommatrixtools.hxx> #include <unotools/ucbstreamhelper.hxx> #include <drawinglayer/primitive2d/metafileprimitive2d.hxx> +#include <sal/log.hxx> #include <wmfreader.hxx> #include <emfreader.hxx> @@ -46,6 +47,7 @@ namespace emfio::emfreader { private: uno::Reference< uno::XComponentContext > context_; + basegfx::B2DTuple maSizeHint; public: explicit XEmfParser( @@ -58,6 +60,7 @@ namespace emfio::emfreader const uno::Reference< ::io::XInputStream >& xEmfStream, const OUString& aAbsolutePath, const uno::Sequence< ::beans::PropertyValue >& rProperties) override; + void SAL_CALL setSizeHint(const geometry::RealPoint2D& rSize) override; // XServiceInfo virtual OUString SAL_CALL getImplementationName() override; @@ -105,7 +108,9 @@ namespace emfio::emfreader if (nMetaType == 0x464d4520) { // read and get possible failure/error, ReadEnhWMF returns success - bReadError = !emfio::EmfReader(*pStream, aMtf).ReadEnhWMF(); + emfio::EmfReader aReader(*pStream, aMtf); + aReader.SetSizeHint(maSizeHint); + bReadError = !aReader.ReadEnhWMF(); } else { @@ -175,12 +180,18 @@ namespace emfio::emfreader } else { - OSL_ENSURE(false, "Invalid stream (!)"); + SAL_WARN("emfio", "Invalid stream (!)"); } return comphelper::containerToSequence(aRetval); } + void XEmfParser::setSizeHint(const geometry::RealPoint2D& rSize) + { + maSizeHint.setX(rSize.X); + maSizeHint.setY(rSize.Y); + } + OUString SAL_CALL XEmfParser::getImplementationName() { return "emfio::emfreader::XEmfParser"; diff --git a/emfio/source/reader/emfreader.cxx b/emfio/source/reader/emfreader.cxx index 7bb4d408203a..2c932a440eeb 100644 --- a/emfio/source/reader/emfreader.cxx +++ b/emfio/source/reader/emfreader.cxx @@ -503,6 +503,10 @@ namespace emfio return; } + // aGraphic will be the only output of the EMF parser, so its size hint can be the same as + // ours. + aGraphic.getVectorGraphicData()->setSizeHint(maSizeHint); + maBmpSaveList.emplace_back(new BSaveStruct(aGraphic.GetBitmapEx(), aOutputRect, SRCCOPY)); const std::shared_ptr<VectorGraphicData> pVectorGraphicData = aGraphic.getVectorGraphicData(); diff --git a/include/vcl/pdfread.hxx b/include/vcl/pdfread.hxx index f60ae8ef243f..bffdb104da42 100644 --- a/include/vcl/pdfread.hxx +++ b/include/vcl/pdfread.hxx @@ -30,7 +30,7 @@ namespace vcl /// Fills the rBitmaps vector with rendered pages. VCL_DLLPUBLIC size_t RenderPDFBitmaps(const void* pBuffer, int nSize, std::vector<Bitmap>& rBitmaps, size_t nFirstPage = 0, int nPages = 1, - double fResolutionDPI = 96.); + const basegfx::B2DTuple* pSizeHint = nullptr); /// Imports a PDF stream into rGraphic as VectorGraphicData. VCL_DLLPUBLIC bool ImportPDF(SvStream& rStream, Graphic& rGraphic); diff --git a/include/vcl/vectorgraphicdata.hxx b/include/vcl/vectorgraphicdata.hxx index 3d30c03d683d..0fdc9abbba42 100644 --- a/include/vcl/vectorgraphicdata.hxx +++ b/include/vcl/vectorgraphicdata.hxx @@ -74,6 +74,9 @@ private: // If the vector format has more pages this denotes which page to render sal_Int32 mnPageIndex; + /// Useful for PDF, which is vector-based, but still rendered to a bitmap. + basegfx::B2DTuple maSizeHint; + // on demand creators void ensurePdfReplacement(); void ensureReplacement(); @@ -118,6 +121,13 @@ public: mnPageIndex = nPageIndex; } + void setSizeHint(const basegfx::B2DTuple& rSizeHint) + { + maSizeHint = rSizeHint; + } + + const basegfx::B2DTuple& getSizeHint() const { return maSizeHint; } + bool isPrimitiveSequenceCreated() const { return mbSequenceCreated; } }; diff --git a/offapi/com/sun/star/graphic/XEmfParser.idl b/offapi/com/sun/star/graphic/XEmfParser.idl index 1c2fd10d7fff..234d70bc1937 100644 --- a/offapi/com/sun/star/graphic/XEmfParser.idl +++ b/offapi/com/sun/star/graphic/XEmfParser.idl @@ -20,6 +20,7 @@ #ifndef __com_sun_star_graphic_XEmfParser_idl__ #define __com_sun_star_graphic_XEmfParser_idl__ +#include <com/sun/star/geometry/RealPoint2D.idl> #include <com/sun/star/uno/XInterface.idl> #include <com/sun/star/io/XInputStream.idl> @@ -51,6 +52,13 @@ interface XEmfParser : ::com::sun::star::uno::XInterface [in] io::XInputStream xEmfStream, [in] string aAbsolutePath, [in] ::com::sun::star::beans::PropertyValues Properties); + + /** Sets a size hint on this object. + + @param Size + the size in 100/th mm + */ + void setSizeHint([in] com::sun::star::geometry::RealPoint2D Size); }; }; }; }; }; diff --git a/svx/source/sdr/properties/defaultproperties.cxx b/svx/source/sdr/properties/defaultproperties.cxx index fb0c4c59369f..e9a9934a9973 100644 --- a/svx/source/sdr/properties/defaultproperties.cxx +++ b/svx/source/sdr/properties/defaultproperties.cxx @@ -30,6 +30,7 @@ #include <libxml/xmlwriter.h> #include <svx/svdmodel.hxx> #include <svx/svdtrans.hxx> +#include <svx/xbtmpit.hxx> namespace sdr::properties { @@ -155,6 +156,21 @@ namespace sdr::properties void DefaultProperties::SetObjectItemSet(const SfxItemSet& rSet) { + if (rSet.HasItem(XATTR_FILLBITMAP)) + { + const XFillBitmapItem* pItem = rSet.GetItem(XATTR_FILLBITMAP); + const std::shared_ptr<VectorGraphicData>& pVectorData + = pItem->GetGraphicObject().GetGraphic().getVectorGraphicData(); + if (pVectorData) + { + // Shape is filled by a vector graphic: tell it our size as a hint. + basegfx::B2DTuple aSizeHint; + aSizeHint.setX(GetSdrObject().GetSnapRect().getWidth()); + aSizeHint.setY(GetSdrObject().GetSnapRect().getHeight()); + pVectorData->setSizeHint(aSizeHint); + } + } + SfxWhichIter aWhichIter(rSet); sal_uInt16 nWhich(aWhichIter.FirstWhich()); const SfxPoolItem *pPoolItem; diff --git a/vcl/source/filter/ipdf/pdfread.cxx b/vcl/source/filter/ipdf/pdfread.cxx index d89283e902ac..39c2933be8d5 100644 --- a/vcl/source/filter/ipdf/pdfread.cxx +++ b/vcl/source/filter/ipdf/pdfread.cxx @@ -24,6 +24,7 @@ #include <unotools/datetime.hxx> #include <vcl/filter/PDFiumLibrary.hxx> +#include <sal/log.hxx> using namespace com::sun::star; @@ -147,9 +148,10 @@ VectorGraphicDataArray createVectorGraphicDataArray(SvStream& rStream) namespace vcl { size_t RenderPDFBitmaps(const void* pBuffer, int nSize, std::vector<Bitmap>& rBitmaps, - const size_t nFirstPage, int nPages, const double fResolutionDPI) + const size_t nFirstPage, int nPages, const basegfx::B2DTuple* pSizeHint) { #if HAVE_FEATURE_PDFIUM + const double fResolutionDPI = 96; auto pPdfium = vcl::pdf::PDFiumLibrary::get(); // Load the buffer using pdfium. @@ -168,9 +170,19 @@ size_t RenderPDFBitmaps(const void* pBuffer, int nSize, std::vector<Bitmap>& rBi if (!pPdfPage) break; + // Calculate the bitmap size in points. + size_t nPageWidthPoints = FPDF_GetPageWidth(pPdfPage); + size_t nPageHeightPoints = FPDF_GetPageHeight(pPdfPage); + if (pSizeHint && pSizeHint->getX() && pSizeHint->getY()) + { + // Have a size hint, prefer that over the logic size from the PDF. + nPageWidthPoints = convertMm100ToTwip(pSizeHint->getX()) / 20; + nPageHeightPoints = convertMm100ToTwip(pSizeHint->getY()) / 20; + } + // Returned unit is points, convert that to pixel. - const size_t nPageWidth = pointToPixel(FPDF_GetPageWidth(pPdfPage), fResolutionDPI); - const size_t nPageHeight = pointToPixel(FPDF_GetPageHeight(pPdfPage), fResolutionDPI); + const size_t nPageWidth = pointToPixel(nPageWidthPoints, fResolutionDPI); + const size_t nPageHeight = pointToPixel(nPageHeightPoints, fResolutionDPI); FPDF_BITMAP pPdfBitmap = FPDFBitmap_Create(nPageWidth, nPageHeight, /*alpha=*/1); if (!pPdfBitmap) break; @@ -217,7 +229,10 @@ bool ImportPDF(SvStream& rStream, Graphic& rGraphic) { VectorGraphicDataArray aPdfDataArray = createVectorGraphicDataArray(rStream); if (!aPdfDataArray.hasElements()) + { + SAL_WARN("vcl.filter", "ImportPDF: empty PDF data array"); return false; + } auto aVectorGraphicDataPtr = std::make_shared<VectorGraphicData>(aPdfDataArray, OUString(), VectorGraphicDataType::Pdf); diff --git a/vcl/source/gdi/vectorgraphicdata.cxx b/vcl/source/gdi/vectorgraphicdata.cxx index bfaa544bc7d4..d0d1e3ca6412 100644 --- a/vcl/source/gdi/vectorgraphicdata.cxx +++ b/vcl/source/gdi/vectorgraphicdata.cxx @@ -150,7 +150,9 @@ void VectorGraphicData::ensurePdfReplacement() sal_Int32 nUsePageIndex = 0; if (mnPageIndex >= 0) nUsePageIndex = mnPageIndex; - vcl::RenderPDFBitmaps(maVectorGraphicDataArray.getConstArray(), maVectorGraphicDataArray.getLength(), aBitmaps, nUsePageIndex, 1/*, fResolutionDPI*/); + vcl::RenderPDFBitmaps(maVectorGraphicDataArray.getConstArray(), + maVectorGraphicDataArray.getLength(), aBitmaps, nUsePageIndex, 1, + &maSizeHint); if (!aBitmaps.empty()) maReplacement = aBitmaps[0]; } @@ -212,7 +214,15 @@ void VectorGraphicData::ensureSequenceAndRange() } if (myInputStream.is()) + { + // Pass the size hint of the graphic to the EMF parser. + geometry::RealPoint2D aSizeHint; + aSizeHint.X = maSizeHint.getX(); + aSizeHint.Y = maSizeHint.getY(); + xEmfParser->setSizeHint(aSizeHint); + maSequence = comphelper::sequenceToContainer<std::deque<css::uno::Reference< css::graphic::XPrimitive2D >>>(xEmfParser->getDecomposition(myInputStream, maPath, aSequence)); + } break; } |