Okular

utils.cpp
1 /*
2  SPDX-FileCopyrightText: 2006 Luigi Toscano <[email protected]>
3  SPDX-FileCopyrightText: 2008 Pino Toscano <[email protected]>
4 
5  SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #include "utils.h"
9 #include "utils_p.h"
10 
11 #include "debug_p.h"
12 #include "settings_core.h"
13 
14 #include <QApplication>
15 #include <QIODevice>
16 #include <QImage>
17 #include <QRect>
18 #include <QScreen>
19 #include <QWidget>
20 #include <QWindow>
21 
22 using namespace Okular;
23 
24 QRect Utils::rotateRect(const QRect source, int width, int height, int orientation)
25 {
26  QRect ret;
27 
28  // adapt the coordinates of the boxes to the rotation
29  switch (orientation) {
30  case 1:
31  ret = QRect(width - source.y() - source.height(), source.x(), source.height(), source.width());
32  break;
33  case 2:
34  ret = QRect(width - source.x() - source.width(), height - source.y() - source.height(), source.width(), source.height());
35  break;
36  case 3:
37  ret = QRect(source.y(), height - source.x() - source.width(), source.height(), source.width());
38  break;
39  case 0: // no modifications
40  default: // other cases
41  ret = source;
42  }
43 
44  return ret;
45 }
46 
47 QSizeF Utils::realDpi(const QWindow *windowOnScreen)
48 {
49  const QScreen *screen = windowOnScreen ? windowOnScreen->screen() : qGuiApp->primaryScreen();
50 
51  if (screen) {
52  const QSizeF res(screen->physicalDotsPerInchX(), screen->physicalDotsPerInchY());
53  if (res.width() > 0 && res.height() > 0) {
54  if (qAbs(res.width() - res.height()) / qMin(res.height(), res.width()) < 0.15) {
55  return res;
56  } else {
57  qCDebug(OkularCoreDebug) << "QScreen calculation returned a non square dpi." << res << ". Falling back";
58  }
59  }
60  }
61  return QSizeF(72, 72);
62 }
63 
64 inline static bool isPaperColor(QRgb argb, QRgb paperColor)
65 {
66  return (argb & 0xFFFFFF) == (paperColor & 0xFFFFFF); // ignore alpha
67 }
68 
70 {
71  if (!image) {
72  return NormalizedRect();
73  }
74 
75  const int width = image->width();
76  const int height = image->height();
77  const QRgb paperColor = SettingsCore::paperColor().rgb();
78  int left, top, bottom, right, x, y;
79 
80 #ifdef BBOX_DEBUG
81  QTime time;
82  time.start();
83 #endif
84 
85  // Scan pixels for top non-white
86  for (top = 0; top < height; ++top) {
87  for (x = 0; x < width; ++x) {
88  if (!isPaperColor(image->pixel(x, top), paperColor)) {
89  goto got_top;
90  }
91  }
92  }
93  return NormalizedRect(0, 0, 0, 0); // the image is blank
94 got_top:
95  left = right = x;
96 
97  // Scan pixels for bottom non-white
98  for (bottom = height - 1; bottom >= top; --bottom) {
99  for (x = width - 1; x >= 0; --x) {
100  if (!isPaperColor(image->pixel(x, bottom), paperColor)) {
101  goto got_bottom;
102  }
103  }
104  }
105  Q_ASSERT(0); // image changed?!
106 got_bottom:
107  if (x < left) {
108  left = x;
109  }
110  if (x > right) {
111  right = x;
112  }
113 
114  // Scan for leftmost and rightmost (we already found some bounds on these):
115  for (y = top; y <= bottom && (left > 0 || right < width - 1); ++y) {
116  for (x = 0; x < left; ++x) {
117  if (!isPaperColor(image->pixel(x, y), paperColor)) {
118  left = x;
119  }
120  }
121  for (x = width - 1; x > right + 1; --x) {
122  if (!isPaperColor(image->pixel(x, y), paperColor)) {
123  right = x;
124  }
125  }
126  }
127 
128  NormalizedRect bbox(QRect(left, top, (right - left + 1), (bottom - top + 1)), image->width(), image->height());
129 
130 #ifdef BBOX_DEBUG
131  qCDebug(OkularCoreDebug) << "Computed bounding box" << bbox << "in" << time.elapsed() << "ms";
132 #endif
133 
134  return bbox;
135 }
136 
137 void Okular::copyQIODevice(QIODevice *from, QIODevice *to)
138 {
139  QByteArray buffer(65536, '\0');
140  qint64 read = 0;
141  qint64 written = 0;
142  while ((read = from->read(buffer.data(), buffer.size())) > 0) {
143  written = to->write(buffer.constData(), read);
144  if (read != written) {
145  break;
146  }
147  }
148 }
149 
150 QTransform Okular::buildRotationMatrix(Rotation rotation)
151 {
152  QTransform matrix;
153  matrix.rotate((int)rotation * 90);
154 
155  switch (rotation) {
156  case Rotation90:
157  matrix.translate(0, -1);
158  break;
159  case Rotation180:
160  matrix.translate(-1, -1);
161  break;
162  case Rotation270:
163  matrix.translate(-1, 0);
164  break;
165  default:;
166  }
167 
168  return matrix;
169 }
170 
171 /* kate: replace-tabs on; indent-width 4; */
qreal height() const const
int height() const const
The documentation to the global Okular namespace.
Definition: action.h:16
QTransform & rotate(qreal angle, Qt::Axis axis)
physicalDotsPerInchY
static NormalizedRect imageBoundingBox(const QImage *image)
Compute the smallest rectangle that contains all non-white pixels in image), in normalized [0,...
Definition: utils.cpp:69
int width() const const
int x() const const
int y() const const
@ Rotation180
Rotated 180 degrees clockwise.
Definition: global.h:48
static QSizeF realDpi(const QWindow *windowOnScreen)
Return the real DPI of the display containing given window.
Definition: utils.cpp:47
QRgb pixel(int x, int y) const const
QTransform & translate(qreal dx, qreal dy)
A NormalizedRect is a rectangle which can be defined by two NormalizedPoints.
Definition: area.h:188
QScreen * screen() const const
@ Rotation90
Rotated 90 degrees clockwise.
Definition: global.h:47
qint64 read(char *data, qint64 maxSize)
int height() const const
void start()
int elapsed() const const
static QRect rotateRect(const QRect source, int width, int height, int orientation)
Rotate the rect source in the area width x height with the specified orientation .
Definition: utils.cpp:24
@ Rotation270
Rotated 2700 degrees clockwise.
Definition: global.h:49
physicalDotsPerInchX
qint64 write(const char *data, qint64 maxSize)
Rotation
A rotation.
Definition: global.h:45
qreal width() const const
int width() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sat Sep 30 2023 03:54:23 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.