diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-02-13 17:05:19 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-02-13 16:54:04 +0000 |
commit | 6657d52417295265367cf3ffe5832b60e3c38011 (patch) | |
tree | a664018f1eb611c88d8d73fd3b0241090ec36f8d /vcl/source/filter/ipdf/pdfread.cxx | |
parent | ofz: move size check before bitmap allocation (diff) | |
download | core-6657d52417295265367cf3ffe5832b60e3c38011.tar.gz core-6657d52417295265367cf3ffe5832b60e3c38011.zip |
vcl pdf import: use pdfium instead of draw_pdf_import
Replace creating a full Draw component with direct pdfium library calls.
This also means that the result is now a bitmap, not a metafile for now.
Also decouple HAVE_FEATURE_PDFIMPORT and HAVE_FEATURE_PDFIUM, the first
is the "import PDF into Draw" feature, the second is the "insert PDF as
image" feature.
Change-Id: I72c25642ec84cc831df362e02b1520c6e6d9adcf
Reviewed-on: https://gerrit.libreoffice.org/34217
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Tested-by: Jenkins <ci@libreoffice.org>
Diffstat (limited to 'vcl/source/filter/ipdf/pdfread.cxx')
-rw-r--r-- | vcl/source/filter/ipdf/pdfread.cxx | 167 |
1 files changed, 94 insertions, 73 deletions
diff --git a/vcl/source/filter/ipdf/pdfread.cxx b/vcl/source/filter/ipdf/pdfread.cxx index ac82050b7a77..ee31af65cc1f 100644 --- a/vcl/source/filter/ipdf/pdfread.cxx +++ b/vcl/source/filter/ipdf/pdfread.cxx @@ -9,60 +9,108 @@ #include "pdfread.hxx" -#include <com/sun/star/beans/XPropertySet.hpp> -#include <com/sun/star/document/XFilter.hpp> -#include <com/sun/star/document/XImporter.hpp> -#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> -#include <com/sun/star/frame/Desktop.hpp> -#include <com/sun/star/io/XStream.hpp> -#include <com/sun/star/lang/XMultiServiceFactory.hpp> - -#include <comphelper/processfactory.hxx> -#include <comphelper/propertyvalue.hxx> -#include <comphelper/scopeguard.hxx> -#include <unotools/streamwrap.hxx> -#include <vcl/wmf.hxx> +#include <config_features.h> + +#if HAVE_FEATURE_PDFIUM +#ifdef WNT +#include <prewin.h> +#endif +#include <fpdfview.h> +#include <fpdf_edit.h> +#ifdef WNT +#include <postwin.h> +#endif +#endif + +#include <vcl/bitmapaccess.hxx> using namespace com::sun::star; namespace { -/// Imports a PDF stream into Draw. -uno::Reference<lang::XComponent> importIntoDraw(SvStream& rStream) +/// Convert to inch, then assume 96 DPI. +double pointToPixel(double fPoint) { - // Create an empty Draw component. - uno::Reference<frame::XDesktop2> xDesktop = css::frame::Desktop::create(comphelper::getProcessComponentContext()); - uno::Reference<frame::XComponentLoader> xComponentLoader(xDesktop, uno::UNO_QUERY); - uno::Sequence<beans::PropertyValue> aLoadArguments = - { - comphelper::makePropertyValue("Hidden", true) - }; - uno::Reference<lang::XComponent> xComponent = xComponentLoader->loadComponentFromURL("private:factory/sdraw", "_default", 0, aLoadArguments); - - // Import the PDF into it. - uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(comphelper::getProcessServiceFactory()); - // Need to go via FilterFactory, otherwise XmlFilterAdaptor::initialize() is not called. - uno::Reference<lang::XMultiServiceFactory> xFilterFactory(xMultiServiceFactory->createInstance("com.sun.star.document.FilterFactory"), uno::UNO_QUERY); - uno::Reference<document::XFilter> xFilter(xFilterFactory->createInstanceWithArguments("draw_pdf_import", uno::Sequence<uno::Any>()), uno::UNO_QUERY); - uno::Reference<document::XImporter> xImporter(xFilter, uno::UNO_QUERY); - xImporter->setTargetDocument(xComponent); - - uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(rStream)); - uno::Sequence<beans::PropertyValue> aImportArguments = - { - // XmlFilterAdaptor::importImpl() mandates URL, even if it's empty. - comphelper::makePropertyValue("URL", OUString()), - comphelper::makePropertyValue("InputStream", xStream), - }; - - if (xFilter->filter(aImportArguments)) - return xComponent; - else + return fPoint / 72 * 96; +} + +/// Does PDF to PNG conversion using pdfium. +bool generatePreview(SvStream& rStream, Graphic& rGraphic) +{ +#if HAVE_FEATURE_PDFIUM + 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; + aInBuffer.WriteStream(rStream); + + // Load the buffer using pdfium. + FPDF_DOCUMENT pPdfDocument = FPDF_LoadMemDocument(aInBuffer.GetData(), aInBuffer.GetSize(), /*password=*/nullptr); + if (!pPdfDocument) + return false; + + // 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. + int nPageWidth = pointToPixel(FPDF_GetPageWidth(pPdfPage)); + int 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; + 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), 32); { - xComponent->dispose(); - return uno::Reference<lang::XComponent>(); + Bitmap::ScopedWriteAccess pWriteAccess(aBitmap); + const char* pPdfBuffer = static_cast<const char*>(FPDFBitmap_GetBuffer(pPdfBitmap)); +#ifndef MACOSX + std::memcpy(pWriteAccess->GetBuffer(), pPdfBuffer, nPageWidth * nPageHeight * 4); +#else + // ARGB -> BGRA + for (int nRow = 0; nRow < nPageHeight; ++nRow) + { + int nStride = FPDFBitmap_GetStride(pPdfBitmap); + const char* pPdfLine = pPdfBuffer + (nStride * nRow); + Scanline pRow = pWriteAccess->GetBuffer() + (nPageWidth * nRow * 4); + for (int nCol = 0; nCol < nPageWidth; ++nCol) + { + pRow[nCol * 4] = pPdfLine[(nCol * 4) + 3]; + pRow[(nCol * 4) + 1] = pPdfLine[(nCol * 4) + 2]; + pRow[(nCol * 4) + 2] = pPdfLine[(nCol * 4) + 1]; + pRow[(nCol * 4) + 3] = pPdfLine[nCol * 4]; + } + } +#endif } + BitmapEx aBitmapEx(aBitmap); +#if defined(WNT) || defined(MACOSX) + aBitmapEx.Mirror(BmpMirrorFlags::Vertical); +#endif + rGraphic = aBitmapEx; + + FPDFBitmap_Destroy(pPdfBitmap); + FPDF_ClosePage(pPdfPage); + FPDF_CloseDocument(pPdfDocument); + FPDF_DestroyLibrary(); +#else + (void)rStream; + (void)rGraphic; +#endif + + return true; } } @@ -72,37 +120,10 @@ namespace vcl bool ImportPDF(SvStream& rStream, Graphic& rGraphic) { - uno::Reference<lang::XComponent> xComponent = importIntoDraw(rStream); - if (!xComponent.is()) - return false; - comphelper::ScopeGuard aGuard([&xComponent]() - { - xComponent->dispose(); - }); - // Get the preview of the first page. - uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(xComponent, uno::UNO_QUERY); - uno::Reference<drawing::XDrawPages> xDrawPages = xDrawPagesSupplier->getDrawPages(); - if (xDrawPages->getCount() <= 0) + if (!generatePreview(rStream, rGraphic)) return false; - uno::Reference<beans::XPropertySet> xFirstPage(xDrawPages->getByIndex(0), uno::UNO_QUERY); - uno::Sequence<sal_Int8> aSequence; - if (!(xFirstPage->getPropertyValue("PreviewMetafile") >>= aSequence)) - return false; - - if (!aSequence.hasElements()) - return false; - - // Convert it into a GDIMetaFile. - SvMemoryStream aPreviewStream(aSequence.getLength()); - aPreviewStream.WriteBytes(aSequence.getArray(), aSequence.getLength()); - aPreviewStream.Seek(0); - GDIMetaFile aMtf; - aMtf.Read(aPreviewStream); - - rGraphic = aMtf; - // Save the original PDF stream for later use. rStream.Seek(STREAM_SEEK_TO_END); uno::Sequence<sal_Int8> aPdfData(rStream.Tell()); |