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#include <QtCore/qttypetraits.h>
25
26
27QT_BEGIN_NAMESPACE
28
29class QImageWriter;
30
31struct Q_GUI_EXPORT QImageData { // internal image data
32 QImageData();
33 ~QImageData();
34 static QImageData *create(const QSize &size, QImage::Format format);
35 static QImageData *create(uchar *data, int w, int h, qsizetype bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr);
36
37 static QImageData *get(QImage &img) noexcept { return img.d; }
38 static const QImageData *get(const QImage &img) noexcept { return img.d; }
39
40 QAtomicInt ref;
41
42 int width;
43 int height;
44 int depth;
45 qsizetype nbytes; // number of bytes data
46 qreal devicePixelRatio;
47 QList<QRgb> colortable;
48 uchar *data;
49 QImage::Format format;
50 qsizetype bytes_per_line;
51 int ser_no; // serial number
52 int detach_no;
53
54 qreal dpmx; // dots per meter X (or 0)
55 qreal dpmy; // dots per meter Y (or 0)
56 QPoint offset; // offset in pixels
57
58 uint own_data : 1;
59 uint ro_data : 1;
60 uint has_alpha_clut : 1;
61 uint is_cached : 1;
62
63 QImageCleanupFunction cleanupFunction;
64 void* cleanupInfo;
65
66 bool checkForAlphaPixels() const;
67
68 // Convert the image in-place, minimizing memory reallocation
69 // Return false if the conversion cannot be done in-place.
70 bool convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags);
71
72 QMap<QString, QString> text;
73
74 bool doImageIO(const QImage *image, QImageWriter* io, int quality) const;
75
76 QPaintEngine *paintEngine;
77
78 QColorSpace colorSpace;
79
80 struct ImageSizeParameters {
81 qsizetype bytesPerLine;
82 qsizetype totalSize;
83 bool isValid() const { return bytesPerLine > 0 && totalSize > 0; }
84 };
85 static ImageSizeParameters calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth);
86};
87
88inline QImageData::ImageSizeParameters
89QImageData::calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth)
90{
91 ImageSizeParameters invalid = { .bytesPerLine: -1, .totalSize: -1 };
92 if (height <= 0)
93 return invalid;
94
95 // calculate the size, taking care of overflows
96 qsizetype bytes_per_line;
97 if (qMulOverflow(v1: width, v2: depth, r: &bytes_per_line))
98 return invalid;
99 if (qAddOverflow(v1: bytes_per_line, v2: qsizetype(31), r: &bytes_per_line))
100 return invalid;
101 // bytes per scanline (must be multiple of 4)
102 bytes_per_line = (bytes_per_line >> 5) << 2; // can't overflow
103
104 qsizetype total_size;
105 if (qMulOverflow(v1: height, v2: bytes_per_line, r: &total_size))
106 return invalid;
107 qsizetype dummy;
108 if (qMulOverflow(v1: height, v2: qsizetype(sizeof(uchar *)), r: &dummy))
109 return invalid; // why is this here?
110 // Disallow images where width * depth calculations might overflow
111 if (width > (INT_MAX - 31) / depth)
112 return invalid;
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 case QImage::Format_CMYK8888:
197 depth = 32;
198 break;
199 }
200 return depth;
201}
202
203#if defined(_M_ARM) && defined(_MSC_VER)
204#pragma optimize("", on)
205#endif
206
207inline QImage::Format qt_opaqueVersion(QImage::Format format)
208{
209 switch (format) {
210 case QImage::Format_ARGB8565_Premultiplied:
211 return QImage::Format_RGB16;
212 case QImage::Format_ARGB8555_Premultiplied:
213 return QImage::Format_RGB555;
214 case QImage::Format_ARGB6666_Premultiplied:
215 return QImage::Format_RGB666;
216 case QImage::Format_ARGB4444_Premultiplied:
217 return QImage::Format_RGB444;
218 case QImage::Format_RGBA8888:
219 case QImage::Format_RGBA8888_Premultiplied:
220 return QImage::Format_RGBX8888;
221 case QImage::Format_A2BGR30_Premultiplied:
222 return QImage::Format_BGR30;
223 case QImage::Format_A2RGB30_Premultiplied:
224 return QImage::Format_RGB30;
225 case QImage::Format_RGBA64:
226 case QImage::Format_RGBA64_Premultiplied:
227 return QImage::Format_RGBX64;
228 case QImage::Format_RGBA16FPx4:
229 case QImage::Format_RGBA16FPx4_Premultiplied:
230 return QImage::Format_RGBX16FPx4;
231 case QImage::Format_RGBA32FPx4:
232 case QImage::Format_RGBA32FPx4_Premultiplied:
233 return QImage::Format_RGBX32FPx4;
234 case QImage::Format_ARGB32_Premultiplied:
235 case QImage::Format_ARGB32:
236 return QImage::Format_RGB32;
237 case QImage::Format_RGB16:
238 case QImage::Format_RGB32:
239 case QImage::Format_RGB444:
240 case QImage::Format_RGB555:
241 case QImage::Format_RGB666:
242 case QImage::Format_RGB888:
243 case QImage::Format_BGR888:
244 case QImage::Format_RGBX8888:
245 case QImage::Format_BGR30:
246 case QImage::Format_RGB30:
247 case QImage::Format_RGBX64:
248 case QImage::Format_RGBX16FPx4:
249 case QImage::Format_RGBX32FPx4:
250 case QImage::Format_Grayscale8:
251 case QImage::Format_Grayscale16:
252 case QImage::Format_CMYK8888:
253 return format;
254 case QImage::Format_Mono:
255 case QImage::Format_MonoLSB:
256 case QImage::Format_Indexed8:
257 case QImage::Format_Alpha8:
258 case QImage::Format_Invalid:
259 case QImage::NImageFormats:
260 break;
261 }
262 return QImage::Format_RGB32;
263}
264
265inline QImage::Format qt_alphaVersion(QImage::Format format)
266{
267 switch (format) {
268 case QImage::Format_RGB32:
269 case QImage::Format_ARGB32:
270 return QImage::Format_ARGB32_Premultiplied;
271 case QImage::Format_RGB16:
272 return QImage::Format_ARGB8565_Premultiplied;
273 case QImage::Format_RGB555:
274 return QImage::Format_ARGB8555_Premultiplied;
275 case QImage::Format_RGB666:
276 return QImage::Format_ARGB6666_Premultiplied;
277 case QImage::Format_RGB444:
278 return QImage::Format_ARGB4444_Premultiplied;
279 case QImage::Format_RGBX8888:
280 case QImage::Format_RGBA8888:
281 return QImage::Format_RGBA8888_Premultiplied;
282 case QImage::Format_BGR30:
283 return QImage::Format_A2BGR30_Premultiplied;
284 case QImage::Format_RGB30:
285 return QImage::Format_A2RGB30_Premultiplied;
286 case QImage::Format_RGBX64:
287 case QImage::Format_RGBA64:
288 case QImage::Format_Grayscale16:
289 return QImage::Format_RGBA64_Premultiplied;
290 case QImage::Format_RGBX16FPx4:
291 case QImage::Format_RGBA16FPx4:
292 return QImage::Format_RGBA16FPx4_Premultiplied;
293 case QImage::Format_RGBX32FPx4:
294 case QImage::Format_RGBA32FPx4:
295 return QImage::Format_RGBA32FPx4_Premultiplied;
296 case QImage::Format_ARGB32_Premultiplied:
297 case QImage::Format_ARGB8565_Premultiplied:
298 case QImage::Format_ARGB8555_Premultiplied:
299 case QImage::Format_ARGB6666_Premultiplied:
300 case QImage::Format_ARGB4444_Premultiplied:
301 case QImage::Format_RGBA8888_Premultiplied:
302 case QImage::Format_A2BGR30_Premultiplied:
303 case QImage::Format_A2RGB30_Premultiplied:
304 case QImage::Format_RGBA64_Premultiplied:
305 case QImage::Format_RGBA16FPx4_Premultiplied:
306 case QImage::Format_RGBA32FPx4_Premultiplied:
307 return format;
308 case QImage::Format_Mono:
309 case QImage::Format_MonoLSB:
310 case QImage::Format_Indexed8:
311 case QImage::Format_RGB888:
312 case QImage::Format_BGR888:
313 case QImage::Format_Alpha8:
314 case QImage::Format_Grayscale8:
315 case QImage::Format_Invalid:
316 case QImage::Format_CMYK8888:
317 case QImage::NImageFormats:
318 break;
319 }
320 return QImage::Format_ARGB32_Premultiplied;
321}
322
323// Returns an opaque version that is compatible with format
324inline QImage::Format qt_maybeDataCompatibleOpaqueVersion(QImage::Format format)
325{
326 switch (format) {
327 case QImage::Format_ARGB6666_Premultiplied:
328 return QImage::Format_RGB666;
329 case QImage::Format_ARGB4444_Premultiplied:
330 return QImage::Format_RGB444;
331 case QImage::Format_RGBA8888:
332 case QImage::Format_RGBA8888_Premultiplied:
333 return QImage::Format_RGBX8888;
334 case QImage::Format_A2BGR30_Premultiplied:
335 return QImage::Format_BGR30;
336 case QImage::Format_A2RGB30_Premultiplied:
337 return QImage::Format_RGB30;
338 case QImage::Format_RGBA64:
339 case QImage::Format_RGBA64_Premultiplied:
340 return QImage::Format_RGBX64;
341 case QImage::Format_RGBA16FPx4:
342 case QImage::Format_RGBA16FPx4_Premultiplied:
343 return QImage::Format_RGBX16FPx4;
344 case QImage::Format_RGBA32FPx4:
345 case QImage::Format_RGBA32FPx4_Premultiplied:
346 return QImage::Format_RGBX32FPx4;
347 case QImage::Format_ARGB32_Premultiplied:
348 case QImage::Format_ARGB32:
349 return QImage::Format_RGB32;
350 case QImage::Format_RGB16:
351 case QImage::Format_RGB32:
352 case QImage::Format_RGB444:
353 case QImage::Format_RGB555:
354 case QImage::Format_RGB666:
355 case QImage::Format_RGB888:
356 case QImage::Format_BGR888:
357 case QImage::Format_RGBX8888:
358 case QImage::Format_BGR30:
359 case QImage::Format_RGB30:
360 case QImage::Format_RGBX64:
361 case QImage::Format_RGBX16FPx4:
362 case QImage::Format_RGBX32FPx4:
363 case QImage::Format_Grayscale8:
364 case QImage::Format_Grayscale16:
365 case QImage::Format_CMYK8888:
366 return format; // Already opaque
367 case QImage::Format_Mono:
368 case QImage::Format_MonoLSB:
369 case QImage::Format_Indexed8:
370 case QImage::Format_ARGB8565_Premultiplied:
371 case QImage::Format_ARGB8555_Premultiplied:
372 case QImage::Format_Alpha8:
373 case QImage::Format_Invalid:
374 case QImage::NImageFormats:
375 break;
376 }
377 return format; // No compatible opaque versions
378}
379
380constexpr QImage::Format qt_toUnpremultipliedFormat(QImage::Format format)
381{
382 // Assumes input is already a premultiplied format with an unpremultiplied counterpart
383 // This abuses the fact unpremultiplied formats are always before their premultiplied counterparts.
384 return static_cast<QImage::Format>(qToUnderlying(e: format) - 1);
385}
386
387constexpr QImage::Format qt_toPremultipliedFormat(QImage::Format format)
388{
389 // Assumes input is already an unpremultiplied format
390 // This abuses the fact unpremultiplied formats are always before their premultiplied counterparts.
391 return static_cast<QImage::Format>(qToUnderlying(e: format) + 1);
392}
393
394inline bool qt_highColorPrecision(QImage::Format format, bool opaque = false)
395{
396 // Formats with higher color precision than ARGB32_Premultiplied.
397 switch (format) {
398 case QImage::Format_ARGB32:
399 case QImage::Format_RGBA8888:
400 return !opaque;
401 case QImage::Format_BGR30:
402 case QImage::Format_RGB30:
403 case QImage::Format_A2BGR30_Premultiplied:
404 case QImage::Format_A2RGB30_Premultiplied:
405 case QImage::Format_RGBX64:
406 case QImage::Format_RGBA64:
407 case QImage::Format_RGBA64_Premultiplied:
408 case QImage::Format_Grayscale16:
409 case QImage::Format_RGBX16FPx4:
410 case QImage::Format_RGBA16FPx4:
411 case QImage::Format_RGBA16FPx4_Premultiplied:
412 case QImage::Format_RGBX32FPx4:
413 case QImage::Format_RGBA32FPx4:
414 case QImage::Format_RGBA32FPx4_Premultiplied:
415 return true;
416 default:
417 break;
418 }
419 return false;
420}
421
422inline bool qt_fpColorPrecision(QImage::Format format)
423{
424 switch (format) {
425 case QImage::Format_RGBX16FPx4:
426 case QImage::Format_RGBA16FPx4:
427 case QImage::Format_RGBA16FPx4_Premultiplied:
428 case QImage::Format_RGBX32FPx4:
429 case QImage::Format_RGBA32FPx4:
430 case QImage::Format_RGBA32FPx4_Premultiplied:
431 return true;
432 default:
433 break;
434 }
435 return false;
436}
437
438inline QColorSpace::ColorModel qt_csColorData(QPixelFormat::ColorModel format)
439{
440 switch (format) {
441 case QPixelFormat::ColorModel::RGB:
442 case QPixelFormat::ColorModel::BGR:
443 case QPixelFormat::ColorModel::Indexed:
444 return QColorSpace::ColorModel::Rgb;
445 case QPixelFormat::ColorModel::Alpha:
446 return QColorSpace::ColorModel::Undefined; // No valid colors
447 case QPixelFormat::ColorModel::Grayscale:
448 return QColorSpace::ColorModel::Gray;
449 case QPixelFormat::ColorModel::CMYK:
450 return QColorSpace::ColorModel::Cmyk;
451 default:
452 break;
453 }
454 return QColorSpace::ColorModel::Undefined;
455}
456
457inline bool qt_compatibleColorModelBase(QPixelFormat::ColorModel data, QColorSpace::ColorModel cs)
458{
459 QColorSpace::ColorModel dataCs = qt_csColorData(format: data);
460
461 if (data == QPixelFormat::ColorModel::Alpha)
462 return true; // Alpha data has no colors and can be handled by any color space
463
464 if (cs == QColorSpace::ColorModel::Undefined || dataCs == QColorSpace::ColorModel::Undefined)
465 return false;
466
467 return (dataCs == cs); // Matching color models
468}
469
470inline bool qt_compatibleColorModelSource(QPixelFormat::ColorModel data, QColorSpace::ColorModel cs)
471{
472 if (qt_compatibleColorModelBase(data, cs))
473 return true;
474
475 if (data == QPixelFormat::ColorModel::Grayscale && cs == QColorSpace::ColorModel::Rgb)
476 return true; // Can apply Rgb CS to Gray input data
477
478 return false;
479}
480
481inline bool qt_compatibleColorModelTarget(QPixelFormat::ColorModel data, QColorSpace::ColorModel cs, QColorSpace::TransformModel tm)
482{
483 if (qt_compatibleColorModelBase(data, cs))
484 return true;
485
486 if (data == QPixelFormat::ColorModel::Grayscale && tm == QColorSpace::TransformModel::ThreeComponentMatrix)
487 return true; // Can apply three-component matrix CS to gray output
488
489 return false;
490}
491
492inline QImage::Format qt_maybeDataCompatibleAlphaVersion(QImage::Format format)
493{
494 switch (format) {
495 case QImage::Format_RGB32:
496 return QImage::Format_ARGB32_Premultiplied;
497 case QImage::Format_RGB666:
498 return QImage::Format_ARGB6666_Premultiplied;
499 case QImage::Format_RGB444:
500 return QImage::Format_ARGB4444_Premultiplied;
501 case QImage::Format_RGBX8888:
502 return QImage::Format_RGBA8888_Premultiplied;
503 case QImage::Format_BGR30:
504 return QImage::Format_A2BGR30_Premultiplied;
505 case QImage::Format_RGB30:
506 return QImage::Format_A2RGB30_Premultiplied;
507 case QImage::Format_RGBX64:
508 return QImage::Format_RGBA64_Premultiplied;
509 case QImage::Format_RGBX16FPx4:
510 return QImage::Format_RGBA16FPx4_Premultiplied;
511 case QImage::Format_RGBX32FPx4:
512 return QImage::Format_RGBA32FPx4_Premultiplied;
513 case QImage::Format_ARGB32:
514 case QImage::Format_ARGB32_Premultiplied:
515 case QImage::Format_ARGB8565_Premultiplied:
516 case QImage::Format_ARGB8555_Premultiplied:
517 case QImage::Format_ARGB6666_Premultiplied:
518 case QImage::Format_ARGB4444_Premultiplied:
519 case QImage::Format_RGBA8888:
520 case QImage::Format_RGBA8888_Premultiplied:
521 case QImage::Format_A2BGR30_Premultiplied:
522 case QImage::Format_A2RGB30_Premultiplied:
523 case QImage::Format_Alpha8:
524 case QImage::Format_RGBA64:
525 case QImage::Format_RGBA64_Premultiplied:
526 case QImage::Format_RGBA16FPx4:
527 case QImage::Format_RGBA16FPx4_Premultiplied:
528 case QImage::Format_RGBA32FPx4:
529 case QImage::Format_RGBA32FPx4_Premultiplied:
530 return format; // Already alpha versions
531 case QImage::Format_Mono:
532 case QImage::Format_MonoLSB:
533 case QImage::Format_Indexed8:
534 case QImage::Format_RGB16:
535 case QImage::Format_RGB555:
536 case QImage::Format_RGB888:
537 case QImage::Format_BGR888:
538 case QImage::Format_Grayscale8:
539 case QImage::Format_Grayscale16:
540 case QImage::Format_CMYK8888:
541 case QImage::Format_Invalid:
542 case QImage::NImageFormats:
543 break;
544 }
545 return format; // No data-compatible alpha version
546}
547
548inline QImage::Format qt_opaqueVersionForPainting(QImage::Format format)
549{
550 QImage::Format toFormat = qt_opaqueVersion(format);
551 // If we are switching depth anyway upgrade to RGB32
552 if (qt_depthForFormat(format) != qt_depthForFormat(format: toFormat) && qt_depthForFormat(format: toFormat) <= 32)
553 toFormat = QImage::Format_RGB32;
554 return toFormat;
555}
556
557inline QImage::Format qt_alphaVersionForPainting(QImage::Format format)
558{
559 QImage::Format toFormat = qt_alphaVersion(format);
560#if defined(__ARM_NEON__) || defined(__SSE2__)
561 // If we are switching depth anyway and we have optimized ARGB32PM routines, upgrade to that.
562 if (qt_depthForFormat(format) != qt_depthForFormat(format: toFormat) && qt_depthForFormat(format: toFormat) <= 32)
563 toFormat = QImage::Format_ARGB32_Premultiplied;
564#endif
565 return toFormat;
566}
567
568Q_GUI_EXPORT QMap<QString, QString> qt_getImageText(const QImage &image, const QString &description);
569Q_GUI_EXPORT QMap<QString, QString> qt_getImageTextFromDescription(const QString &description);
570
571QT_END_NAMESPACE
572
573#endif // QIMAGE_P_H
574

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