1 | #include <QtCore/QDebug> |
2 | #include <QtCore/QFile> |
3 | #include <QtWidgets/QApplication> |
4 | #include <QtGui/QImage> |
5 | #include <QtWidgets/QLabel> |
6 | #include <QtGui/QMouseEvent> |
7 | #include <QtGui/QPainter> |
8 | #include <QtGui/QPaintEvent> |
9 | #include <QtWidgets/QToolTip> |
10 | #include <QtWidgets/QWidget> |
11 | |
12 | #include <poppler-qt6.h> |
13 | |
14 | class PDFDisplay : public QWidget // picture display widget |
15 | { |
16 | Q_OBJECT |
17 | public: |
18 | PDFDisplay(std::unique_ptr<Poppler::Document> &&d, bool qpainter, QWidget *parent = nullptr); |
19 | ~PDFDisplay() override; |
20 | void setShowTextRects(bool show); |
21 | void display(); |
22 | |
23 | protected: |
24 | void paintEvent(QPaintEvent *) override; |
25 | void keyPressEvent(QKeyEvent *) override; |
26 | void mousePressEvent(QMouseEvent *) override; |
27 | |
28 | private: |
29 | int m_currentPage; |
30 | QImage image; |
31 | std::unique_ptr<Poppler::Document> doc; |
32 | QString backendString; |
33 | bool showTextRects; |
34 | std::vector<std::unique_ptr<Poppler::TextBox>> textRects; |
35 | }; |
36 | |
37 | PDFDisplay::PDFDisplay(std::unique_ptr<Poppler::Document> &&d, bool qpainter, QWidget *parent) : QWidget(parent) |
38 | { |
39 | showTextRects = false; |
40 | doc = std::move(d); |
41 | m_currentPage = 0; |
42 | if (qpainter) { |
43 | backendString = QStringLiteral("QPainter" ); |
44 | doc->setRenderBackend(Poppler::Document::QPainterBackend); |
45 | } else { |
46 | backendString = QStringLiteral("Splash" ); |
47 | doc->setRenderBackend(Poppler::Document::SplashBackend); |
48 | } |
49 | doc->setRenderHint(hint: Poppler::Document::Antialiasing, on: true); |
50 | doc->setRenderHint(hint: Poppler::Document::TextAntialiasing, on: true); |
51 | } |
52 | |
53 | void PDFDisplay::setShowTextRects(bool show) |
54 | { |
55 | showTextRects = show; |
56 | } |
57 | |
58 | void PDFDisplay::display() |
59 | { |
60 | if (doc) { |
61 | std::unique_ptr<Poppler::Page> page = doc->page(index: m_currentPage); |
62 | if (page) { |
63 | qDebug() << "Displaying page using" << backendString << "backend: " << m_currentPage; |
64 | QTime t = QTime::currentTime(); |
65 | image = page->renderToImage(); |
66 | qDebug() << "Rendering took" << t.msecsTo(t: QTime::currentTime()) << "msecs" ; |
67 | if (showTextRects) { |
68 | QPainter painter(&image); |
69 | painter.setPen(Qt::red); |
70 | textRects = page->textList(); |
71 | for (const std::unique_ptr<Poppler::TextBox> &tb : textRects) { |
72 | painter.drawRect(rect: tb->boundingBox()); |
73 | } |
74 | } else { |
75 | textRects.clear(); |
76 | } |
77 | update(); |
78 | } |
79 | } else { |
80 | qWarning() << "doc not loaded" ; |
81 | } |
82 | } |
83 | |
84 | PDFDisplay::~PDFDisplay() { } |
85 | |
86 | void PDFDisplay::paintEvent(QPaintEvent *e) |
87 | { |
88 | QPainter paint(this); // paint widget |
89 | if (!image.isNull()) { |
90 | paint.drawImage(x: 0, y: 0, image); |
91 | } else { |
92 | qWarning() << "null image" ; |
93 | } |
94 | } |
95 | |
96 | void PDFDisplay::keyPressEvent(QKeyEvent *e) |
97 | { |
98 | if (e->key() == Qt::Key_Down) { |
99 | if (m_currentPage + 1 < doc->numPages()) { |
100 | m_currentPage++; |
101 | display(); |
102 | } |
103 | } else if (e->key() == Qt::Key_Up) { |
104 | if (m_currentPage > 0) { |
105 | m_currentPage--; |
106 | display(); |
107 | } |
108 | } else if (e->key() == Qt::Key_Q) { |
109 | exit(status: 0); |
110 | } |
111 | } |
112 | |
113 | void PDFDisplay::mousePressEvent(QMouseEvent *e) |
114 | { |
115 | int i = 0; |
116 | for (const std::unique_ptr<Poppler::TextBox> &tb : textRects) { |
117 | if (tb->boundingBox().contains(p: e->pos())) { |
118 | const QString tt = QStringLiteral("Text: \"%1\"\nIndex in text list: %2" ).arg(a: tb->text()).arg(a: i); |
119 | QToolTip::showText(pos: e->globalPosition().toPoint(), text: tt, w: this); |
120 | break; |
121 | } |
122 | ++i; |
123 | } |
124 | } |
125 | |
126 | int main(int argc, char **argv) |
127 | { |
128 | QApplication a(argc, argv); // QApplication required! |
129 | |
130 | if (argc < 2 || (argc == 3 && strcmp(s1: argv[2], s2: "-extract" ) != 0 && strcmp(s1: argv[2], s2: "-qpainter" ) != 0 && strcmp(s1: argv[2], s2: "-textRects" ) != 0) || argc > 3) { |
131 | // use argument as file name |
132 | qWarning() << "usage: test-poppler-qt6 filename [-extract|-qpainter|-textRects]" ; |
133 | exit(status: 1); |
134 | } |
135 | |
136 | std::unique_ptr<Poppler::Document> doc = Poppler::Document::load(filePath: QFile::decodeName(localFileName: argv[1])); |
137 | if (!doc) { |
138 | qWarning() << "doc not loaded" ; |
139 | exit(status: 1); |
140 | } |
141 | |
142 | if (doc->isLocked()) { |
143 | qWarning() << "document locked (needs password)" ; |
144 | exit(status: 0); |
145 | } |
146 | |
147 | // output some meta-data |
148 | auto pdfVersion = doc->getPdfVersion(); |
149 | qDebug() << " PDF Version: " << qPrintable(QStringLiteral("%1.%2" ).arg(pdfVersion.major).arg(pdfVersion.minor)); |
150 | qDebug() << " Title: " << doc->info(QStringLiteral("Title" )); |
151 | qDebug() << " Subject: " << doc->info(QStringLiteral("Subject" )); |
152 | qDebug() << " Author: " << doc->info(QStringLiteral("Author" )); |
153 | qDebug() << " Key words: " << doc->info(QStringLiteral("Keywords" )); |
154 | qDebug() << " Creator: " << doc->info(QStringLiteral("Creator" )); |
155 | qDebug() << " Producer: " << doc->info(QStringLiteral("Producer" )); |
156 | qDebug() << " Date created: " << doc->date(QStringLiteral("CreationDate" )).toString(); |
157 | qDebug() << " Date modified: " << doc->date(QStringLiteral("ModDate" )).toString(); |
158 | qDebug() << "Number of pages: " << doc->numPages(); |
159 | qDebug() << " Linearised: " << doc->isLinearized(); |
160 | qDebug() << " Encrypted: " << doc->isEncrypted(); |
161 | qDebug() << " OK to print: " << doc->okToPrint(); |
162 | qDebug() << " OK to copy: " << doc->okToCopy(); |
163 | qDebug() << " OK to change: " << doc->okToChange(); |
164 | qDebug() << "OK to add notes: " << doc->okToAddNotes(); |
165 | qDebug() << " Page mode: " << doc->pageMode(); |
166 | qDebug() << " Metadata: " << doc->metadata(); |
167 | |
168 | if (doc->hasEmbeddedFiles()) { |
169 | qDebug() << "Embedded files:" ; |
170 | foreach (Poppler::EmbeddedFile *file, doc->embeddedFiles()) { |
171 | qDebug() << " " << file->name(); |
172 | } |
173 | qDebug(); |
174 | } else { |
175 | qDebug() << "No embedded files" ; |
176 | } |
177 | |
178 | if (doc->numPages() <= 0) { |
179 | qDebug() << "Doc has no pages" ; |
180 | return 0; |
181 | } |
182 | |
183 | { |
184 | std::unique_ptr<Poppler::Page> page = doc->page(index: 0); |
185 | if (page) { |
186 | qDebug() << "Page 1 size: " << page->pageSize().width() / 72 << "inches x " << page->pageSize().height() / 72 << "inches" ; |
187 | } |
188 | } |
189 | |
190 | if (argc == 2 || (argc == 3 && strcmp(s1: argv[2], s2: "-qpainter" ) == 0) || (argc == 3 && strcmp(s1: argv[2], s2: "-textRects" ) == 0)) { |
191 | bool useQPainter = (argc == 3 && strcmp(s1: argv[2], s2: "-qpainter" ) == 0); |
192 | PDFDisplay test(std::move(doc), useQPainter); // create picture display |
193 | test.setWindowTitle(QStringLiteral("Poppler-Qt6 Test" )); |
194 | test.setShowTextRects(argc == 3 && strcmp(s1: argv[2], s2: "-textRects" ) == 0); |
195 | test.display(); |
196 | test.show(); // show it |
197 | |
198 | return a.exec(); // start event loop |
199 | } else { |
200 | std::unique_ptr<Poppler::Page> page = doc->page(index: 0); |
201 | |
202 | QLabel *l = new QLabel(page->text(rect: QRectF()), nullptr); |
203 | l->show(); |
204 | return a.exec(); |
205 | } |
206 | } |
207 | |
208 | #include "test-poppler-qt6.moc" |
209 | |