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 7b319a7..347b646 100644
--- a/include/vcl/filter/PDFiumLibrary.hxx
+++ b/include/vcl/filter/PDFiumLibrary.hxx
@@ -61,7 +61,8 @@
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 296e5ba..deb3411 100644
--- a/vcl/source/filter/ipdf/pdfread.cxx
+++ b/vcl/source/filter/ipdf/pdfread.cxx
@@ -65,12 +65,10 @@
// 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 @@
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 ad2f333..9fa2918 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 @@
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 @@
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 @@
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 @@
// 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);