diff options
-rw-r--r-- | core/fpdfapi/page/cpdf_page.cpp | 29 | ||||
-rw-r--r-- | core/fpdfapi/page/cpdf_page.h | 7 | ||||
-rw-r--r-- | fpdfsdk/fpdfview.cpp | 16 | ||||
-rw-r--r-- | fpdfsdk/fpdfview_embeddertest.cpp | 113 | ||||
-rw-r--r-- | public/fpdfview.h | 4 | ||||
-rw-r--r-- | testing/resources/rectangles.in | 14 | ||||
-rw-r--r-- | testing/resources/rectangles.pdf | 16 |
7 files changed, 142 insertions, 57 deletions
diff --git a/core/fpdfapi/page/cpdf_page.cpp b/core/fpdfapi/page/cpdf_page.cpp index dfbd342f13..6213e5fccb 100644 --- a/core/fpdfapi/page/cpdf_page.cpp +++ b/core/fpdfapi/page/cpdf_page.cpp @@ -178,6 +178,35 @@ CFX_Matrix CPDF_Page::GetDisplayMatrix(int xPos, return matrix; } +// This method follows the same apparent logic as GetDisplayMatrix(). For +// example, consider point 0. First, take the top left coordinate of the +// rectangle in the transformed space. Now, calculate what this point was in the +// original space by inverting. Note that this is not necessarily the same as +// the top left corner of the original rectangle. +CFX_Matrix CPDF_Page::GetDisplayMatrixWithTransformation( + int xPos, + int yPos, + int xSize, + int ySize, + const CFX_Matrix& transformation) { + CFX_FloatRect rect(xPos, yPos, xPos + xSize, yPos + ySize); + rect = transformation.TransformRect(rect); + CFX_Matrix inverse = transformation.GetInverse(); + CFX_PointF point0(rect.left, rect.top); + CFX_PointF point1(rect.left, rect.bottom); + CFX_PointF point2(rect.right, rect.top); + point0 = inverse.Transform(point0); + point1 = inverse.Transform(point1); + point2 = inverse.Transform(point2); + + CFX_Matrix matrix = m_PageMatrix; + matrix.Concat(CFX_Matrix( + (point2.x - point0.x) / m_PageWidth, (point2.y - point0.y) / m_PageWidth, + (point1.x - point0.x) / m_PageHeight, + (point1.y - point0.y) / m_PageHeight, point0.x, point0.y)); + return matrix; +} + int CPDF_Page::GetPageRotation() const { CPDF_Object* pRotate = GetPageAttr("Rotate"); int rotate = pRotate ? (pRotate->GetInteger() / 90) % 4 : 0; diff --git a/core/fpdfapi/page/cpdf_page.h b/core/fpdfapi/page/cpdf_page.h index 1891e651be..47fba3caec 100644 --- a/core/fpdfapi/page/cpdf_page.h +++ b/core/fpdfapi/page/cpdf_page.h @@ -38,11 +38,16 @@ class CPDF_Page : public CPDF_PageObjectHolder { int xSize, int ySize, int iRotate) const; + CFX_Matrix GetDisplayMatrixWithTransformation( + int xPos, + int yPos, + int xSize, + int ySize, + const CFX_Matrix& transformation); float GetPageWidth() const { return m_PageWidth; } float GetPageHeight() const { return m_PageHeight; } CFX_FloatRect GetPageBBox() const { return m_BBox; } - const CFX_Matrix& GetPageMatrix() const { return m_PageMatrix; } int GetPageRotation() const; CPDF_PageRenderCache* GetRenderCache() const { return m_pPageRender.get(); } diff --git a/fpdfsdk/fpdfview.cpp b/fpdfsdk/fpdfview.cpp index e93e8bcd58..5bcc643ac1 100644 --- a/fpdfsdk/fpdfview.cpp +++ b/fpdfsdk/fpdfview.cpp @@ -1004,15 +1004,13 @@ FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap, clipping_rect.top = clipping->top; } FX_RECT clip_rect = clipping_rect.ToFxRect(); - - CFX_Matrix transform_matrix = pPage->GetDisplayMatrix( - clip_rect.left, clip_rect.top, clip_rect.Width(), clip_rect.Height(), 0); - if (matrix) { - transform_matrix.Concat(CFX_Matrix(matrix->a, matrix->b, matrix->c, - matrix->d, matrix->e, matrix->f)); - } - RenderPageImpl(pContext, pPage, transform_matrix, clip_rect, flags, true, - nullptr); + RenderPageImpl( + pContext, pPage, + pPage->GetDisplayMatrixWithTransformation( + clip_rect.left, clip_rect.top, clip_rect.Width(), clip_rect.Height(), + CFX_Matrix(matrix->a, matrix->b, matrix->c, matrix->d, matrix->e, + matrix->f)), + clip_rect, flags, true, nullptr); pPage->SetRenderContext(nullptr); } diff --git a/fpdfsdk/fpdfview_embeddertest.cpp b/fpdfsdk/fpdfview_embeddertest.cpp index 8576104c2e..97ba9d7c4c 100644 --- a/fpdfsdk/fpdfview_embeddertest.cpp +++ b/fpdfsdk/fpdfview_embeddertest.cpp @@ -5,6 +5,7 @@ #include <limits> #include <string> +#include "core/fxcrt/fx_coordinates.h" #include "fpdfsdk/fpdfview_c_api_test.h" #include "public/fpdfview.h" #include "testing/embedder_test.h" @@ -350,75 +351,119 @@ TEST_F(FPDFViewEmbeddertest, Hang_360) { } TEST_F(FPDFViewEmbeddertest, FPDF_RenderPageBitmapWithMatrix) { - const char kOriginalMD5[] = "210157942bcce97b057a1107a1fd62f8"; - const char kTopLeftQuarterMD5[] = "c54d58dda13e3cd04eb63e1d0db0feda"; - const char kTrimmedMD5[] = "88225d7951a21d0eef191cfed06c36ce"; - const char kRotatedMD5[] = "7d38bc58aa50ad271bc432e77256d3de"; + const char* const kRotatedMD5[4] = { + "0a90de37f52127619c3dfb642b5fa2fe", "d599429574ff0dcad3bc898ea8b874ca", + "0113386bb0bd45125bacc6dee78bfe78", "051fcfa4c1f9de28765705633a8ef3a9"}; + const char kTopLeftQuarterMD5[] = "4982be08db3f6d2e6409186ebbced9eb"; + const char kHoriStretchedMD5[] = "004bf38f3c5c76a644e6fca204747f21"; + const char kRotateandStretchMD5[] = "0ea95cacc716d003cf063a2c5ed6c8d7"; EXPECT_TRUE(OpenDocument("rectangles.pdf")); FPDF_PAGE page = LoadPage(0); EXPECT_NE(nullptr, page); - const int width = static_cast<int>(FPDF_GetPageWidth(page)); - const int height = static_cast<int>(FPDF_GetPageHeight(page)); - EXPECT_EQ(200, width); - EXPECT_EQ(200, height); + const int initial_width = static_cast<int>(FPDF_GetPageWidth(page)); + const int initial_height = static_cast<int>(FPDF_GetPageHeight(page)); + EXPECT_EQ(200, initial_width); + EXPECT_EQ(300, initial_height); FPDF_BITMAP bitmap = RenderPage(page); - CompareBitmap(bitmap, width, height, kOriginalMD5); + CompareBitmap(bitmap, initial_width, initial_height, kRotatedMD5[0]); FPDFBitmap_Destroy(bitmap); - // Try rendering with an identity matrix. The output should be the same as - // the RenderPage() output. - FS_MATRIX matrix; - matrix.a = 1; - matrix.b = 0; - matrix.c = 0; - matrix.d = 1; - matrix.e = 0; - matrix.f = 0; - + int width; + int height; FS_RECTF rect; rect.left = 0; rect.top = 0; - rect.right = width; - rect.bottom = height; + FS_MATRIX matrix; - bitmap = FPDFBitmap_Create(width, height, 0); - FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF); - FPDF_RenderPageBitmapWithMatrix(bitmap, page, &matrix, &rect, 0); - CompareBitmap(bitmap, width, height, kOriginalMD5); - FPDFBitmap_Destroy(bitmap); + // Try the easy rotations: 0, 90, 180, 270 clockwise. The output should be the + // same as FPDF_RenderPageBitmap with the appropriate rotation flag. Per PDF + // spec section 4.2.2, a t degree rotation is represented by [cos(t) sin(t) + // -sin(t) cos(t) 0 0] (matrix goes on the right in the multiplication). + rect.right = initial_width; + rect.bottom = initial_height; + CFX_Matrix rot_matrices[4] = { + CFX_Matrix(1, 0, 0, 1, 0, 0), CFX_Matrix(0, -1, 1, 0, 0, 0), + CFX_Matrix(-1, 0, 0, -1, 0, 0), CFX_Matrix(0, 1, -1, 0, 0, 0)}; + for (int rot = 0; rot < 4; ++rot) { + matrix.a = rot_matrices[rot].a; + matrix.b = rot_matrices[rot].b; + matrix.c = rot_matrices[rot].c; + matrix.d = rot_matrices[rot].d; + matrix.e = rot_matrices[rot].e; + matrix.f = rot_matrices[rot].f; + if (rot % 2 == 0) { + width = initial_width; + height = initial_height; + } else { + width = initial_height; + height = initial_width; + } + rect.right = width; + rect.bottom = height; + + bitmap = FPDFBitmap_Create(width, height, 0); + FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF); + FPDF_RenderPageBitmap(bitmap, page, 0, 0, width, height, rot, 0); + CompareBitmap(bitmap, width, height, kRotatedMD5[rot]); + FPDFBitmap_Destroy(bitmap); + + bitmap = FPDFBitmap_Create(width, height, 0); + FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF); + FPDF_RenderPageBitmapWithMatrix(bitmap, page, &matrix, &rect, 0); + CompareBitmap(bitmap, width, height, kRotatedMD5[rot]); + FPDFBitmap_Destroy(bitmap); + } + // TODO(npm): what to do with transformations that do not align the page with + // the axis, like a 45 degree rotation (currently, part of the page gets cut + // out). pdfium:849 // Now render again with the image scaled smaller. + width = initial_width / 2; + height = initial_height / 2; matrix.a = 0.5; + matrix.b = 0; + matrix.c = 0; matrix.d = 0.5; + rect.right = width; + rect.bottom = height; + bitmap = FPDFBitmap_Create(width, height, 0); FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF); FPDF_RenderPageBitmapWithMatrix(bitmap, page, &matrix, &rect, 0); CompareBitmap(bitmap, width, height, kTopLeftQuarterMD5); FPDFBitmap_Destroy(bitmap); - // Now render again with the image scaled larger horizontally (will be - // trimmed). + // Now render again with the image scaled larger horizontally. + width = initial_width * 2; + height = initial_height; matrix.a = 2; matrix.d = 1; + rect.right = width; + rect.bottom = height; bitmap = FPDFBitmap_Create(width, height, 0); FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF); FPDF_RenderPageBitmapWithMatrix(bitmap, page, &matrix, &rect, 0); - CompareBitmap(bitmap, width, height, kTrimmedMD5); + CompareBitmap(bitmap, width, height, kHoriStretchedMD5); FPDFBitmap_Destroy(bitmap); - // Now try a 90 degree rotation + // Test a rotation followed by a stretch. + width = initial_height * 2; + height = initial_width; matrix.a = 0; - matrix.b = 1; - matrix.c = -1; + matrix.b = -1; + matrix.c = 2; matrix.d = 0; - matrix.e = width; + matrix.e = 0; + matrix.f = 0; + rect.right = width; + rect.bottom = height; bitmap = FPDFBitmap_Create(width, height, 0); FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF); FPDF_RenderPageBitmapWithMatrix(bitmap, page, &matrix, &rect, 0); - CompareBitmap(bitmap, width, height, kRotatedMD5); + CompareBitmap(bitmap, width, height, kRotateandStretchMD5); FPDFBitmap_Destroy(bitmap); UnloadPage(page); diff --git a/public/fpdfview.h b/public/fpdfview.h index c74fcb99d0..135d00a8f4 100644 --- a/public/fpdfview.h +++ b/public/fpdfview.h @@ -666,7 +666,7 @@ FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, // by FPDFBitmap_Create or retrieved by // FPDFImageObj_GetBitmap. // page - Handle to the page. Returned by FPDF_LoadPage -// matrix - The transform matrix. +// matrix - The transform matrix. It must be invertible. // clipping - The rect to clip to. // flags - 0 for normal display, or combination of the Page // Rendering flags defined above. With the FPDF_ANNOT @@ -674,7 +674,7 @@ FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, // user-interaction, which are all annotations except // widget and popup annotations. // Return value: -// None. +// None. Note that behavior is undefined if det of |matrix| is 0. FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap, FPDF_PAGE page, diff --git a/testing/resources/rectangles.in b/testing/resources/rectangles.in index ed71cf830a..49932fff2a 100644 --- a/testing/resources/rectangles.in +++ b/testing/resources/rectangles.in @@ -6,7 +6,7 @@ endobj {{object 2 0}} << /Type /Pages - /MediaBox [ 0 0 200 200 ] + /MediaBox [ 0 0 200 300 ] /Count 1 /Kids [ 3 0 R ] >> @@ -22,13 +22,17 @@ endobj stream q 0 0 0 rg -10 80 50 30 re B* +0 290 10 10 re B* +10 150 50 30 re B* 0 0 1 rg -70 135 50 30 re B* +190 290 10 10 re B* +70 232 50 30 re B* 0 1 0 rg -130 80 50 30 re B* +190 0 10 10 re B* +130 150 50 30 re B* 1 0 0 rg -70 25 50 30 re B* +0 0 10 10 re B* +70 67 50 30 re B* Q endstream endobj diff --git a/testing/resources/rectangles.pdf b/testing/resources/rectangles.pdf index 718bee56d9..7bad251ba7 100644 --- a/testing/resources/rectangles.pdf +++ b/testing/resources/rectangles.pdf @@ -7,7 +7,7 @@ endobj 2 0 obj << /Type /Pages - /MediaBox [ 0 0 200 200 ] + /MediaBox [ 0 0 200 300 ] /Count 1 /Kids [ 3 0 R ] >> @@ -23,13 +23,17 @@ endobj stream q 0 0 0 rg -10 80 50 30 re B* +0 290 10 10 re B* +10 150 50 30 re B* 0 0 1 rg -70 135 50 30 re B* +190 290 10 10 re B* +70 232 50 30 re B* 0 1 0 rg -130 80 50 30 re B* +190 0 10 10 re B* +130 150 50 30 re B* 1 0 0 rg -70 25 50 30 re B* +0 0 10 10 re B* +70 67 50 30 re B* Q endstream endobj @@ -42,5 +46,5 @@ xref 0000000230 00000 n trailer<< /Root 1 0 R /Size 5 >> startxref -382 +456 %%EOF |