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::Mask) {
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);
51 pdfImg.d->m_colorMap.reset(colorMap->copy());
53 pdfImg.d->m_sourceHeight = height;
54 pdfImg.d->m_sourceWidth = width;
55 pdfImg.d->m_width = width;
56 pdfImg.d->m_height = height;
58 const auto sourceAspectRatio = (double)width / (
double)height;
59 const auto targetAspectRatio = std::abs(state->getCTM()[0] / -state->getCTM()[3]);
60 if (!qFuzzyCompare(sourceAspectRatio, targetAspectRatio) && qFuzzyIsNull(state->getCTM()[1]) && qFuzzyIsNull(state->getCTM()[2])) {
61 if (targetAspectRatio > sourceAspectRatio) {
62 pdfImg.d->m_width = width * targetAspectRatio / sourceAspectRatio;
64 pdfImg.d->m_height = height * sourceAspectRatio / targetAspectRatio;
67 pdfImg.d->m_transform = PopplerUtils::currentTransform(state);
68 pdfImg.d->m_format = format;
71 pdfImg.d->load(str, colorMap);
74 m_images.push_back(pdfImg);
77void PdfExtractorOutputDevice::drawImageMask(GfxState *state, Object *ref, Stream *str,
int width,
int height,
bool invert,
bool interpolate,
bool inlineImg)
80 Q_UNUSED(interpolate);
82 if (!str && !inlineImg) {
85 addRasterImage(state, ref, str, width, height,
nullptr, PdfImageType::Mask);
88void PdfExtractorOutputDevice::drawImage(GfxState* state, Object* ref, Stream* str,
int width,
int height, GfxImageColorMap* colorMap,
bool interpolate, PopplerMaskColors* maskColors,
bool inlineImg)
93 if (!str && !inlineImg) {
96 addRasterImage(state, ref, str, width, height, colorMap, PdfImageType::Image);
99void 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)
101 Q_UNUSED(interpolate)
103 Q_UNUSED(maskInterpolate)
105 addRasterImage(state, ref, str, width, height, colorMap, PdfImageType::Image);
108 const auto dict = str->getDict();
109 const auto maskObj = dict->lookup(
"Mask");
110 if (maskObj.isStream()) {
111 addRasterImage(state, ref, maskStr, maskWidth, maskHeight,
nullptr, PdfImageType::Mask);
116void PdfExtractorOutputDevice::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
int width,
int height, GfxImageColorMap *colorMap,
bool interpolate, Stream *maskStr,
int maskWidth,
int maskHeight, GfxImageColorMap *maskColorMap,
bool maskInterpolate)
118 Q_UNUSED(interpolate);
119 Q_UNUSED(maskInterpolate);
121 addRasterImage(state, ref, str, width, height, colorMap, PdfImageType::Image);
123 const auto dict = str->getDict();
124 const auto maskObj = dict->lookup(
"SMask");
125 if (maskObj.isStream()) {
126 addRasterImage(state, ref, maskStr, maskWidth, maskHeight, maskColorMap, PdfImageType::SMask);
131void PdfExtractorOutputDevice::saveState(GfxState *state)
134 m_vectorOps.push_back(VectorOp{VectorOp::PushState, {}, {}});
137void PdfExtractorOutputDevice::restoreState(GfxState *state)
140 if (m_vectorOps.empty()) {
143 const auto &lastOp = *(m_vectorOps.end() -1);
144 if (lastOp.type == VectorOp::PushState) {
145 m_vectorOps.resize(m_vectorOps.size() - 1);
147 m_vectorOps.push_back(VectorOp{VectorOp::PopState, {}, {}});
151static bool isRelevantStroke(
const QPen &pen)
158 qreal x = 0.0, y = 0.0;
159 for (
int i = 0; i <
path.elementCount(); ++i) {
160 const auto elem =
path.elementAt(i);
167 if (x != elem.x && y != elem.y) {
168 qDebug() <<
"path contains diagonal line, discarding";
176 qDebug() <<
"path contains a curve, discarding";
184void PdfExtractorOutputDevice::stroke(GfxState *state)
186 const auto pen = PopplerUtils::currentPen(state);
187 if (!isRelevantStroke(pen)) {
192 if (!isRectangularPath(path)) {
195 const auto t = PopplerUtils::currentTransform(state);
196 m_vectorOps.push_back(VectorOp{VectorOp::Path, t, {
path, pen,
QBrush()}});
199static bool isRelevantFill(
const QBrush &brush)
204void PdfExtractorOutputDevice::fill(GfxState *state)
206 const auto brush = PopplerUtils::currentBrush(state);
207 if (!isRelevantFill(brush)) {
212 const auto b =
path.boundingRect();
213 if (b.width() == 0 || b.height() == 0) {
217 const auto t = PopplerUtils::currentTransform(state);
218 m_vectorOps.push_back(VectorOp{VectorOp::Path, t, {
path,
QPen(), brush}});
221void PdfExtractorOutputDevice::eoFill(GfxState *state)
223 const auto brush = PopplerUtils::currentBrush(state);
224 if (!isRelevantFill(brush)) {
229 const auto b =
path.boundingRect();
230 if (b.width() == 0 || b.height() == 0) {
234 const auto t = PopplerUtils::currentTransform(state);
235 m_vectorOps.push_back(VectorOp{VectorOp::Path, t, {
path,
QPen(), brush}});
238void PdfExtractorOutputDevice::finalize()
241 std::vector<VectorOp> mergedOps;
242 mergedOps.reserve(m_vectorOps.size());
243 for (
auto it = m_vectorOps.begin(); it != m_vectorOps.end(); ++it) {
244 if ((*it).type == VectorOp::PushState && std::distance(it, m_vectorOps.end()) >= 2 && (*(it + 1)).type == VectorOp::Path && (*(it + 2)).type == VectorOp::PopState) {
246 mergedOps.push_back(*it);
249 mergedOps.push_back(*it);
254 std::vector<PdfVectorPicture::PathStroke> strokes;
256 for (
const auto &op : mergedOps) {
257 if (op.type == VectorOp::Path) {
261 if (t != op.transform) {
265 strokes.push_back(op.stroke);
266 }
else if (!strokes.empty()) {
267 PdfVectorPicture pic;
268 pic.setStrokes(std::move(strokes));
274 if (!strokes.empty()) {
275 PdfVectorPicture pic;
276 pic.setStrokes(std::move(strokes));
282void PdfExtractorOutputDevice::addVectorImage(
const PdfVectorPicture &pic)
284 if (PdfBarcodeUtil::isPlausiblePath(pic.pathElementsCount(), BarcodeDecoder::Any) == BarcodeDecoder::None) {
289 img.d->m_height = pic.height();
290 img.d->m_width = pic.width();
291 img.d->m_sourceHeight = pic.sourceHeight();
292 img.d->m_sourceWidth = pic.sourceWidth();
293 img.d->m_transform = pic.transform();
294 img.d->m_vectorPicture = pic;
295 m_images.push_back(img);
298void PdfExtractorOutputDevice::processLink(AnnotLink *link)
300 TextOutputDev::processLink(link);
301 if (!
link->isOk() || !
link->getAction() ||
link->getAction()->getKind() != actionURI) {
305 const auto uriLink =
static_cast<LinkURI*
>(
link->getAction());
306 double xd1, yd1, xd2, yd2;
307 link->getRect(&xd1, &yd1, &xd2, &yd2);
309 double xu1, yu1, xu2, yu2;
310 cvtDevToUser(xd1, yd1, &xu1, &yu1);
311 cvtDevToUser(xd2, yd2, &xu2, &yu2);
313 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)