diff options
author | Simon Hausmann <simon.hausmann@theqtcompany.com> | 2014-12-15 12:50:13 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@theqtcompany.com> | 2014-12-15 12:50:13 +0100 |
commit | a7cecb51731d054a89b458d8343e896e8dd9e620 (patch) | |
tree | f65e7956769aa5133980fde8f177dd799f2dab9f | |
parent | 3c152e3703c74f468edb3ea7de9992bfc612dc04 (diff) |
Implement basic document loading from a file
-rw-r--r-- | src/pdf/jsbridge.cpp (renamed from src/qpdf/jsbridge.cpp) | 0 | ||||
-rw-r--r-- | src/pdf/pdf.pro (renamed from src/qpdf/qpdf.pro) | 8 | ||||
-rw-r--r-- | src/pdf/qpdfdocument.cpp | 96 | ||||
-rw-r--r-- | src/pdf/qpdfdocument.h | 35 | ||||
-rw-r--r-- | src/pdf/qpdfdocument_p.h | 20 | ||||
-rw-r--r-- | src/pdf/qtpdfglobal.h | 23 | ||||
-rw-r--r-- | src/src.pro | 2 | ||||
-rw-r--r-- | sync.profile | 2 | ||||
-rw-r--r-- | tests/auto/auto.pro | 2 | ||||
-rw-r--r-- | tests/auto/qpdfdocument/qpdfdocument.pro | 6 | ||||
-rw-r--r-- | tests/auto/qpdfdocument/tst_qpdfdocument.cpp | 46 | ||||
-rw-r--r-- | tests/tests.pro | 2 |
12 files changed, 239 insertions, 3 deletions
diff --git a/src/qpdf/jsbridge.cpp b/src/pdf/jsbridge.cpp index 3959c3e..3959c3e 100644 --- a/src/qpdf/jsbridge.cpp +++ b/src/pdf/jsbridge.cpp diff --git a/src/qpdf/qpdf.pro b/src/pdf/pdf.pro index ebe3c73..4c3244c 100644 --- a/src/qpdf/qpdf.pro +++ b/src/pdf/pdf.pro @@ -16,4 +16,10 @@ msvc { } SOURCES += \ - jsbridge.cpp + jsbridge.cpp \ + qpdfdocument.cpp + +HEADERS += \ + qpdfdocument.h \ + qpdfdocument_p.h \ + qtpdfglobal.h diff --git a/src/pdf/qpdfdocument.cpp b/src/pdf/qpdfdocument.cpp new file mode 100644 index 0000000..f05310d --- /dev/null +++ b/src/pdf/qpdfdocument.cpp @@ -0,0 +1,96 @@ +#include "qpdfdocument.h" + +#include "qpdfdocument_p.h" + +#include <QFile> +#include <QIODevice> +#include <QMutex> + +static int libraryRefCount; +static QMutex libraryInitializerMutex; + +// PDFium stores the error code when loading a document in a global +// variable, but that is only set from the FPDF_Load*Document functions. +// Therefore this mutex serializes access to the loading. +static QMutex documentLoadMutex; + +QPdfDocumentPrivate::QPdfDocumentPrivate() + : doc(0) +{ + { + QMutexLocker lock(&libraryInitializerMutex); + if (libraryRefCount == 0) + FPDF_InitLibrary(); + ++libraryRefCount; + } +} + +QPdfDocumentPrivate::~QPdfDocumentPrivate() +{ + if (doc) + FPDF_CloseDocument(doc); + doc = 0; + + { + QMutexLocker lock(&libraryInitializerMutex); + if (!--libraryRefCount) + FPDF_DestroyLibrary(); + } +} + +QPdfDocument::QPdfDocument(QObject *parent) + : QObject(parent) + , d(new QPdfDocumentPrivate) +{ +} + +QPdfDocument::~QPdfDocument() +{ +} + +static int fpdf_GetBlock(void* param, unsigned long position, unsigned char* pBuf, unsigned long size) +{ + QIODevice *dev = reinterpret_cast<QIODevice*>(param); + dev->seek(position); + return dev->read(reinterpret_cast<char *>(pBuf), size); +} + +QPdfDocument::Error QPdfDocument::load(const QString &fileName, const QString &password) +{ + if (d->doc) + FPDF_CloseDocument(d->doc); + + QFile *file = new QFile(fileName); + d->device.reset(file); + + if (!d->device->open(QIODevice::ReadOnly)) + return FileNotFoundError; + + FPDF_FILEACCESS access; + access.m_FileLen = file->size(); + access.m_GetBlock = fpdf_GetBlock; + access.m_Param = d->device.data(); + + d->password = password.toUtf8(); + + QMutexLocker loadLocker(&documentLoadMutex); + d->doc = FPDF_LoadCustomDocument(&access, d->password.constData()); + switch (FPDF_GetLastError()) { + case FPDF_ERR_SUCCESS: return NoError; + case FPDF_ERR_UNKNOWN: return UnknownError; + case FPDF_ERR_FILE: return FileNotFoundError; + case FPDF_ERR_FORMAT: return InvalidFileFormatError; + case FPDF_ERR_PASSWORD: return IncorrectPasswordError; + case FPDF_ERR_SECURITY: return UnsupportedSecuritySchemeError; + default: + Q_UNREACHABLE(); + } + return UnknownError; +} + +int QPdfDocument::pageCount() const +{ + if (!d->doc) + return 0; + return FPDF_GetPageCount(d->doc); +} diff --git a/src/pdf/qpdfdocument.h b/src/pdf/qpdfdocument.h new file mode 100644 index 0000000..32baebb --- /dev/null +++ b/src/pdf/qpdfdocument.h @@ -0,0 +1,35 @@ +#ifndef QPDFDOCUMENT_H +#define QPDFDOCUMENT_H + +#include <QObject> +#include "qtpdfglobal.h" + +class QPdfDocumentPrivate; + +class Q_PDF_EXPORT QPdfDocument : public QObject +{ + Q_OBJECT + Q_PROPERTY(int pageCount READ pageCount FINAL) +public: + + enum Error { + NoError, + UnknownError, + FileNotFoundError, + InvalidFileFormatError, + IncorrectPasswordError, + UnsupportedSecuritySchemeError + }; + + explicit QPdfDocument(QObject *parent = 0); + ~QPdfDocument(); + + Error load(const QString &fileName, const QString &password = QString()); + + int pageCount() const; + +private: + QScopedPointer<QPdfDocumentPrivate> d; +}; + +#endif // QPDFDOCUMENT_H diff --git a/src/pdf/qpdfdocument_p.h b/src/pdf/qpdfdocument_p.h new file mode 100644 index 0000000..5a30b1f --- /dev/null +++ b/src/pdf/qpdfdocument_p.h @@ -0,0 +1,20 @@ +#ifndef QPDFDOCUMENT_P_H +#define QPDFDOCUMENT_P_H + +#include "fpdfview.h" + +#include <qiodevice.h> + +class QPdfDocumentPrivate +{ +public: + QPdfDocumentPrivate(); + ~QPdfDocumentPrivate(); + + FPDF_DOCUMENT doc; + QScopedPointer<QIODevice> device; + QByteArray password; +}; + +#endif // QPDFDOCUMENT_P_H + diff --git a/src/pdf/qtpdfglobal.h b/src/pdf/qtpdfglobal.h new file mode 100644 index 0000000..a4b6d53 --- /dev/null +++ b/src/pdf/qtpdfglobal.h @@ -0,0 +1,23 @@ +#ifndef QTPDFGLOBAL_H +#define QTPDFGLOBAL_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +#ifndef Q_PDF_EXPORT +# ifndef QT_STATIC +# if defined(QT_BUILD_PDF_LIB) +# define Q_PDF_EXPORT Q_DECL_EXPORT +# else +# define Q_PDF_EXPORT Q_DECL_IMPORT +# endif +# else +# define Q_PDF_EXPORT +# endif +#endif + +QT_END_NAMESPACE + +#endif // QTPDFGLOBAL_H + diff --git a/src/src.pro b/src/src.pro index d2216d4..f1d52eb 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,2 +1,2 @@ TEMPLATE = subdirs -SUBDIRS = 3rdparty lib qpdf +SUBDIRS = 3rdparty lib pdf diff --git a/sync.profile b/sync.profile index c9d0e17..0fe0418 100644 --- a/sync.profile +++ b/sync.profile @@ -1,5 +1,5 @@ %modules = ( # path to module name map - "QtQPdf" => "$basedir/src/qpdf", + "QtQPdf" => "$basedir/src/pdf", ); # Module dependencies. # Every module that is required to build this module should have one entry. diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro new file mode 100644 index 0000000..41c081c --- /dev/null +++ b/tests/auto/auto.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = qpdfdocument diff --git a/tests/auto/qpdfdocument/qpdfdocument.pro b/tests/auto/qpdfdocument/qpdfdocument.pro new file mode 100644 index 0000000..28e56e0 --- /dev/null +++ b/tests/auto/qpdfdocument/qpdfdocument.pro @@ -0,0 +1,6 @@ +CONFIG += testcase +TARGET = tst_qpdfdocument +QT += pdf printsupport testlib +macx:CONFIG -= app_bundle +SOURCES += tst_qpdfdocument.cpp + diff --git a/tests/auto/qpdfdocument/tst_qpdfdocument.cpp b/tests/auto/qpdfdocument/tst_qpdfdocument.cpp new file mode 100644 index 0000000..080f808 --- /dev/null +++ b/tests/auto/qpdfdocument/tst_qpdfdocument.cpp @@ -0,0 +1,46 @@ + +#include <QtTest/QtTest> + +#include <QPainter> +#include <QPdfDocument> +#include <QPrinter> +#include <QTemporaryFile> + +class tst_QPdfDocument: public QObject +{ + Q_OBJECT +public: + +private slots: + void pageCount(); +}; + + +void tst_QPdfDocument::pageCount() +{ + QTemporaryFile tempPdf; + tempPdf.setAutoRemove(true); + QVERIFY(tempPdf.open()); + { + QPrinter printer; + printer.setOutputFormat(QPrinter::PdfFormat); + printer.setOutputFileName(tempPdf.fileName()); + + { + QPainter painter(&printer); + painter.drawText(0, 0, QStringLiteral("Hello Page 1")); + printer.newPage(); + painter.drawText(0, 0, QStringLiteral("Hello Page 2")); + } + } + + QPdfDocument doc; + QCOMPARE(doc.pageCount(), 0); + QCOMPARE(doc.load(tempPdf.fileName()), QPdfDocument::NoError); + QCOMPARE(doc.pageCount(), 2); +} + +QTEST_MAIN(tst_QPdfDocument) + +#include "tst_qpdfdocument.moc" + diff --git a/tests/tests.pro b/tests/tests.pro new file mode 100644 index 0000000..7fbc8a9 --- /dev/null +++ b/tests/tests.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = auto |