KItinerary

pdfimage.cpp
1/*
2 SPDX-FileCopyrightText: 2019 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "pdfimage.h"
8#include "pdfimage_p.h"
9#include "pdfdocument_p.h"
10#include "popplerglobalparams_p.h"
11#include "popplerutils_p.h"
12
13#include <QDebug>
14#include <QScopedValueRollback>
15
16#include <Gfx.h>
17#include <GlobalParams.h>
18#include <PDFDoc.h>
19#include <Stream.h>
20#include <OutputDev.h>
21
22using namespace KItinerary;
23
24static inline bool isColor(GfxRGB rgb)
25{
26 enum { Threshold = 72 * 256 }; // GfxComp is stored as color value * 255
27
28 // barcode images for SNCF and Renfe for example are anti-aliased, so we cannot simply filter for black or white
29 // KLM/AF use tinted barcodes, so checking for R = G = B doesn't help either
30 return std::abs(rgb.r - rgb.g) > Threshold || std::abs(rgb.r - rgb.b) > Threshold || std::abs(rgb.g - rgb.b) > Threshold;
31}
32
33QImage PdfImagePrivate::load(Stream* str, GfxImageColorMap* colorMap)
34{
35 if (m_format == QImage::Format_Mono) { // bitmasks are not stored as image streams
36 auto img = QImage(m_sourceWidth, m_sourceHeight, QImage::Format_Mono); // TODO implicit Format_Grayscale8 conversion
37 str->reset();
38 const int rowSize = (m_sourceWidth + 7) / 8;
39 for (int y = 0; y < m_sourceHeight; ++y) {
40 auto imgData = img.scanLine(y);
41 for (int x = 0; x < rowSize; x++) {
42 const auto c = str->getChar();
43 *imgData++ = c ^ 0xff;
44 }
45 }
46
47 if (!m_ref.isNull()) {
48 m_page->m_doc->m_imageData[m_ref] = img;
49 } else {
50 m_inlineImageData = img;
51 }
52 return img;
53 }
54
55 auto img = QImage(m_sourceWidth, m_sourceHeight, (m_loadingHints & PdfImage::ConvertToGrayscaleHint) ? QImage::Format_Grayscale8 : m_format);
56 const auto bytesPerPixel = colorMap->getNumPixelComps();
57 std::unique_ptr<ImageStream> imgStream(new ImageStream(str, m_sourceWidth, bytesPerPixel, colorMap->getBits()));
58 imgStream->reset();
59
60 switch (m_format) {
62 for (int i = 0; i < m_sourceHeight; ++i) {
63 const auto row = imgStream->getLine();
64 auto imgData = img.scanLine(i);
65 GfxRGB rgb;
66 for (int j = 0; j < m_sourceWidth; ++j) {
67 colorMap->getRGB(row + (j * bytesPerPixel), &rgb);
68 if ((m_loadingHints & PdfImage::AbortOnColorHint) && isColor(rgb)) {
69 return {};
70 }
71 if ((m_loadingHints & PdfImage::ConvertToGrayscaleHint)) {
72 *imgData++ = colToByte(rgb.g); // technically not correct but good enough
73 } else {
74 *imgData++ = colToByte(rgb.r);
75 *imgData++ = colToByte(rgb.g);
76 *imgData++ = colToByte(rgb.b);
77 }
78 }
79 }
80 break;
82 for (int i = 0; i < m_sourceHeight; ++i) {
83 const auto row = imgStream->getLine();
84 auto imgData = img.scanLine(i);
85 GfxGray gray;
86 for (int j = 0; j < m_sourceWidth; ++j) {
87 colorMap->getGray(row + j, &gray);
88 *imgData++ = m_ref.m_type == PdfImageType::SMask ? (colToByte(gray) ^ 0xff) : colToByte(gray);
89 }
90 }
91 break;
92 default:
93 break;
94 }
95 imgStream->close();
96
97 if (!m_ref.isNull()) {
98 m_page->m_doc->m_imageData[m_ref] = img;
99 } else {
100 m_inlineImageData = img;
101 }
102 return img;
103}
104
105QImage PdfImagePrivate::load()
106{
107 const auto it = m_page->m_doc->m_imageData.find(m_ref);
108 if (it != m_page->m_doc->m_imageData.end()) {
109 return (*it).second;
110 }
111
112 PopplerGlobalParams gp;
113
114 const auto xref = m_page->m_doc->m_popplerDoc->getXRef();
115 const auto obj = xref->fetch(refNum(), refGen());
116
117 switch (m_ref.m_type) {
118 case PdfImageType::Image:
119 return load(obj.getStream(), m_colorMap.get());
120 case PdfImageType::Mask:
121 {
122 const auto dict = obj.getStream()->getDict();
123 const auto maskObj = dict->lookup("Mask");
124 return load(maskObj.getStream(), m_colorMap.get());
125 }
126 case PdfImageType::SMask:
127 {
128 const auto dict = obj.getStream()->getDict();
129 const auto maskObj = dict->lookup("SMask");
130 return load(maskObj.getStream(), m_colorMap.get());
131 }
132 }
133
134 return {};
135}
136
137
138PdfImage::PdfImage()
139 : d(new PdfImagePrivate)
140{
141}
142
143PdfImage::PdfImage(const PdfImage&) = default;
144PdfImage::~PdfImage() = default;
145PdfImage& PdfImage::operator=(const PdfImage&) = default;
146
147int PdfImage::height() const
148{
149 if (d->m_format == QImage::Format_Invalid) {
150 return d->m_height;
151 }
152 return d->m_transform.map(QRectF(0, 0, 1, -1)).boundingRect().height();
153}
154
155int PdfImage::width() const
156{
157 if (d->m_format == QImage::Format_Invalid) {
158 return d->m_width;
159 }
160 return d->m_transform.map(QRectF(0, 0, 1, -1)).boundingRect().width();
161}
162
164{
165 return d->m_sourceHeight;
166}
167
169{
170 return d->m_sourceWidth;
171}
172
174{
175 return d->m_transform;
176}
177
179{
180 d->m_loadingHints = hints;
181}
182
184{
185 if (!d->m_inlineImageData.isNull()) {
186 return d->m_inlineImageData;
187 }
188 if (d->m_format == QImage::Format_Invalid) {
189 return d->m_vectorPicture.renderToImage();
190 }
191 return d->load();
192}
193
195{
196 return !d->m_ref.isNull();
197}
198
200{
201 return d->m_ref;
202}
203
205{
206 return !d->m_vectorPicture.isNull();
207}
208
210{
211 return d->m_vectorPicture.pathElementsCount();
212}
213
215{
216 return d->m_format != QImage::Format_Invalid && (d->m_width != d->m_sourceWidth || d->m_height != d->m_sourceHeight);
217}
218
220{
221 return image.scaled(d->m_width, d->m_height);
222}
223
225{
226 return d->m_ref.m_type;
227}
228
229#include "moc_pdfimage.cpp"
PDF object reference for an image, with the ability to address attached masks as well.
Definition pdfimage.h:43
An image in a PDF document.
Definition pdfimage.h:74
PdfImageType type() const
PDF image type.
Definition pdfimage.cpp:224
@ AbortOnColorHint
Abort loading when encountering a non black/white pixel, as a shortcut for barcode detection.
Definition pdfimage.h:102
@ ConvertToGrayscaleHint
Convert to QImage::Format_Grayscale8 during loading. More efficient than converting later if all you ...
Definition pdfimage.h:103
QImage image() const
The source image without display transformations applied.
Definition pdfimage.cpp:183
int pathElementsCount() const
If this is a vector image, this returns the number of vector path elemets.
Definition pdfimage.cpp:209
void setLoadingHints(LoadingHints hints)
Sets image loading hints.
Definition pdfimage.cpp:178
QTransform transform() const
Transformation from source image to final size/position on the page.
Definition pdfimage.cpp:173
bool isVectorImage() const
Returns whether this is a raster or vector image.
Definition pdfimage.cpp:204
bool hasAspectRatioTransform() const
Returns true if this image has an aspect-ratio changing transform.
Definition pdfimage.cpp:214
QImage applyAspectRatioTransform(const QImage &image) const
Applies the aspect ratio changing part of the transform to the given image (which typically should be...
Definition pdfimage.cpp:219
int sourceWidth() const
Width of the source image.
Definition pdfimage.cpp:168
bool hasObjectId() const
Returns whether this image has an object id.
Definition pdfimage.cpp:194
PdfImageRef objectId() const
PDF-internal unique identifier of this image.
Definition pdfimage.cpp:199
int sourceHeight() const
Height of the source image.
Definition pdfimage.cpp:163
QAction * load(const QObject *recvr, const char *slot, QObject *parent)
Classes for reservation/travel data models, data extraction and data augmentation.
Definition berelement.h:17
PdfImageType
PDF image element type.
Definition pdfimage.h:35
QImage scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 4 2024 12:00:26 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.