[Libreoffice-commits] core.git: config_host/config_features.h.in configure.ac sd/qa sd/source svtools/qa svtools/source svx/qa svx/source sw/qa sw/source vcl/CppunitTest_vcl_wmf_test.mk vcl/Library_vcl.mk vcl/source

Miklos Vajna vmiklos at collabora.co.uk
Mon Feb 13 16:54:24 UTC 2017


 config_host/config_features.h.in      |    5 +
 configure.ac                          |    1 
 sd/qa/unit/export-tests.cxx           |    2 
 sd/source/ui/view/drviews2.cxx        |    2 
 svtools/qa/unit/GraphicObjectTest.cxx |    2 
 svtools/source/graphic/grfcache.cxx   |    8 -
 svx/qa/unit/xoutdev.cxx               |    2 
 svx/source/svdraw/svdograf.cxx        |    4 
 sw/qa/extras/odfexport/odfexport.cxx  |    2 
 sw/source/core/graphic/ndgrf.cxx      |    4 
 vcl/CppunitTest_vcl_wmf_test.mk       |    1 
 vcl/Library_vcl.mk                    |    1 
 vcl/source/filter/ipdf/pdfread.cxx    |  167 +++++++++++++++++++---------------
 vcl/source/gdi/impgraph.cxx           |   23 ++--
 14 files changed, 127 insertions(+), 97 deletions(-)

New commits:
commit 6657d52417295265367cf3ffe5832b60e3c38011
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Mon Feb 13 17:05:19 2017 +0100

    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 at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>

diff --git a/config_host/config_features.h.in b/config_host/config_features.h.in
index 5dd85df..8e52a65 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 7338bb5..7667bae 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 3f28823..797bf36 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 2ff7c77..93e2289 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 7d93874..031a3eab 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 273afff..2b15869 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 5bd3179..7b472b9 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 0103498..4875a4f 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 e513aaa..caae889 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 13a1f87..e5b2ace 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 5f21cd8..737c320 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 3132d9e..29c85d6 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 ac82050..ee31af6 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 57f7ba5..546b953 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 );
             }


More information about the Libreoffice-commits mailing list