Add a more complex test for a PDF saving bug Add a second PDFEditImgTest case to further demonstrate a PDF saving bug, where a no-op FPDFPageObj_SetMatrix() call causes the saved PDF to have incorrect transformation matrices. This second test case has an image inside a form. This test also demonstrates FPDFPageObj_GetMatrix() behavior and shows what the matrix is relative to. Mention this in the API's documentation. Bug: pdfium:2132 Change-Id: Ibdfac7de37c43ffec45da6d093c2e8798b85950d Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/116911 Reviewed-by: Thomas Sepez <tsepez@google.com> Reviewed-by: Tom Sepez <tsepez@chromium.org> Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/fpdfsdk/fpdf_editimg_embeddertest.cpp b/fpdfsdk/fpdf_editimg_embeddertest.cpp index ebb6452..c06d495 100644 --- a/fpdfsdk/fpdf_editimg_embeddertest.cpp +++ b/fpdfsdk/fpdf_editimg_embeddertest.cpp
@@ -223,3 +223,73 @@ constexpr char kWrongChecksum[] = "d01c62c9ee094f5be545f006148808b5"; VerifySavedDocument(kExpectedWidth, kExpectedHeight, kWrongChecksum); } + +TEST_F(PDFEditImgTest, GetAndSetMatrixForFormWithImage) { + constexpr int kExpectedWidth = 200; + constexpr int kExpectedHeight = 300; + constexpr char kExpectedChecksum[] = "fcb9007fd901d2052e2bd1c147b82800"; + + OpenDocument("form_object_with_image.pdf"); + FPDF_PAGE page = LoadPage(0); + ASSERT_TRUE(page); + + { + ScopedFPDFBitmap bitmap = RenderLoadedPage(page); + CompareBitmap(bitmap.get(), kExpectedWidth, kExpectedHeight, + kExpectedChecksum); + } + + FPDF_PAGEOBJECT form = FPDFPage_GetObject(page, 0); + ASSERT_TRUE(form); + ASSERT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(form)); + + FS_MATRIX matrix; + ASSERT_TRUE(FPDFPageObj_GetMatrix(form, &matrix)); + EXPECT_FLOAT_EQ(60.0f, matrix.a); + EXPECT_FLOAT_EQ(0.0f, matrix.b); + EXPECT_FLOAT_EQ(0.0f, matrix.c); + EXPECT_FLOAT_EQ(30.0f, matrix.d); + EXPECT_FLOAT_EQ(0.0f, matrix.e); + EXPECT_FLOAT_EQ(270.0f, matrix.f); + + ASSERT_TRUE(FPDFPageObj_SetMatrix(form, &matrix)); + { + ScopedFPDFBitmap bitmap = RenderLoadedPage(page); + CompareBitmap(bitmap.get(), kExpectedWidth, kExpectedHeight, + kExpectedChecksum); + } + + FPDF_PAGEOBJECT image = FPDFFormObj_GetObject(form, 0); + ASSERT_TRUE(image); + ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(image)); + + ASSERT_TRUE(FPDFPageObj_GetMatrix(image, &matrix)); + EXPECT_FLOAT_EQ(1.0f, matrix.a); + EXPECT_FLOAT_EQ(0.0f, matrix.b); + EXPECT_FLOAT_EQ(0.0f, matrix.c); + EXPECT_FLOAT_EQ(1.0f, matrix.d); + EXPECT_FLOAT_EQ(1.0f, matrix.e); + EXPECT_FLOAT_EQ(0.0f, matrix.f); + + ASSERT_TRUE(FPDFPageObj_SetMatrix(image, &matrix)); + { + ScopedFPDFBitmap bitmap = RenderLoadedPage(page); + CompareBitmap(bitmap.get(), kExpectedWidth, kExpectedHeight, + kExpectedChecksum); + } + + ASSERT_TRUE(FPDFPage_GenerateContent(page)); + ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0)); + + { + ScopedFPDFBitmap bitmap = RenderLoadedPage(page); + CompareBitmap(bitmap.get(), kExpectedWidth, kExpectedHeight, + kExpectedChecksum); + } + + UnloadPage(page); + + // TODO(crbug.com/pdfium/2132): Should be `kExpectedChecksum`. + constexpr char kWrongChecksum[] = "308e2263f01744b2749d68a9ca711fc6"; + VerifySavedDocument(kExpectedWidth, kExpectedHeight, kWrongChecksum); +}
diff --git a/public/fpdf_edit.h b/public/fpdf_edit.h index 082e39b..e2135f2 100644 --- a/public/fpdf_edit.h +++ b/public/fpdf_edit.h
@@ -292,6 +292,11 @@ // |b d f| // and used to scale, rotate, shear and translate the page object. // +// For page objects outside form objects, the matrix values are relative to the +// page that contains it. +// For page objects inside form objects, the matrix values are relative to the +// form that contains it. +// // Returns TRUE on success. FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetMatrix(FPDF_PAGEOBJECT page_object, FS_MATRIX* matrix);
diff --git a/testing/resources/form_object_with_image.in b/testing/resources/form_object_with_image.in new file mode 100644 index 0000000..ea499f8 --- /dev/null +++ b/testing/resources/form_object_with_image.in
@@ -0,0 +1,68 @@ +{{header}} +{{object 1 0}} << + /Type /Catalog + /Pages 2 0 R +>> +endobj +{{object 2 0}} << + /Type /Pages + /MediaBox [0 0 200 300] + /Count 1 + /Kids [3 0 R] +>> +endobj +{{object 3 0}} << + /Type /Page + /Parent 2 0 R + /Contents 4 0 R + /Resources << + /XObject << + /F1 5 0 R + >> + >> +>> +endobj +{{object 4 0}} << + {{streamlen}} +>> +stream +1 0 0 -1 0 300 cm +q +60 0 0 -30 0 30 cm +/F1 Do +Q +endstream +endobj +{{object 5 0}} << + /Type /XObject + /Subtype /Form + /BBox [0 0 200 30] + /Resources << + /XObject << + /IM1 6 0 R + >> + >> +>> +stream +1 0 0 1 1 0 cm +/IM1 Do +endstream +endobj +{{object 6 0}} << + /Type /XObject + /Subtype /Image + /Width 50 + /Height 50 + /BitsPerComponent 8 + /ColorSpace /DeviceRGB + /Filter [/ASCIIHexDecode /FlateDecode] + {{streamlen}} +>> +stream +789cedc2310d00000c03a07f2aaab3ea7bcf03842655555555555555f5bf01cc7818dc +endstream +endobj +{{xref}} +{{trailer}} +{{startxref}} +%%EOF
diff --git a/testing/resources/form_object_with_image.pdf b/testing/resources/form_object_with_image.pdf new file mode 100644 index 0000000..e243a84 --- /dev/null +++ b/testing/resources/form_object_with_image.pdf
@@ -0,0 +1,81 @@ +%PDF-1.7 +% ò¤ô +1 0 obj << + /Type /Catalog + /Pages 2 0 R +>> +endobj +2 0 obj << + /Type /Pages + /MediaBox [0 0 200 300] + /Count 1 + /Kids [3 0 R] +>> +endobj +3 0 obj << + /Type /Page + /Parent 2 0 R + /Contents 4 0 R + /Resources << + /XObject << + /F1 5 0 R + >> + >> +>> +endobj +4 0 obj << + /Length 48 +>> +stream +1 0 0 -1 0 300 cm +q +60 0 0 -30 0 30 cm +/F1 Do +Q +endstream +endobj +5 0 obj << + /Type /XObject + /Subtype /Form + /BBox [0 0 200 30] + /Resources << + /XObject << + /IM1 6 0 R + >> + >> +>> +stream +1 0 0 1 1 0 cm +/IM1 Do +endstream +endobj +6 0 obj << + /Type /XObject + /Subtype /Image + /Width 50 + /Height 50 + /BitsPerComponent 8 + /ColorSpace /DeviceRGB + /Filter [/ASCIIHexDecode /FlateDecode] + /Length 71 +>> +stream +789cedc2310d00000c03a07f2aaab3ea7bcf03842655555555555555f5bf01cc7818dc +endstream +endobj +xref +0 7 +0000000000 65535 f +0000000015 00000 n +0000000068 00000 n +0000000157 00000 n +0000000286 00000 n +0000000385 00000 n +0000000562 00000 n +trailer << + /Root 1 0 R + /Size 7 +>> +startxref +832 +%%EOF