/src/qtbase/src/gui/image/qpixmap_raster.cpp
Line | Count | Source |
1 | | // Copyright (C) 2016 The Qt Company Ltd. |
2 | | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | | // Qt-Security score:significant reason:default |
4 | | |
5 | | #include "qpixmap.h" |
6 | | |
7 | | #include <private/qfont_p.h> |
8 | | |
9 | | #include "qpixmap_raster_p.h" |
10 | | #include "qimage_p.h" |
11 | | #include "qpaintengine.h" |
12 | | |
13 | | #include "qbitmap.h" |
14 | | #include "qimage.h" |
15 | | #include <QBuffer> |
16 | | #include <QImageReader> |
17 | | #include <QGuiApplication> |
18 | | #include <QScreen> |
19 | | #include <private/qsimd_p.h> |
20 | | #include <private/qdrawhelper_p.h> |
21 | | #include <qpa/qplatformscreen.h> |
22 | | |
23 | | QT_BEGIN_NAMESPACE |
24 | | |
25 | | QPixmap qt_toRasterPixmap(const QImage &image) |
26 | 0 | { |
27 | 0 | QPlatformPixmap *data = |
28 | 0 | new QRasterPlatformPixmap(image.depth() == 1 |
29 | 0 | ? QPlatformPixmap::BitmapType |
30 | 0 | : QPlatformPixmap::PixmapType); |
31 | |
|
32 | 0 | data->fromImage(image, Qt::AutoColor); |
33 | |
|
34 | 0 | return QPixmap(data); |
35 | 0 | } |
36 | | |
37 | | QPixmap qt_toRasterPixmap(const QPixmap &pixmap) |
38 | 0 | { |
39 | 0 | if (pixmap.isNull()) |
40 | 0 | return QPixmap(); |
41 | | |
42 | 0 | if (QPixmap(pixmap).data_ptr()->classId() == QPlatformPixmap::RasterClass) |
43 | 0 | return pixmap; |
44 | | |
45 | 0 | return qt_toRasterPixmap(pixmap.toImage()); |
46 | 0 | } |
47 | | |
48 | | QRasterPlatformPixmap::QRasterPlatformPixmap(PixelType type) |
49 | 0 | : QPlatformPixmap(type, RasterClass) |
50 | 0 | { |
51 | 0 | } |
52 | | |
53 | | QRasterPlatformPixmap::~QRasterPlatformPixmap() |
54 | 0 | { |
55 | 0 | } |
56 | | |
57 | | QImage::Format QRasterPlatformPixmap::systemNativeFormat() |
58 | 0 | { |
59 | 0 | if (!QGuiApplication::primaryScreen()) |
60 | 0 | return QImage::Format_RGB32; |
61 | 0 | return QGuiApplication::primaryScreen()->handle()->format(); |
62 | 0 | } |
63 | | |
64 | | QPlatformPixmap *QRasterPlatformPixmap::createCompatiblePlatformPixmap() const |
65 | 0 | { |
66 | 0 | return new QRasterPlatformPixmap(pixelType()); |
67 | 0 | } |
68 | | |
69 | | void QRasterPlatformPixmap::resize(int width, int height) |
70 | 0 | { |
71 | 0 | QImage::Format format; |
72 | 0 | if (pixelType() == BitmapType) |
73 | 0 | format = QImage::Format_MonoLSB; |
74 | 0 | else |
75 | 0 | format = systemNativeFormat(); |
76 | |
|
77 | 0 | image = QImage(width, height, format); |
78 | 0 | w = width; |
79 | 0 | h = height; |
80 | 0 | d = image.depth(); |
81 | 0 | is_null = (w <= 0 || h <= 0); |
82 | |
|
83 | 0 | if (pixelType() == BitmapType && !image.isNull()) { |
84 | 0 | image.setColorCount(2); |
85 | 0 | image.setColor(0, QColor(Qt::color0).rgba()); |
86 | 0 | image.setColor(1, QColor(Qt::color1).rgba()); |
87 | 0 | } |
88 | |
|
89 | 0 | setSerialNumber(image.cacheKey() >> 32); |
90 | 0 | } |
91 | | |
92 | | bool QRasterPlatformPixmap::fromData(const uchar *buffer, uint len, const char *format, |
93 | | Qt::ImageConversionFlags flags) |
94 | 0 | { |
95 | 0 | QByteArray a = QByteArray::fromRawData(reinterpret_cast<const char *>(buffer), len); |
96 | 0 | QBuffer b(&a); |
97 | 0 | b.open(QIODevice::ReadOnly); |
98 | 0 | QImage image = QImageReader(&b, format).read(); |
99 | 0 | if (image.isNull()) |
100 | 0 | return false; |
101 | | |
102 | 0 | createPixmapForImage(std::move(image), flags); |
103 | 0 | return !isNull(); |
104 | 0 | } |
105 | | |
106 | | void QRasterPlatformPixmap::fromImage(const QImage &sourceImage, |
107 | | Qt::ImageConversionFlags flags) |
108 | 0 | { |
109 | 0 | QImage image = sourceImage; |
110 | 0 | createPixmapForImage(std::move(image), flags); |
111 | 0 | } |
112 | | |
113 | | void QRasterPlatformPixmap::fromImageInPlace(QImage &sourceImage, |
114 | | Qt::ImageConversionFlags flags) |
115 | 0 | { |
116 | 0 | createPixmapForImage(std::move(sourceImage), flags); |
117 | 0 | } |
118 | | |
119 | | void QRasterPlatformPixmap::fromImageReader(QImageReader *imageReader, |
120 | | Qt::ImageConversionFlags flags) |
121 | 0 | { |
122 | 0 | Q_UNUSED(flags); |
123 | 0 | QImage image = imageReader->read(); |
124 | 0 | if (image.isNull()) |
125 | 0 | return; |
126 | | |
127 | 0 | createPixmapForImage(std::move(image), flags); |
128 | 0 | } |
129 | | |
130 | | // from qbackingstore.cpp |
131 | | extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); |
132 | | |
133 | | void QRasterPlatformPixmap::copy(const QPlatformPixmap *data, const QRect &rect) |
134 | 0 | { |
135 | 0 | fromImage(data->toImage(rect).copy(), Qt::NoOpaqueDetection); |
136 | 0 | } |
137 | | |
138 | | bool QRasterPlatformPixmap::scroll(int dx, int dy, const QRect &rect) |
139 | 0 | { |
140 | 0 | if (!image.isNull()) |
141 | 0 | qt_scrollRectInImage(image, rect, QPoint(dx, dy)); |
142 | 0 | return true; |
143 | 0 | } |
144 | | |
145 | | void QRasterPlatformPixmap::fill(const QColor &color) |
146 | 0 | { |
147 | 0 | uint pixel; |
148 | |
|
149 | 0 | if (image.depth() == 1) { |
150 | 0 | int gray = qGray(color.rgba()); |
151 | | // Pick the best approximate color in the image's colortable. |
152 | 0 | if (qAbs(qGray(image.color(0)) - gray) < qAbs(qGray(image.color(1)) - gray)) |
153 | 0 | pixel = 0; |
154 | 0 | else |
155 | 0 | pixel = 1; |
156 | 0 | } else if (image.depth() >= 15) { |
157 | 0 | int alpha = color.alpha(); |
158 | 0 | if (alpha != 255) { |
159 | 0 | if (!image.hasAlphaChannel()) { |
160 | 0 | QImage::Format toFormat = qt_alphaVersionForPainting(image.format()); |
161 | 0 | if (!image.reinterpretAsFormat(toFormat)) |
162 | 0 | image = QImage(image.width(), image.height(), toFormat); |
163 | 0 | } |
164 | 0 | } |
165 | 0 | image.fill(color); |
166 | 0 | return; |
167 | 0 | } else if (image.format() == QImage::Format_Alpha8) { |
168 | 0 | pixel = qAlpha(color.rgba()); |
169 | 0 | } else if (image.format() == QImage::Format_Grayscale8) { |
170 | 0 | pixel = qGray(color.rgba()); |
171 | 0 | } else if (image.format() == QImage::Format_Grayscale16) { |
172 | 0 | QRgba64 c = color.rgba64(); |
173 | 0 | pixel = qGray(c.red(), c.green(), c.blue()); |
174 | 0 | } else |
175 | 0 | { |
176 | 0 | pixel = 0; |
177 | | // ### what about 8 bit indexed? |
178 | 0 | } |
179 | | |
180 | 0 | image.fill(pixel); |
181 | 0 | } |
182 | | |
183 | | bool QRasterPlatformPixmap::hasAlphaChannel() const |
184 | 0 | { |
185 | 0 | return image.hasAlphaChannel(); |
186 | 0 | } |
187 | | |
188 | | QImage QRasterPlatformPixmap::toImage() const |
189 | 0 | { |
190 | 0 | if (!image.isNull()) { |
191 | 0 | QImageData *data = const_cast<QImage &>(image).data_ptr(); |
192 | 0 | if (data->paintEngine && data->paintEngine->isActive() |
193 | 0 | && data->paintEngine->paintDevice() == &image) |
194 | 0 | { |
195 | 0 | return image.copy(); |
196 | 0 | } |
197 | 0 | } |
198 | | |
199 | 0 | return image; |
200 | 0 | } |
201 | | |
202 | | QImage QRasterPlatformPixmap::toImage(const QRect &rect) const |
203 | 0 | { |
204 | 0 | if (rect.isNull()) |
205 | 0 | return image; |
206 | | |
207 | 0 | QRect clipped = rect.intersected(QRect(0, 0, w, h)); |
208 | 0 | const uint du = uint(d); |
209 | 0 | if ((du % 8 == 0) && (((uint(clipped.x()) * du)) % 32 == 0)) { |
210 | 0 | QImage newImage(image.scanLine(clipped.y()) + clipped.x() * (du / 8), |
211 | 0 | clipped.width(), clipped.height(), |
212 | 0 | image.bytesPerLine(), image.format()); |
213 | 0 | newImage.setDevicePixelRatio(image.devicePixelRatio()); |
214 | 0 | return newImage; |
215 | 0 | } else { |
216 | 0 | return image.copy(clipped); |
217 | 0 | } |
218 | 0 | } |
219 | | |
220 | | QPaintEngine* QRasterPlatformPixmap::paintEngine() const |
221 | 0 | { |
222 | 0 | return image.paintEngine(); |
223 | 0 | } |
224 | | |
225 | | int QRasterPlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const |
226 | 0 | { |
227 | 0 | QImageData *d = image.d; |
228 | 0 | if (!d) |
229 | 0 | return 0; |
230 | | |
231 | | // override the image dpi with the screen dpi when rendering to a pixmap |
232 | 0 | switch (metric) { |
233 | 0 | case QPaintDevice::PdmWidth: |
234 | 0 | return w; |
235 | 0 | case QPaintDevice::PdmHeight: |
236 | 0 | return h; |
237 | 0 | case QPaintDevice::PdmWidthMM: |
238 | 0 | return qRound(d->width * 25.4 / qt_defaultDpiX()); |
239 | 0 | case QPaintDevice::PdmHeightMM: |
240 | 0 | return qRound(d->height * 25.4 / qt_defaultDpiY()); |
241 | 0 | case QPaintDevice::PdmNumColors: |
242 | 0 | return d->colortable.size(); |
243 | 0 | case QPaintDevice::PdmDepth: |
244 | 0 | return this->d; |
245 | 0 | case QPaintDevice::PdmDpiX: |
246 | 0 | return qt_defaultDpiX(); |
247 | 0 | case QPaintDevice::PdmPhysicalDpiX: |
248 | 0 | return qt_defaultDpiX(); |
249 | 0 | case QPaintDevice::PdmDpiY: |
250 | 0 | return qt_defaultDpiY(); |
251 | 0 | case QPaintDevice::PdmPhysicalDpiY: |
252 | 0 | return qt_defaultDpiY(); |
253 | 0 | case QPaintDevice::PdmDevicePixelRatio: |
254 | 0 | return image.devicePixelRatio(); |
255 | 0 | case QPaintDevice::PdmDevicePixelRatioScaled: |
256 | 0 | return image.devicePixelRatio() * QPaintDevice::devicePixelRatioFScale(); |
257 | 0 | case QPaintDevice::PdmDevicePixelRatioF_EncodedA: |
258 | 0 | Q_FALLTHROUGH(); |
259 | 0 | case QPaintDevice::PdmDevicePixelRatioF_EncodedB: |
260 | 0 | return QPaintDevice::encodeMetricF(metric, image.devicePixelRatio()); |
261 | | |
262 | 0 | default: |
263 | 0 | qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric); |
264 | 0 | break; |
265 | 0 | } |
266 | | |
267 | 0 | return 0; |
268 | 0 | } |
269 | | |
270 | | void QRasterPlatformPixmap::createPixmapForImage(QImage sourceImage, Qt::ImageConversionFlags flags) |
271 | 0 | { |
272 | 0 | QImage::Format format; |
273 | 0 | if (flags & Qt::NoFormatConversion) |
274 | 0 | format = sourceImage.format(); |
275 | 0 | else |
276 | 0 | if (pixelType() == BitmapType) { |
277 | 0 | format = QImage::Format_MonoLSB; |
278 | 0 | } else { |
279 | 0 | if (sourceImage.depth() == 1) { |
280 | 0 | format = sourceImage.hasAlphaChannel() |
281 | 0 | ? QImage::Format_ARGB32_Premultiplied |
282 | 0 | : QImage::Format_RGB32; |
283 | 0 | } else { |
284 | 0 | QImage::Format nativeFormat = systemNativeFormat(); |
285 | 0 | QImage::Format opaqueFormat = qt_opaqueVersionForPainting(nativeFormat); |
286 | 0 | QImage::Format alphaFormat = qt_alphaVersionForPainting(nativeFormat); |
287 | |
|
288 | 0 | if (!sourceImage.hasAlphaChannel()) { |
289 | 0 | format = opaqueFormat; |
290 | 0 | } else if ((flags & Qt::NoOpaqueDetection) == 0 |
291 | 0 | && !sourceImage.data_ptr()->checkForAlphaPixels()) |
292 | 0 | { |
293 | 0 | format = opaqueFormat; |
294 | 0 | } else { |
295 | 0 | format = alphaFormat; |
296 | 0 | } |
297 | 0 | } |
298 | 0 | } |
299 | | |
300 | | // image has alpha format but is really opaque, so try to do a |
301 | | // more efficient conversion |
302 | 0 | if (format == QImage::Format_RGB32 && (sourceImage.format() == QImage::Format_ARGB32 |
303 | 0 | || sourceImage.format() == QImage::Format_ARGB32_Premultiplied)) |
304 | 0 | { |
305 | 0 | image = std::move(sourceImage); |
306 | 0 | image.reinterpretAsFormat(QImage::Format_RGB32); |
307 | 0 | } else { |
308 | 0 | image = std::move(sourceImage).convertToFormat(format, flags); |
309 | 0 | } |
310 | |
|
311 | 0 | if (image.d) { |
312 | 0 | w = image.d->width; |
313 | 0 | h = image.d->height; |
314 | 0 | d = image.d->depth; |
315 | 0 | } else { |
316 | 0 | w = h = d = 0; |
317 | 0 | } |
318 | 0 | is_null = (w <= 0 || h <= 0); |
319 | | |
320 | | //ensure the pixmap and the image resulting from toImage() have the same cacheKey(); |
321 | 0 | setSerialNumber(image.cacheKey() >> 32); |
322 | 0 | if (image.d) |
323 | 0 | setDetachNumber(image.d->detach_no); |
324 | 0 | } |
325 | | |
326 | | QImage* QRasterPlatformPixmap::buffer() |
327 | 0 | { |
328 | 0 | return ℑ |
329 | 0 | } |
330 | | |
331 | | qreal QRasterPlatformPixmap::devicePixelRatio() const |
332 | 0 | { |
333 | 0 | return image.devicePixelRatio(); |
334 | 0 | } |
335 | | |
336 | | void QRasterPlatformPixmap::setDevicePixelRatio(qreal scaleFactor) |
337 | 0 | { |
338 | 0 | image.setDevicePixelRatio(scaleFactor); |
339 | 0 | } |
340 | | |
341 | | QT_END_NAMESPACE |