pdfium: Keep the PDF data in memory, so that we can really share them.
Otherwise the swap out / swap in creates new copy of the underlying PDF stream. Change-Id: I88a16a69143783a998201e183bea1a9553e337bd Reviewed-on: https://gerrit.libreoffice.org/56266 Reviewed-by: Ashod Nakashian <ashnakash@gmail.com> Tested-by: Ashod Nakashian <ashnakash@gmail.com> Reviewed-on: https://gerrit.libreoffice.org/69626 Reviewed-by: Jan Holesovsky <kendy@collabora.com> Tested-by: Jan Holesovsky <kendy@collabora.com> (cherry picked from commit 826208d2da6c92e94b38ef447e47550285742755) Reviewed-on: https://gerrit.libreoffice.org/77687 Tested-by: Jenkins
This commit is contained in:
committed by
Ashod Nakashian
parent
b26a3db534
commit
e4cec56a69
@@ -31,6 +31,11 @@ class Graphic;
|
||||
|
||||
namespace vcl
|
||||
{
|
||||
/// Fills the rBitmaps vector with rendered pages.
|
||||
VCL_DLLPUBLIC size_t RenderPDFBitmaps(const void* pBuffer, int nSize, std::vector<Bitmap>& rBitmaps,
|
||||
const size_t nFirstPage = 0, int nPages = 1,
|
||||
const double fResolutionDPI = 96.);
|
||||
|
||||
/// Imports a PDF stream into rGraphic as a GDIMetaFile.
|
||||
VCL_DLLPUBLIC bool ImportPDF(SvStream& rStream, Bitmap& rBitmap, size_t nPageIndex,
|
||||
css::uno::Sequence<sal_Int8>& rPdfData,
|
||||
|
||||
@@ -41,80 +41,23 @@ int CompatibleWriterCallback(FPDF_FILEWRITE* pFileWrite, const void* pData, unsi
|
||||
}
|
||||
|
||||
/// Convert to inch, then assume 96 DPI.
|
||||
double pointToPixel(const double fPoint, const double fResolutionDPI)
|
||||
inline double pointToPixel(const double fPoint, const double fResolutionDPI)
|
||||
{
|
||||
return fPoint * fResolutionDPI / 72.;
|
||||
}
|
||||
|
||||
/// Does PDF to bitmap conversion using pdfium.
|
||||
size_t generatePreview(SvStream& rStream, std::vector<Bitmap>& rBitmaps, sal_uInt64 nPos,
|
||||
sal_uInt64 nSize, const size_t nFirstPage, int nPages,
|
||||
sal_uInt64 nSize, const size_t nFirstPage = 0, int nPages = 1,
|
||||
const double fResolutionDPI = 96.)
|
||||
{
|
||||
FPDF_LIBRARY_CONFIG aConfig;
|
||||
aConfig.version = 2;
|
||||
aConfig.m_pUserFontPaths = nullptr;
|
||||
aConfig.m_pIsolate = nullptr;
|
||||
aConfig.m_v8EmbedderSlot = 0;
|
||||
FPDF_InitLibraryWithConfig(&aConfig);
|
||||
|
||||
// Read input into a buffer.
|
||||
SvMemoryStream aInBuffer;
|
||||
rStream.Seek(nPos);
|
||||
aInBuffer.WriteStream(rStream, nSize);
|
||||
|
||||
// Load the buffer using pdfium.
|
||||
FPDF_DOCUMENT pPdfDocument
|
||||
= FPDF_LoadMemDocument(aInBuffer.GetData(), aInBuffer.GetSize(), /*password=*/nullptr);
|
||||
if (!pPdfDocument)
|
||||
return 0;
|
||||
|
||||
const int nPageCount = FPDF_GetPageCount(pPdfDocument);
|
||||
if (nPages <= 0)
|
||||
nPages = nPageCount;
|
||||
const size_t nLastPage = std::min<int>(nPageCount, nFirstPage + nPages) - 1;
|
||||
for (size_t nPageIndex = nFirstPage; nPageIndex <= nLastPage; ++nPageIndex)
|
||||
{
|
||||
// Render next page.
|
||||
FPDF_PAGE pPdfPage = FPDF_LoadPage(pPdfDocument, nPageIndex);
|
||||
if (!pPdfPage)
|
||||
break;
|
||||
|
||||
// Returned unit is points, convert that to pixel.
|
||||
const size_t nPageWidth = pointToPixel(FPDF_GetPageWidth(pPdfPage), fResolutionDPI);
|
||||
const size_t nPageHeight = pointToPixel(FPDF_GetPageHeight(pPdfPage), fResolutionDPI);
|
||||
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);
|
||||
{
|
||||
BitmapScopedWriteAccess pWriteAccess(aBitmap);
|
||||
const auto pPdfBuffer = static_cast<ConstScanline>(FPDFBitmap_GetBuffer(pPdfBitmap));
|
||||
const int nStride = FPDFBitmap_GetStride(pPdfBitmap);
|
||||
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);
|
||||
}
|
||||
|
||||
FPDF_CloseDocument(pPdfDocument);
|
||||
FPDF_DestroyLibrary();
|
||||
|
||||
return rBitmaps.size();
|
||||
return vcl::RenderPDFBitmaps(aInBuffer.GetData(), aInBuffer.GetSize(), rBitmaps, nFirstPage,
|
||||
nPages, fResolutionDPI);
|
||||
}
|
||||
|
||||
/// Decide if PDF data is old enough to be compatible.
|
||||
@@ -205,6 +148,69 @@ bool getCompatibleStream(SvStream& rInStream, SvStream& rOutStream, sal_uInt64 n
|
||||
|
||||
namespace vcl
|
||||
{
|
||||
size_t RenderPDFBitmaps(const void* pBuffer, int nSize, std::vector<Bitmap>& rBitmaps,
|
||||
const size_t nFirstPage, int nPages, const double fResolutionDPI)
|
||||
{
|
||||
FPDF_LIBRARY_CONFIG aConfig;
|
||||
aConfig.version = 2;
|
||||
aConfig.m_pUserFontPaths = nullptr;
|
||||
aConfig.m_pIsolate = nullptr;
|
||||
aConfig.m_v8EmbedderSlot = 0;
|
||||
FPDF_InitLibraryWithConfig(&aConfig);
|
||||
|
||||
// Load the buffer using pdfium.
|
||||
FPDF_DOCUMENT pPdfDocument = FPDF_LoadMemDocument(pBuffer, nSize, /*password=*/nullptr);
|
||||
if (!pPdfDocument)
|
||||
return 0;
|
||||
|
||||
const int nPageCount = FPDF_GetPageCount(pPdfDocument);
|
||||
if (nPages <= 0)
|
||||
nPages = nPageCount;
|
||||
const size_t nLastPage = std::min<int>(nPageCount, nFirstPage + nPages) - 1;
|
||||
for (size_t nPageIndex = nFirstPage; nPageIndex <= nLastPage; ++nPageIndex)
|
||||
{
|
||||
// Render next page.
|
||||
FPDF_PAGE pPdfPage = FPDF_LoadPage(pPdfDocument, nPageIndex);
|
||||
if (!pPdfPage)
|
||||
break;
|
||||
|
||||
// Returned unit is points, convert that to pixel.
|
||||
const size_t nPageWidth = pointToPixel(FPDF_GetPageWidth(pPdfPage), fResolutionDPI);
|
||||
const size_t nPageHeight = pointToPixel(FPDF_GetPageHeight(pPdfPage), fResolutionDPI);
|
||||
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);
|
||||
{
|
||||
BitmapScopedWriteAccess pWriteAccess(aBitmap);
|
||||
const auto pPdfBuffer = static_cast<ConstScanline>(FPDFBitmap_GetBuffer(pPdfBitmap));
|
||||
const int nStride = FPDFBitmap_GetStride(pPdfBitmap);
|
||||
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);
|
||||
}
|
||||
|
||||
FPDF_CloseDocument(pPdfDocument);
|
||||
FPDF_DestroyLibrary();
|
||||
|
||||
return rBitmaps.size();
|
||||
}
|
||||
|
||||
bool ImportPDF(SvStream& rStream, Bitmap& rBitmap, size_t nPageIndex,
|
||||
css::uno::Sequence<sal_Int8>& rPdfData, sal_uInt64 nPos, sal_uInt64 nSize,
|
||||
const double fResolutionDPI)
|
||||
|
||||
+24
-16
@@ -41,6 +41,7 @@
|
||||
#include <com/sun/star/ucb/ContentCreationException.hpp>
|
||||
#include <com/sun/star/graphic/XPrimitive2D.hpp>
|
||||
#include <vcl/dibtools.hxx>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vcl/gdimetafiletools.hxx>
|
||||
|
||||
@@ -1731,6 +1732,7 @@ bool ImpGraphic::ImplExportNative( SvStream& rOStm ) const
|
||||
return bResult;
|
||||
}
|
||||
|
||||
static std::map<BitmapChecksum, std::shared_ptr<css::uno::Sequence<sal_Int8>>> sPdfDataCache;
|
||||
|
||||
void ReadImpGraphic( SvStream& rIStm, ImpGraphic& rImpGraphic )
|
||||
{
|
||||
@@ -1879,23 +1881,25 @@ void ReadImpGraphic( SvStream& rIStm, ImpGraphic& rImpGraphic )
|
||||
else if (nMagic == nPdfMagic)
|
||||
{
|
||||
// Stream in PDF data.
|
||||
sal_uInt32 nPdfDataLength = 0;
|
||||
rIStm.ReadUInt32(nPdfDataLength);
|
||||
BitmapChecksum nPdfId = 0;
|
||||
rIStm.ReadUInt64(nPdfId);
|
||||
|
||||
rImpGraphic.mnPageNumber = 0;
|
||||
rIStm.ReadInt32(rImpGraphic.mnPageNumber);
|
||||
|
||||
auto it = sPdfDataCache.find(nPdfId);
|
||||
assert(it != sPdfDataCache.end());
|
||||
|
||||
rImpGraphic.mpPdfData = it->second;
|
||||
|
||||
Bitmap aBitmap;
|
||||
rImpGraphic.maEx = aBitmap;
|
||||
|
||||
if (nPdfDataLength && !rIStm.GetError())
|
||||
{
|
||||
if (!rImpGraphic.mpPdfData)
|
||||
rImpGraphic.mpPdfData.reset(new uno::Sequence<sal_Int8>());
|
||||
std::vector<Bitmap> aBitmaps;
|
||||
if (vcl::RenderPDFBitmaps(rImpGraphic.mpPdfData->getConstArray(), rImpGraphic.mpPdfData->getLength(), aBitmaps, rImpGraphic.mnPageNumber, 1) == 1)
|
||||
rImpGraphic.maEx = aBitmaps[0];
|
||||
|
||||
if (vcl::ImportPDF(rIStm, aBitmap, rImpGraphic.mnPageNumber,
|
||||
*rImpGraphic.mpPdfData,
|
||||
rIStm.Tell(), nPdfDataLength))
|
||||
{
|
||||
rImpGraphic.maEx = aBitmap;
|
||||
rImpGraphic.meType = GraphicType::Bitmap;
|
||||
}
|
||||
}
|
||||
rImpGraphic.meType = GraphicType::Bitmap;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1988,10 +1992,14 @@ void WriteImpGraphic(SvStream& rOStm, const ImpGraphic& rImpGraphic)
|
||||
}
|
||||
else if (rImpGraphic.hasPdfData())
|
||||
{
|
||||
BitmapChecksum nPdfId = vcl_get_checksum(0, rImpGraphic.mpPdfData->getConstArray(), rImpGraphic.mpPdfData->getLength());
|
||||
if (sPdfDataCache.find(nPdfId) == sPdfDataCache.end())
|
||||
sPdfDataCache.emplace(nPdfId, rImpGraphic.mpPdfData);
|
||||
|
||||
// Stream out PDF data.
|
||||
rOStm.WriteUInt32(nPdfMagic);
|
||||
rOStm.WriteUInt32(rImpGraphic.mpPdfData->getLength());
|
||||
rOStm.WriteBytes(rImpGraphic.mpPdfData->getConstArray(), rImpGraphic.mpPdfData->getLength());
|
||||
rOStm.WriteUInt64(nPdfId);
|
||||
rOStm.WriteInt32(rImpGraphic.mnPageNumber);
|
||||
}
|
||||
else if( rImpGraphic.ImplIsAnimated())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user