7#include "third_party/pdfium/public/fpdf_doc.h"
8#include "third_party/pdfium/public/fpdf_text.h"
12#include <QElapsedTimer>
15#include <QLoggingCategory>
21#include <QtCore/private/qtools_p.h>
42 QMetaEnum rolesMetaEnum = doc->metaObject()->enumerator(doc->metaObject()->indexOfEnumerator(
"PageModelRole"));
46 m_roleNames.insert(
r,
name);
63 return document()->pageLabel(
index.row());
65 return document()->pagePointSize(
index.row());
72 return pageThumbnail(
index.row());
74 return document()->pageLabel(
index.row());
82 QHash<int, QByteArray>
roleNames()
const override {
return m_roleNames; }
91 auto size = doc->pagePointSize(
page);
102 QHash<int, QByteArray> m_roleNames;
103 mutable QHash<int, QPixmap> m_thumbnails;
109 , loadComplete(
false)
123 qCDebug(qLcDoc) <<
"FPDF_InitLibrary took" <<
timer.elapsed() <<
"ms";
132 FX_FILEAVAIL::version = 1;
136 FX_DOWNLOADHINTS::version = 1;
147 qCDebug(qLcDoc) <<
"FPDF_DestroyLibrary";
148 FPDF_DestroyLibrary();
157 FPDF_CloseDocument(
doc);
161 FPDFAvail_Destroy(
avail);
168 emit q->pageModelChanged();
189 const unsigned long error = FPDF_GetLastError();
208 if (transferDeviceOwnership)
213 if (newDevice->isSequential()) {
220 qWarning() <<
"QPdfDocument: Loading from sequential devices only supported with QNetworkAccessManager.";
231 this->setStatus(QPdfDocument::Status::Error);
257 const int newPageCount = FPDF_GetPageCount(
doc);
262 emit q->pageModelChanged();
288 if (!contentLength.
isValid()) {
304 m_FileLen = totalSize;
308 avail = FPDFAvail_Create(
this,
this);
329 switch (FPDFAvail_IsDocAvail(
avail,
this)) {
331 qCDebug(qLcDoc) <<
"error loading";
333 case PDF_DATA_NOTAVAIL:
334 qCDebug(qLcDoc) <<
"data not yet available";
352 FPDF_CloseDocument(
doc);
356 emit q->passwordRequired();
375 const int newPageCount = FPDF_GetPageCount(
doc);
376 for (
int i = 0;
i < newPageCount; ++
i) {
377 int result = PDF_DATA_NOTAVAIL;
378 while (
result == PDF_DATA_NOTAVAIL) {
382 if (
result == PDF_DATA_ERROR)
392 emit q->pageModelChanged();
408 int result = PDF_DATA_NOTAVAIL;
409 while (
result == PDF_DATA_NOTAVAIL)
413 if (
result == PDF_DATA_ERROR)
416 return (
result != PDF_DATA_ERROR);
421 if (
status == documentStatus)
431 return offset + size <= static_cast<quint64>(
d->device->size());
438 return qMax(
qint64(0),
d->device->read(
reinterpret_cast<char *
>(pBuf),
size));
453 int len = FPDFText_GetText(textPage, startIndex,
count,
buf.data());
461 const int count = FPDFText_CountChars(textPage);
462 if (FPDFText_GetCharOrigin(textPage,
qMin(
count - 1, charIndex), &
x, &
y))
470 if (FPDFText_GetCharBox(textPage, charIndex, &l, &
r, &
b, &
t))
484 const auto pageHeight = FPDF_GetPageHeight(pdfPage);
485 const auto pageWidth = FPDF_GetPageWidth(pdfPage);
487 if (FPDF_PageToDevice(pdfPage, 0, 0,
qRound(pageWidth),
qRound(pageHeight), 0,
x,
y, &
rx, &
ry))
502 const auto pageHeight = FPDF_GetPageHeight(pdfPage);
503 const auto pageWidth = FPDF_GetPageWidth(pdfPage);
504 int xfmLeft, xfmTop, xfmRight, xfmBottom;
505 if ( FPDF_PageToDevice(pdfPage, 0, 0,
qRound(pageWidth),
qRound(pageHeight), 0,
left,
top, &xfmLeft, &xfmTop) &&
506 FPDF_PageToDevice(pdfPage, 0, 0,
qRound(pageWidth),
qRound(pageHeight), 0,
right,
bottom, &xfmRight, &xfmBottom) )
507 return QRectF(xfmLeft, xfmTop, xfmRight - xfmLeft, xfmBottom - xfmTop);
519 const auto pageHeight = FPDF_GetPageHeight(pdfPage);
520 const auto pageWidth = FPDF_GetPageWidth(pdfPage);
532 FPDF_PAGE pdfPage = FPDF_LoadPage(
doc,
page);
533 FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage);
535 int hitIndex = FPDFText_GetCharIndexAtPos(textPage, pagePos.x(), pagePos.y(),
539 if (!charPos.isNull()) {
544 charPos.setX(charBox.right());
547 qCDebug(qLcDoc) <<
"on page" <<
page <<
"@" <<
position <<
"got char position" << charPos <<
"index" << hitIndex;
548 result = { charPos, charBox.height(), hitIndex };
552 FPDFText_ClosePage(textPage);
553 FPDF_ClosePage(pdfPage);
599 d->
load(
f.release(),
true);
608QString QPdfDocument::fileName()
const
612 return f->fileName();
709 fieldName =
"ModDate";
712 fieldName =
QByteArray(fieldsMetaEnum.valueToKey(
int(field)));
717 const unsigned long len = FPDF_GetMetaText(d->
doc, fieldName.
constData(),
nullptr, 0);
867 const unsigned long len = FPDF_GetPageLabel(d->
doc,
page,
nullptr, 0);
912 FPDF_PAGE pdfPage = FPDF_LoadPage(d->
doc,
page);
920 const QPdfDocumentRenderOptions::RenderFlags renderFlags = renderOptions.renderFlags();
925 flags |= FPDF_LCD_TEXT;
927 flags |= FPDF_GRAYSCALE;
929 flags |= FPDF_RENDER_FORCEHALFTONE;
931 flags |= FPDF_RENDER_NO_SMOOTHTEXT;
933 flags |= FPDF_RENDER_NO_SMOOTHIMAGE;
935 flags |= FPDF_RENDER_NO_SMOOTHPATH;
937 if (renderOptions.scaledClipRect().isValid()) {
938 const QRect &clipRect = renderOptions.scaledClipRect();
941 float x0 = clipRect.
left();
942 float y0 = clipRect.
top();
943 float x1 = clipRect.
left();
946 float y2 = clipRect.
top();
949 if (!renderOptions.scaledSize().isNull()) {
950 pageScale =
QVector2D(renderOptions.scaledSize().width() /
float(origSize.width()),
951 renderOptions.scaledSize().height() /
float(origSize.height()));
962 qCDebug(qLcDoc) <<
"page" <<
page <<
"region" << renderOptions.scaledClipRect()
970 FPDFBitmap_Destroy(
bitmap);
972 FPDF_ClosePage(pdfPage);
983 FPDF_PAGE pdfPage = FPDF_LoadPage(d->
doc,
page);
986 FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage);
987 int startIndex = FPDFText_GetCharIndexAtPos(textPage, pageStart.x(), pageStart.y(),
989 int endIndex = FPDFText_GetCharIndexAtPos(textPage, pageEnd.x(), pageEnd.y(),
994 if (startIndex >= 0 && endIndex != startIndex) {
995 if (startIndex > endIndex)
996 qSwap(startIndex, endIndex);
1001 if (
qAbs(endCharBox.right() -
end.x()) <
qAbs(endCharBox.x() -
end.x()))
1004 int count = endIndex - startIndex;
1006 QList<QPolygonF> bounds;
1008 int rectCount = FPDFText_CountRects(textPage, startIndex, endIndex - startIndex);
1009 for (
int i = 0;
i < rectCount; ++
i) {
1011 FPDFText_GetRect(textPage,
i, &l, &
t, &
r, &
b);
1016 hull = hull.united(
rect);
1025 FPDFText_ClosePage(textPage);
1026 FPDF_ClosePage(pdfPage);
1041 FPDF_PAGE pdfPage = FPDF_LoadPage(d->
doc,
page);
1042 FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage);
1043 int pageCount = FPDFText_CountChars(textPage);
1046 QList<QPolygonF> bounds;
1052 rectCount = FPDFText_CountRects(textPage, startIndex,
text.
size());
1053 for (
int i = 0;
i < rectCount; ++
i) {
1055 FPDFText_GetRect(textPage,
i, &l, &
t, &
r, &
b);
1060 hull = hull.united(
rect);
1064 if (bounds.isEmpty())
1067 <<
"got" <<
text.
size() <<
"chars," << rectCount <<
"rects within" << hull;
1069 FPDFText_ClosePage(textPage);
1070 FPDF_ClosePage(pdfPage);
1081 FPDF_PAGE pdfPage = FPDF_LoadPage(d->
doc,
page);
1082 FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage);
1083 int count = FPDFText_CountChars(textPage);
1087 QList<QPolygonF> bounds;
1089 int rectCount = FPDFText_CountRects(textPage, 0,
count);
1090 for (
int i = 0;
i < rectCount; ++
i) {
1092 FPDFText_GetRect(textPage,
i, &l, &
t, &
r, &
b);
1097 hull = hull.united(
rect);
1100 qCDebug(qLcDoc) <<
"on page" <<
page <<
"got" <<
count <<
"chars," << rectCount <<
"rects within" << hull;
1102 FPDFText_ClosePage(textPage);
1103 FPDF_ClosePage(pdfPage);
1110#include "qpdfdocument.moc"
1111#include "moc_qpdfdocument.cpp"
IOBluetoothDevice * device
virtual QHash< int, QByteArray > roleNames() const
bool open(OpenMode openMode) override
\reimp
void setData(const QByteArray &data)
Sets the contents of the internal buffer to be data.
void close() override
\reimp
qint64 size() const override
\reimp
bool seek(qint64 off) override
\reimp
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
void clear()
Clears the contents of the byte array and makes it null.
\inmodule QtCore \reentrant
virtual qint64 size() const
For open random-access devices, this function returns the size of the device.
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
virtual qint64 bytesAvailable() const
Returns the number of bytes that are available for reading.
virtual bool seek(qint64 pos)
For random-access devices, this function sets the current position to pos, returning true on success,...
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read.
The QNetworkReply class contains the data and headers for a request sent with QNetworkAccessManager.
NetworkError error() const
Returns the error that was found during the processing of this request.
QVariant header(QNetworkRequest::KnownHeaders header) const
Returns the value of the known header header, if that header was sent by the remote server.
void finished()
This signal is emitted when the reply has finished processing.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
TextPosition hitTest(int page, QPointF position)
void _q_copyFromSequentialSourceDevice()
QPointF getCharPosition(FPDF_PAGE pdfPage, FPDF_TEXTPAGE textPage, int charIndex) const
void _q_tryLoadingWithSizeFromContentHeader()
QPointer< QIODevice > device
void load(QIODevice *device, bool ownDevice)
static void fpdf_AddSegment(struct _FX_DOWNLOADHINTS *pThis, size_t offset, size_t size)
QString getText(FPDF_TEXTPAGE textPage, int startIndex, int count) const
static FPDF_BOOL fpdf_IsDataAvail(struct _FX_FILEAVAIL *pThis, size_t offset, size_t size)
QPointF mapPageToView(FPDF_PAGE pdfPage, double x, double y) const
QPdfDocument::Status status
QRectF getCharBox(FPDF_PAGE pdfPage, FPDF_TEXTPAGE textPage, int charIndex) const
bool checkPageComplete(int page)
void initiateAsyncLoadWithTotalSizeKnown(quint64 totalSize)
QScopedPointer< QIODevice > ownDevice
static constexpr QFPDFRotation toFPDFRotation(QPdfDocumentRenderOptions::Rotation rotation)
QPointer< QIODevice > sequentialSourceDevice
static int fpdf_GetBlock(void *param, unsigned long position, unsigned char *pBuf, unsigned long size)
QPdfPageModel * pageModel
QPdfDocument::Error lastError
QPointF mapViewToPage(FPDF_PAGE pdfPage, QPointF position) const
void setStatus(QPdfDocument::Status status)
The QPdfDocument class loads a PDF document and renders pages from it.
Error error() const
Returns the type of error if \l status is Error, or NoError if there is no error.
QString password
This property holds the document password.
QImage render(int page, QSize imageSize, QPdfDocumentRenderOptions options=QPdfDocumentRenderOptions())
Renders the page into a QImage of size imageSize according to the provided renderOptions.
Status status
This property holds the current status of the document.
void close()
Closes the document.
MetaDataField
This enum describes the available fields of meta data.
QAbstractListModel * pageModel
This property holds an instance of QAbstractListModel to provide page-specific metadata,...
Q_INVOKABLE QPdfSelection getAllText(int page)
Returns all the text and its bounds on the given page.
Status
This enum describes the current status of the document.
~QPdfDocument() override
Destroys the document.
Q_INVOKABLE QPdfSelection getSelectionAtIndex(int page, int startIndex, int maxLength)
Returns information about the text on the given page that can be found beginning at the given startIn...
PageModelRole
Roles in pageModel().
int pageCount
This property holds the number of pages in the loaded document or 0 if no document is loaded.
Error
This enum describes the error while attempting the last operation on the document.
@ UnsupportedSecurityScheme
Q_INVOKABLE int pageIndexForLabel(const QString &label)
Returns the index of the page that has the label, or -1 if not found.
Q_INVOKABLE QPdfSelection getSelection(int page, QPointF start, QPointF end)
Returns information about the text on the given page that can be found between the given start and en...
QVariant metaData(MetaDataField field) const
Returns the meta data of the document for the given field.
Q_INVOKABLE QString pageLabel(int page)
Returns the page number to be used for display purposes.
void setPassword(const QString &password)
Error load(const QString &fileName)
Loads the document contents from fileName.
void statusChanged(QPdfDocument::Status status)
friend class QPdfPageModel
Q_INVOKABLE QSizeF pagePointSize(int page) const
Returns the size of page page in points (1/72 of an inch).
int rowCount(const QModelIndex &=QModelIndex()) const override
Returns the number of rows under the given parent.
QPdfPageModel(QPdfDocument *doc)
QHash< int, QByteArray > roleNames() const override
QVariant data(const QModelIndex &index, int role) const override
Returns the data stored under the given role for the item referred to by the index.
The QPdfSelection class defines a range of text that has been selected on one page in a PDF document,...
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
static QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags=Qt::AutoColor)
Converts the given image to a pixmap using the specified flags to control the conversion.
\inmodule QtCore\reentrant
T * data() const noexcept
The QPolygonF class provides a list of points using floating point precision.
\inmodule QtCore\reentrant
\inmodule QtCore\reentrant
constexpr int bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
constexpr int right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
const_iterator constEnd() const noexcept
const_iterator constFind(const T &value) const
\macro QT_RESTRICTED_CAST_FROM_ASCII
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
QString & replace(qsizetype i, qsizetype len, QChar after)
void chop(qsizetype n)
Removes n characters from the end of the string.
QString mid(qsizetype position, qsizetype n=-1) const &
static QString fromUtf16(const char16_t *, qsizetype size=-1)
qsizetype size() const noexcept
Returns the number of characters in this string.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
QString & insert(qsizetype i, QChar c)
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QByteArray toUtf8() const &
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
bool isValid() const
Returns true if the storage type of this variant is not QMetaType::UnknownType; otherwise returns fal...
qulonglong toULongLong(bool *ok=nullptr) const
Returns the variant as an unsigned long long int if the variant has type() \l QMetaType::ULongLong,...
The QVector2D class represents a vector or vertex in 2D space.
QSet< QString >::iterator it
Combined button and popup list for selecting options.
constexpr char toAsciiLower(char ch) noexcept
emscripten::val document()
DBusConnection const char DBusError * error
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
int qRound(qfloat16 d) noexcept
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
constexpr T qAbs(const T &t)
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLfloat GLfloat GLfloat x1
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint GLsizei const GLchar * label
[43]
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum const GLint * param
GLenum GLuint GLintptr offset
GLuint GLfloat GLfloat y0
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei imageSize
GLfixed GLfixed GLfixed y2
GLsizei GLfixed GLfixed GLfixed GLfixed const GLubyte * bitmap
GLdouble GLdouble GLdouble GLdouble q
static QT_BEGIN_NAMESPACE int libraryRefCount
static const double CharacterHitTolerance
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
QT_BEGIN_NAMESPACE constexpr void qSwap(T &value1, T &value2) noexcept(std::is_nothrow_swappable_v< T >)
unsigned long long quint64
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
obj metaObject() -> className()
\inmodule QtCore \reentrant