vcl/qa/cppunit/pdfexport/data/ref-to-kids.pdf |binary vcl/qa/cppunit/pdfexport/pdfexport.cxx | 55 ++++++++++++++++++++++++++ vcl/source/gdi/pdfwriter_impl.cxx | 29 +++++++++++-- 3 files changed, 79 insertions(+), 5 deletions(-)
New commits: commit a67dcc248a103098de883a4dd2fa9ff2e1cc1f90 Author: Dennis Francis <[email protected]> AuthorDate: Thu Dec 1 11:47:12 2022 +0530 Commit: Miklos Vajna <[email protected]> CommitDate: Fri Dec 16 13:46:59 2022 +0000 vcl: use /MediaBox origin in the ctm... of the inner XObject, else the clip polypolygon may clip out partly or whole contents. Adjusting the clip polypolygon is not straightforward. Change-Id: If3b208ba850c3579c9e16c15e4fb2f947dad4406 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143561 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/vcl/qa/cppunit/pdfexport/data/ref-to-kids.pdf b/vcl/qa/cppunit/pdfexport/data/ref-to-kids.pdf index 598358a636aa..0390ccad8410 100644 Binary files a/vcl/qa/cppunit/pdfexport/data/ref-to-kids.pdf and b/vcl/qa/cppunit/pdfexport/data/ref-to-kids.pdf differ diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx index 0e5a5b621950..8b9541e9478e 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx @@ -3439,6 +3439,61 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testRexportFilterSingletonArray) #endif } +CPPUNIT_TEST_FIXTURE(PdfExportTest, testRexportMediaBoxOrigin) +{ +// setenv only works on unix based systems +#ifndef _WIN32 + // We need to enable PDFium import (and make sure to disable after the test) + bool bResetEnvVar = false; + if (getenv("LO_IMPORT_USE_PDFIUM") == nullptr) + { + bResetEnvVar = true; + setenv("LO_IMPORT_USE_PDFIUM", "1", false); + } + comphelper::ScopeGuard aPDFiumEnvVarGuard([&]() { + if (bResetEnvVar) + unsetenv("LO_IMPORT_USE_PDFIUM"); + }); + + // Load the PDF and save as PDF + vcl::filter::PDFDocument aDocument; + load(u"ref-to-kids.pdf", aDocument); + + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(size_t(5), aPages.size()); + + // Directly go to the inner XObject Im10 that contains the rectangle drawings in page 2. + auto pInnerIm = aDocument.LookupObject(10); + CPPUNIT_ASSERT(pInnerIm); + + auto pMatrix = dynamic_cast<vcl::filter::PDFArrayElement*>(pInnerIm->Lookup("Matrix")); + CPPUNIT_ASSERT(pMatrix); + const auto& rElements = pMatrix->GetElements(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(6), rElements.size()); + sal_Int32 aMatTranslate[2] = { 600, -400 }; + for (sal_Int32 nIdx = 4; nIdx < 6; ++nIdx) + { + const auto* pNumElement = dynamic_cast<vcl::filter::PDFNumberElement*>(rElements[nIdx]); + CPPUNIT_ASSERT(pNumElement); + CPPUNIT_ASSERT_EQUAL(aMatTranslate[nIdx - 4], + static_cast<sal_Int32>(pNumElement->GetValue())); + } + + auto pBBox = dynamic_cast<vcl::filter::PDFArrayElement*>(pInnerIm->Lookup("BBox")); + CPPUNIT_ASSERT(pBBox); + const auto& rElements2 = pBBox->GetElements(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rElements2.size()); + sal_Int32 aBBox[2] = { -800, -600 }; + for (sal_Int32 nIdx = 0; nIdx < 2; ++nIdx) + { + const auto* pNumElement = dynamic_cast<vcl::filter::PDFNumberElement*>(rElements2[nIdx]); + CPPUNIT_ASSERT(pNumElement); + CPPUNIT_ASSERT_EQUAL(aBBox[nIdx], static_cast<sal_Int32>(pNumElement->GetValue())); + } + +#endif +} + } // end anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index eb861cd69c6b..647f861d31e8 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -8517,6 +8517,21 @@ void PDFWriterImpl::writeReferenceXObject(const ReferenceXObjectEmit& rEmit) return; } + double aOrigin[2] = { 0.0, 0.0 }; + if (auto* pArray = dynamic_cast<filter::PDFArrayElement*>(pPage->Lookup("MediaBox"))) + { + const auto& rElements = pArray->GetElements(); + if (rElements.size() >= 4) + { + // get x1, y1 of the rectangle. + for (sal_Int32 nIdx = 0; nIdx < 2; ++nIdx) + { + if (const auto* pNumElement = dynamic_cast<filter::PDFNumberElement*>(rElements[nIdx])) + aOrigin[nIdx] = pNumElement->GetValue(); + } + } + } + std::vector<filter::PDFObjectElement*> aContentStreams; if (filter::PDFObjectElement* pContentStream = pPage->LookupObject("Contents")) aContentStreams.push_back(pContentStream); @@ -8618,7 +8633,7 @@ void PDFWriterImpl::writeReferenceXObject(const ReferenceXObjectEmit& rEmit) // Now transform the object: rotate around the center and make sure that the rotation // doesn't affect the aspect ratio. basegfx::B2DHomMatrix aMat; - aMat.translate(-0.5 * aBBox.getWidth(), -0.5 * aBBox.getHeight()); + aMat.translate(-0.5 * aBBox.getWidth() - aOrigin[0], -0.5 * aBBox.getHeight() - aOrigin[1]); aMat.rotate(basegfx::deg2rad(nAngle)); aMat.translate(0.5 * nWidth, 0.5 * nHeight); @@ -8641,10 +8656,14 @@ void PDFWriterImpl::writeReferenceXObject(const ReferenceXObjectEmit& rEmit) auto & rResources = rExternalPDFStream.getCopiedResources(); aCopier.copyPageResources(pPage, aLine, rResources); - aLine.append(" /BBox [ 0 0 "); - aLine.append(aBBox.getWidth()); - aLine.append(" "); - aLine.append(aBBox.getHeight()); + aLine.append(" /BBox [ "); + aLine.append(aOrigin[0]); + aLine.append(' '); + aLine.append(aOrigin[1]); + aLine.append(' '); + aLine.append(aBBox.getWidth() + aOrigin[0]); + aLine.append(' '); + aLine.append(aBBox.getHeight() + aOrigin[1]); aLine.append(" ]"); if (!g_bDebugDisableCompression)
