diff options
-rw-r--r-- | config_host/config_features.h.in | 5 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | sd/qa/unit/export-tests.cxx | 2 | ||||
-rw-r--r-- | sd/source/ui/view/drviews2.cxx | 2 | ||||
-rw-r--r-- | svtools/qa/unit/GraphicObjectTest.cxx | 2 | ||||
-rw-r--r-- | svtools/source/graphic/grfcache.cxx | 8 | ||||
-rw-r--r-- | svx/qa/unit/xoutdev.cxx | 2 | ||||
-rw-r--r-- | svx/source/svdraw/svdograf.cxx | 4 | ||||
-rw-r--r-- | sw/qa/extras/odfexport/odfexport.cxx | 2 | ||||
-rw-r--r-- | sw/source/core/graphic/ndgrf.cxx | 4 | ||||
-rw-r--r-- | vcl/CppunitTest_vcl_wmf_test.mk | 1 | ||||
-rw-r--r-- | vcl/Library_vcl.mk | 1 | ||||
-rw-r--r-- | vcl/source/filter/ipdf/pdfread.cxx | 167 | ||||
-rw-r--r-- | vcl/source/gdi/impgraph.cxx | 23 |
14 files changed, 127 insertions, 97 deletions
diff --git a/config_host/config_features.h.in b/config_host/config_features.h.in index 5dd85dfc3ea6..8e52a6576c8d 100644 --- a/config_host/config_features.h.in +++ b/config_host/config_features.h.in @@ -184,4 +184,9 @@ */ #define HAVE_FEATURE_NSS 0 +/* + * Whether pdfium is available + */ +#define HAVE_FEATURE_PDFIUM 0 + #endif diff --git a/configure.ac b/configure.ac index 7338bb5ec2b0..7667baedae3b 100644 --- a/configure.ac +++ b/configure.ac @@ -10334,6 +10334,7 @@ ENABLE_PDFIUM= if test -z "$enable_pdfium" -o "$enable_pdfium" = yes; then AC_MSG_RESULT([yes]) ENABLE_PDFIUM=TRUE + AC_DEFINE(HAVE_FEATURE_PDFIUM) BUILD_TYPE="$BUILD_TYPE PDFIUM" else AC_MSG_RESULT([no]) diff --git a/sd/qa/unit/export-tests.cxx b/sd/qa/unit/export-tests.cxx index 3f2882384031..797bf36d6192 100644 --- a/sd/qa/unit/export-tests.cxx +++ b/sd/qa/unit/export-tests.cxx @@ -540,7 +540,7 @@ void SdExportTest::testTdf62176() void SdExportTest::testEmbeddedPdf() { -#if HAVE_FEATURE_PDFIMPORT +#if HAVE_FEATURE_PDFIUM sd::DrawDocShellRef xShell = loadURL(m_directories.getURLFromSrc("/sd/qa/unit/data/odp/embedded-pdf.odp"), ODP); xShell = saveAndReload( xShell.get(), ODP ); uno::Reference<drawing::XDrawPage> xPage = getPage(0, xShell); diff --git a/sd/source/ui/view/drviews2.cxx b/sd/source/ui/view/drviews2.cxx index 2ff7c77137c2..93e228981a44 100644 --- a/sd/source/ui/view/drviews2.cxx +++ b/sd/source/ui/view/drviews2.cxx @@ -927,7 +927,7 @@ void DrawViewShell::FuTemporary(SfxRequest& rReq) if( rMarkList.GetMarkCount() == 1 ) { const SdrGrafObj* pObj = dynamic_cast<const SdrGrafObj*>(rMarkList.GetMark(0)->GetMarkedSdrObj()); - if (pObj && (pObj->GetGraphicType() == GraphicType::Bitmap || pObj->GetGraphicObject().GetGraphic().getPdfData().hasElements())) + if (pObj && pObj->GetGraphicType() == GraphicType::Bitmap) { GraphicObject aGraphicObject(pObj->GetGraphicObject()); { diff --git a/svtools/qa/unit/GraphicObjectTest.cxx b/svtools/qa/unit/GraphicObjectTest.cxx index 7d938746a76b..031a3eab6d58 100644 --- a/svtools/qa/unit/GraphicObjectTest.cxx +++ b/svtools/qa/unit/GraphicObjectTest.cxx @@ -311,7 +311,7 @@ void GraphicObjectTest::testTdf88935() void GraphicObjectTest::testPdf() { -#if HAVE_FEATURE_PDFIMPORT +#if HAVE_FEATURE_PDFIUM uno::Reference<lang::XComponent> xComponent = loadFromDesktop(m_directories.getURLFromSrc("svtools/qa/unit/data/pdf.odt"), "com.sun.star.text.TextDocument"); SwXTextDocument* pTxtDoc = dynamic_cast<SwXTextDocument*>(xComponent.get()); CPPUNIT_ASSERT(pTxtDoc); diff --git a/svtools/source/graphic/grfcache.cxx b/svtools/source/graphic/grfcache.cxx index 273afffaeedc..2b158698548b 100644 --- a/svtools/source/graphic/grfcache.cxx +++ b/svtools/source/graphic/grfcache.cxx @@ -240,6 +240,8 @@ bool GraphicCacheEntry::ImplInit( const GraphicObject& rObj ) else { mpBmpEx = new BitmapEx( rGraphic.GetBitmapEx() ); + if (rGraphic.getPdfData().hasElements()) + maPdfData = rGraphic.getPdfData(); } } break; @@ -247,8 +249,6 @@ bool GraphicCacheEntry::ImplInit( const GraphicObject& rObj ) case GraphicType::GdiMetafile: { mpMtf = new GDIMetaFile( rGraphic.GetGDIMetaFile() ); - if (rGraphic.getPdfData().hasElements()) - maPdfData = rGraphic.getPdfData(); } break; @@ -287,6 +287,8 @@ void GraphicCacheEntry::ImplFillSubstitute( Graphic& rSubstitute ) else if( mpBmpEx ) { rSubstitute = *mpBmpEx; + if (maPdfData.hasElements()) + rSubstitute.setPdfData(maPdfData); } else if( mpAnimation ) { @@ -295,8 +297,6 @@ void GraphicCacheEntry::ImplFillSubstitute( Graphic& rSubstitute ) else if( mpMtf ) { rSubstitute = *mpMtf; - if (maPdfData.hasElements()) - rSubstitute.setPdfData(maPdfData); } else { diff --git a/svx/qa/unit/xoutdev.cxx b/svx/qa/unit/xoutdev.cxx index 5bd31799eaee..7b472b9628d7 100644 --- a/svx/qa/unit/xoutdev.cxx +++ b/svx/qa/unit/xoutdev.cxx @@ -34,7 +34,7 @@ public: void XOutdevTest::testPdfGraphicExport() { -#if HAVE_FEATURE_PDFIMPORT +#if HAVE_FEATURE_PDFIUM // Import the graphic. Graphic aGraphic; test::Directories aDirectories; diff --git a/svx/source/svdraw/svdograf.cxx b/svx/source/svdraw/svdograf.cxx index 0103498ca4af..4875a4f8d6c0 100644 --- a/svx/source/svdraw/svdograf.cxx +++ b/svx/source/svdraw/svdograf.cxx @@ -439,8 +439,8 @@ const GraphicObject* SdrGrafObj::GetReplacementGraphicObject() const const_cast< SdrGrafObj* >(this)->mpReplacementGraphic = new GraphicObject(rSvgDataPtr->getReplacement()); } else if (pGraphic->GetGraphic().getPdfData().hasElements()) - // Replacement graphic for metafile + PDF is just the metafile. - const_cast<SdrGrafObj*>(this)->mpReplacementGraphic = new GraphicObject(pGraphic->GetGraphic().GetGDIMetaFile()); + // Replacement graphic for bitmap + PDF is just the bitmap. + const_cast<SdrGrafObj*>(this)->mpReplacementGraphic = new GraphicObject(pGraphic->GetGraphic().GetBitmapEx()); } return mpReplacementGraphic; diff --git a/sw/qa/extras/odfexport/odfexport.cxx b/sw/qa/extras/odfexport/odfexport.cxx index e513aaa68fd0..caae889a30a2 100644 --- a/sw/qa/extras/odfexport/odfexport.cxx +++ b/sw/qa/extras/odfexport/odfexport.cxx @@ -848,7 +848,7 @@ DECLARE_ODFEXPORT_TEST(testCellUserDefineAttr, "userdefattr-tablecell.odt") getUserDefineAttribute(uno::makeAny(xCellC1), "proName", "v3"); } -#if HAVE_FEATURE_PDFIMPORT +#if HAVE_FEATURE_PDFIUM DECLARE_ODFEXPORT_TEST(testEmbeddedPdf, "embedded-pdf.odt") { uno::Reference<drawing::XShape> xShape = getShape(1); diff --git a/sw/source/core/graphic/ndgrf.cxx b/sw/source/core/graphic/ndgrf.cxx index 13a1f87d6134..e5b2ace6af87 100644 --- a/sw/source/core/graphic/ndgrf.cxx +++ b/sw/source/core/graphic/ndgrf.cxx @@ -401,8 +401,8 @@ const GraphicObject* SwGrfNode::GetReplacementGrfObj() const const_cast< SwGrfNode* >(this)->mpReplacementGraphic = new GraphicObject(rSvgDataPtr->getReplacement()); } else if (GetGrfObj().GetGraphic().getPdfData().hasElements()) - // This returns the metafile, without the pdf data. - const_cast<SwGrfNode*>(this)->mpReplacementGraphic = new GraphicObject(GetGrfObj().GetGraphic().GetGDIMetaFile()); + // This returns the bitmap, without the pdf data. + const_cast<SwGrfNode*>(this)->mpReplacementGraphic = new GraphicObject(GetGrfObj().GetGraphic().GetBitmapEx()); } return mpReplacementGraphic; diff --git a/vcl/CppunitTest_vcl_wmf_test.mk b/vcl/CppunitTest_vcl_wmf_test.mk index 5f21cd84c23c..737c3208ca78 100644 --- a/vcl/CppunitTest_vcl_wmf_test.mk +++ b/vcl/CppunitTest_vcl_wmf_test.mk @@ -16,6 +16,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,vcl_wmf_test, \ $(eval $(call gb_CppunitTest_use_externals,vcl_wmf_test,\ boost_headers \ libxml2 \ + $(if $(filter PDFIUM,$(BUILD_TYPE)),pdfium) \ )) $(eval $(call gb_CppunitTest_set_include,vcl_wmf_test,\ diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 3132d9e181b5..29c85d615ab4 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -60,6 +60,7 @@ $(eval $(call gb_Library_use_externals,vcl,\ curl) \ jpeg \ libeot \ + $(if $(filter PDFIUM,$(BUILD_TYPE)),pdfium) \ )) ifeq ($(TLS),NSS) 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()); diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx index 57f7ba58163d..546b953bc19b 100644 --- a/vcl/source/gdi/impgraph.cxx +++ b/vcl/source/gdi/impgraph.cxx @@ -1361,15 +1361,16 @@ BitmapChecksum ImpGraphic::ImplGetChecksum() const { nRet = maEx.GetChecksum(); } - } - break; - default: - nRet = maMetaFile.GetChecksum(); if (maPdfData.hasElements()) // Include the PDF data in the checksum, so a metafile with // and without PDF data is considered to be different. nRet = vcl_get_checksum(nRet, maPdfData.getConstArray(), maPdfData.getLength()); + } + break; + + default: + nRet = maMetaFile.GetChecksum(); break; } } @@ -1618,6 +1619,13 @@ void WriteImpGraphic(SvStream& rOStm, const ImpGraphic& rImpGraphic) rOStm.WriteUniOrByteString(rImpGraphic.getSvgData()->getPath(), rOStm.GetStreamCharSet()); } + else if (rImpGraphic.maPdfData.hasElements()) + { + // Stream out PDF data. + rOStm.WriteUInt32(nPdfMagic); + rOStm.WriteUInt32(rImpGraphic.maPdfData.getLength()); + rOStm.WriteBytes(rImpGraphic.maPdfData.getConstArray(), rImpGraphic.maPdfData.getLength()); + } else if( rImpGraphic.ImplIsAnimated()) { WriteAnimation( rOStm, *rImpGraphic.mpAnimation ); @@ -1631,13 +1639,6 @@ void WriteImpGraphic(SvStream& rOStm, const ImpGraphic& rImpGraphic) default: { - if (rImpGraphic.maPdfData.hasElements()) - { - // Stream out PDF data. - rOStm.WriteUInt32(nPdfMagic); - rOStm.WriteUInt32(rImpGraphic.maPdfData.getLength()); - rOStm.WriteBytes(rImpGraphic.maPdfData.getConstArray(), rImpGraphic.maPdfData.getLength()); - } if( rImpGraphic.ImplIsSupportedGraphic() ) WriteGDIMetaFile( rOStm, rImpGraphic.maMetaFile ); } |