diff options
-rw-r--r-- | include/vcl/pdfread.hxx | 5 | ||||
-rw-r--r-- | vcl/source/filter/ipdf/pdfread.cxx | 128 | ||||
-rw-r--r-- | vcl/source/gdi/impgraph.cxx | 40 |
3 files changed, 96 insertions, 77 deletions
diff --git a/include/vcl/pdfread.hxx b/include/vcl/pdfread.hxx index 346c39a3a897..1de9cfc9b259 100644 --- a/include/vcl/pdfread.hxx +++ b/include/vcl/pdfread.hxx @@ -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, diff --git a/vcl/source/filter/ipdf/pdfread.cxx b/vcl/source/filter/ipdf/pdfread.cxx index edd354f19e5b..63162c6e2ad2 100644 --- a/vcl/source/filter/ipdf/pdfread.cxx +++ b/vcl/source/filter/ipdf/pdfread.cxx @@ -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) diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx index 69e578d0e235..8b283081b966 100644 --- a/vcl/source/gdi/impgraph.cxx +++ b/vcl/source/gdi/impgraph.cxx @@ -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()) { |