[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-6.4' - vcl/qa vcl/source

Miklos Vajna (via logerrit) logerrit at kemper.freedesktop.org
Wed May 19 07:17:18 UTC 2021


 vcl/qa/cppunit/pdfexport/data/pdf-image-rotate-180.pdf |binary
 vcl/qa/cppunit/pdfexport/pdfexport.cxx                 |   72 +++++++++++++++++
 vcl/source/gdi/pdfwriter_impl.cxx                      |   53 +++++++-----
 3 files changed, 104 insertions(+), 21 deletions(-)

New commits:
commit 52add3bae28b1e7cda0234110341f3c6e0b06fdc
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Mon May 17 13:51:31 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Wed May 19 09:16:57 2021 +0200

    vcl PDF export: fix re-exporting PDF images with arbitrary page-level rotation
    
    Building on top of commit bd520b177637d4b7d9d93733103cff17a3c91b0a (vcl
    PDF export: fix re-exporting PDF images with page-level rotation,
    2019-11-06), this was already working for 90 degrees, now generalize
    this to work with 180 degrees as well.
    
    (cherry picked from commit d7d43cf460d66354a40ffa3b34c0f9efcd42d0be)
    
    Conflicts:
            vcl/qa/cppunit/pdfexport/pdfexport.cxx
            vcl/source/gdi/pdfwriter_impl.cxx
    
    Change-Id: I5a5d51662399814d5554d7c2cb86a6c9a2974012
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/115712
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Ashod Nakashian <ash at collabora.com>

diff --git a/vcl/qa/cppunit/pdfexport/data/pdf-image-rotate-180.pdf b/vcl/qa/cppunit/pdfexport/data/pdf-image-rotate-180.pdf
new file mode 100644
index 000000000000..981ca32061cd
Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/pdf-image-rotate-180.pdf differ
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index 5f50661b013e..aa96ee8a0f99 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -146,6 +146,7 @@ public:
     void testVersion15();
     void testDefaultVersion();
     void testMultiPagePDF();
+    void testPdfImageRotate180();
 
 
     CPPUNIT_TEST_SUITE(PdfExportTest);
@@ -189,6 +190,7 @@ public:
     CPPUNIT_TEST(testVersion15);
     CPPUNIT_TEST(testDefaultVersion);
     CPPUNIT_TEST(testMultiPagePDF);
+    CPPUNIT_TEST(testPdfImageRotate180);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -2180,6 +2182,76 @@ void PdfExportTest::testMultiPagePDF()
 #endif
 }
 
+void PdfExportTest::testPdfImageRotate180()
+{
+    // Create an empty document.
+    uno::Reference<lang::XComponent> xComponent = loadFromDesktop("private:factory/swriter");
+    uno::Reference<text::XTextDocument> xTextDocument(xComponent, uno::UNO_QUERY);
+    uno::Reference<text::XText> xText = xTextDocument->getText();
+    uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+
+    // Insert the PDF image.
+    uno::Reference<lang::XMultiServiceFactory> xFactory(xComponent, uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> xGraphicObject(
+        xFactory->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY);
+    OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "pdf-image-rotate-180.pdf";
+    xGraphicObject->setPropertyValue("GraphicURL", uno::makeAny(aURL));
+    uno::Reference<drawing::XShape> xShape(xGraphicObject, uno::UNO_QUERY);
+    xShape->setSize(awt::Size(1000, 1000));
+    uno::Reference<text::XTextContent> xTextContent(xGraphicObject, uno::UNO_QUERY);
+    xText->insertTextContent(xCursor->getStart(), xTextContent, /*bAbsorb=*/false);
+
+    // Save as PDF.
+    uno::Reference<frame::XStorable> xStorable(xComponent, uno::UNO_QUERY);
+    utl::MediaDescriptor aMediaDescriptor;
+    aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
+    utl::TempFile aTempFile;
+    aTempFile.EnableKillingFile();
+    xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
+    xComponent->dispose();
+
+    // Parse the export result.
+    SvFileStream aFile(aTempFile.GetURL(), StreamMode::READ);
+    SvMemoryStream aMemory;
+    aMemory.WriteStream(aFile);
+    DocumentHolder pPdfDocument(FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr));
+    CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get()));
+
+    // Make sure that the page -> form -> form has a child image.
+    PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0));
+    CPPUNIT_ASSERT(pPdfPage.get());
+    CPPUNIT_ASSERT_EQUAL(1, FPDFPage_CountObjects(pPdfPage.get()));
+    FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), 0);
+    CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(pPageObject));
+    // 2: white background and the actual object.
+    CPPUNIT_ASSERT_EQUAL(2, FPDFFormObj_CountObjects(pPageObject));
+    FPDF_PAGEOBJECT pFormObject = FPDFFormObj_GetObject(pPageObject, 1);
+    CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(pFormObject));
+    CPPUNIT_ASSERT_EQUAL(1, FPDFFormObj_CountObjects(pFormObject));
+
+    // Check if the inner form object (original page object in the pdf image) has the correct
+    // rotation.
+    FPDF_PAGEOBJECT pInnerFormObject = FPDFFormObj_GetObject(pFormObject, 0);
+    CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(pInnerFormObject));
+    CPPUNIT_ASSERT_EQUAL(1, FPDFFormObj_CountObjects(pInnerFormObject));
+    FPDF_PAGEOBJECT pImage = FPDFFormObj_GetObject(pInnerFormObject, 0);
+    CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(pImage));
+    FS_MATRIX aMatrix;
+    FPDFFormObj_GetMatrix(pInnerFormObject, &aMatrix);
+    basegfx::B2DHomMatrix aMat{ aMatrix.a, aMatrix.c, aMatrix.e, aMatrix.b, aMatrix.d, aMatrix.f };
+    basegfx::B2DTuple aScale;
+    basegfx::B2DTuple aTranslate;
+    double fRotate = 0;
+    double fShearX = 0;
+    aMat.decompose(aScale, aTranslate, fRotate, fShearX);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: -1
+    // - Actual  : 1
+    // i.e. the 180 degrees rotation didn't happen (via a combination of horizontal + vertical
+    // flip).
+    CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, aScale.getX(), 0.01);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(PdfExportTest);
 
 }
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index cfc8ffeffedc..3cf733449d31 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -8748,29 +8748,40 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
 
         long nWidth = aSize.Width();
         long nHeight = aSize.Height();
+        basegfx::B2DRange aBBox(0, 0, aSize.Width(),  aSize.Height());
         if (auto pRotate = dynamic_cast<filter::PDFNumberElement*>(pPage->Lookup("Rotate")))
         {
             // The original page was rotated, then construct a transformation matrix which does the
             // same with our form object.
-            if (rtl::math::approxEqual(pRotate->GetValue(), 90))
-            {
-                std::swap(nWidth, nHeight);
-                basegfx::B2DHomMatrix aMat;
-                aMat.rotate(basegfx::deg2rad(pRotate->GetValue()));
-                // Rotate around the origo (bottom left corner) counter-clockwise, then translate
-                // horizontally to effectively keep the bottom left corner unchanged.
-                aLine.append(" /Matrix [ ");
-                aLine.append(aMat.get(0, 0));
-                aLine.append(" ");
-                aLine.append(aMat.get(0, 1));
-                aLine.append(" ");
-                aLine.append(aMat.get(1, 0));
-                aLine.append(" ");
-                aLine.append(aMat.get(1, 1));
-                aLine.append(" 0 ");
-                aLine.append(nWidth);
-                aLine.append(" ] ");
-            }
+            sal_Int32 nRotAngle = static_cast<sal_Int32>(pRotate->GetValue()) % 360;
+            // /Rotate is clockwise, matrix rotate is counter-clockwise.
+            sal_Int32 nAngle = -1 * nRotAngle;
+
+            // The bounding box just rotates.
+            basegfx::B2DHomMatrix aBBoxMat;
+            aBBoxMat.rotate(basegfx::deg2rad(pRotate->GetValue()));
+            aBBox.transform(aBBoxMat);
+
+            // 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.rotate(basegfx::deg2rad(nAngle));
+            aMat.translate(0.5 * nWidth, 0.5 * nHeight);
+
+            aLine.append(" /Matrix [ ");
+            aLine.append(aMat.a());
+            aLine.append(" ");
+            aLine.append(aMat.b());
+            aLine.append(" ");
+            aLine.append(aMat.c());
+            aLine.append(" ");
+            aLine.append(aMat.d());
+            aLine.append(" ");
+            aLine.append(aMat.e());
+            aLine.append(" ");
+            aLine.append(aMat.f());
+            aLine.append(" ] ");
         }
 
         PDFObjectCopier aCopier(*this);
@@ -8778,9 +8789,9 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
         aCopier.copyPageResources(pPage, aLine, rResources);
 
         aLine.append(" /BBox [ 0 0 ");
-        aLine.append(nWidth);
+        aLine.append(aBBox.getWidth());
         aLine.append(" ");
-        aLine.append(nHeight);
+        aLine.append(aBBox.getHeight());
         aLine.append(" ]");
 
         if (!g_bDebugDisableCompression)


More information about the Libreoffice-commits mailing list