summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2019-11-06 16:48:55 +0100
committerMiklos Vajna <vmiklos@collabora.com>2019-11-06 17:56:59 +0100
commitbd520b177637d4b7d9d93733103cff17a3c91b0a (patch)
tree9111fcadfebcf18bfed89a3f6397300cf4089589
parent032b6698c11f6b6e67fa3a12c2d34f1f7afe63f6 (diff)
vcl PDF export: fix re-exporting PDF images with page-level rotation
PDF images are effectively 1 page PDF documents. The page object may have a /Rotate key, which was simply ignored before. We turn page objects into form XObjects on PDF export, such rotation can be expressed with a /Matrix key. Add support for the 90 degrees rotation case, this can be generalized later if wanted. Change-Id: I55a4f63e0b986637ccdeba0b783f1db9a85c4d93 Reviewed-on: https://gerrit.libreoffice.org/82154 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--vcl/CppunitTest_vcl_pdfexport.mk1
-rw-r--r--vcl/qa/cppunit/pdfexport/data/pdf-image-resource-inline-xobject-ref.pdfbin1361 -> 1372 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/pdfexport.cxx28
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx32
4 files changed, 59 insertions, 2 deletions
diff --git a/vcl/CppunitTest_vcl_pdfexport.mk b/vcl/CppunitTest_vcl_pdfexport.mk
index 45123e7c2811..2721d15e410b 100644
--- a/vcl/CppunitTest_vcl_pdfexport.mk
+++ b/vcl/CppunitTest_vcl_pdfexport.mk
@@ -16,6 +16,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,vcl_pdfexport, \
$(eval $(call gb_CppunitTest_use_sdk_api,vcl_pdfexport))
$(eval $(call gb_CppunitTest_use_libraries,vcl_pdfexport, \
+ basegfx \
comphelper \
cppu \
cppuhelper \
diff --git a/vcl/qa/cppunit/pdfexport/data/pdf-image-resource-inline-xobject-ref.pdf b/vcl/qa/cppunit/pdfexport/data/pdf-image-resource-inline-xobject-ref.pdf
index b62068eae9dd..739a80c4766d 100644
--- a/vcl/qa/cppunit/pdfexport/data/pdf-image-resource-inline-xobject-ref.pdf
+++ b/vcl/qa/cppunit/pdfexport/data/pdf-image-resource-inline-xobject-ref.pdf
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index ba62f301bec4..22585a9827eb 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -36,6 +36,7 @@
#include <fpdf_doc.h>
#include <fpdfview.h>
#include <vcl/graphicfilter.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
using namespace ::com::sun::star;
@@ -1877,6 +1878,33 @@ void PdfExportTest::testPdfImageResourceInlineXObjectRef()
// - Actual : 0
// i.e. the sub-form was missing its image.
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));
+ double fA = 0;
+ double fB = 0;
+ double fC = 0;
+ double fD = 0;
+ double fE = 0;
+ double fF = 0;
+ FPDFFormObj_GetMatrix(pInnerFormObject, &fA, &fB, &fC, &fD, &fE, &fF);
+ basegfx::B2DHomMatrix aMat{ fA, fC, fE, fB, fD, fF };
+ basegfx::B2DTuple aScale;
+ basegfx::B2DTuple aTranslate;
+ double fRotate = 0;
+ double fShearX = 0;
+ aMat.decompose(aScale, aTranslate, fRotate, fShearX);
+ int nRotateDeg = basegfx::rad2deg(fRotate);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: -90
+ // - Actual : 0
+ // i.e. rotation was lost on pdf export.
+ CPPUNIT_ASSERT_EQUAL(-90, nRotateDeg);
}
CPPUNIT_TEST_SUITE_REGISTRATION(PdfExportTest);
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index faabdd8769f9..a63a2152e6b7 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -8842,6 +8842,34 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
aLine.append(" 0 obj\n");
aLine.append("<< /Type /XObject");
aLine.append(" /Subtype /Form");
+
+ long nWidth = aSize.Width();
+ long nHeight = 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(" ] ");
+ }
+ }
+
aLine.append(" /Resources <<");
static const std::initializer_list<OString> aKeys =
{
@@ -8855,9 +8883,9 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
aLine.append(copyExternalResources(*pPage, rKey, aCopiedResources));
aLine.append(">>");
aLine.append(" /BBox [ 0 0 ");
- aLine.append(aSize.Width());
+ aLine.append(nWidth);
aLine.append(" ");
- aLine.append(aSize.Height());
+ aLine.append(nHeight);
aLine.append(" ]");
if (!g_bDebugDisableCompression)