1// Copyright (C) 2021 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
4#ifndef QIMAGE_P_H
5#define QIMAGE_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtGui/private/qtguiglobal_p.h>
19#include <QtGui/qcolorspace.h>
20#include <QtGui/qimage.h>
21#include <QtCore/private/qnumeric_p.h>
22#include <QtCore/qlist.h>
23#include <QtCore/qmap.h>
24
25QT_BEGIN_NAMESPACE
26
27class QImageWriter;
28
29struct Q_GUI_EXPORT QImageData { // internal image data
30 QImageData();
31 ~QImageData();
32 static QImageData *create(const QSize &size, QImage::Format format);
33 static QImageData *create(uchar *data, int w, int h, qsizetype bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr);
34
35 static QImageData *get(QImage &img) noexcept { return img.d; }
36 static const QImageData *get(const QImage &img) noexcept { return img.d; }
37
38 QAtomicInt ref;
39
40 int width;
41 int height;
42 int depth;
43 qsizetype nbytes; // number of bytes data
44 qreal devicePixelRatio;
45 QList<QRgb> colortable;
46 uchar *data;
47 QImage::Format format;
48 qsizetype bytes_per_line;
49 int ser_no; // serial number
50 int detach_no;
51
52 qreal dpmx; // dots per meter X (or 0)
53 qreal dpmy; // dots per meter Y (or 0)
54 QPoint offset; // offset in pixels
55
56 uint own_data : 1;
57 uint ro_data : 1;
58 uint has_alpha_clut : 1;
59 uint is_cached : 1;
60
61 QImageCleanupFunction cleanupFunction;
62 void* cleanupInfo;
63
64 bool checkForAlphaPixels() const;
65
66 // Convert the image in-place, minimizing memory reallocation
67 // Return false if the conversion cannot be done in-place.
68 bool convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags);
69
70 QMap<QString, QString> text;
71
72 bool doImageIO(const QImage *image, QImageWriter* io, int quality) const;
73
74 QPaintEngine *paintEngine;
75
76 QColorSpace colorSpace;
77
78 struct ImageSizeParameters {
79 qsizetype bytesPerLine;
80 qsizetype totalSize;
81 bool isValid() const { return bytesPerLine > 0 && totalSize > 0; }
82 };
83 static ImageSizeParameters calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth);
84};
85
86inline QImageData::ImageSizeParameters
87QImageData::calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth)
88{
89 ImageSizeParameters invalid = { .bytesPerLine: -1, .totalSize: -1 };
90 if (height <= 0)
91 return invalid;
92
93 // calculate the size, taking care of overflows
94 qsizetype bytes_per_line;
95 if (qMulOverflow(v1: width, v2: depth, r: &bytes_per_line))
96 return invalid;
97 if (qAddOverflow(v1: bytes_per_line, v2: qsizetype(31), r: &bytes_per_line))
98 return invalid;
99 // bytes per scanline (must be multiple of 4)
100 bytes_per_line = (bytes_per_line >> 5) << 2; // can't overflow
101
102 qsizetype total_size;
103 if (qMulOverflow(v1: height, v2: bytes_per_line, r: &total_size))
104 return invalid;
105 qsizetype dummy;
106 if (qMulOverflow(v1: height, v2: qsizetype(sizeof(uchar *)), r: &dummy))
107 return invalid; // why is this here?
108#if 1 || QT_VERSION < QT_VERSION_CHECK(6,0,0) // ### can only fix this if QImage dimensions are not int anymore
109 // Disallow images where width * depth calculations might overflow
110 if (width > (INT_MAX - 31) / depth)
111 return invalid;
112#endif
113
114 return { .bytesPerLine: bytes_per_line, .totalSize: total_size };
115}
116
117typedef void (*Image_Converter)(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
118typedef bool (*InPlace_Image_Converter)(QImageData *data, Qt::ImageConversionFlags);
119
120extern Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats];
121extern InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats];
122
123void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
124void convert_generic_over_rgb64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
125bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags);
126bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags);
127#if QT_CONFIG(raster_fp)
128void convert_generic_over_rgba32f(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
129bool convert_generic_inplace_over_rgba32f(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags);
130#endif
131
132void dither_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags, bool fromalpha);
133
134const uchar *qt_get_bitflip_array();
135Q_GUI_EXPORT void qGamma_correct_back_to_linear_cs(QImage *image);
136
137#if defined(_M_ARM) && defined(_MSC_VER) // QTBUG-42038
138#pragma optimize("", off)
139#endif
140inline int qt_depthForFormat(QImage::Format format)
141{
142 int depth = 0;
143 switch(format) {
144 case QImage::Format_Invalid:
145 case QImage::NImageFormats:
146 Q_UNREACHABLE();
147 case QImage::Format_Mono:
148 case QImage::Format_MonoLSB:
149 depth = 1;
150 break;
151 case QImage::Format_Indexed8:
152 case QImage::Format_Alpha8:
153 case QImage::Format_Grayscale8:
154 depth = 8;
155 break;
156 case QImage::Format_RGB32:
157 case QImage::Format_ARGB32:
158 case QImage::Format_ARGB32_Premultiplied:
159 case QImage::Format_RGBX8888:
160 case QImage::Format_RGBA8888:
161 case QImage::Format_RGBA8888_Premultiplied:
162 case QImage::Format_BGR30:
163 case QImage::Format_A2BGR30_Premultiplied:
164 case QImage::Format_RGB30:
165 case QImage::Format_A2RGB30_Premultiplied:
166 depth = 32;
167 break;
168 case QImage::Format_RGB555:
169 case QImage::Format_RGB16:
170 case QImage::Format_RGB444:
171 case QImage::Format_ARGB4444_Premultiplied:
172 case QImage::Format_Grayscale16:
173 depth = 16;
174 break;
175 case QImage::Format_RGB666:
176 case QImage::Format_ARGB6666_Premultiplied:
177 case QImage::Format_ARGB8565_Premultiplied:
178 case QImage::Format_ARGB8555_Premultiplied:
179 case QImage::Format_RGB888:
180 case QImage::Format_BGR888:
181 depth = 24;
182 break;
183 case QImage::Format_RGBX64:
184 case QImage::Format_RGBA64:
185 case QImage::Format_RGBA64_Premultiplied:
186 case QImage::Format_RGBX16FPx4:
187 case QImage::Format_RGBA16FPx4:
188 case QImage::Format_RGBA16FPx4_Premultiplied:
189 depth = 64;
190 break;
191 case QImage::Format_RGBX32FPx4:
192 case QImage::Format_RGBA32FPx4:
193 case QImage::Format_RGBA32FPx4_Premultiplied:
194 depth = 128;
195 break;
196 }
197 return depth;
198}
199
200#if defined(_M_ARM) && defined(_MSC_VER)
201#pragma optimize("", on)
202#endif
203
204inline QImage::Format qt_opaqueVersion(QImage::Format format)
205{
206 switch (format) {
207 case QImage::Format_ARGB8565_Premultiplied:
208 return QImage::Format_RGB16;
209 case QImage::Format_ARGB8555_Premultiplied:
210 return QImage::Format_RGB555;
211 case QImage::Format_ARGB6666_Premultiplied:
212 return QImage::Format_RGB666;
213 case QImage::Format_ARGB4444_Premultiplied:
214 return QImage::Format_RGB444;
215 case QImage::Format_RGBA8888:
216 case QImage::Format_RGBA8888_Premultiplied:
217 return QImage::Format_RGBX8888;
218 case QImage::Format_A2BGR30_Premultiplied:
219 return QImage::Format_BGR30;
220 case QImage::Format_A2RGB30_Premultiplied:
221 return QImage::Format_RGB30;
222 case QImage::Format_RGBA64:
223 case QImage::Format_RGBA64_Premultiplied:
224 return QImage::Format_RGBX64;
225 case QImage::Format_RGBA16FPx4:
226 case QImage::Format_RGBA16FPx4_Premultiplied:
227 return QImage::Format_RGBX16FPx4;
228 case QImage::Format_RGBA32FPx4:
229 case QImage::Format_RGBA32FPx4_Premultiplied:
230 return QImage::Format_RGBX32FPx4;
231 case QImage::Format_ARGB32_Premultiplied:
232 case QImage::Format_ARGB32:
233 return QImage::Format_RGB32;
234 case QImage::Format_RGB16:
235 case QImage::Format_RGB32:
236 case QImage::Format_RGB444:
237 case QImage::Format_RGB555:
238 case QImage::Format_RGB666:
239 case QImage::Format_RGB888:
240 case QImage::Format_BGR888:
241 case QImage::Format_RGBX8888:
242 case QImage::Format_BGR30:
243 case QImage::Format_RGB30:
244 case QImage::Format_RGBX64:
245 case QImage::Format_RGBX16FPx4:
246 case QImage::Format_RGBX32FPx4:
247 case QImage::Format_Grayscale8:
248 case QImage::Format_Grayscale16:
249 return format;
250 case QImage::Format_Mono:
251 case QImage::Format_MonoLSB:
252 case QImage::Format_Indexed8:
253 case QImage::Format_Alpha8:
254 case QImage::Format_Invalid:
255 case QImage::NImageFormats:
256 break;
257 }
258 return QImage::Format_RGB32;
259}
260
261inline QImage::Format qt_alphaVersion(QImage::Format format)
262{
263 switch (format) {
264 case QImage::Format_RGB32:
265 case QImage::Format_ARGB32:
266 return QImage::Format_ARGB32_Premultiplied;
267 case QImage::Format_RGB16:
268 return QImage::Format_ARGB8565_Premultiplied;
269 case QImage::Format_RGB555:
270 return QImage::Format_ARGB8555_Premultiplied;
271 case QImage::Format_RGB666:
272 return QImage::Format_ARGB6666_Premultiplied;
273 case QImage::Format_RGB444:
274 return QImage::Format_ARGB4444_Premultiplied;
275 case QImage::Format_RGBX8888:
276 case QImage::Format_RGBA8888:
277 return QImage::Format_RGBA8888_Premultiplied;
278 case QImage::Format_BGR30:
279 return QImage::Format_A2BGR30_Premultiplied;
280 case QImage::Format_RGB30:
281 return QImage::Format_A2RGB30_Premultiplied;
282 case QImage::Format_RGBX64:
283 case QImage::Format_RGBA64:
284 case QImage::Format_Grayscale16:
285 return QImage::Format_RGBA64_Premultiplied;
286 case QImage::Format_RGBX16FPx4:
287 case QImage::Format_RGBA16FPx4:
288 return QImage::Format_RGBA16FPx4_Premultiplied;
289 case QImage::Format_RGBX32FPx4:
290 case QImage::Format_RGBA32FPx4:
291 return QImage::Format_RGBA32FPx4_Premultiplied;
292 case QImage::Format_ARGB32_Premultiplied:
293 case QImage::Format_ARGB8565_Premultiplied:
294 case QImage::Format_ARGB8555_Premultiplied:
295 case QImage::Format_ARGB6666_Premultiplied:
296 case QImage::Format_ARGB4444_Premultiplied:
297 case QImage::Format_RGBA8888_Premultiplied:
298 case QImage::Format_A2BGR30_Premultiplied:
299 case QImage::Format_A2RGB30_Premultiplied:
300 case QImage::Format_RGBA64_Premultiplied:
301 case QImage::Format_RGBA16FPx4_Premultiplied:
302 case QImage::Format_RGBA32FPx4_Premultiplied:
303 return format;
304 case QImage::Format_Mono:
305 case QImage::Format_MonoLSB:
306 case QImage::Format_Indexed8:
307 case QImage::Format_RGB888:
308 case QImage::Format_BGR888:
309 case QImage::Format_Alpha8:
310 case QImage::Format_Grayscale8:
311 case QImage::Format_Invalid:
312 case QImage::NImageFormats:
313 break;
314 }
315 return QImage::Format_ARGB32_Premultiplied;
316}
317
318inline bool qt_highColorPrecision(QImage::Format format, bool opaque = false)
319{
320 // Formats with higher color precision than ARGB32_Premultiplied.
321 switch (format) {
322 case QImage::Format_ARGB32:
323 case QImage::Format_RGBA8888:
324 return !opaque;
325 case QImage::Format_BGR30:
326 case QImage::Format_RGB30:
327 case QImage::Format_A2BGR30_Premultiplied:
328 case QImage::Format_A2RGB30_Premultiplied:
329 case QImage::Format_RGBX64:
330 case QImage::Format_RGBA64:
331 case QImage::Format_RGBA64_Premultiplied:
332 case QImage::Format_Grayscale16:
333 case QImage::Format_RGBX16FPx4:
334 case QImage::Format_RGBA16FPx4:
335 case QImage::Format_RGBA16FPx4_Premultiplied:
336 case QImage::Format_RGBX32FPx4:
337 case QImage::Format_RGBA32FPx4:
338 case QImage::Format_RGBA32FPx4_Premultiplied:
339 return true;
340 default:
341 break;
342 }
343 return false;
344}
345
346inline bool qt_fpColorPrecision(QImage::Format format)
347{
348 switch (format) {
349 case QImage::Format_RGBX16FPx4:
350 case QImage::Format_RGBA16FPx4:
351 case QImage::Format_RGBA16FPx4_Premultiplied:
352 case QImage::Format_RGBX32FPx4:
353 case QImage::Format_RGBA32FPx4:
354 case QImage::Format_RGBA32FPx4_Premultiplied:
355 return true;
356 default:
357 break;
358 }
359 return false;
360}
361
362inline QImage::Format qt_maybeAlphaVersionWithSameDepth(QImage::Format format)
363{
364 const QImage::Format toFormat = qt_alphaVersion(format);
365 return qt_depthForFormat(format) == qt_depthForFormat(format: toFormat) ? toFormat : format;
366}
367
368inline QImage::Format qt_opaqueVersionForPainting(QImage::Format format)
369{
370 QImage::Format toFormat = qt_opaqueVersion(format);
371 // If we are switching depth anyway upgrade to RGB32
372 if (qt_depthForFormat(format) != qt_depthForFormat(format: toFormat) && qt_depthForFormat(format: toFormat) <= 32)
373 toFormat = QImage::Format_RGB32;
374 return toFormat;
375}
376
377inline QImage::Format qt_alphaVersionForPainting(QImage::Format format)
378{
379 QImage::Format toFormat = qt_alphaVersion(format);
380#if defined(__ARM_NEON__) || defined(__SSE2__)
381 // If we are switching depth anyway and we have optimized ARGB32PM routines, upgrade to that.
382 if (qt_depthForFormat(format) != qt_depthForFormat(format: toFormat) && qt_depthForFormat(format: toFormat) <= 32)
383 toFormat = QImage::Format_ARGB32_Premultiplied;
384#endif
385 return toFormat;
386}
387
388Q_GUI_EXPORT QMap<QString, QString> qt_getImageText(const QImage &image, const QString &description);
389Q_GUI_EXPORT QMap<QString, QString> qt_getImageTextFromDescription(const QString &description);
390
391QT_END_NAMESPACE
392
393#endif // QIMAGE_P_H
394

source code of qtbase/src/gui/image/qimage_p.h