Kaydet (Commit) 3102b8c8 authored tarafından Ashod Nakashian's avatar Ashod Nakashian Kaydeden (comit) Ashod Nakashian

vcl: support rendering multiple PDF pages to bitmap

Change-Id: Id42ecabcad90dde84475a01e5df4ed94f221f5ce
Reviewed-on: https://gerrit.libreoffice.org/51255Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarAshod Nakashian <ashnakash@gmail.com>
üst ac6e6753
...@@ -58,8 +58,9 @@ double pointToPixel(double fPoint) ...@@ -58,8 +58,9 @@ double pointToPixel(double fPoint)
} }
/// Does PDF to bitmap conversion using pdfium. /// Does PDF to bitmap conversion using pdfium.
bool generatePreview(SvStream& rStream, Bitmap& rBitmap, size_t generatePreview(SvStream& rStream, std::vector<Bitmap>& rBitmaps,
sal_uInt64 nPos, sal_uInt64 nSize) sal_uInt64 nPos, sal_uInt64 nSize,
const size_t nFirstPage = 0, int nPages = 1)
{ {
FPDF_LIBRARY_CONFIG aConfig; FPDF_LIBRARY_CONFIG aConfig;
aConfig.version = 2; aConfig.version = 2;
...@@ -76,45 +77,53 @@ bool generatePreview(SvStream& rStream, Bitmap& rBitmap, ...@@ -76,45 +77,53 @@ bool generatePreview(SvStream& rStream, Bitmap& rBitmap,
// Load the buffer using pdfium. // Load the buffer using pdfium.
FPDF_DOCUMENT pPdfDocument = FPDF_LoadMemDocument(aInBuffer.GetData(), aInBuffer.GetSize(), /*password=*/nullptr); FPDF_DOCUMENT pPdfDocument = FPDF_LoadMemDocument(aInBuffer.GetData(), aInBuffer.GetSize(), /*password=*/nullptr);
if (!pPdfDocument) if (!pPdfDocument)
return false; return 0;
// Render the first page.
FPDF_PAGE pPdfPage = FPDF_LoadPage(pPdfDocument, /*page_index=*/0);
if (!pPdfPage)
return false;
// Returned unit is points, convert that to pixel.
size_t nPageWidth = pointToPixel(FPDF_GetPageWidth(pPdfPage));
size_t nPageHeight = pointToPixel(FPDF_GetPageHeight(pPdfPage));
FPDF_BITMAP pPdfBitmap = FPDFBitmap_Create(nPageWidth, nPageHeight, /*alpha=*/1);
if (!pPdfBitmap)
return false;
FPDF_DWORD nColor = FPDFPage_HasTransparency(pPdfPage) ? 0x00000000 : 0xFFFFFFFF; const int nPageCount = FPDF_GetPageCount(pPdfDocument);
FPDFBitmap_FillRect(pPdfBitmap, 0, 0, nPageWidth, nPageHeight, nColor); if (nPages <= 0)
FPDF_RenderPageBitmap(pPdfBitmap, pPdfPage, /*start_x=*/0, /*start_y=*/0, nPageWidth, nPageHeight, /*rotate=*/0, /*flags=*/0); nPages = nPageCount;
const size_t nLastPage = std::min<int>(nPageCount, nFirstPage + nPages) - 1;
// Save the buffer as a bitmap. for (size_t nPageIndex = nFirstPage; nPageIndex <= nLastPage; ++nPageIndex)
Bitmap aBitmap(Size(nPageWidth, nPageHeight), 24);
{ {
BitmapScopedWriteAccess pWriteAccess(aBitmap); // Render next page.
auto pPdfBuffer = static_cast<ConstScanline>(FPDFBitmap_GetBuffer(pPdfBitmap)); FPDF_PAGE pPdfPage = FPDF_LoadPage(pPdfDocument, nPageIndex);
for (size_t nRow = 0; nRow < nPageHeight; ++nRow) if (!pPdfPage)
break;
// Returned unit is points, convert that to pixel.
const size_t nPageWidth = pointToPixel(FPDF_GetPageWidth(pPdfPage));
const size_t nPageHeight = pointToPixel(FPDF_GetPageHeight(pPdfPage));
FPDF_BITMAP pPdfBitmap = FPDFBitmap_Create(nPageWidth, nPageHeight, /*alpha=*/1);
if (!pPdfBitmap)
break;
const FPDF_DWORD nColor = FPDFPage_HasTransparency(pPdfPage) ? 0x00000000 : 0xFFFFFFFF;
FPDFBitmap_FillRect(pPdfBitmap, 0, 0, nPageWidth, nPageHeight, nColor);
FPDF_RenderPageBitmap(pPdfBitmap, pPdfPage, /*start_x=*/0, /*start_y=*/0, nPageWidth, nPageHeight, /*rotate=*/0, /*flags=*/0);
// Save the buffer as a bitmap.
Bitmap aBitmap(Size(nPageWidth, nPageHeight), 24);
{ {
int nStride = FPDFBitmap_GetStride(pPdfBitmap); BitmapScopedWriteAccess pWriteAccess(aBitmap);
ConstScanline pPdfLine = pPdfBuffer + (nStride * nRow); const auto pPdfBuffer = static_cast<ConstScanline>(FPDFBitmap_GetBuffer(pPdfBitmap));
// pdfium byte order is BGRA. const int nStride = FPDFBitmap_GetStride(pPdfBitmap);
pWriteAccess->CopyScanline(nRow, pPdfLine, ScanlineFormat::N32BitTcBgra, nStride); for (size_t nRow = 0; nRow < nPageHeight; ++nRow)
{
ConstScanline pPdfLine = pPdfBuffer + (nStride * nRow);
// pdfium byte order is BGRA.
pWriteAccess->CopyScanline(nRow, pPdfLine, ScanlineFormat::N32BitTcBgra, nStride);
}
} }
rBitmaps.emplace_back(std::move(aBitmap));
FPDFBitmap_Destroy(pPdfBitmap);
FPDF_ClosePage(pPdfPage);
} }
rBitmap = aBitmap;
FPDFBitmap_Destroy(pPdfBitmap);
FPDF_ClosePage(pPdfPage);
FPDF_CloseDocument(pPdfDocument); FPDF_CloseDocument(pPdfDocument);
FPDF_DestroyLibrary(); FPDF_DestroyLibrary();
return true; return rBitmaps.size();
} }
/// Decide if PDF data is old enough to be compatible. /// Decide if PDF data is old enough to be compatible.
...@@ -182,10 +191,11 @@ bool getCompatibleStream(SvStream& rInStream, SvStream& rOutStream, ...@@ -182,10 +191,11 @@ bool getCompatibleStream(SvStream& rInStream, SvStream& rOutStream,
return rOutStream.good(); return rOutStream.good();
} }
#else #else
bool generatePreview(SvStream&, Bitmap&, size_t generatePreview(SvStream&, std::vector<Bitmap>&,
sal_uInt64, sal_uInt64) sal_uInt64 nPos, sal_uInt64 nSize,
size_t nFirstPage = 0, int nLastPage = 0)
{ {
return true; return false;
} }
bool getCompatibleStream(SvStream& rInStream, SvStream& rOutStream, bool getCompatibleStream(SvStream& rInStream, SvStream& rOutStream,
...@@ -207,9 +217,12 @@ bool ImportPDF(SvStream& rStream, Bitmap& rBitmap, ...@@ -207,9 +217,12 @@ bool ImportPDF(SvStream& rStream, Bitmap& rBitmap,
sal_uInt64 nPos, sal_uInt64 nSize) sal_uInt64 nPos, sal_uInt64 nSize)
{ {
// Get the preview of the first page. // Get the preview of the first page.
if (!generatePreview(rStream, rBitmap, nPos, nSize)) std::vector<Bitmap> aBitmaps;
if (generatePreview(rStream, aBitmaps, nPos, nSize, 0, 1) != 1)
return false; return false;
rBitmap = aBitmaps[0];
// Save the original PDF stream for later use. // Save the original PDF stream for later use.
SvMemoryStream aMemoryStream; SvMemoryStream aMemoryStream;
if (!getCompatibleStream(rStream, aMemoryStream, nPos, nSize)) if (!getCompatibleStream(rStream, aMemoryStream, nPos, nSize))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment