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);
