From a78ba6043eafc9fd05481e64c37002b487357bbf Mon Sep 17 00:00:00 2001 From: thestig Date: Wed, 23 Nov 2016 15:25:48 -0800 Subject: Add FPDF_RenderPageBitmapWithMatrix API. BUG=pdfium:522 Review-Url: https://codereview.chromium.org/2526473002 --- core/fpdfdoc/cpdf_annotlist.cpp | 6 +- core/fpdfdoc/cpdf_annotlist.h | 6 +- fpdfsdk/fpdfview.cpp | 168 ++++++++++++++++++++++++++------------ fpdfsdk/fpdfview_c_api_test.c | 1 + fpdfsdk/fpdfview_embeddertest.cpp | 51 ++++++++++++ public/fpdfview.h | 32 ++++++-- 6 files changed, 199 insertions(+), 65 deletions(-) diff --git a/core/fpdfdoc/cpdf_annotlist.cpp b/core/fpdfdoc/cpdf_annotlist.cpp index e68e08a1f6..1ad6ab23a6 100644 --- a/core/fpdfdoc/cpdf_annotlist.cpp +++ b/core/fpdfdoc/cpdf_annotlist.cpp @@ -106,7 +106,7 @@ void CPDF_AnnotList::DisplayPass(CPDF_Page* pPage, CFX_RenderDevice* pDevice, CPDF_RenderContext* pContext, bool bPrinting, - CFX_Matrix* pMatrix, + const CFX_Matrix* pMatrix, bool bWidgetPass, CPDF_RenderOptions* pOptions, FX_RECT* clip_rect) { @@ -156,7 +156,7 @@ void CPDF_AnnotList::DisplayAnnots(CPDF_Page* pPage, CFX_RenderDevice* pDevice, CPDF_RenderContext* pContext, bool bPrinting, - CFX_Matrix* pUser2Device, + const CFX_Matrix* pUser2Device, uint32_t dwAnnotFlags, CPDF_RenderOptions* pOptions, FX_RECT* pClipRect) { @@ -173,7 +173,7 @@ void CPDF_AnnotList::DisplayAnnots(CPDF_Page* pPage, void CPDF_AnnotList::DisplayAnnots(CPDF_Page* pPage, CPDF_RenderContext* pContext, bool bPrinting, - CFX_Matrix* pMatrix, + const CFX_Matrix* pMatrix, bool bShowWidget, CPDF_RenderOptions* pOptions) { uint32_t dwAnnotFlags = bShowWidget ? ANNOTFLAG_INVISIBLE | ANNOTFLAG_HIDDEN diff --git a/core/fpdfdoc/cpdf_annotlist.h b/core/fpdfdoc/cpdf_annotlist.h index e17b958517..3443277b68 100644 --- a/core/fpdfdoc/cpdf_annotlist.h +++ b/core/fpdfdoc/cpdf_annotlist.h @@ -28,7 +28,7 @@ class CPDF_AnnotList { void DisplayAnnots(CPDF_Page* pPage, CPDF_RenderContext* pContext, bool bPrinting, - CFX_Matrix* pMatrix, + const CFX_Matrix* pMatrix, bool bShowWidget, CPDF_RenderOptions* pOptions); @@ -36,7 +36,7 @@ class CPDF_AnnotList { CFX_RenderDevice* pDevice, CPDF_RenderContext* pContext, bool bPrinting, - CFX_Matrix* pMatrix, + const CFX_Matrix* pMatrix, uint32_t dwAnnotFlags, CPDF_RenderOptions* pOptions, FX_RECT* pClipRect); @@ -52,7 +52,7 @@ class CPDF_AnnotList { CFX_RenderDevice* pDevice, CPDF_RenderContext* pContext, bool bPrinting, - CFX_Matrix* pMatrix, + const CFX_Matrix* pMatrix, bool bWidget, CPDF_RenderOptions* pOptions, FX_RECT* clip_rect); diff --git a/fpdfsdk/fpdfview.cpp b/fpdfsdk/fpdfview.cpp index 3f5115afd6..c7cc1242fe 100644 --- a/fpdfsdk/fpdfview.cpp +++ b/fpdfsdk/fpdfview.cpp @@ -48,6 +48,74 @@ #include "core/fxge/cfx_windowsdevice.h" #endif +namespace { + +void RenderPageImpl(CPDF_PageRenderContext* pContext, + CPDF_Page* pPage, + const CFX_Matrix& matrix, + const FX_RECT& clipping_rect, + int flags, + bool bNeedToRestore, + IFSDK_PAUSE_Adapter* pause) { + if (!pContext->m_pOptions) + pContext->m_pOptions = pdfium::MakeUnique(); + + if (flags & FPDF_LCD_TEXT) + pContext->m_pOptions->m_Flags |= RENDER_CLEARTYPE; + else + pContext->m_pOptions->m_Flags &= ~RENDER_CLEARTYPE; + + if (flags & FPDF_NO_NATIVETEXT) + pContext->m_pOptions->m_Flags |= RENDER_NO_NATIVETEXT; + if (flags & FPDF_RENDER_LIMITEDIMAGECACHE) + pContext->m_pOptions->m_Flags |= RENDER_LIMITEDIMAGECACHE; + if (flags & FPDF_RENDER_FORCEHALFTONE) + pContext->m_pOptions->m_Flags |= RENDER_FORCE_HALFTONE; +#ifndef PDF_ENABLE_XFA + if (flags & FPDF_RENDER_NO_SMOOTHTEXT) + pContext->m_pOptions->m_Flags |= RENDER_NOTEXTSMOOTH; + if (flags & FPDF_RENDER_NO_SMOOTHIMAGE) + pContext->m_pOptions->m_Flags |= RENDER_NOIMAGESMOOTH; + if (flags & FPDF_RENDER_NO_SMOOTHPATH) + pContext->m_pOptions->m_Flags |= RENDER_NOPATHSMOOTH; +#endif // PDF_ENABLE_XFA + + // Grayscale output + if (flags & FPDF_GRAYSCALE) { + pContext->m_pOptions->m_ColorMode = RENDER_COLOR_GRAY; + pContext->m_pOptions->m_ForeColor = 0; + pContext->m_pOptions->m_BackColor = 0xffffff; + } + + const CPDF_OCContext::UsageType usage = + (flags & FPDF_PRINTING) ? CPDF_OCContext::Print : CPDF_OCContext::View; + pContext->m_pOptions->m_AddFlags = flags >> 8; + pContext->m_pOptions->m_pOCContext = + new CPDF_OCContext(pPage->m_pDocument, usage); + + pContext->m_pDevice->SaveState(); + pContext->m_pDevice->SetClip_Rect(clipping_rect); + + pContext->m_pContext = pdfium::MakeUnique(pPage); + pContext->m_pContext->AppendLayer(pPage, &matrix); + + if (flags & FPDF_ANNOT) { + pContext->m_pAnnots = pdfium::MakeUnique(pPage); + bool bPrinting = pContext->m_pDevice->GetDeviceClass() != FXDC_DISPLAY; + pContext->m_pAnnots->DisplayAnnots(pPage, pContext->m_pContext.get(), + bPrinting, &matrix, false, nullptr); + } + + pContext->m_pRenderer = pdfium::MakeUnique( + pContext->m_pContext.get(), pContext->m_pDevice.get(), + pContext->m_pOptions.get()); + pContext->m_pRenderer->Start(pause); + if (bNeedToRestore) + pContext->m_pDevice->RestoreState(false); +} + +} // namespace + UnderlyingDocumentType* UnderlyingFromFPDFDocument(FPDF_DOCUMENT doc) { return static_cast(doc); } @@ -604,6 +672,50 @@ DLLEXPORT void STDCALL FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, pPage->SetRenderContext(nullptr); } +DLLEXPORT void STDCALL FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap, + FPDF_PAGE page, + const FS_MATRIX* matrix, + const FS_RECTF* clipping, + int flags) { + if (!bitmap) + return; + + CPDF_Page* pPage = CPDFPageFromFPDFPage(page); + if (!pPage) + return; + + CPDF_PageRenderContext* pContext = new CPDF_PageRenderContext; + pPage->SetRenderContext(pdfium::WrapUnique(pContext)); + CFX_FxgeDevice* pDevice = new CFX_FxgeDevice; + pContext->m_pDevice.reset(pDevice); + CFX_DIBitmap* pBitmap = CFXBitmapFromFPDFBitmap(bitmap); + pDevice->Attach(pBitmap, !!(flags & FPDF_REVERSE_BYTE_ORDER), nullptr, false); + + CFX_Matrix transform_matrix = pPage->GetPageMatrix(); + if (matrix) { + CFX_Matrix cmatrix; + cmatrix.a = matrix->a; + cmatrix.b = matrix->b; + cmatrix.c = matrix->c; + cmatrix.d = matrix->d; + cmatrix.e = matrix->e; + cmatrix.f = matrix->f; + transform_matrix.Concat(cmatrix); + } + + CFX_FloatRect clipping_rect; + if (clipping) { + clipping_rect.left = clipping->left; + clipping_rect.bottom = clipping->bottom; + clipping_rect.right = clipping->right; + clipping_rect.top = clipping->top; + } + RenderPageImpl(pContext, pPage, transform_matrix, clipping_rect.ToFxRect(), + flags, true, nullptr); + + pPage->SetRenderContext(nullptr); +} + #ifdef _SKIA_SUPPORT_ DLLEXPORT FPDF_RECORDER STDCALL FPDF_RenderPageSkp(FPDF_PAGE page, int size_x, @@ -813,62 +925,10 @@ void FPDF_RenderPage_Retail(CPDF_PageRenderContext* pContext, if (!pPage) return; - if (!pContext->m_pOptions) - pContext->m_pOptions = pdfium::MakeUnique(); - - if (flags & FPDF_LCD_TEXT) - pContext->m_pOptions->m_Flags |= RENDER_CLEARTYPE; - else - pContext->m_pOptions->m_Flags &= ~RENDER_CLEARTYPE; - if (flags & FPDF_NO_NATIVETEXT) - pContext->m_pOptions->m_Flags |= RENDER_NO_NATIVETEXT; - if (flags & FPDF_RENDER_LIMITEDIMAGECACHE) - pContext->m_pOptions->m_Flags |= RENDER_LIMITEDIMAGECACHE; - if (flags & FPDF_RENDER_FORCEHALFTONE) - pContext->m_pOptions->m_Flags |= RENDER_FORCE_HALFTONE; -#ifndef PDF_ENABLE_XFA - if (flags & FPDF_RENDER_NO_SMOOTHTEXT) - pContext->m_pOptions->m_Flags |= RENDER_NOTEXTSMOOTH; - if (flags & FPDF_RENDER_NO_SMOOTHIMAGE) - pContext->m_pOptions->m_Flags |= RENDER_NOIMAGESMOOTH; - if (flags & FPDF_RENDER_NO_SMOOTHPATH) - pContext->m_pOptions->m_Flags |= RENDER_NOPATHSMOOTH; -#endif // PDF_ENABLE_XFA - // Grayscale output - if (flags & FPDF_GRAYSCALE) { - pContext->m_pOptions->m_ColorMode = RENDER_COLOR_GRAY; - pContext->m_pOptions->m_ForeColor = 0; - pContext->m_pOptions->m_BackColor = 0xffffff; - } - const CPDF_OCContext::UsageType usage = - (flags & FPDF_PRINTING) ? CPDF_OCContext::Print : CPDF_OCContext::View; - pContext->m_pOptions->m_AddFlags = flags >> 8; - pContext->m_pOptions->m_pOCContext = - new CPDF_OCContext(pPage->m_pDocument, usage); - CFX_Matrix matrix; pPage->GetDisplayMatrix(matrix, start_x, start_y, size_x, size_y, rotate); - - pContext->m_pDevice->SaveState(); - pContext->m_pDevice->SetClip_Rect( - FX_RECT(start_x, start_y, start_x + size_x, start_y + size_y)); - - pContext->m_pContext = pdfium::MakeUnique(pPage); - pContext->m_pContext->AppendLayer(pPage, &matrix); - - if (flags & FPDF_ANNOT) { - pContext->m_pAnnots = pdfium::MakeUnique(pPage); - bool bPrinting = pContext->m_pDevice->GetDeviceClass() != FXDC_DISPLAY; - pContext->m_pAnnots->DisplayAnnots(pPage, pContext->m_pContext.get(), - bPrinting, &matrix, false, nullptr); - } - - pContext->m_pRenderer = pdfium::MakeUnique( - pContext->m_pContext.get(), pContext->m_pDevice.get(), - pContext->m_pOptions.get()); - pContext->m_pRenderer->Start(pause); - if (bNeedToRestore) - pContext->m_pDevice->RestoreState(false); + FX_RECT rect(start_x, start_y, start_x + size_x, start_y + size_y); + RenderPageImpl(pContext, pPage, matrix, rect, flags, bNeedToRestore, pause); } DLLEXPORT int STDCALL FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document, diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c index ed9a3fafe2..8cbbf4f3db 100644 --- a/fpdfsdk/fpdfview_c_api_test.c +++ b/fpdfsdk/fpdfview_c_api_test.c @@ -225,6 +225,7 @@ int CheckPDFiumCApi() { CHK(FPDF_GetPageHeight); CHK(FPDF_GetPageSizeByIndex); CHK(FPDF_RenderPageBitmap); + CHK(FPDF_RenderPageBitmapWithMatrix); CHK(FPDF_ClosePage); CHK(FPDF_CloseDocument); CHK(FPDF_DeviceToPage); diff --git a/fpdfsdk/fpdfview_embeddertest.cpp b/fpdfsdk/fpdfview_embeddertest.cpp index 65e52fec39..1d94b72553 100644 --- a/fpdfsdk/fpdfview_embeddertest.cpp +++ b/fpdfsdk/fpdfview_embeddertest.cpp @@ -327,3 +327,54 @@ TEST_F(FPDFViewEmbeddertest, Hang_355) { TEST_F(FPDFViewEmbeddertest, Hang_360) { EXPECT_FALSE(OpenDocument("bug_360.pdf")); } + +TEST_F(FPDFViewEmbeddertest, FPDF_RenderPageBitmapWithMatrix) { + const char kAllBlackMd5sum[] = "5708fc5c4a8bd0abde99c8e8f0390615"; + const char kTopLeftQuarterBlackMd5sum[] = "24e4d1ec06fa0258af758cfc8b2ad50a"; + + EXPECT_TRUE(OpenDocument("black.pdf")); + FPDF_PAGE page = LoadPage(0); + EXPECT_NE(nullptr, page); + const int width = static_cast(FPDF_GetPageWidth(page)); + const int height = static_cast(FPDF_GetPageHeight(page)); + EXPECT_EQ(612, width); + EXPECT_EQ(792, height); + + FPDF_BITMAP bitmap = RenderPage(page); + CompareBitmap(bitmap, width, height, kAllBlackMd5sum); + 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; + + FS_RECTF rect; + rect.left = 0; + rect.top = 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, kAllBlackMd5sum); + FPDFBitmap_Destroy(bitmap); + + // Now render again with the image scaled. + matrix.a = 0.5; + matrix.d = 0.5; + + 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, kTopLeftQuarterBlackMd5sum); + FPDFBitmap_Destroy(bitmap); + + UnloadPage(page); +} diff --git a/public/fpdfview.h b/public/fpdfview.h index 581951c7e2..403f4e46ec 100644 --- a/public/fpdfview.h +++ b/public/fpdfview.h @@ -596,11 +596,11 @@ DLLEXPORT void STDCALL FPDF_RenderPage(HDC dc, // 1 (rotated 90 degrees clockwise) // 2 (rotated 180 degrees) // 3 (rotated 90 degrees counter-clockwise) -// flags - 0 for normal display, or combination of flags -// defined above. With FPDF_ANNOT flag, it renders all -// annotations that does not require user-interaction, -// which are all annotations except widget and popup -// annotations. +// flags - 0 for normal display, or combination of the Page +// Rendering flags defined above. With the FPDF_ANNOT +// flag, it renders all annotations that do not require +// user-interaction, which are all annotations except +// widget and popup annotations. // Return value: // None. DLLEXPORT void STDCALL FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, @@ -612,6 +612,28 @@ DLLEXPORT void STDCALL FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, int rotate, int flags); +// Function: FPDF_RenderPageBitmapWithMatrix +// Render contents of a page to a device independent bitmap. +// Parameters: +// bitmap - Handle to the device independent bitmap (as the +// output buffer). The bitmap handle can be created +// by FPDFBitmap_Create. +// page - Handle to the page. Returned by FPDF_LoadPage +// matrix - The transform matrix. +// clipping - The rect to clip to. +// flags - 0 for normal display, or combination of the Page +// Rendering flags defined above. With the FPDF_ANNOT +// flag, it renders all annotations that do not require +// user-interaction, which are all annotations except +// widget and popup annotations. +// Return value: +// None. +DLLEXPORT void STDCALL FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap, + FPDF_PAGE page, + const FS_MATRIX* matrix, + const FS_RECTF* clipping, + int flags); + #ifdef _SKIA_SUPPORT_ DLLEXPORT FPDF_RECORDER STDCALL FPDF_RenderPageSkp(FPDF_PAGE page, int size_x, -- cgit v1.2.3