summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2017-02-13 17:05:19 +0100
committerMiklos Vajna <vmiklos@collabora.co.uk>2017-02-13 16:54:04 +0000
commit6657d52417295265367cf3ffe5832b60e3c38011 (patch)
treea664018f1eb611c88d8d73fd3b0241090ec36f8d
parent7c9c6a4425b679596acae6f67ee8ac5f3d98bd6e (diff)
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>
-rw-r--r--config_host/config_features.h.in5
-rw-r--r--configure.ac1
-rw-r--r--sd/qa/unit/export-tests.cxx2
-rw-r--r--sd/source/ui/view/drviews2.cxx2
-rw-r--r--svtools/qa/unit/GraphicObjectTest.cxx2
-rw-r--r--svtools/source/graphic/grfcache.cxx8
-rw-r--r--svx/qa/unit/xoutdev.cxx2
-rw-r--r--svx/source/svdraw/svdograf.cxx4
-rw-r--r--sw/qa/extras/odfexport/odfexport.cxx2
-rw-r--r--sw/source/core/graphic/ndgrf.cxx4
-rw-r--r--vcl/CppunitTest_vcl_wmf_test.mk1
-rw-r--r--vcl/Library_vcl.mk1
-rw-r--r--vcl/source/filter/ipdf/pdfread.cxx167
-rw-r--r--vcl/source/gdi/impgraph.cxx23
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 );
}