include/vcl/filter/PDFiumLibrary.hxx |    3 +-
 vcl/source/filter/ipdf/pdfread.cxx   |   14 ++++------
 vcl/source/pdf/PDFiumLibrary.cxx     |   49 ++++++++++++++++++++++++++---------
 3 files changed, 45 insertions(+), 21 deletions(-)

New commits:
commit a5c1cbcbb506e1c33c7e80673bfc01a34c834ed5
Author:     Szymon Kłos <[email protected]>
AuthorDate: Mon Nov 21 15:23:59 2022 +0100
Commit:     Szymon Kłos <[email protected]>
CommitDate: Fri Nov 25 08:01:20 2022 +0100

    pdfium: reduce size if cannot create bitmap
    
    In files with large pages it was rendering white, empty
    content. That was because bitmap creation in the PDFium
    failed. This reduces the size to possible value.
    
    Signed-off-by: Szymon Kłos <[email protected]>
    Change-Id: I093a6aff94104cdc8223d7b8cbc00ff9217021b8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143037
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Miklos Vajna <[email protected]>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143243
    Tested-by: Jenkins

diff --git a/include/vcl/filter/PDFiumLibrary.hxx 
b/include/vcl/filter/PDFiumLibrary.hxx
index 7b319a727259..347b64619045 100644
--- a/include/vcl/filter/PDFiumLibrary.hxx
+++ b/include/vcl/filter/PDFiumLibrary.hxx
@@ -61,7 +61,8 @@ public:
                                                          const OString& 
rPassword)
         = 0;
     virtual PDFErrorType getLastErrorCode() = 0;
-    virtual std::unique_ptr<PDFiumBitmap> createBitmap(int nWidth, int 
nHeight, int nAlpha) = 0;
+    /// createBitmap can reduce requested size to possible value
+    virtual std::unique_ptr<PDFiumBitmap> createBitmap(int& nWidth, int& 
nHeight, int nAlpha) = 0;
 };
 
 class PDFiumPage;
diff --git a/vcl/source/filter/ipdf/pdfread.cxx 
b/vcl/source/filter/ipdf/pdfread.cxx
index 296e5ba69a5c..deb341157137 100644
--- a/vcl/source/filter/ipdf/pdfread.cxx
+++ b/vcl/source/filter/ipdf/pdfread.cxx
@@ -65,12 +65,10 @@ size_t RenderPDFBitmaps(const void* pBuffer, int nSize, 
std::vector<BitmapEx>& r
 
         // Returned unit is points, convert that to pixel.
 
-        const size_t nPageWidth
-            = std::round(vcl::pdf::pointToPixel(nPageWidthPoints, 
fResolutionDPI)
-                         * PDF_INSERT_MAGIC_SCALE_FACTOR);
-        const size_t nPageHeight
-            = std::round(vcl::pdf::pointToPixel(nPageHeightPoints, 
fResolutionDPI)
-                         * PDF_INSERT_MAGIC_SCALE_FACTOR);
+        int nPageWidth = std::round(vcl::pdf::pointToPixel(nPageWidthPoints, 
fResolutionDPI)
+                                    * PDF_INSERT_MAGIC_SCALE_FACTOR);
+        int nPageHeight = std::round(vcl::pdf::pointToPixel(nPageHeightPoints, 
fResolutionDPI)
+                                     * PDF_INSERT_MAGIC_SCALE_FACTOR);
         std::unique_ptr<vcl::pdf::PDFiumBitmap> pPdfBitmap
             = pPdfium->createBitmap(nPageWidth, nPageHeight, /*nAlpha=*/1);
         if (!pPdfBitmap)
@@ -97,12 +95,12 @@ size_t RenderPDFBitmaps(const void* pBuffer, int nSize, 
std::vector<BitmapEx>& r
             ConstScanline pPdfBuffer = pPdfBitmap->getBuffer();
             const int nStride = pPdfBitmap->getStride();
             std::vector<sal_uInt8> aScanlineAlpha(nPageWidth);
-            for (size_t nRow = 0; nRow < nPageHeight; ++nRow)
+            for (int nRow = 0; nRow < nPageHeight; ++nRow)
             {
                 ConstScanline pPdfLine = pPdfBuffer + (nStride * nRow);
                 // pdfium byte order is BGRA.
                 pWriteAccess->CopyScanline(nRow, pPdfLine, 
ScanlineFormat::N32BitTcBgra, nStride);
-                for (size_t nCol = 0; nCol < nPageWidth; ++nCol)
+                for (int nCol = 0; nCol < nPageWidth; ++nCol)
                 {
                     // Invert alpha (source is alpha, target is opacity).
                     aScanlineAlpha[nCol] = ~pPdfLine[3];
diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx
index ad2f3332bea9..9fa291898f8c 100644
--- a/vcl/source/pdf/PDFiumLibrary.cxx
+++ b/vcl/source/pdf/PDFiumLibrary.cxx
@@ -12,6 +12,7 @@
 
 #include <cassert>
 
+#include <sal/log.hxx>
 #include <fpdf_doc.h>
 #include <fpdf_annot.h>
 #include <fpdf_edit.h>
@@ -466,7 +467,8 @@ public:
     std::unique_ptr<PDFiumDocument> openDocument(const void* pData, int nSize,
                                                  const OString& rPassword) 
override;
     PDFErrorType getLastErrorCode() override;
-    std::unique_ptr<PDFiumBitmap> createBitmap(int nWidth, int nHeight, int 
nAlpha) override;
+    /// @brief creates bitmap, can reduce size if needed, check nWidth and 
nHeight
+    std::unique_ptr<PDFiumBitmap> createBitmap(int& nWidth, int& nHeight, int 
nAlpha) override;
 };
 }
 
@@ -537,13 +539,36 @@ PDFErrorType PDFiumImpl::getLastErrorCode()
     return static_cast<PDFErrorType>(FPDF_GetLastError());
 }
 
-std::unique_ptr<PDFiumBitmap> PDFiumImpl::createBitmap(int nWidth, int 
nHeight, int nAlpha)
+std::unique_ptr<PDFiumBitmap> PDFiumImpl::createBitmap(int& nWidth, int& 
nHeight, int nAlpha)
 {
     std::unique_ptr<PDFiumBitmap> pPDFiumBitmap;
+
     FPDF_BITMAP pPdfBitmap = FPDFBitmap_Create(nWidth, nHeight, nAlpha);
+    if (!pPdfBitmap)
+    {
+        int nOriginal = nHeight;
+        // PDFium cannot create big bitmaps, max 2^14 x 2^14 x 4 bytes per 
pixel
+        if (nHeight > 16384)
+            nHeight = 16384;
+
+        if (nWidth > 16384)
+        {
+            nWidth = 16384.0 / nOriginal * nWidth;
+        }
+
+        if (nWidth * nHeight > 16384 * 16384)
+        {
+            nOriginal = nWidth;
+            nHeight = 16384.0 / nOriginal * nHeight;
+        }
+
+        pPdfBitmap = FPDFBitmap_Create(nWidth, nHeight, nAlpha);
+    }
+
     if (!pPdfBitmap)
     {
         maLastError = "Failed to create bitmap";
+        SAL_WARN("vcl.filter", "PDFiumImpl: " << getLastError());
     }
     else
     {
@@ -955,14 +980,14 @@ bool PDFiumPageObjectImpl::getDrawMode(PDFFillMode& 
rFillMode, bool& rStroke)
 
 BitmapChecksum PDFiumPageImpl::getChecksum(int nMDPPerm)
 {
-    size_t nPageWidth = getWidth();
-    size_t nPageHeight = getHeight();
-    auto pPdfBitmap = std::make_unique<PDFiumBitmapImpl>(
-        FPDFBitmap_Create(nPageWidth, nPageHeight, /*alpha=*/1));
+    int nPageWidth = getWidth();
+    int nPageHeight = getHeight();
+    std::unique_ptr<PDFiumBitmap> pPdfBitmap
+        = PDFiumLibrary::get()->createBitmap(nPageWidth, nPageHeight, 
/*nAlpha=*/1);
     if (!pPdfBitmap)
-    {
         return 0;
-    }
+
+    PDFiumBitmapImpl* pBitmapImpl = 
static_cast<PDFiumBitmapImpl*>(pPdfBitmap.get());
 
     int nFlags = 0;
     if (nMDPPerm != 3)
@@ -970,16 +995,16 @@ BitmapChecksum PDFiumPageImpl::getChecksum(int nMDPPerm)
         // Annotations/commenting should affect the checksum, signature 
verification wants this.
         nFlags = FPDF_ANNOT;
     }
-    FPDF_RenderPageBitmap(pPdfBitmap->getPointer(), mpPage, /*start_x=*/0, 
/*start_y=*/0,
+    FPDF_RenderPageBitmap(pBitmapImpl->getPointer(), mpPage, /*start_x=*/0, 
/*start_y=*/0,
                           nPageWidth, nPageHeight,
                           /*rotate=*/0, nFlags);
     Bitmap aBitmap(Size(nPageWidth, nPageHeight), vcl::PixelFormat::N24_BPP);
     {
         BitmapScopedWriteAccess pWriteAccess(aBitmap);
         const auto pPdfBuffer
-            = 
static_cast<ConstScanline>(FPDFBitmap_GetBuffer(pPdfBitmap->getPointer()));
-        const int nStride = FPDFBitmap_GetStride(pPdfBitmap->getPointer());
-        for (size_t nRow = 0; nRow < nPageHeight; ++nRow)
+            = 
static_cast<ConstScanline>(FPDFBitmap_GetBuffer(pBitmapImpl->getPointer()));
+        const int nStride = FPDFBitmap_GetStride(pBitmapImpl->getPointer());
+        for (int nRow = 0; nRow < nPageHeight; ++nRow)
         {
             ConstScanline pPdfLine = pPdfBuffer + (nStride * nRow);
             pWriteAccess->CopyScanline(nRow, pPdfLine, 
ScanlineFormat::N32BitTcBgra, nStride);

Reply via email to