7#include "pdfextractoroutputdevice_p.h"
8#include "pdfbarcodeutil_p.h"
10#include "pdfimage_p.h"
11#include "popplerutils_p.h"
21PdfExtractorOutputDevice::PdfExtractorOutputDevice()
22 : TextOutputDev(nullptr, false, 0, false, false)
26void PdfExtractorOutputDevice::addRasterImage(GfxState *state, Object *ref, Stream *str,
int width,
int height, GfxImageColorMap *colorMap,
PdfImageType type)
28 if ((!colorMap && type == PdfImageType::Image) || (colorMap && !colorMap->isOk()) || (ref && !ref->isRef()) || (!ref && !str)) {
33 if (!colorMap && type != PdfImageType::Image) {
35 }
else if (colorMap->getColorSpace()->getMode() == csIndexed) {
37 }
else if (colorMap->getNumPixelComps() == 1 && (colorMap->getBits() >= 1 && colorMap->getBits() <= 8)) {
39 }
else if (colorMap->getNumPixelComps() == 3 && colorMap->getBits() == 8) {
47 pdfImg.d->m_ref =
PdfImageRef(ref->getRef().num, ref->getRef().gen, type);
50#if KPOPPLER_VERSION >= QT_VERSION_CHECK(0, 69, 0)
52 pdfImg.d->m_colorMap.reset(colorMap->copy());
55 pdfImg.d->m_sourceHeight = height;
56 pdfImg.d->m_sourceWidth = width;
57 pdfImg.d->m_width = width;
58 pdfImg.d->m_height = height;
60 const auto sourceAspectRatio = (double)width / (
double)height;
61 const auto targetAspectRatio = std::abs(state->getCTM()[0] / -state->getCTM()[3]);
62 if (!qFuzzyCompare(sourceAspectRatio, targetAspectRatio) && qFuzzyIsNull(state->getCTM()[1]) && qFuzzyIsNull(state->getCTM()[2])) {
63 if (targetAspectRatio > sourceAspectRatio) {
64 pdfImg.d->m_width = width * targetAspectRatio / sourceAspectRatio;
66 pdfImg.d->m_height = height * sourceAspectRatio / targetAspectRatio;
69 pdfImg.d->m_transform = PopplerUtils::currentTransform(state);
70 pdfImg.d->m_format = format;
73 pdfImg.d->load(str, colorMap);
76 m_images.push_back(pdfImg);
79void PdfExtractorOutputDevice::drawImageMask(GfxState *state, Object *ref, Stream *str,
int width,
int height,
bool invert,
bool interpolate,
bool inlineImg)
82 Q_UNUSED(interpolate);
84 if (!str && !inlineImg) {
87 addRasterImage(state, ref, str, width, height,
nullptr, PdfImageType::Mask);
90void PdfExtractorOutputDevice::drawImage(GfxState* state, Object* ref, Stream* str,
int width,
int height, GfxImageColorMap* colorMap,
bool interpolate, PopplerMaskColors* maskColors,
bool inlineImg)
95 if (!str && !inlineImg) {
98 addRasterImage(state, ref, str, width, height, colorMap, PdfImageType::Image);
101void PdfExtractorOutputDevice::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
int width,
int height, GfxImageColorMap *colorMap,
bool interpolate, Stream *maskStr,
int maskWidth,
int maskHeight,
bool maskInvert,
bool maskInterpolate)
103 Q_UNUSED(interpolate)
105 Q_UNUSED(maskInterpolate)
107 addRasterImage(state, ref, str, width, height, colorMap, PdfImageType::Image);
110 const auto dict = str->getDict();
111 const auto maskObj = dict->lookup(
"Mask");
112 if (maskObj.isStream()) {
113 addRasterImage(state, ref, maskStr, maskWidth, maskHeight,
nullptr, PdfImageType::Mask);
118void PdfExtractorOutputDevice::saveState(GfxState *state)
121 m_vectorOps.push_back(VectorOp{VectorOp::PushState, {}, {}});
124void PdfExtractorOutputDevice::restoreState(GfxState *state)
127 if (m_vectorOps.empty()) {
130 const auto &lastOp = *(m_vectorOps.end() -1);
131 if (lastOp.type == VectorOp::PushState) {
132 m_vectorOps.resize(m_vectorOps.size() - 1);
134 m_vectorOps.push_back(VectorOp{VectorOp::PopState, {}, {}});
138static bool isRelevantStroke(
const QPen &pen)
145 qreal x = 0.0, y = 0.0;
146 for (
int i = 0; i <
path.elementCount(); ++i) {
147 const auto elem =
path.elementAt(i);
154 if (x != elem.x && y != elem.y) {
155 qDebug() <<
"path contains diagonal line, discarding";
163 qDebug() <<
"path contains a curve, discarding";
171void PdfExtractorOutputDevice::stroke(GfxState *state)
173 const auto pen = PopplerUtils::currentPen(state);
174 if (!isRelevantStroke(pen)) {
179 if (!isRectangularPath(path)) {
182 const auto t = PopplerUtils::currentTransform(state);
183 m_vectorOps.push_back(VectorOp{VectorOp::Path, t, {
path, pen,
QBrush()}});
186static bool isRelevantFill(
const QBrush &brush)
191void PdfExtractorOutputDevice::fill(GfxState *state)
193 const auto brush = PopplerUtils::currentBrush(state);
194 if (!isRelevantFill(brush)) {
199 const auto b =
path.boundingRect();
200 if (b.width() == 0 || b.height() == 0) {
204 const auto t = PopplerUtils::currentTransform(state);
205 m_vectorOps.push_back(VectorOp{VectorOp::Path, t, {
path,
QPen(), brush}});
208void PdfExtractorOutputDevice::eoFill(GfxState *state)
210 const auto brush = PopplerUtils::currentBrush(state);
211 if (!isRelevantFill(brush)) {
216 const auto b =
path.boundingRect();
217 if (b.width() == 0 || b.height() == 0) {
221 const auto t = PopplerUtils::currentTransform(state);
222 m_vectorOps.push_back(VectorOp{VectorOp::Path, t, {
path,
QPen(), brush}});
225void PdfExtractorOutputDevice::finalize()
228 std::vector<VectorOp> mergedOps;
229 mergedOps.reserve(m_vectorOps.size());
230 for (
auto it = m_vectorOps.begin(); it != m_vectorOps.end(); ++it) {
231 if ((*it).type == VectorOp::PushState && std::distance(it, m_vectorOps.end()) >= 2 && (*(it + 1)).type == VectorOp::Path && (*(it + 2)).type == VectorOp::PopState) {
233 mergedOps.push_back(*it);
236 mergedOps.push_back(*it);
241 std::vector<PdfVectorPicture::PathStroke> strokes;
243 for (
const auto &op : mergedOps) {
244 if (op.type == VectorOp::Path) {
248 if (t != op.transform) {
252 strokes.push_back(op.stroke);
253 }
else if (!strokes.empty()) {
254 PdfVectorPicture pic;
255 pic.setStrokes(std::move(strokes));
261 if (!strokes.empty()) {
262 PdfVectorPicture pic;
263 pic.setStrokes(std::move(strokes));
269void PdfExtractorOutputDevice::addVectorImage(
const PdfVectorPicture &pic)
271 if (PdfBarcodeUtil::isPlausiblePath(pic.pathElementsCount(), BarcodeDecoder::Any) == BarcodeDecoder::None) {
276 img.d->m_height = pic.height();
277 img.d->m_width = pic.width();
278 img.d->m_sourceHeight = pic.sourceHeight();
279 img.d->m_sourceWidth = pic.sourceWidth();
280 img.d->m_transform = pic.transform();
281 img.d->m_vectorPicture = pic;
282 m_images.push_back(img);
285void PdfExtractorOutputDevice::processLink(AnnotLink *link)
287 TextOutputDev::processLink(link);
288 if (!
link->isOk() || !
link->getAction() ||
link->getAction()->getKind() != actionURI) {
292 const auto uriLink =
static_cast<LinkURI*
>(
link->getAction());
293 double xd1, yd1, xd2, yd2;
294 link->getRect(&xd1, &yd1, &xd2, &yd2);
296 double xu1, yu1, xu2, yu2;
297 cvtDevToUser(xd1, yd1, &xu1, &yu1);
298 cvtDevToUser(xd2, yd2, &xu2, &yu2);
300 m_links.push_back(std::move(l));
PDF object reference for an image, with the ability to address attached masks as well.
An image in a PDF document.
An external link in a PDF file.
KIOCORE_EXPORT CopyJob * link(const QList< QUrl > &src, const QUrl &destDir, JobFlags flags=DefaultFlags)
Classes for reservation/travel data models, data extraction and data augmentation.
PdfImageType
PDF image element type.
QString path(const QString &relativePath)
const QColor & color() const const
QColor color() const const
qreal widthF() const const
QString fromStdString(const std::string &str)