KItinerary

pdfvectorpicture.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 "pdfvectorpicture_p.h"
8
9#include <QDebug>
10#include <QImage>
11#include <QPainter>
12
13#include <cmath>
14
15constexpr inline const auto RenderDPI = 150.0; // target dpi for rendering
16
17using namespace KItinerary;
18
19namespace KItinerary {
20class PdfVectorPicturePrivate : public QSharedData {
21public:
22 std::vector<PdfVectorPicture::PathStroke> strokes;
23 QRectF boundingRect;
24 QImage image;
25 QTransform transform;
26};
27}
28
29PdfVectorPicture::PdfVectorPicture()
30 : d(new PdfVectorPicturePrivate)
31{
32}
33
34PdfVectorPicture::PdfVectorPicture(const PdfVectorPicture&) = default;
35PdfVectorPicture::~PdfVectorPicture() = default;
36PdfVectorPicture& PdfVectorPicture::operator=(const PdfVectorPicture&) = default;
37
38bool PdfVectorPicture::isNull() const
39{
40 return d->strokes.empty();
41}
42
43void PdfVectorPicture::setStrokes(std::vector<PdfVectorPicture::PathStroke> &&strokes)
44{
45 d.detach();
46 d->strokes = std::move(strokes);
47 d->image = QImage();
48 d->boundingRect = QRectF();
49}
50
51QTransform PdfVectorPicture::transform() const
52{
53 return d->transform;
54}
55
56void PdfVectorPicture::setTransform(const QTransform &t)
57{
58 d.detach();
59 d->transform = t;
60}
61
62QRectF PdfVectorPicture::boundingRect() const
63{
64 if (d->strokes.empty()) {
65 return {};
66 }
67
68 if (d->boundingRect.isEmpty()) {
69 double maxPenWidth = 0.0;
70 for (const auto &stroke : d->strokes) {
71 d->boundingRect = d->boundingRect.united(stroke.path.boundingRect());
72 maxPenWidth = std::max(maxPenWidth, stroke.pen.widthF());
73 }
74 // include the pen width, for strokes drawn on the boundary
75 d->boundingRect.adjust(-maxPenWidth, -maxPenWidth, maxPenWidth, maxPenWidth);
76 }
77
78 return d->boundingRect;
79}
80
81int PdfVectorPicture::pathElementsCount() const
82{
83 int c = 0;
84 for (const auto &stroke : d->strokes) {
85 c += stroke.path.elementCount();
86 }
87 return c;
88}
89
90static double scaleFromTransform(QTransform t, bool *shouldFlip = nullptr)
91{
92 if (t.isRotating()) {
93 t.rotate(90);
94 if (t.isRotating()) {
95 qDebug() << "non-90° rotation, likely not a barcode";
96 return 1.0;
97 }
98 }
99
100 if (std::abs(std::abs(t.m11()) - std::abs(t.m22())) < 0.1) {
101 if (shouldFlip && t.m22() < 0) {
102 *shouldFlip = true;
103 }
104 return std::max(std::abs(t.m11()), std::abs(t.m22()));
105 }
106 qDebug() << "asymmetric scale not supported yet" << t;
107 return 1.0;
108}
109
110QImage PdfVectorPicture::renderToImage() const
111{
112 if (d->image.isNull()) {
113 bool shouldFlip = false;
114 const double scale = (RenderDPI / 72.0) * scaleFromTransform(d->transform, &shouldFlip); // 1/72 dpi is the unit for the vector coordinates
115 const int width = std::ceil(boundingRect().width() * scale);
116 const int height = std::ceil(boundingRect().height() * scale);
117 d->image = QImage(width, height, QImage::Format_Grayscale8);
118 d->image.fill(Qt::white);
119 QPainter p(&d->image);
120 if (shouldFlip) {
121 p.translate(0.0, height);
122 p.scale(scale, -scale);
123 } else {
124 p.scale(scale, scale);
125 }
126 for (const auto &stroke : d->strokes) {
127 if (stroke.brush.style() == Qt::NoBrush) {
128 p.strokePath(stroke.path.translated(-boundingRect().x(), -boundingRect().y()), stroke.pen);
129 } else {
130 p.fillPath(stroke.path.translated(-boundingRect().x(), -boundingRect().y()), stroke.brush);
131 }
132 }
133 }
134
135 return d->image;
136}
137
138int PdfVectorPicture::sourceWidth() const
139{
140 // 1/72 dpi is the unit for the vector coordinates
141 return boundingRect().width() * (RenderDPI / 72.0);
142}
143
144int PdfVectorPicture::sourceHeight() const
145{
146 // 1/72 dpi is the unit for the vector coordinates
147 return boundingRect().height() * (RenderDPI / 72.0);
148}
149
150int PdfVectorPicture::width() const
151{
152 return boundingRect().width() * scaleFromTransform(d->transform);
153}
154
155int PdfVectorPicture::height() const
156{
157 return boundingRect().height() * scaleFromTransform(d->transform);
158}
Classes for reservation/travel data models, data extraction and data augmentation.
Definition berelement.h:17
Format_Grayscale8
QRectF united(const QRectF &rectangle) const const
bool isRotating() const const
qreal m11() const const
qreal m22() const const
QTransform & rotate(qreal a, Qt::Axis axis)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:49 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.