Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qimage.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 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#include "qimage.h"
5
6#include "qbuffer.h"
7#include "qdatastream.h"
8#include "qcolortransform.h"
9#include "qfloat16.h"
10#include "qmap.h"
11#include "qtransform.h"
12#include "qimagereader.h"
13#include "qimagewriter.h"
14#include "qrgbafloat.h"
15#include "qstringlist.h"
16#include "qvariant.h"
18#include <qpa/qplatformintegration.h>
19#include <private/qguiapplication_p.h>
20#include <ctype.h>
21#include <stdlib.h>
22#include <limits.h>
23#include <qpa/qplatformpixmap.h>
24#include <private/qcolorspace_p.h>
25#include <private/qcolortransform_p.h>
26#include <private/qmemrotate_p.h>
27#include <private/qimagescale_p.h>
28#include <private/qpixellayout_p.h>
29#include <private/qsimd_p.h>
30
31#include <qhash.h>
32
33#include <private/qpaintengine_raster_p.h>
34
35#include <private/qimage_p.h>
36#include <private/qfont_p.h>
37
38#if QT_CONFIG(thread)
39#include <qsemaphore.h>
40#include <qthreadpool.h>
41#include <private/qthreadpool_p.h>
42#endif
43
44#include <qtgui_tracepoints_p.h>
45
46#include <memory>
47
49class QCmyk32;
50
51using namespace Qt::StringLiterals;
52
53// MSVC 19.28 does show spurious warning "C4723: potential divide by 0" for code that divides
54// by height() in release builds. Anyhow, all the code paths in this file are only executed
55// for valid QImage's, where height() cannot be 0. Therefore disable the warning.
57
58#if defined(Q_CC_DEC) && defined(__alpha) && (__DECCXX_VER-0 >= 50190001)
59#pragma message disable narrowptr
60#endif
61
62
63#define QIMAGE_SANITYCHECK_MEMORY(image) \
64 if ((image).isNull()) { \
65 qWarning("QImage: out of memory, returning null image"); \
66 return QImage(); \
67 }
68
70 "#include <qimagereader.h>"
71);
72
74"ENUM { } QImage::Format;" \
75"FLAGS { } Qt::ImageConversionFlags;"
76);
77
80
81static QImage rotated90(const QImage &src);
82static QImage rotated180(const QImage &src);
83static QImage rotated270(const QImage &src);
84
86{
87 Q_CONSTINIT static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
88 return 1 + serial.fetchAndAddRelaxed(1);
89}
90
92 : ref(0), width(0), height(0), depth(0), nbytes(0), devicePixelRatio(1.0), data(nullptr),
93 format(QImage::Format_ARGB32), bytes_per_line(0),
95 detach_no(0),
96 dpmx(qt_defaultDpiX() * 100 / qreal(2.54)),
97 dpmy(qt_defaultDpiY() * 100 / qreal(2.54)),
98 offset(0, 0), own_data(true), ro_data(false), has_alpha_clut(false),
99 is_cached(false), cleanupFunction(nullptr), cleanupInfo(nullptr),
100 paintEngine(nullptr)
101{
102}
103
112{
113 if (size.isEmpty() || format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
114 return nullptr; // invalid parameter(s)
115
116 Q_TRACE_SCOPE(QImageData_create, size, format);
117
118 int width = size.width();
119 int height = size.height();
122 if (!params.isValid())
123 return nullptr;
124
125 auto d = std::make_unique<QImageData>();
126
127 switch (format) {
130 d->colortable.resize(2);
131 d->colortable[0] = QColor(Qt::black).rgba();
132 d->colortable[1] = QColor(Qt::white).rgba();
133 break;
134 default:
135 break;
136 }
137
138 d->width = width;
139 d->height = height;
140 d->depth = depth;
141 d->format = format;
142 d->has_alpha_clut = false;
143 d->is_cached = false;
144
145 d->bytes_per_line = params.bytesPerLine;
146 d->nbytes = params.totalSize;
147 d->data = (uchar *)malloc(d->nbytes);
148
149 if (!d->data)
150 return nullptr;
151
152 d->ref.ref();
153 return d.release();
154}
155
157{
158 if (cleanupFunction)
160 if (is_cached)
162 delete paintEngine;
163 if (data && own_data)
164 free(data);
165 data = nullptr;
166}
167
168#if defined(_M_ARM) && defined(_MSC_VER)
169#pragma optimize("", off)
170#endif
171
173{
174 bool has_alpha_pixels = false;
175
176 switch (format) {
177
181 has_alpha_pixels = has_alpha_clut;
182 break;
184 has_alpha_pixels = true;
185 break;
188 const uchar *bits = data;
189 for (int y=0; y<height && !has_alpha_pixels; ++y) {
190 uint alphaAnd = 0xff000000;
191 for (int x=0; x<width; ++x)
192 alphaAnd &= reinterpret_cast<const uint*>(bits)[x];
193 has_alpha_pixels = (alphaAnd != 0xff000000);
195 }
196 } break;
197
200 const uchar *bits = data;
201 for (int y=0; y<height && !has_alpha_pixels; ++y) {
202 uchar alphaAnd = 0xff;
203 for (int x=0; x<width; ++x)
204 alphaAnd &= bits[x * 4+ 3];
205 has_alpha_pixels = (alphaAnd != 0xff);
207 }
208 } break;
209
212 const uchar *bits = data;
213 for (int y=0; y<height && !has_alpha_pixels; ++y) {
214 uint alphaAnd = 0xc0000000;
215 for (int x=0; x<width; ++x)
216 alphaAnd &= reinterpret_cast<const uint*>(bits)[x];
217 has_alpha_pixels = (alphaAnd != 0xc0000000);
219 }
220 } break;
221
224 const uchar *bits = data;
225 const uchar *end_bits = data + bytes_per_line;
226
227 for (int y=0; y<height && !has_alpha_pixels; ++y) {
228 uchar alphaAnd = 0xff;
229 while (bits < end_bits) {
230 alphaAnd &= bits[0];
231 bits += 3;
232 }
233 has_alpha_pixels = (alphaAnd != 0xff);
234 bits = end_bits;
235 end_bits += bytes_per_line;
236 }
237 } break;
238
240 const uchar *bits = data;
241 const uchar *end_bits = data + bytes_per_line;
242
243 for (int y=0; y<height && !has_alpha_pixels; ++y) {
244 uchar alphaAnd = 0xfc;
245 while (bits < end_bits) {
246 alphaAnd &= bits[0];
247 bits += 3;
248 }
249 has_alpha_pixels = (alphaAnd != 0xfc);
250 bits = end_bits;
251 end_bits += bytes_per_line;
252 }
253 } break;
254
256 const uchar *bits = data;
257 for (int y=0; y<height && !has_alpha_pixels; ++y) {
258 ushort alphaAnd = 0xf000;
259 for (int x=0; x<width; ++x)
260 alphaAnd &= reinterpret_cast<const ushort*>(bits)[x];
261 has_alpha_pixels = (alphaAnd != 0xf000);
263 }
264 } break;
267 uchar *bits = data;
268 for (int y=0; y<height && !has_alpha_pixels; ++y) {
269 for (int x=0; x<width; ++x) {
270 has_alpha_pixels |= !(((QRgba64 *)bits)[x].isOpaque());
271 }
273 }
274 } break;
277 uchar *bits = data;
278 for (int y = 0; y < height && !has_alpha_pixels; ++y) {
279 for (int x = 0; x < width; ++x)
280 has_alpha_pixels |= ((qfloat16 *)bits)[x * 4 + 3] < 1.0f;
282 }
283 } break;
286 uchar *bits = data;
287 for (int y = 0; y < height && !has_alpha_pixels; ++y) {
288 for (int x = 0; x < width; ++x)
289 has_alpha_pixels |= ((float *)bits)[x * 4 + 3] < 1.0f;
291 }
292 } break;
293
310 break;
313 Q_UNREACHABLE();
314 break;
315 }
316
317 return has_alpha_pixels;
318}
319#if defined(_M_ARM) && defined(_MSC_VER)
320#pragma optimize("", on)
321#endif
322
781/*****************************************************************************
782 QImage member functions
783 *****************************************************************************/
784
792 : QPaintDevice()
793{
794 d = nullptr;
795}
796
811
826
827
828
829QImageData *QImageData::create(uchar *data, int width, int height, qsizetype bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
830{
831 if (width <= 0 || height <= 0 || !data || format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
832 return nullptr;
833
834 const int depth = qt_depthForFormat(format);
836 if (!params.isValid())
837 return nullptr;
838
839 if (bpl > 0) {
840 // can't overflow, because has calculateImageParameters already done this multiplication
841 const qsizetype min_bytes_per_line = (qsizetype(width) * depth + 7)/8;
842 if (bpl < min_bytes_per_line)
843 return nullptr;
844
845 // recalculate the total with this value
846 params.bytesPerLine = bpl;
847 if (qMulOverflow<qsizetype>(bpl, height, &params.totalSize))
848 return nullptr;
849 }
850
851 QImageData *d = new QImageData;
852 d->ref.ref();
853
854 d->own_data = false;
855 d->ro_data = readOnly;
856 d->data = data;
857 d->width = width;
858 d->height = height;
859 d->depth = depth;
860 d->format = format;
861
862 d->bytes_per_line = params.bytesPerLine;
863 d->nbytes = params.totalSize;
864
865 d->cleanupFunction = cleanupFunction;
866 d->cleanupInfo = cleanupInfo;
867
868 return d;
869}
870
888QImage::QImage(uchar* data, int width, int height, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
889 : QPaintDevice()
890{
891 d = QImageData::create(data, width, height, 0, format, false, cleanupFunction, cleanupInfo);
892}
893
919QImage::QImage(const uchar* data, int width, int height, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
920 : QPaintDevice()
921{
922 d = QImageData::create(const_cast<uchar*>(data), width, height, 0, format, true, cleanupFunction, cleanupInfo);
923}
924
943QImage::QImage(uchar *data, int width, int height, qsizetype bytesPerLine, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
944 :QPaintDevice()
945{
946 d = QImageData::create(data, width, height, bytesPerLine, format, false, cleanupFunction, cleanupInfo);
947}
948
974QImage::QImage(const uchar *data, int width, int height, qsizetype bytesPerLine, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
975 :QPaintDevice()
976{
977 d = QImageData::create(const_cast<uchar*>(data), width, height, bytesPerLine, format, true, cleanupFunction, cleanupInfo);
978}
979
1001 : QPaintDevice()
1002{
1003 d = nullptr;
1005}
1006
1007#ifndef QT_NO_IMAGEFORMAT_XPM
1008extern bool qt_read_xpm_image_or_array(QIODevice *device, const char * const *source, QImage &image);
1009
1026QImage::QImage(const char * const xpm[])
1027 : QPaintDevice()
1028{
1029 d = nullptr;
1030 if (!xpm)
1031 return;
1032 if (!qt_read_xpm_image_or_array(nullptr, xpm, *this))
1033 // Issue: Warning because the constructor may be ambiguous
1034 qWarning("QImage::QImage(), XPM is not supported");
1035}
1036#endif // QT_NO_IMAGEFORMAT_XPM
1037
1048 : QPaintDevice()
1049{
1050 if (image.paintingActive()) {
1051 d = nullptr;
1052 image.copy().swap(*this);
1053 } else {
1054 d = image.d;
1055 if (d)
1056 d->ref.ref();
1057 }
1058}
1059
1065{
1066 if (d && !d->ref.deref())
1067 delete d;
1068}
1069
1081{
1082 if (image.paintingActive()) {
1083 operator=(image.copy());
1084 } else {
1085 if (image.d)
1086 image.d->ref.ref();
1087 if (d && !d->ref.deref())
1088 delete d;
1089 d = image.d;
1090 }
1091 return *this;
1092}
1093
1105{
1106 return QInternal::Image;
1107}
1108
1112QImage::operator QVariant() const
1113{
1114 return QVariant::fromValue(*this);
1115}
1116
1129{
1130 if (d) {
1131 if (d->is_cached && d->ref.loadRelaxed() == 1)
1133
1134 if (d->ref.loadRelaxed() != 1 || d->ro_data)
1135 *this = copy();
1136
1137 if (d)
1138 ++d->detach_no;
1139 }
1140}
1141
1142
1151void QImage::detachMetadata(bool invalidateCache)
1152{
1153 if (d) {
1154 if (d->is_cached && d->ref.loadRelaxed() == 1)
1156
1157 if (d->ref.loadRelaxed() != 1)
1158 *this = copy();
1159
1160 if (d && invalidateCache)
1161 ++d->detach_no;
1162 }
1163}
1164
1166{
1167 dst->dpmx = src->dpmx;
1168 dst->dpmy = src->dpmy;
1169 dst->devicePixelRatio = src->devicePixelRatio;
1170}
1171
1173{
1174 // Doesn't copy colortable and alpha_clut.
1176 dst->text = src->text;
1177 dst->offset = src->offset;
1178 dst->colorSpace = src->colorSpace;
1179}
1180
1181static void copyMetadata(QImage *dst, const QImage &src)
1182{
1183 dst->setDotsPerMeterX(src.dotsPerMeterX());
1184 dst->setDotsPerMeterY(src.dotsPerMeterY());
1185 dst->setDevicePixelRatio(src.devicePixelRatio());
1186 const auto textKeys = src.textKeys();
1187 for (const auto &key: textKeys)
1188 dst->setText(key, src.text(key));
1189
1190}
1191
1222QImage Q_TRACE_INSTRUMENT(qtgui) QImage::copy(const QRect& r) const
1223{
1224 Q_TRACE_SCOPE(QImage_copy, r);
1225 if (!d)
1226 return QImage();
1227
1228 if (r.isNull()) {
1229 QImage image(d->width, d->height, d->format);
1230 if (image.isNull())
1231 return image;
1232
1233 // Qt for Embedded Linux can create images with non-default bpl
1234 // make sure we don't crash.
1235 if (image.d->nbytes != d->nbytes) {
1236 qsizetype bpl = qMin(bytesPerLine(), image.bytesPerLine());
1237 for (int i = 0; i < height(); i++)
1238 memcpy(image.scanLine(i), scanLine(i), bpl);
1239 } else
1240 memcpy(image.bits(), bits(), d->nbytes);
1241 image.d->colortable = d->colortable;
1242 image.d->has_alpha_clut = d->has_alpha_clut;
1243 copyMetadata(image.d, d);
1244 return image;
1245 }
1246
1247 int x = r.x();
1248 int y = r.y();
1249 int w = r.width();
1250 int h = r.height();
1251
1252 int dx = 0;
1253 int dy = 0;
1254 if (w <= 0 || h <= 0)
1255 return QImage();
1256
1257 QImage image(w, h, d->format);
1258 if (image.isNull())
1259 return image;
1260
1261 if (x < 0 || y < 0 || x + w > d->width || y + h > d->height) {
1262 // bitBlt will not cover entire image - clear it.
1263 image.fill(0);
1264 if (x < 0) {
1265 dx = -x;
1266 x = 0;
1267 }
1268 if (y < 0) {
1269 dy = -y;
1270 y = 0;
1271 }
1272 }
1273
1274 image.d->colortable = d->colortable;
1275
1276 int pixels_to_copy = qMax(w - dx, 0);
1277 if (x > d->width)
1278 pixels_to_copy = 0;
1279 else if (pixels_to_copy > d->width - x)
1280 pixels_to_copy = d->width - x;
1281 int lines_to_copy = qMax(h - dy, 0);
1282 if (y > d->height)
1283 lines_to_copy = 0;
1284 else if (lines_to_copy > d->height - y)
1285 lines_to_copy = d->height - y;
1286
1287 bool byteAligned = true;
1288 if (d->format == Format_Mono || d->format == Format_MonoLSB)
1289 byteAligned = !(dx & 7) && !(x & 7) && !(pixels_to_copy & 7);
1290
1291 if (byteAligned) {
1292 const uchar *src = d->data + ((x * d->depth) >> 3) + y * d->bytes_per_line;
1293 uchar *dest = image.d->data + ((dx * d->depth) >> 3) + dy * image.d->bytes_per_line;
1294 const qsizetype bytes_to_copy = (qsizetype(pixels_to_copy) * d->depth) >> 3;
1295 for (int i = 0; i < lines_to_copy; ++i) {
1296 memcpy(dest, src, bytes_to_copy);
1297 src += d->bytes_per_line;
1298 dest += image.d->bytes_per_line;
1299 }
1300 } else if (d->format == Format_Mono) {
1301 const uchar *src = d->data + y * d->bytes_per_line;
1302 uchar *dest = image.d->data + dy * image.d->bytes_per_line;
1303 for (int i = 0; i < lines_to_copy; ++i) {
1304 for (int j = 0; j < pixels_to_copy; ++j) {
1305 if (src[(x + j) >> 3] & (0x80 >> ((x + j) & 7)))
1306 dest[(dx + j) >> 3] |= (0x80 >> ((dx + j) & 7));
1307 else
1308 dest[(dx + j) >> 3] &= ~(0x80 >> ((dx + j) & 7));
1309 }
1310 src += d->bytes_per_line;
1311 dest += image.d->bytes_per_line;
1312 }
1313 } else { // Format_MonoLSB
1314 Q_ASSERT(d->format == Format_MonoLSB);
1315 const uchar *src = d->data + y * d->bytes_per_line;
1316 uchar *dest = image.d->data + dy * image.d->bytes_per_line;
1317 for (int i = 0; i < lines_to_copy; ++i) {
1318 for (int j = 0; j < pixels_to_copy; ++j) {
1319 if (src[(x + j) >> 3] & (0x1 << ((x + j) & 7)))
1320 dest[(dx + j) >> 3] |= (0x1 << ((dx + j) & 7));
1321 else
1322 dest[(dx + j) >> 3] &= ~(0x1 << ((dx + j) & 7));
1323 }
1324 src += d->bytes_per_line;
1325 dest += image.d->bytes_per_line;
1326 }
1327 }
1328
1329 copyMetadata(image.d, d);
1330 image.d->has_alpha_clut = d->has_alpha_clut;
1331 return image;
1332}
1333
1334
1342bool QImage::isNull() const
1343{
1344 return !d;
1345}
1346
1354int QImage::width() const
1355{
1356 return d ? d->width : 0;
1357}
1358
1366int QImage::height() const
1367{
1368 return d ? d->height : 0;
1369}
1370
1378QSize QImage::size() const
1379{
1380 return d ? QSize(d->width, d->height) : QSize(0, 0);
1381}
1382
1391QRect QImage::rect() const
1392{
1393 return d ? QRect(0, 0, d->width, d->height) : QRect();
1394}
1395
1408int QImage::depth() const
1409{
1410 return d ? d->depth : 0;
1411}
1412
1424int QImage::colorCount() const
1425{
1426 return d ? d->colortable.size() : 0;
1427}
1428
1440void QImage::setColorTable(const QList<QRgb> &colors)
1441{
1442 if (!d)
1443 return;
1444 detachMetadata(true);
1445
1446 // In case detach() ran out of memory
1447 if (!d)
1448 return;
1449
1450 d->colortable = colors;
1451 d->has_alpha_clut = false;
1452 for (int i = 0; i < d->colortable.size(); ++i) {
1453 if (qAlpha(d->colortable.at(i)) != 255) {
1454 d->has_alpha_clut = true;
1455 break;
1456 }
1457 }
1458}
1459
1466QList<QRgb> QImage::colorTable() const
1467{
1468 return d ? d->colortable : QList<QRgb>();
1469}
1470
1483{
1484 if (!d)
1485 return 1.0;
1486 return d->devicePixelRatio;
1487}
1488
1511{
1512 if (!d)
1513 return;
1514
1515 if (scaleFactor == d->devicePixelRatio)
1516 return;
1517
1519 if (d)
1520 d->devicePixelRatio = scaleFactor;
1521}
1522
1534{
1535 if (!d)
1536 return QSizeF(0, 0);
1537 return QSizeF(d->width, d->height) / d->devicePixelRatio;
1538}
1539
1540
1549{
1550 return d ? d->nbytes : 0;
1551}
1552
1561{
1562 return d ? d->bytes_per_line : 0;
1563}
1564
1565
1578{
1579 Q_ASSERT(i < colorCount());
1580 return d ? d->colortable.at(i) : QRgb(uint(-1));
1581}
1582
1596{
1597 if (!d)
1598 return;
1599 if (i < 0 || d->depth > 8 || i >= 1<<d->depth) {
1600 qWarning("QImage::setColor: Index out of bound %d", i);
1601 return;
1602 }
1603 detachMetadata(true);
1604
1605 // In case detach() run out of memory
1606 if (!d)
1607 return;
1608
1609 if (i >= d->colortable.size())
1610 setColorCount(i+1);
1611 d->colortable[i] = c;
1612 d->has_alpha_clut |= (qAlpha(c) != 255);
1613}
1614
1638{
1639 if (!d)
1640 return nullptr;
1641
1642 detach();
1643
1644 // In case detach() ran out of memory
1645 if (!d)
1646 return nullptr;
1647
1648 return d->data + i * d->bytes_per_line;
1649}
1650
1654const uchar *QImage::scanLine(int i) const
1655{
1656 if (!d)
1657 return nullptr;
1658
1659 Q_ASSERT(i >= 0 && i < height());
1660 return d->data + i * d->bytes_per_line;
1661}
1662
1663
1679{
1680 if (!d)
1681 return nullptr;
1682
1683 Q_ASSERT(i >= 0 && i < height());
1684 return d->data + i * d->bytes_per_line;
1685}
1686
1699{
1700 if (!d)
1701 return nullptr;
1702 detach();
1703
1704 // In case detach ran out of memory...
1705 if (!d)
1706 return nullptr;
1707
1708 return d->data;
1709}
1710
1718const uchar *QImage::bits() const
1719{
1720 return d ? d->data : nullptr;
1721}
1722
1723
1734{
1735 return d ? d->data : nullptr;
1736}
1737
1759{
1760 if (!d)
1761 return;
1762
1763 detach();
1764
1765 // In case detach() ran out of memory
1766 if (!d)
1767 return;
1768
1769 if (d->depth == 1 || d->depth == 8) {
1770 int w = d->width;
1771 if (d->depth == 1) {
1772 if (pixel & 1)
1773 pixel = 0xffffffff;
1774 else
1775 pixel = 0;
1776 w = (w + 7) / 8;
1777 } else {
1778 pixel &= 0xff;
1779 }
1780 qt_rectfill<quint8>(d->data, pixel, 0, 0,
1781 w, d->height, d->bytes_per_line);
1782 return;
1783 } else if (d->depth == 16) {
1784 if (d->format == Format_RGB444)
1785 pixel |= 0xf000;
1786 qt_rectfill<quint16>(reinterpret_cast<quint16*>(d->data), pixel,
1787 0, 0, d->width, d->height, d->bytes_per_line);
1788 return;
1789 } else if (d->depth == 24) {
1790 if (d->format == Format_RGB666)
1791 pixel |= 0xfc0000;
1792 qt_rectfill<quint24>(reinterpret_cast<quint24*>(d->data), pixel,
1793 0, 0, d->width, d->height, d->bytes_per_line);
1794 return;
1795 } else if (d->format >= QImage::Format_RGBX64 && d->format <= QImage::Format_RGBA64_Premultiplied) {
1796 qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), QRgba64::fromArgb32(pixel),
1797 0, 0, d->width, d->height, d->bytes_per_line);
1798 return;
1799 } else if (d->format >= QImage::Format_RGBX16FPx4 && d->format <= QImage::Format_RGBA16FPx4_Premultiplied) {
1800 quint64 cu;
1802 ::memcpy(&cu, &cf, sizeof(quint64));
1803 qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), cu,
1804 0, 0, d->width, d->height, d->bytes_per_line);
1805 return;
1806 } else if (d->format >= QImage::Format_RGBX32FPx4 && d->format <= QImage::Format_RGBA32FPx4_Premultiplied) {
1808 uchar *data = d->data;
1809 for (int y = 0; y < d->height; ++y) {
1810 QRgbaFloat32 *line = reinterpret_cast<QRgbaFloat32 *>(data);
1811 for (int x = 0; x < d->width; ++x)
1812 line[x] = cf;
1813 data += d->bytes_per_line;
1814 }
1815 return;
1816 }
1817 Q_ASSERT(d->depth == 32);
1818
1819 if (d->format == Format_RGB32)
1820 pixel |= 0xff000000;
1821 if (d->format == Format_RGBX8888)
1822#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1823 pixel |= 0xff000000;
1824#else
1825 pixel |= 0x000000ff;
1826#endif
1827 if (d->format == Format_BGR30 || d->format == Format_RGB30)
1828 pixel |= 0xc0000000;
1829
1830 qt_rectfill<uint>(reinterpret_cast<uint*>(d->data), pixel,
1831 0, 0, d->width, d->height, d->bytes_per_line);
1832}
1833
1834
1847
1848
1849
1866{
1867 if (!d)
1868 return;
1869 detach();
1870
1871 // In case we run out of memory
1872 if (!d)
1873 return;
1874
1875 QRgba64 opaque = color.rgba64();
1876 opaque.setAlpha(65535);
1877 switch (d->format) {
1880 fill(color.rgba());
1881 break;
1883 fill(qPremultiply(color.rgba()));
1884 break;
1886 fill(ARGB2RGBA(color.rgba() | 0xff000000));
1887 break;
1889 fill(ARGB2RGBA(color.rgba()));
1890 break;
1892 fill(ARGB2RGBA(qPremultiply(color.rgba())));
1893 break;
1895 fill(qConvertRgb64ToRgb30<PixelOrderBGR>(opaque));
1896 break;
1898 fill(qConvertRgb64ToRgb30<PixelOrderRGB>(opaque));
1899 break;
1901 fill((uint) qConvertRgb32To16(color.rgba()));
1902 break;
1904 uint pixel = 0;
1905 for (int i=0; i<d->colortable.size(); ++i) {
1906 if (color.rgba() == d->colortable.at(i)) {
1907 pixel = i;
1908 break;
1909 }
1910 }
1911 fill(pixel);
1912 break;
1913 }
1916 if (color == Qt::color1)
1917 fill((uint) 1);
1918 else
1919 fill((uint) 0);
1920 break;
1922 qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), opaque,
1923 0, 0, d->width, d->height, d->bytes_per_line);
1924 break;
1926 qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), color.rgba64(),
1927 0, 0, d->width, d->height, d->bytes_per_line);
1928 break;
1930 qt_rectfill<quint64>(reinterpret_cast<quint64 *>(d->data), color.rgba64().premultiplied(),
1931 0, 0, d->width, d->height, d->bytes_per_line);
1932 break;
1939 float r, g, b, a;
1940 color.getRgbF(&r, &g, &b, &a);
1941 if (!hasAlphaChannel())
1942 a = 1.0f;
1943 if (depth() == 64) {
1945 if (d->format == Format_RGBA16FPx4_Premultiplied)
1946 c16 = c16.premultiplied();
1947 qt_rectfill<QRgbaFloat16>(reinterpret_cast<QRgbaFloat16 *>(d->data), c16,
1948 0, 0, d->width, d->height, d->bytes_per_line);
1949 } else {
1950 QRgbaFloat32 c32{r, g, b, a};
1951 if (d->format == Format_RGBA32FPx4_Premultiplied)
1952 c32 = c32.premultiplied();
1953 qt_rectfill<QRgbaFloat32>(reinterpret_cast<QRgbaFloat32 *>(d->data), c32,
1954 0, 0, d->width, d->height, d->bytes_per_line);
1955 }
1956 break;
1957 }
1958 default: {
1959 QPainter p(this);
1960 p.setCompositionMode(QPainter::CompositionMode_Source);
1961 p.fillRect(rect(), color);
1962 }}
1963}
1964
1965
1966
1988{
1989 if (!d)
1990 return;
1991
1992 detach();
1993
1994 // In case detach() ran out of memory
1995 if (!d)
1996 return;
1997
1998 QImage::Format originalFormat = d->format;
1999 // Inverting premultiplied pixels would produce invalid image data.
2000 if (hasAlphaChannel() && qPixelLayouts[d->format].premultiplied) {
2002 if (!d->convertInPlace(QImage::Format_RGBA16FPx4, { }))
2004 } else if (d->format == QImage::Format_RGBA32FPx4_Premultiplied) {
2005 if (!d->convertInPlace(QImage::Format_RGBA32FPx4, { }))
2007 } else if (depth() > 32) {
2008 if (!d->convertInPlace(QImage::Format_RGBA64, { }))
2010 } else {
2011 if (!d->convertInPlace(QImage::Format_ARGB32, { }))
2013 }
2014 }
2015
2016 if (depth() < 32) {
2017 // This assumes no alpha-channel as the only formats with non-premultipled alpha are 32bit.
2018 qsizetype bpl = (qsizetype(d->width) * d->depth + 7) / 8;
2019 int pad = d->bytes_per_line - bpl;
2020 uchar *sl = d->data;
2021 for (int y=0; y<d->height; ++y) {
2022 for (qsizetype x=0; x<bpl; ++x)
2023 *sl++ ^= 0xff;
2024 sl += pad;
2025 }
2027 qfloat16 *p = reinterpret_cast<qfloat16 *>(d->data);
2028 qfloat16 *end = reinterpret_cast<qfloat16 *>(d->data + d->nbytes);
2029 while (p < end) {
2030 p[0] = qfloat16(1) - p[0];
2031 p[1] = qfloat16(1) - p[1];
2032 p[2] = qfloat16(1) - p[2];
2033 if (mode == InvertRgba)
2034 p[3] = qfloat16(1) - p[3];
2035 p += 4;
2036 }
2038 uchar *data = d->data;
2039 for (int y = 0; y < d->height; ++y) {
2040 float *p = reinterpret_cast<float *>(data);
2041 for (int x = 0; x < d->width; ++x) {
2042 p[0] = 1.0f - p[0];
2043 p[1] = 1.0f - p[1];
2044 p[2] = 1.0f - p[2];
2045 if (mode == InvertRgba)
2046 p[3] = 1.0f - p[3];
2047 p += 4;
2048 }
2049 data += d->bytes_per_line;
2050 }
2051 } else if (depth() == 64) {
2052 quint16 *p = (quint16*)d->data;
2053 quint16 *end = (quint16*)(d->data + d->nbytes);
2054 quint16 xorbits = 0xffff;
2055 while (p < end) {
2056 *p++ ^= xorbits;
2057 *p++ ^= xorbits;
2058 *p++ ^= xorbits;
2059 if (mode == InvertRgba)
2060 *p++ ^= xorbits;
2061 else
2062 p++;
2063 }
2064 } else {
2065 quint32 *p = (quint32*)d->data;
2066 quint32 *end = (quint32*)(d->data + d->nbytes);
2067 quint32 xorbits = 0xffffffff;
2068 switch (d->format) {
2070 if (mode == InvertRgba)
2071 break;
2072 Q_FALLTHROUGH();
2074#if Q_BYTE_ORDER == Q_BIG_ENDIAN
2075 xorbits = 0xffffff00;
2076 break;
2077#else
2078 xorbits = 0x00ffffff;
2079 break;
2080#endif
2082 if (mode == InvertRgba)
2083 break;
2084 Q_FALLTHROUGH();
2086 xorbits = 0x00ffffff;
2087 break;
2090 xorbits = 0x3fffffff;
2091 break;
2092 default:
2093 Q_UNREACHABLE();
2094 xorbits = 0;
2095 break;
2096 }
2097 while (p < end)
2098 *p++ ^= xorbits;
2099 }
2100
2101 if (originalFormat != d->format) {
2102 if (!d->convertInPlace(originalFormat, { }))
2103 *this = convertToFormat(originalFormat);
2104 }
2105}
2106
2107// Windows defines these
2108#if defined(write)
2109# undef write
2110#endif
2111#if defined(close)
2112# undef close
2113#endif
2114#if defined(read)
2115# undef read
2116#endif
2117
2132void QImage::setColorCount(int colorCount)
2133{
2134 if (!d) {
2135 qWarning("QImage::setColorCount: null image");
2136 return;
2137 }
2138
2139 detachMetadata(true);
2140
2141 // In case detach() ran out of memory
2142 if (!d)
2143 return;
2144
2145 if (colorCount == d->colortable.size())
2146 return;
2147 if (colorCount <= 0) { // use no color table
2148 d->colortable.clear();
2149 return;
2150 }
2151 int nc = d->colortable.size();
2152 d->colortable.resize(colorCount);
2153 for (int i = nc; i < colorCount; ++i)
2154 d->colortable[i] = 0;
2155}
2156
2163{
2164 return d ? d->format : Format_Invalid;
2165}
2166
2196{
2197 if (!d || d->format == format)
2198 return *this;
2199
2200 if (d->format == Format_Invalid || format <= Format_Invalid || format >= NImageFormats)
2201 return QImage();
2202
2203 const QPixelLayout *destLayout = &qPixelLayouts[format];
2204 Image_Converter converter = qimage_converter_map[d->format][format];
2205 if (!converter && format > QImage::Format_Indexed8 && d->format > QImage::Format_Indexed8) {
2206 if (qt_highColorPrecision(d->format, !destLayout->hasAlphaChannel)
2208#if QT_CONFIG(raster_fp)
2210 converter = convert_generic_over_rgba32f;
2211 else
2212#endif
2213 converter = convert_generic_over_rgb64;
2214 } else
2215 converter = convert_generic;
2216 }
2217 if (converter) {
2218 QImage image(d->width, d->height, format);
2219
2221
2222 copyMetadata(image.d, d);
2223
2224 converter(image.d, d, flags);
2225 return image;
2226 }
2227
2228 // Convert indexed formats over ARGB32 or RGB32 to the final format.
2230 Q_ASSERT(d->format != QImage::Format_ARGB32 && d->format != QImage::Format_RGB32);
2231
2232 if (!hasAlphaChannel())
2234
2236}
2237
2242{
2243 return d && d->convertInPlace(format, flags);
2244}
2245
2246static inline int pixel_distance(QRgb p1, QRgb p2) {
2247 int r1 = qRed(p1);
2248 int g1 = qGreen(p1);
2249 int b1 = qBlue(p1);
2250 int a1 = qAlpha(p1);
2251
2252 int r2 = qRed(p2);
2253 int g2 = qGreen(p2);
2254 int b2 = qBlue(p2);
2255 int a2 = qAlpha(p2);
2256
2257 return abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2) + abs(a1 - a2);
2258}
2259
2260static inline int closestMatch(QRgb pixel, const QList<QRgb> &clut) {
2261 int idx = 0;
2262 int current_distance = INT_MAX;
2263 for (int i=0; i<clut.size(); ++i) {
2264 int dist = pixel_distance(pixel, clut.at(i));
2265 if (dist < current_distance) {
2266 current_distance = dist;
2267 idx = i;
2268 }
2269 }
2270 return idx;
2271}
2272
2274 const QList<QRgb> &clut) {
2275 QImage dest(src.size(), format);
2276 dest.setColorTable(clut);
2277
2279
2280 int h = src.height();
2281 int w = src.width();
2282
2283 QHash<QRgb, int> cache;
2284
2286 for (int y=0; y<h; ++y) {
2287 const QRgb *src_pixels = (const QRgb *) src.scanLine(y);
2288 uchar *dest_pixels = (uchar *) dest.scanLine(y);
2289 for (int x=0; x<w; ++x) {
2290 int src_pixel = src_pixels[x];
2291 int value = cache.value(src_pixel, -1);
2292 if (value == -1) {
2293 value = closestMatch(src_pixel, clut);
2294 cache.insert(src_pixel, value);
2295 }
2296 dest_pixels[x] = (uchar) value;
2297 }
2298 }
2299 } else {
2300 QList<QRgb> table = clut;
2301 table.resize(2);
2302 for (int y=0; y<h; ++y) {
2303 const QRgb *src_pixels = (const QRgb *) src.scanLine(y);
2304 for (int x=0; x<w; ++x) {
2305 int src_pixel = src_pixels[x];
2306 int value = cache.value(src_pixel, -1);
2307 if (value == -1) {
2308 value = closestMatch(src_pixel, table);
2309 cache.insert(src_pixel, value);
2310 }
2311 dest.setPixel(x, y, value);
2312 }
2313 }
2314 }
2315
2316 return dest;
2317}
2318
2329QImage QImage::convertToFormat(Format format, const QList<QRgb> &colorTable, Qt::ImageConversionFlags flags) const
2330{
2331 if (!d || d->format == format)
2332 return *this;
2333
2334 if (format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
2335 return QImage();
2338
2339 return convertToFormat(format, flags);
2340}
2341
2366{
2367 if (!d)
2368 return false;
2369 if (d->format == format)
2370 return true;
2372 return false;
2373 if (!isDetached()) { // Detach only if shared, not for read-only data.
2374 QImageData *oldD = d;
2375 detach();
2376 // In case detach() ran out of memory
2377 if (!d) {
2378 d = oldD;
2379 d->ref.ref();
2380 return false;
2381 }
2382 }
2383
2384 d->format = format;
2385 return true;
2386}
2387
2399void QImage::convertTo(Format format, Qt::ImageConversionFlags flags)
2400{
2401 if (!d || format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
2402 return;
2403
2404 if (d->format == format)
2405 return;
2406
2407 detach();
2409 return;
2410
2412}
2413
2429bool QImage::valid(int x, int y) const
2430{
2431 return d
2432 && x >= 0 && x < d->width
2433 && y >= 0 && y < d->height;
2434}
2435
2452int QImage::pixelIndex(int x, int y) const
2453{
2454 if (!d || x < 0 || x >= d->width || y < 0 || y >= height()) {
2455 qWarning("QImage::pixelIndex: coordinate (%d,%d) out of range", x, y);
2456 return -12345;
2457 }
2458 const uchar * s = scanLine(y);
2459 switch(d->format) {
2460 case Format_Mono:
2461 return (*(s + (x >> 3)) >> (7- (x & 7))) & 1;
2462 case Format_MonoLSB:
2463 return (*(s + (x >> 3)) >> (x & 7)) & 1;
2464 case Format_Indexed8:
2465 return (int)s[x];
2466 default:
2467 qWarning("QImage::pixelIndex: Not applicable for %d-bpp images (no palette)", d->depth);
2468 }
2469 return 0;
2470}
2471
2472
2493QRgb QImage::pixel(int x, int y) const
2494{
2495 if (!d || x < 0 || x >= d->width || y < 0 || y >= d->height) {
2496 qWarning("QImage::pixel: coordinate (%d,%d) out of range", x, y);
2497 return 12345;
2498 }
2499
2500 const uchar *s = d->data + y * d->bytes_per_line;
2501
2502 int index = -1;
2503 switch (d->format) {
2504 case Format_Mono:
2505 index = (*(s + (x >> 3)) >> (~x & 7)) & 1;
2506 break;
2507 case Format_MonoLSB:
2508 index = (*(s + (x >> 3)) >> (x & 7)) & 1;
2509 break;
2510 case Format_Indexed8:
2511 index = s[x];
2512 break;
2513 default:
2514 break;
2515 }
2516 if (index >= 0) { // Indexed format
2517 if (index >= d->colortable.size()) {
2518 qWarning("QImage::pixel: color table index %d out of range.", index);
2519 return 0;
2520 }
2521 return d->colortable.at(index);
2522 }
2523
2524 switch (d->format) {
2525 case Format_RGB32:
2526 return 0xff000000 | reinterpret_cast<const QRgb *>(s)[x];
2527 case Format_ARGB32: // Keep old behaviour.
2529 return reinterpret_cast<const QRgb *>(s)[x];
2530 case Format_RGBX8888:
2531 case Format_RGBA8888: // Match ARGB32 behavior.
2533 return RGBA2ARGB(reinterpret_cast<const quint32 *>(s)[x]);
2534 case Format_BGR30:
2536 return qConvertA2rgb30ToArgb32<PixelOrderBGR>(reinterpret_cast<const quint32 *>(s)[x]);
2537 case Format_RGB30:
2539 return qConvertA2rgb30ToArgb32<PixelOrderRGB>(reinterpret_cast<const quint32 *>(s)[x]);
2540 case Format_RGB16:
2541 return qConvertRgb16To32(reinterpret_cast<const quint16 *>(s)[x]);
2542 case Format_RGBX64:
2543 case Format_RGBA64: // Match ARGB32 behavior.
2545 return reinterpret_cast<const QRgba64 *>(s)[x].toArgb32();
2546 case Format_RGBX16FPx4:
2547 case Format_RGBA16FPx4: // Match ARGB32 behavior.
2549 return reinterpret_cast<const QRgbaFloat16 *>(s)[x].toArgb32();
2550 case Format_RGBX32FPx4:
2551 case Format_RGBA32FPx4: // Match ARGB32 behavior.
2553 return reinterpret_cast<const QRgbaFloat32 *>(s)[x].toArgb32();
2554 default:
2555 break;
2556 }
2557 const QPixelLayout *layout = &qPixelLayouts[d->format];
2558 uint result;
2559 return *layout->fetchToARGB32PM(&result, s, x, 1, nullptr, nullptr);
2560}
2561
2588void QImage::setPixel(int x, int y, uint index_or_rgb)
2589{
2590 if (!d || x < 0 || x >= width() || y < 0 || y >= height()) {
2591 qWarning("QImage::setPixel: coordinate (%d,%d) out of range", x, y);
2592 return;
2593 }
2594 // detach is called from within scanLine
2595 uchar * s = scanLine(y);
2596 switch(d->format) {
2597 case Format_Mono:
2598 case Format_MonoLSB:
2599 if (index_or_rgb > 1) {
2600 qWarning("QImage::setPixel: Index %d out of range", index_or_rgb);
2601 } else if (format() == Format_MonoLSB) {
2602 if (index_or_rgb==0)
2603 *(s + (x >> 3)) &= ~(1 << (x & 7));
2604 else
2605 *(s + (x >> 3)) |= (1 << (x & 7));
2606 } else {
2607 if (index_or_rgb==0)
2608 *(s + (x >> 3)) &= ~(1 << (7-(x & 7)));
2609 else
2610 *(s + (x >> 3)) |= (1 << (7-(x & 7)));
2611 }
2612 return;
2613 case Format_Indexed8:
2614 if (index_or_rgb >= (uint)d->colortable.size()) {
2615 qWarning("QImage::setPixel: Index %d out of range", index_or_rgb);
2616 return;
2617 }
2618 s[x] = index_or_rgb;
2619 return;
2620 case Format_RGB32:
2621 //make sure alpha is 255, we depend on it in qdrawhelper for cases
2622 // when image is set as a texture pattern on a qbrush
2623 ((uint *)s)[x] = 0xff000000 | index_or_rgb;
2624 return;
2625 case Format_ARGB32:
2627 ((uint *)s)[x] = index_or_rgb;
2628 return;
2629 case Format_RGB16:
2630 ((quint16 *)s)[x] = qConvertRgb32To16(index_or_rgb);
2631 return;
2632 case Format_RGBX8888:
2633 ((uint *)s)[x] = ARGB2RGBA(0xff000000 | index_or_rgb);
2634 return;
2635 case Format_RGBA8888:
2637 ((uint *)s)[x] = ARGB2RGBA(index_or_rgb);
2638 return;
2639 case Format_BGR30:
2640 ((uint *)s)[x] = qConvertRgb32ToRgb30<PixelOrderBGR>(index_or_rgb);
2641 return;
2643 ((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderBGR>(index_or_rgb);
2644 return;
2645 case Format_RGB30:
2646 ((uint *)s)[x] = qConvertRgb32ToRgb30<PixelOrderRGB>(index_or_rgb);
2647 return;
2649 ((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderRGB>(index_or_rgb);
2650 return;
2651 case Format_RGBX64:
2652 ((QRgba64 *)s)[x] = QRgba64::fromArgb32(index_or_rgb | 0xff000000);
2653 return;
2654 case Format_RGBA64:
2656 ((QRgba64 *)s)[x] = QRgba64::fromArgb32(index_or_rgb);
2657 return;
2658 case Format_RGBX16FPx4:
2659 ((QRgbaFloat16 *)s)[x] = QRgbaFloat16::fromArgb32(index_or_rgb | 0xff000000);
2660 return;
2661 case Format_RGBA16FPx4:
2663 ((QRgbaFloat16 *)s)[x] = QRgbaFloat16::fromArgb32(index_or_rgb);
2664 return;
2665 case Format_RGBX32FPx4:
2666 ((QRgbaFloat32 *)s)[x] = QRgbaFloat32::fromArgb32(index_or_rgb | 0xff000000);
2667 return;
2668 case Format_RGBA32FPx4:
2670 ((QRgbaFloat32 *)s)[x] = QRgbaFloat32::fromArgb32(index_or_rgb);
2671 return;
2672 case Format_Invalid:
2673 case NImageFormats:
2674 Q_ASSERT(false);
2675 return;
2676 default:
2677 break;
2678 }
2679
2680 const QPixelLayout *layout = &qPixelLayouts[d->format];
2681 if (!hasAlphaChannel())
2682 layout->storeFromRGB32(s, &index_or_rgb, x, 1, nullptr, nullptr);
2683 else
2684 layout->storeFromARGB32PM(s, &index_or_rgb, x, 1, nullptr, nullptr);
2685}
2686
2710{
2711 if (!d || x < 0 || x >= d->width || y < 0 || y >= height()) {
2712 qWarning("QImage::pixelColor: coordinate (%d,%d) out of range", x, y);
2713 return QColor();
2714 }
2715
2716 QRgba64 c;
2717 const uchar * s = constScanLine(y);
2718 switch (d->format) {
2719 case Format_BGR30:
2721 c = qConvertA2rgb30ToRgb64<PixelOrderBGR>(reinterpret_cast<const quint32 *>(s)[x]);
2722 break;
2723 case Format_RGB30:
2725 c = qConvertA2rgb30ToRgb64<PixelOrderRGB>(reinterpret_cast<const quint32 *>(s)[x]);
2726 break;
2727 case Format_RGBX64:
2728 case Format_RGBA64:
2730 c = reinterpret_cast<const QRgba64 *>(s)[x];
2731 break;
2732 case Format_Grayscale16: {
2733 quint16 v = reinterpret_cast<const quint16 *>(s)[x];
2734 return QColor(qRgba64(v, v, v, 0xffff));
2735 }
2736 case Format_RGBX16FPx4:
2737 case Format_RGBA16FPx4:
2739 QRgbaFloat16 p = reinterpret_cast<const QRgbaFloat16 *>(s)[x];
2740 if (d->format == Format_RGBA16FPx4_Premultiplied)
2741 p = p.unpremultiplied();
2742 QColor color;
2743 color.setRgbF(p.red(), p.green(), p.blue(), p.alpha());
2744 return color;
2745 }
2746 case Format_RGBX32FPx4:
2747 case Format_RGBA32FPx4:
2749 QRgbaFloat32 p = reinterpret_cast<const QRgbaFloat32 *>(s)[x];
2750 if (d->format == Format_RGBA32FPx4_Premultiplied)
2751 p = p.unpremultiplied();
2752 QColor color;
2753 color.setRgbF(p.red(), p.green(), p.blue(), p.alpha());
2754 return color;
2755 }
2756 default:
2758 break;
2759 }
2760 // QColor is always unpremultiplied
2761 if (hasAlphaChannel() && qPixelLayouts[d->format].premultiplied)
2762 c = c.unpremultiplied();
2763 return QColor(c);
2764}
2765
2788void QImage::setPixelColor(int x, int y, const QColor &color)
2789{
2790 if (!d || x < 0 || x >= width() || y < 0 || y >= height()) {
2791 qWarning("QImage::setPixelColor: coordinate (%d,%d) out of range", x, y);
2792 return;
2793 }
2794
2795 if (!color.isValid()) {
2796 qWarning("QImage::setPixelColor: color is invalid");
2797 return;
2798 }
2799
2800 // QColor is always unpremultiplied
2801 QRgba64 c = color.rgba64();
2802 if (!hasAlphaChannel())
2803 c.setAlpha(65535);
2804 else if (qPixelLayouts[d->format].premultiplied)
2805 c = c.premultiplied();
2806 // detach is called from within scanLine
2807 uchar * s = scanLine(y);
2808 switch (d->format) {
2809 case Format_Mono:
2810 case Format_MonoLSB:
2811 case Format_Indexed8:
2812 qWarning("QImage::setPixelColor: called on monochrome or indexed format");
2813 return;
2814 case Format_BGR30:
2815 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderBGR>(c) | 0xc0000000;
2816 return;
2819 return;
2820 case Format_RGB30:
2821 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderRGB>(c) | 0xc0000000;
2822 return;
2825 return;
2826 case Format_RGBX64:
2827 case Format_RGBA64:
2829 ((QRgba64 *)s)[x] = c;
2830 return;
2831 case Format_RGBX16FPx4:
2832 case Format_RGBA16FPx4:
2834 float r, g, b, a;
2835 color.getRgbF(&r, &g, &b, &a);
2836 if (d->format == Format_RGBX16FPx4)
2837 a = 1.0f;
2839 if (d->format == Format_RGBA16FPx4_Premultiplied)
2840 c16f = c16f.premultiplied();
2841 ((QRgbaFloat16 *)s)[x] = c16f;
2842 return;
2843 }
2844 case Format_RGBX32FPx4:
2845 case Format_RGBA32FPx4:
2847 float r, g, b, a;
2848 color.getRgbF(&r, &g, &b, &a);
2849 if (d->format == Format_RGBX32FPx4)
2850 a = 1.0f;
2851 QRgbaFloat32 c32f{r, g, b, a};
2852 if (d->format == Format_RGBA32FPx4_Premultiplied)
2853 c32f = c32f.premultiplied();
2854 ((QRgbaFloat32 *)s)[x] = c32f;
2855 return;
2856 }
2857 default:
2858 setPixel(x, y, c.toArgb32());
2859 return;
2860 }
2861}
2862
2873{
2874 if (!d)
2875 return true;
2876
2877 switch (d->format) {
2878 case Format_Mono:
2879 case Format_MonoLSB:
2880 case Format_Indexed8:
2881 for (int i = 0; i < d->colortable.size(); ++i) {
2882 if (!qIsGray(d->colortable.at(i)))
2883 return false;
2884 }
2885 return true;
2886 case Format_Alpha8:
2887 return false;
2888 case Format_Grayscale8:
2889 case Format_Grayscale16:
2890 return true;
2891 case Format_RGB32:
2892 case Format_ARGB32:
2894#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
2895 case Format_RGBX8888:
2896 case Format_RGBA8888:
2898#endif
2899 for (int j = 0; j < d->height; ++j) {
2900 const QRgb *b = (const QRgb *)constScanLine(j);
2901 for (int i = 0; i < d->width; ++i) {
2902 if (!qIsGray(b[i]))
2903 return false;
2904 }
2905 }
2906 return true;
2907 case Format_RGB16:
2908 for (int j = 0; j < d->height; ++j) {
2909 const quint16 *b = (const quint16 *)constScanLine(j);
2910 for (int i = 0; i < d->width; ++i) {
2911 if (!qIsGray(qConvertRgb16To32(b[i])))
2912 return false;
2913 }
2914 }
2915 return true;
2916 default:
2917 break;
2918 }
2919
2921 const QPixelLayout *layout = &qPixelLayouts[d->format];
2922 const auto fetch = layout->fetchToARGB32PM;
2923 for (int j = 0; j < d->height; ++j) {
2924 const uchar *b = constScanLine(j);
2925 int x = 0;
2926 while (x < d->width) {
2927 int l = qMin(d->width - x, BufferSize);
2928 const uint *ptr = fetch(buffer, b, x, l, nullptr, nullptr);
2929 for (int i = 0; i < l; ++i) {
2930 if (!qIsGray(ptr[i]))
2931 return false;
2932 }
2933 x += l;
2934 }
2935 }
2936 return true;
2937}
2938
2949{
2950 if (!d)
2951 return false;
2952
2953 if (d->format == QImage::Format_Alpha8)
2954 return false;
2955
2956 if (d->format == QImage::Format_Grayscale8 || d->format == QImage::Format_Grayscale16)
2957 return true;
2958
2959 switch (depth()) {
2960 case 32:
2961 case 24:
2962 case 16:
2963 return allGray();
2964 case 8: {
2966 for (int i = 0; i < colorCount(); i++)
2967 if (d->colortable.at(i) != qRgb(i,i,i))
2968 return false;
2969 return true;
2970 }
2971 }
2972 return false;
2973}
2974
3014{
3015 if (!d) {
3016 qWarning("QImage::scaled: Image is a null image");
3017 return QImage();
3018 }
3019 if (s.isEmpty())
3020 return QImage();
3021
3022 QSize newSize = size();
3023 newSize.scale(s, aspectMode);
3024 newSize.rwidth() = qMax(newSize.width(), 1);
3025 newSize.rheight() = qMax(newSize.height(), 1);
3026 if (newSize == size())
3027 return *this;
3028
3029 Q_TRACE_SCOPE(QImage_scaled, s, aspectMode, mode);
3030
3031 QTransform wm = QTransform::fromScale((qreal)newSize.width() / width(), (qreal)newSize.height() / height());
3032 QImage img = transformed(wm, mode);
3033 return img;
3034}
3035
3051{
3052 if (!d) {
3053 qWarning("QImage::scaleWidth: Image is a null image");
3054 return QImage();
3055 }
3056 if (w <= 0)
3057 return QImage();
3058
3059 Q_TRACE_SCOPE(QImage_scaledToWidth, w, mode);
3060
3061 qreal factor = (qreal) w / width();
3062 QTransform wm = QTransform::fromScale(factor, factor);
3063 return transformed(wm, mode);
3064}
3065
3081{
3082 if (!d) {
3083 qWarning("QImage::scaleHeight: Image is a null image");
3084 return QImage();
3085 }
3086 if (h <= 0)
3087 return QImage();
3088
3089 Q_TRACE_SCOPE(QImage_scaledToHeight, h, mode);
3090
3091 qreal factor = (qreal) h / height();
3092 QTransform wm = QTransform::fromScale(factor, factor);
3093 return transformed(wm, mode);
3094}
3095
3113QImage Q_TRACE_INSTRUMENT(qtgui) QImage::createAlphaMask(Qt::ImageConversionFlags flags) const
3114{
3115 if (!d || d->format == QImage::Format_RGB32)
3116 return QImage();
3117
3118 if (d->depth == 1) {
3119 // A monochrome pixmap, with alpha channels on those two colors.
3120 // Pretty unlikely, so use less efficient solution.
3122 }
3123
3124 QImage mask(d->width, d->height, Format_MonoLSB);
3125 if (!mask.isNull()) {
3126 dither_to_Mono(mask.d, d, flags, true);
3128 }
3129 return mask;
3130}
3131
3132#ifndef QT_NO_IMAGE_HEURISTIC_MASK
3157QImage QImage::createHeuristicMask(bool clipTight) const
3158{
3159 if (!d)
3160 return QImage();
3161
3162 if (d->depth != 32) {
3164 return img32.createHeuristicMask(clipTight);
3165 }
3166
3167#define PIX(x,y) (*((const QRgb*)scanLine(y)+x) & 0x00ffffff)
3168
3169 int w = width();
3170 int h = height();
3173 m.setColorCount(2);
3174 m.setColor(0, QColor(Qt::color0).rgba());
3175 m.setColor(1, QColor(Qt::color1).rgba());
3176 m.fill(0xff);
3177
3178 QRgb background = PIX(0,0);
3179 if (background != PIX(w-1,0) &&
3180 background != PIX(0,h-1) &&
3181 background != PIX(w-1,h-1)) {
3182 background = PIX(w-1,0);
3183 if (background != PIX(w-1,h-1) &&
3184 background != PIX(0,h-1) &&
3185 PIX(0,h-1) == PIX(w-1,h-1)) {
3186 background = PIX(w-1,h-1);
3187 }
3188 }
3189
3190 int x,y;
3191 bool done = false;
3192 uchar *ypp, *ypc, *ypn;
3193 while(!done) {
3194 done = true;
3195 ypn = m.scanLine(0);
3196 ypc = nullptr;
3197 for (y = 0; y < h; y++) {
3198 ypp = ypc;
3199 ypc = ypn;
3200 ypn = (y == h-1) ? nullptr : m.scanLine(y+1);
3201 const QRgb *p = (const QRgb *)scanLine(y);
3202 for (x = 0; x < w; x++) {
3203 // slowness here - it's possible to do six of these tests
3204 // together in one go. oh well.
3205 if ((x == 0 || y == 0 || x == w-1 || y == h-1 ||
3206 !(*(ypc + ((x-1) >> 3)) & (1 << ((x-1) & 7))) ||
3207 !(*(ypc + ((x+1) >> 3)) & (1 << ((x+1) & 7))) ||
3208 !(*(ypp + (x >> 3)) & (1 << (x & 7))) ||
3209 !(*(ypn + (x >> 3)) & (1 << (x & 7)))) &&
3210 ( (*(ypc + (x >> 3)) & (1 << (x & 7)))) &&
3211 ((*p & 0x00ffffff) == background)) {
3212 done = false;
3213 *(ypc + (x >> 3)) &= ~(1 << (x & 7));
3214 }
3215 p++;
3216 }
3217 }
3218 }
3219
3220 if (!clipTight) {
3221 ypn = m.scanLine(0);
3222 ypc = nullptr;
3223 for (y = 0; y < h; y++) {
3224 ypp = ypc;
3225 ypc = ypn;
3226 ypn = (y == h-1) ? nullptr : m.scanLine(y+1);
3227 const QRgb *p = (const QRgb *)scanLine(y);
3228 for (x = 0; x < w; x++) {
3229 if ((*p & 0x00ffffff) != background) {
3230 if (x > 0)
3231 *(ypc + ((x-1) >> 3)) |= (1 << ((x-1) & 7));
3232 if (x < w-1)
3233 *(ypc + ((x+1) >> 3)) |= (1 << ((x+1) & 7));
3234 if (y > 0)
3235 *(ypp + (x >> 3)) |= (1 << (x & 7));
3236 if (y < h-1)
3237 *(ypn + (x >> 3)) |= (1 << (x & 7));
3238 }
3239 p++;
3240 }
3241 }
3242 }
3243
3244#undef PIX
3245
3247 return m;
3248}
3249#endif //QT_NO_IMAGE_HEURISTIC_MASK
3250
3262{
3263 if (!d)
3264 return QImage();
3265 QImage maskImage(size(), QImage::Format_MonoLSB);
3266 QIMAGE_SANITYCHECK_MEMORY(maskImage);
3267 maskImage.fill(0);
3268 uchar *s = maskImage.bits();
3269 if (!s)
3270 return QImage();
3271
3272 if (depth() == 32) {
3273 for (int h = 0; h < d->height; h++) {
3274 const uint *sl = (const uint *) scanLine(h);
3275 for (int w = 0; w < d->width; w++) {
3276 if (sl[w] == color)
3277 *(s + (w >> 3)) |= (1 << (w & 7));
3278 }
3279 s += maskImage.bytesPerLine();
3280 }
3281 } else {
3282 for (int h = 0; h < d->height; h++) {
3283 for (int w = 0; w < d->width; w++) {
3284 if ((uint) pixel(w, h) == color)
3285 *(s + (w >> 3)) |= (1 << (w & 7));
3286 }
3287 s += maskImage.bytesPerLine();
3288 }
3289 }
3290 if (mode == Qt::MaskOutColor)
3291 maskImage.invertPixels();
3292
3293 copyPhysicalMetadata(maskImage.d, d);
3294 return maskImage;
3295}
3296
3320template<class T> inline void do_mirror_data(QImageData *dst, QImageData *src,
3321 int dstX0, int dstY0,
3322 int dstXIncr, int dstYIncr,
3323 int w, int h)
3324{
3325 if (dst == src) {
3326 // When mirroring in-place, stop in the middle for one of the directions, since we
3327 // are swapping the bytes instead of merely copying.
3328 const int srcXEnd = (dstX0 && !dstY0) ? w / 2 : w;
3329 const int srcYEnd = dstY0 ? h / 2 : h;
3330 for (int srcY = 0, dstY = dstY0; srcY < srcYEnd; ++srcY, dstY += dstYIncr) {
3331 T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3332 T *dstPtr = (T *) (dst->data + dstY * dst->bytes_per_line);
3333 for (int srcX = 0, dstX = dstX0; srcX < srcXEnd; ++srcX, dstX += dstXIncr)
3334 std::swap(srcPtr[srcX], dstPtr[dstX]);
3335 }
3336 // If mirroring both ways, the middle line needs to be mirrored horizontally only.
3337 if (dstX0 && dstY0 && (h & 1)) {
3338 int srcY = h / 2;
3339 int srcXEnd2 = w / 2;
3340 T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3341 for (int srcX = 0, dstX = dstX0; srcX < srcXEnd2; ++srcX, dstX += dstXIncr)
3342 std::swap(srcPtr[srcX], srcPtr[dstX]);
3343 }
3344 } else {
3345 for (int srcY = 0, dstY = dstY0; srcY < h; ++srcY, dstY += dstYIncr) {
3346 T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3347 T *dstPtr = (T *) (dst->data + dstY * dst->bytes_per_line);
3348 for (int srcX = 0, dstX = dstX0; srcX < w; ++srcX, dstX += dstXIncr)
3349 dstPtr[dstX] = srcPtr[srcX];
3350 }
3351 }
3352}
3353
3354inline void do_flip(QImageData *dst, QImageData *src, int w, int h, int depth)
3355{
3356 const int data_bytes_per_line = w * (depth / 8);
3357 if (dst == src) {
3358 uint *srcPtr = reinterpret_cast<uint *>(src->data);
3359 uint *dstPtr = reinterpret_cast<uint *>(dst->data + (h - 1) * dst->bytes_per_line);
3360 h = h / 2;
3361 const int uint_per_line = (data_bytes_per_line + 3) >> 2; // bytes per line must be a multiple of 4
3362 for (int y = 0; y < h; ++y) {
3363 // This is auto-vectorized, no need for SSE2 or NEON versions:
3364 for (int x = 0; x < uint_per_line; x++) {
3365 const uint d = dstPtr[x];
3366 const uint s = srcPtr[x];
3367 dstPtr[x] = s;
3368 srcPtr[x] = d;
3369 }
3370 srcPtr += src->bytes_per_line >> 2;
3371 dstPtr -= dst->bytes_per_line >> 2;
3372 }
3373
3374 } else {
3375 const uchar *srcPtr = src->data;
3376 uchar *dstPtr = dst->data + (h - 1) * dst->bytes_per_line;
3377 for (int y = 0; y < h; ++y) {
3378 memcpy(dstPtr, srcPtr, data_bytes_per_line);
3379 srcPtr += src->bytes_per_line;
3380 dstPtr -= dst->bytes_per_line;
3381 }
3382 }
3383}
3384
3385inline void do_mirror(QImageData *dst, QImageData *src, bool horizontal, bool vertical)
3386{
3387 Q_ASSERT(src->width == dst->width && src->height == dst->height && src->depth == dst->depth);
3388 int w = src->width;
3389 int h = src->height;
3390 int depth = src->depth;
3391
3392 if (src->depth == 1) {
3393 w = (w + 7) / 8; // byte aligned width
3394 depth = 8;
3395 }
3396
3397 if (vertical && !horizontal) {
3398 // This one is simple and common, so do it a little more optimized
3399 do_flip(dst, src, w, h, depth);
3400 return;
3401 }
3402
3403 int dstX0 = 0, dstXIncr = 1;
3404 int dstY0 = 0, dstYIncr = 1;
3405 if (horizontal) {
3406 // 0 -> w-1, 1 -> w-2, 2 -> w-3, ...
3407 dstX0 = w - 1;
3408 dstXIncr = -1;
3409 }
3410 if (vertical) {
3411 // 0 -> h-1, 1 -> h-2, 2 -> h-3, ...
3412 dstY0 = h - 1;
3413 dstYIncr = -1;
3414 }
3415
3416 switch (depth) {
3417 case 128:
3418 do_mirror_data<QRgbaFloat32>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3419 break;
3420 case 64:
3421 do_mirror_data<quint64>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3422 break;
3423 case 32:
3424 do_mirror_data<quint32>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3425 break;
3426 case 24:
3427 do_mirror_data<quint24>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3428 break;
3429 case 16:
3430 do_mirror_data<quint16>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3431 break;
3432 case 8:
3433 do_mirror_data<quint8>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3434 break;
3435 default:
3436 Q_ASSERT(false);
3437 break;
3438 }
3439
3440 // The bytes are now all in the correct place. In addition, the bits in the individual
3441 // bytes have to be flipped too when horizontally mirroring a 1 bit-per-pixel image.
3442 if (horizontal && dst->depth == 1) {
3443 Q_ASSERT(dst->format == QImage::Format_Mono || dst->format == QImage::Format_MonoLSB);
3444 const int shift = 8 - (dst->width % 8);
3446 for (int y = 0; y < h; ++y) {
3447 uchar *begin = dst->data + y * dst->bytes_per_line;
3448 uchar *end = begin + dst->bytes_per_line;
3449 for (uchar *p = begin; p < end; ++p) {
3450 *p = bitflip[*p];
3451 // When the data is non-byte aligned, an extra bit shift (of the number of
3452 // unused bits at the end) is needed for the entire scanline.
3453 if (shift != 8 && p != begin) {
3454 if (dst->format == QImage::Format_Mono) {
3455 for (int i = 0; i < shift; ++i) {
3456 p[-1] <<= 1;
3457 p[-1] |= (*p & (128 >> i)) >> (7 - i);
3458 }
3459 } else {
3460 for (int i = 0; i < shift; ++i) {
3461 p[-1] >>= 1;
3462 p[-1] |= (*p & (1 << i)) << (7 - i);
3463 }
3464 }
3465 }
3466 }
3467 if (shift != 8) {
3468 if (dst->format == QImage::Format_Mono)
3469 end[-1] <<= shift;
3470 else
3471 end[-1] >>= shift;
3472 }
3473 }
3474 }
3475}
3476
3480QImage QImage::mirrored_helper(bool horizontal, bool vertical) const
3481{
3482 if (!d)
3483 return QImage();
3484
3485 if ((d->width <= 1 && d->height <= 1) || (!horizontal && !vertical))
3486 return *this;
3487
3488 // Create result image, copy colormap
3489 QImage result(d->width, d->height, d->format);
3491
3492 // check if we ran out of of memory..
3493 if (!result.d)
3494 return QImage();
3495
3496 result.d->colortable = d->colortable;
3497 result.d->has_alpha_clut = d->has_alpha_clut;
3498 copyMetadata(result.d, d);
3499
3500 do_mirror(result.d, d, horizontal, vertical);
3501
3502 return result;
3503}
3504
3508void QImage::mirrored_inplace(bool horizontal, bool vertical)
3509{
3510 if (!d || (d->width <= 1 && d->height <= 1) || (!horizontal && !vertical))
3511 return;
3512
3513 detach();
3514 if (!d)
3515 return;
3516 if (!d->own_data)
3517 *this = copy();
3518
3519 do_mirror(d, d, horizontal, vertical);
3520}
3521
3545static inline void rgbSwapped_generic(int width, int height, const QImage *src, QImage *dst, const QPixelLayout* layout)
3546{
3547 const RbSwapFunc func = layout->rbSwap;
3548 if (!func) {
3549 qWarning("Trying to rb-swap an image format where it doesn't make sense");
3550 if (src != dst)
3551 *dst = *src;
3552 return;
3553 }
3554
3555 for (int i = 0; i < height; ++i) {
3556 uchar *q = dst->scanLine(i);
3557 const uchar *p = src->constScanLine(i);
3558 func(q, p, width);
3559 }
3560}
3561
3566{
3567 if (isNull())
3568 return *this;
3569
3570 Q_TRACE_SCOPE(QImage_rgbSwapped_helper);
3571
3572 QImage res;
3573
3574 switch (d->format) {
3575 case Format_Invalid:
3576 case NImageFormats:
3577 Q_ASSERT(false);
3578 break;
3579 case Format_Alpha8:
3580 case Format_Grayscale8:
3581 case Format_Grayscale16:
3582 return *this;
3583 case Format_Mono:
3584 case Format_MonoLSB:
3585 case Format_Indexed8:
3586 res = copy();
3587 for (int i = 0; i < res.d->colortable.size(); i++) {
3588 QRgb c = res.d->colortable.at(i);
3589 res.d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
3590 }
3591 break;
3592 case Format_RGBX8888:
3593 case Format_RGBA8888:
3595#if Q_BYTE_ORDER == Q_BIG_ENDIAN
3596 res = QImage(d->width, d->height, d->format);
3598 for (int i = 0; i < d->height; i++) {
3599 uint *q = (uint*)res.scanLine(i);
3600 const uint *p = (const uint*)constScanLine(i);
3601 const uint *end = p + d->width;
3602 while (p < end) {
3603 uint c = *p;
3604 *q = ((c << 16) & 0xff000000) | ((c >> 16) & 0xff00) | (c & 0x00ff00ff);
3605 p++;
3606 q++;
3607 }
3608 }
3609 break;
3610#else
3611 // On little-endian rgba8888 is abgr32 and can use same rgb-swap as argb32
3612 Q_FALLTHROUGH();
3613#endif
3614 case Format_RGB32:
3615 case Format_ARGB32:
3617 res = QImage(d->width, d->height, d->format);
3619 for (int i = 0; i < d->height; i++) {
3620 uint *q = (uint*)res.scanLine(i);
3621 const uint *p = (const uint*)constScanLine(i);
3622 const uint *end = p + d->width;
3623 while (p < end) {
3624 uint c = *p;
3625 *q = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
3626 p++;
3627 q++;
3628 }
3629 }
3630 break;
3631 case Format_RGB16:
3632 res = QImage(d->width, d->height, d->format);
3634 for (int i = 0; i < d->height; i++) {
3635 ushort *q = (ushort*)res.scanLine(i);
3636 const ushort *p = (const ushort*)constScanLine(i);
3637 const ushort *end = p + d->width;
3638 while (p < end) {
3639 ushort c = *p;
3640 *q = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
3641 p++;
3642 q++;
3643 }
3644 }
3645 break;
3646 default:
3647 res = QImage(d->width, d->height, d->format);
3649 rgbSwapped_generic(d->width, d->height, this, &res, &qPixelLayouts[d->format]);
3650 break;
3651 }
3652 copyMetadata(res.d, d);
3653 return res;
3654}
3655
3660{
3661 if (isNull())
3662 return;
3663
3664 detach();
3665 if (!d)
3666 return;
3667 if (!d->own_data)
3668 *this = copy();
3669
3670 switch (d->format) {
3671 case Format_Invalid:
3672 case NImageFormats:
3673 Q_ASSERT(false);
3674 break;
3675 case Format_Alpha8:
3676 case Format_Grayscale8:
3677 case Format_Grayscale16:
3678 return;
3679 case Format_Mono:
3680 case Format_MonoLSB:
3681 case Format_Indexed8:
3682 for (int i = 0; i < d->colortable.size(); i++) {
3683 QRgb c = d->colortable.at(i);
3684 d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
3685 }
3686 break;
3687 case Format_RGBX8888:
3688 case Format_RGBA8888:
3690#if Q_BYTE_ORDER == Q_BIG_ENDIAN
3691 for (int i = 0; i < d->height; i++) {
3692 uint *p = (uint*)scanLine(i);
3693 uint *end = p + d->width;
3694 while (p < end) {
3695 uint c = *p;
3696 *p = ((c << 16) & 0xff000000) | ((c >> 16) & 0xff00) | (c & 0x00ff00ff);
3697 p++;
3698 }
3699 }
3700 break;
3701#else
3702 // On little-endian rgba8888 is abgr32 and can use same rgb-swap as argb32
3703 Q_FALLTHROUGH();
3704#endif
3705 case Format_RGB32:
3706 case Format_ARGB32:
3708 for (int i = 0; i < d->height; i++) {
3709 uint *p = (uint*)scanLine(i);
3710 uint *end = p + d->width;
3711 while (p < end) {
3712 uint c = *p;
3713 *p = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
3714 p++;
3715 }
3716 }
3717 break;
3718 case Format_RGB16:
3719 for (int i = 0; i < d->height; i++) {
3720 ushort *p = (ushort*)scanLine(i);
3721 ushort *end = p + d->width;
3722 while (p < end) {
3723 ushort c = *p;
3724 *p = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
3725 p++;
3726 }
3727 }
3728 break;
3729 case Format_BGR30:
3731 case Format_RGB30:
3733 for (int i = 0; i < d->height; i++) {
3734 uint *p = (uint*)scanLine(i);
3735 uint *end = p + d->width;
3736 while (p < end) {
3737 *p = qRgbSwapRgb30(*p);
3738 p++;
3739 }
3740 }
3741 break;
3742 default:
3743 rgbSwapped_generic(d->width, d->height, this, this, &qPixelLayouts[d->format]);
3744 break;
3745 }
3746}
3747
3767bool QImage::load(const QString &fileName, const char* format)
3768{
3769 *this = QImageReader(fileName, format).read();
3770 return !isNull();
3771}
3772
3781{
3782 *this = QImageReader(device, format).read();
3783 return !isNull();
3784}
3785
3800{
3801 *this = fromData(data, format);
3802 return !isNull();
3803}
3804
3813bool QImage::loadFromData(const uchar *buf, int len, const char *format)
3814{
3816}
3817
3842{
3843 QByteArray a = QByteArray::fromRawData(data.constData(), data.size());
3844 QBuffer b;
3845 b.setData(a);
3846 b.open(QIODevice::ReadOnly);
3847 return QImageReader(&b, format).read();
3848}
3849
3858QImage QImage::fromData(const uchar *data, int size, const char *format)
3859{
3861}
3862
3888bool QImage::save(const QString &fileName, const char *format, int quality) const
3889{
3890 if (isNull())
3891 return false;
3892 QImageWriter writer(fileName, format);
3893 return d->doImageIO(this, &writer, quality);
3894}
3895
3907bool QImage::save(QIODevice* device, const char* format, int quality) const
3908{
3909 if (isNull())
3910 return false; // nothing to save
3911 QImageWriter writer(device, format);
3912 return d->doImageIO(this, &writer, quality);
3913}
3914
3915/* \internal
3916*/
3917
3918bool QImageData::doImageIO(const QImage *image, QImageWriter *writer, int quality) const
3919{
3920 if (quality > 100 || quality < -1)
3921 qWarning("QImage::save: Quality out of range [-1, 100]");
3922 if (quality >= 0)
3923 writer->setQuality(qMin(quality,100));
3924 const bool result = writer->write(*image);
3925#ifdef QT_DEBUG
3926 if (!result)
3927 qWarning("QImage::save: failed to write image - %s", qPrintable(writer->errorString()));
3928#endif
3929 return result;
3930}
3931
3932/*****************************************************************************
3933 QImage stream functions
3934 *****************************************************************************/
3935#if !defined(QT_NO_DATASTREAM)
3948{
3949 if (s.version() >= 5) {
3950 if (image.isNull()) {
3951 s << (qint32) 0; // null image marker
3952 return s;
3953 } else {
3954 s << (qint32) 1;
3955 // continue ...
3956 }
3957 }
3958 QImageWriter writer(s.device(), s.version() == 1 ? "bmp" : "png");
3959 writer.write(image);
3960 return s;
3961}
3962
3974{
3975 if (s.version() >= 5) {
3976 qint32 nullMarker;
3977 s >> nullMarker;
3978 if (!nullMarker) {
3979 image = QImage(); // null image
3980 return s;
3981 }
3982 }
3983 image = QImageReader(s.device(), s.version() == 1 ? "bmp" : "png").read();
3984 if (image.isNull() && s.version() >= 5)
3985 s.setStatus(QDataStream::ReadPastEnd);
3986 return s;
3987}
3988#endif // QT_NO_DATASTREAM
3989
3990
3991
4005bool QImage::operator==(const QImage & i) const
4006{
4007 // same object, or shared?
4008 if (i.d == d)
4009 return true;
4010 if (!i.d || !d)
4011 return false;
4012
4013 // obviously different stuff?
4014 if (i.d->height != d->height || i.d->width != d->width || i.d->format != d->format || i.d->colorSpace != d->colorSpace)
4015 return false;
4016
4017 if (d->format != Format_RGB32) {
4018 if (d->format >= Format_ARGB32) { // all bits defined
4019 const int n = d->width * d->depth / 8;
4020 if (n == d->bytes_per_line && n == i.d->bytes_per_line) {
4021 if (memcmp(bits(), i.bits(), d->nbytes))
4022 return false;
4023 } else {
4024 for (int y = 0; y < d->height; ++y) {
4025 if (memcmp(scanLine(y), i.scanLine(y), n))
4026 return false;
4027 }
4028 }
4029 } else {
4030 const int w = width();
4031 const int h = height();
4032 const QList<QRgb> &colortable = d->colortable;
4033 const QList<QRgb> &icolortable = i.d->colortable;
4034 for (int y=0; y<h; ++y) {
4035 for (int x=0; x<w; ++x) {
4036 if (colortable[pixelIndex(x, y)] != icolortable[i.pixelIndex(x, y)])
4037 return false;
4038 }
4039 }
4040 }
4041 } else {
4042 //alpha channel undefined, so we must mask it out
4043 for(int l = 0; l < d->height; l++) {
4044 int w = d->width;
4045 const uint *p1 = reinterpret_cast<const uint*>(scanLine(l));
4046 const uint *p2 = reinterpret_cast<const uint*>(i.scanLine(l));
4047 while (w--) {
4048 if ((*p1++ & 0x00ffffff) != (*p2++ & 0x00ffffff))
4049 return false;
4050 }
4051 }
4052 }
4053 return true;
4054}
4055
4056
4070bool QImage::operator!=(const QImage & i) const
4071{
4072 return !(*this == i);
4073}
4074
4075
4076
4077
4087{
4088 return d ? qRound(d->dpmx) : 0;
4089}
4090
4100{
4101 return d ? qRound(d->dpmy) : 0;
4102}
4103
4117{
4118 if (!d || !x || d->dpmx == x)
4119 return;
4121
4122 if (d)
4123 d->dpmx = x;
4124}
4125
4139{
4140 if (!d || !y || d->dpmy == y)
4141 return;
4143
4144 if (d)
4145 d->dpmy = y;
4146}
4147
4157{
4158 return d ? d->offset : QPoint();
4159}
4160
4161
4171{
4172 if (!d || d->offset == p)
4173 return;
4175
4176 if (d)
4177 d->offset = p;
4178}
4179
4189{
4190 return d ? QStringList(d->text.keys()) : QStringList();
4191}
4192
4201{
4202 if (!d)
4203 return QString();
4204
4205 if (!key.isEmpty())
4206 return d->text.value(key);
4207
4208 QString tmp;
4209 for (auto it = d->text.begin(), end = d->text.end(); it != end; ++it)
4210 tmp += it.key() + ": "_L1 + it.value().simplified() + "\n\n"_L1;
4211 if (!tmp.isEmpty())
4212 tmp.chop(2); // remove final \n\n
4213 return tmp;
4214}
4215
4241{
4242 if (!d)
4243 return;
4245
4246 if (d)
4247 d->text.insert(key, value);
4248}
4249
4256{
4257 if (!d)
4258 return nullptr;
4259
4260 if (!d->paintEngine) {
4261 QPaintDevice *paintDevice = const_cast<QImage *>(this);
4263 if (platformIntegration)
4264 d->paintEngine = platformIntegration->createImagePaintEngine(paintDevice);
4265 if (!d->paintEngine)
4266 d->paintEngine = new QRasterPaintEngine(paintDevice);
4267 }
4268
4269 return d->paintEngine;
4270}
4271
4272
4279{
4280 if (!d)
4281 return 0;
4282
4283 switch (metric) {
4284 case PdmWidth:
4285 return d->width;
4286
4287 case PdmHeight:
4288 return d->height;
4289
4290 case PdmWidthMM:
4291 return qRound(d->width * 1000 / d->dpmx);
4292
4293 case PdmHeightMM:
4294 return qRound(d->height * 1000 / d->dpmy);
4295
4296 case PdmNumColors:
4297 return d->colortable.size();
4298
4299 case PdmDepth:
4300 return d->depth;
4301
4302 case PdmDpiX:
4303 return qRound(d->dpmx * 0.0254);
4304 break;
4305
4306 case PdmDpiY:
4307 return qRound(d->dpmy * 0.0254);
4308 break;
4309
4310 case PdmPhysicalDpiX:
4311 return qRound(d->dpmx * 0.0254);
4312 break;
4313
4314 case PdmPhysicalDpiY:
4315 return qRound(d->dpmy * 0.0254);
4316 break;
4317
4319 return d->devicePixelRatio;
4320 break;
4321
4323 return d->devicePixelRatio * QPaintDevice::devicePixelRatioFScale();
4324 break;
4325
4326 default:
4327 qWarning("QImage::metric(): Unhandled metric type %d", metric);
4328 break;
4329 }
4330 return 0;
4331}
4332
4333
4334
4335/*****************************************************************************
4336 QPixmap (and QImage) helper functions
4337 *****************************************************************************/
4338/*
4339 This internal function contains the common (i.e. platform independent) code
4340 to do a transformation of pixel data. It is used by QPixmap::transform() and by
4341 QImage::transform().
4342
4343 \a trueMat is the true transformation matrix (see QPixmap::trueMatrix()) and
4344 \a xoffset is an offset to the matrix.
4345
4346 \a msbfirst specifies for 1bpp images, if the MSB or LSB comes first and \a
4347 depth specifies the colordepth of the data.
4348
4349 \a dptr is a pointer to the destination data, \a dbpl specifies the bits per
4350 line for the destination data, \a p_inc is the offset that we advance for
4351 every scanline and \a dHeight is the height of the destination image.
4352
4353 \a sprt is the pointer to the source data, \a sbpl specifies the bits per
4354 line of the source data, \a sWidth and \a sHeight are the width and height of
4355 the source data.
4356*/
4357
4358#undef IWX_MSB
4359#define IWX_MSB(b) if (trigx < maxws && trigy < maxhs) { \
4360 if (*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
4361 (1 << (7-((trigx>>12)&7)))) \
4362 *dptr |= b; \
4363 } \
4364 trigx += m11; \
4365 trigy += m12;
4366 // END OF MACRO
4367#undef IWX_LSB
4368#define IWX_LSB(b) if (trigx < maxws && trigy < maxhs) { \
4369 if (*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
4370 (1 << ((trigx>>12)&7))) \
4371 *dptr |= b; \
4372 } \
4373 trigx += m11; \
4374 trigy += m12;
4375 // END OF MACRO
4376#undef IWX_PIX
4377#define IWX_PIX(b) if (trigx < maxws && trigy < maxhs) { \
4378 if ((*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
4379 (1 << (7-((trigx>>12)&7)))) == 0) \
4380 *dptr &= ~b; \
4381 } \
4382 trigx += m11; \
4383 trigy += m12;
4384 // END OF MACRO
4385bool qt_xForm_helper(const QTransform &trueMat, int xoffset, int type, int depth,
4386 uchar *dptr, qsizetype dbpl, int p_inc, int dHeight,
4387 const uchar *sptr, qsizetype sbpl, int sWidth, int sHeight)
4388{
4389 int m11 = int(trueMat.m11()*4096.0);
4390 int m12 = int(trueMat.m12()*4096.0);
4391 int m21 = int(trueMat.m21()*4096.0);
4392 int m22 = int(trueMat.m22()*4096.0);
4393 int dx = qRound(trueMat.dx()*4096.0);
4394 int dy = qRound(trueMat.dy()*4096.0);
4395
4396 int m21ydx = dx + (xoffset<<16) + (m11 + m21) / 2;
4397 int m22ydy = dy + (m12 + m22) / 2;
4398 uint trigx;
4399 uint trigy;
4400 uint maxws = sWidth<<12;
4401 uint maxhs = sHeight<<12;
4402
4403 for (int y=0; y<dHeight; y++) { // for each target scanline
4404 trigx = m21ydx;
4405 trigy = m22ydy;
4406 uchar *maxp = dptr + dbpl;
4407 if (depth != 1) {
4408 switch (depth) {
4409 case 8: // 8 bpp transform
4410 while (dptr < maxp) {
4411 if (trigx < maxws && trigy < maxhs)
4412 *dptr = *(sptr+sbpl*(trigy>>12)+(trigx>>12));
4413 trigx += m11;
4414 trigy += m12;
4415 dptr++;
4416 }
4417 break;
4418
4419 case 16: // 16 bpp transform
4420 while (dptr < maxp) {
4421 if (trigx < maxws && trigy < maxhs)
4422 *((ushort*)dptr) = *((const ushort *)(sptr+sbpl*(trigy>>12) +
4423 ((trigx>>12)<<1)));
4424 trigx += m11;
4425 trigy += m12;
4426 dptr++;
4427 dptr++;
4428 }
4429 break;
4430
4431 case 24: // 24 bpp transform
4432 while (dptr < maxp) {
4433 if (trigx < maxws && trigy < maxhs) {
4434 const uchar *p2 = sptr+sbpl*(trigy>>12) + ((trigx>>12)*3);
4435 dptr[0] = p2[0];
4436 dptr[1] = p2[1];
4437 dptr[2] = p2[2];
4438 }
4439 trigx += m11;
4440 trigy += m12;
4441 dptr += 3;
4442 }
4443 break;
4444
4445 case 32: // 32 bpp transform
4446 while (dptr < maxp) {
4447 if (trigx < maxws && trigy < maxhs)
4448 *((uint*)dptr) = *((const uint *)(sptr+sbpl*(trigy>>12) +
4449 ((trigx>>12)<<2)));
4450 trigx += m11;
4451 trigy += m12;
4452 dptr += 4;
4453 }
4454 break;
4455
4456 default: {
4457 return false;
4458 }
4459 }
4460 } else {
4461 switch (type) {
4463 while (dptr < maxp) {
4464 IWX_MSB(128);
4465 IWX_MSB(64);
4466 IWX_MSB(32);
4467 IWX_MSB(16);
4468 IWX_MSB(8);
4469 IWX_MSB(4);
4470 IWX_MSB(2);
4471 IWX_MSB(1);
4472 dptr++;
4473 }
4474 break;
4476 while (dptr < maxp) {
4477 IWX_LSB(1);
4478 IWX_LSB(2);
4479 IWX_LSB(4);
4480 IWX_LSB(8);
4481 IWX_LSB(16);
4482 IWX_LSB(32);
4483 IWX_LSB(64);
4484 IWX_LSB(128);
4485 dptr++;
4486 }
4487 break;
4488 }
4489 }
4490 m21ydx += m21;
4491 m22ydy += m22;
4492 dptr += p_inc;
4493 }
4494 return true;
4495}
4496#undef IWX_MSB
4497#undef IWX_LSB
4498#undef IWX_PIX
4499
4508{
4509 if (!d)
4510 return 0;
4511 else
4512 return (((qint64) d->ser_no) << 32) | ((qint64) d->detach_no);
4513}
4514
4524{
4525 return d && d->ref.loadRelaxed() == 1;
4526}
4527
4528
4548void QImage::setAlphaChannel(const QImage &alphaChannel)
4549{
4550 if (!d || alphaChannel.isNull())
4551 return;
4552
4553 if (d->paintEngine && d->paintEngine->isActive()) {
4554 qWarning("QImage::setAlphaChannel: "
4555 "Unable to set alpha channel while image is being painted on");
4556 return;
4557 }
4558
4559 const Format alphaFormat = qt_alphaVersionForPainting(d->format);
4560 if (d->format == alphaFormat)
4561 detach();
4562 else
4563 convertTo(alphaFormat);
4564
4565 if (isNull())
4566 return;
4567
4568 QImage sourceImage;
4569 if (alphaChannel.format() == QImage::Format_Alpha8 || (alphaChannel.d->depth == 8 && alphaChannel.isGrayscale()))
4570 sourceImage = alphaChannel;
4571 else
4572 sourceImage = alphaChannel.convertToFormat(QImage::Format_Grayscale8);
4573 if (!sourceImage.reinterpretAsFormat(QImage::Format_Alpha8))
4574 return;
4575
4576 QPainter painter(this);
4577 if (sourceImage.size() != size())
4580 painter.drawImage(rect(), sourceImage);
4581}
4582
4590{
4591 if (!d)
4592 return false;
4594 if (format.alphaUsage() == QPixelFormat::UsesAlpha)
4595 return true;
4596 if (format.colorModel() == QPixelFormat::Indexed)
4597 return d->has_alpha_clut;
4598 return false;
4599}
4600
4612{
4613 if (!d)
4614 return 0;
4615 int bpc = 0;
4616 switch (d->format) {
4618 break;
4621 bpc = 30;
4622 break;
4625 bpc = 24;
4626 break;
4628 bpc = 18;
4629 break;
4631 bpc = 15;
4632 break;
4634 bpc = 23;
4635 break;
4637 bpc = 12;
4638 break;
4641 bpc = 48;
4642 break;
4644 bpc = 96;
4645 break;
4646 default:
4647 bpc = qt_depthForFormat(d->format);
4648 break;
4649 }
4650 return bpc;
4651}
4652
4665{
4666 QImage src = *this;
4667 switch (src.format()) {
4670#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4672#endif
4674#if QT_CONFIG(raster_64bit)
4677 break;
4681 break;
4682#endif
4683#if QT_CONFIG(raster_fp)
4686 break;
4688 src.convertTo(QImage::Format_RGBX32FPx4);
4689 break;
4694 break;
4695#endif
4696 default:
4697 if (src.hasAlphaChannel())
4699 else
4700 src.convertTo(QImage::Format_RGB32);
4701 }
4703 if (!src.isNull())
4704 copyMetadata(src.d, d);
4705 return src;
4706}
4707
4709{
4710 QImage out(image.height(), image.width(), image.format());
4711 if (out.isNull())
4712 return out;
4714 if (image.colorCount() > 0)
4715 out.setColorTable(image.colorTable());
4716 int w = image.width();
4717 int h = image.height();
4718 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][2];
4719 if (memrotate) {
4720 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4721 } else {
4722 for (int y=0; y<h; ++y) {
4723 if (image.colorCount())
4724 for (int x=0; x<w; ++x)
4725 out.setPixel(h-y-1, x, image.pixelIndex(x, y));
4726 else
4727 for (int x=0; x<w; ++x)
4728 out.setPixel(h-y-1, x, image.pixel(x, y));
4729 }
4730 }
4731 return out;
4732}
4733
4735{
4736 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][1];
4737 if (!memrotate)
4738 return image.mirrored(true, true);
4739
4740 QImage out(image.width(), image.height(), image.format());
4741 if (out.isNull())
4742 return out;
4744 if (image.colorCount() > 0)
4745 out.setColorTable(image.colorTable());
4746 int w = image.width();
4747 int h = image.height();
4748 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4749 return out;
4750}
4751
4753{
4754 QImage out(image.height(), image.width(), image.format());
4755 if (out.isNull())
4756 return out;
4758 if (image.colorCount() > 0)
4759 out.setColorTable(image.colorTable());
4760 int w = image.width();
4761 int h = image.height();
4762 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][0];
4763 if (memrotate) {
4764 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4765 } else {
4766 for (int y=0; y<h; ++y) {
4767 if (image.colorCount())
4768 for (int x=0; x<w; ++x)
4769 out.setPixel(y, w-x-1, image.pixelIndex(x, y));
4770 else
4771 for (int x=0; x<w; ++x)
4772 out.setPixel(y, w-x-1, image.pixel(x, y));
4773 }
4774 }
4775 return out;
4776}
4777
4803{
4804 if (!d)
4805 return QImage();
4806
4807 Q_TRACE_PARAM_REPLACE(const QTransform &, double[9]);
4808 Q_TRACE_SCOPE(QImage_transformed, QList<double>({matrix.m11(), matrix.m12(), matrix.m13(),
4809 matrix.m21(), matrix.m22(), matrix.m23(),
4810 matrix.m31(), matrix.m32(), matrix.m33()}).data(), mode);
4811
4812 // source image data
4813 const int ws = width();
4814 const int hs = height();
4815
4816 // target image data
4817 int wd;
4818 int hd;
4819
4820 // compute size of target image
4821 QTransform mat = trueMatrix(matrix, ws, hs);
4822 bool complex_xform = false;
4823 bool scale_xform = false;
4824 bool nonpaintable_scale_xform = false;
4825 if (mat.type() <= QTransform::TxScale) {
4826 if (mat.type() == QTransform::TxNone) // identity matrix
4827 return *this;
4828 else if (mat.m11() == -1. && mat.m22() == -1.)
4829 return rotated180(*this);
4830
4831 hd = qRound(qAbs(mat.m22()) * hs);
4832 wd = qRound(qAbs(mat.m11()) * ws);
4833 scale_xform = true;
4834 // The paint-based scaling is only bilinear, and has problems
4835 // with scaling smoothly more than 2x down.
4836 if (hd * 2 < hs || wd * 2 < ws)
4837 nonpaintable_scale_xform = true;
4838 } else {
4839 if (mat.type() <= QTransform::TxRotate && mat.m11() == 0 && mat.m22() == 0) {
4840 if (mat.m12() == 1. && mat.m21() == -1.)
4841 return rotated90(*this);
4842 else if (mat.m12() == -1. && mat.m21() == 1.)
4843 return rotated270(*this);
4844 }
4845
4846 QPolygonF a(QRectF(0, 0, ws, hs));
4847 a = mat.map(a);
4848 QRect r = a.boundingRect().toAlignedRect();
4849 wd = r.width();
4850 hd = r.height();
4851 complex_xform = true;
4852 }
4853
4854 if (wd == 0 || hd == 0)
4855 return QImage();
4856
4857 if (scale_xform && mode == Qt::SmoothTransformation) {
4858 switch (format()) {
4861#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4863#endif
4865#if QT_CONFIG(raster_64bit)
4868#endif
4869 // Use smoothScaled for scaling when we can do so without conversion.
4870 if (mat.m11() > 0.0F && mat.m22() > 0.0F)
4871 return smoothScaled(wd, hd);
4872 break;
4873 default:
4874 break;
4875 }
4876 // Otherwise only use it when the scaling factor demands it, or the image is large enough to scale multi-threaded
4877 if (nonpaintable_scale_xform
4878#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
4879 || (ws * hs) >= (1<<20)
4880#endif
4881 ) {
4882 QImage scaledImage;
4883 if (mat.m11() < 0.0F && mat.m22() < 0.0F) { // horizontal/vertical flip
4884 scaledImage = smoothScaled(wd, hd).mirrored(true, true);
4885 } else if (mat.m11() < 0.0F) { // horizontal flip
4886 scaledImage = smoothScaled(wd, hd).mirrored(true, false);
4887 } else if (mat.m22() < 0.0F) { // vertical flip
4888 scaledImage = smoothScaled(wd, hd).mirrored(false, true);
4889 } else { // no flipping
4890 scaledImage = smoothScaled(wd, hd);
4891 }
4892
4893 switch (format()) {
4897 return scaledImage;
4898 default:
4899 return scaledImage.convertToFormat(format());
4900 }
4901 }
4902 }
4903
4904 int bpp = depth();
4905
4906 qsizetype sbpl = bytesPerLine();
4907 const uchar *sptr = bits();
4908
4909 QImage::Format target_format = d->format;
4910
4911 if (complex_xform || mode == Qt::SmoothTransformation) {
4912 if (d->format < QImage::Format_RGB32 || (!hasAlphaChannel() && complex_xform)) {
4913 target_format = qt_alphaVersion(d->format);
4914 }
4915 }
4916
4917 QImage dImage(wd, hd, target_format);
4919
4920 if (target_format == QImage::Format_MonoLSB
4921 || target_format == QImage::Format_Mono
4922 || target_format == QImage::Format_Indexed8) {
4923 dImage.d->colortable = d->colortable;
4924 dImage.d->has_alpha_clut = d->has_alpha_clut | complex_xform;
4925 }
4926
4927 // initizialize the data
4928 if (target_format == QImage::Format_Indexed8) {
4929 if (dImage.d->colortable.size() < 256) {
4930 // colors are left in the color table, so pick that one as transparent
4931 dImage.d->colortable.append(0x0);
4932 memset(dImage.bits(), dImage.d->colortable.size() - 1, dImage.d->nbytes);
4933 } else {
4934 memset(dImage.bits(), 0, dImage.d->nbytes);
4935 }
4936 } else
4937 memset(dImage.bits(), 0x00, dImage.d->nbytes);
4938
4939 if (target_format >= QImage::Format_RGB32) {
4940 // Prevent QPainter from applying devicePixelRatio corrections
4941 QImage sImage = (devicePixelRatio() != 1) ? QImage(constBits(), width(), height(), format()) : *this;
4942 if (sImage.d != d
4943 && (d->format == QImage::Format_MonoLSB
4944 || d->format == QImage::Format_Mono
4945 || d->format == QImage::Format_Indexed8)) {
4946 sImage.d->colortable = d->colortable;
4947 sImage.d->has_alpha_clut = d->has_alpha_clut;
4948 }
4949
4950 Q_ASSERT(sImage.devicePixelRatio() == 1);
4951 Q_ASSERT(sImage.devicePixelRatio() == dImage.devicePixelRatio());
4952
4953 QPainter p(&dImage);
4955 p.setRenderHint(QPainter::Antialiasing);
4956 p.setRenderHint(QPainter::SmoothPixmapTransform);
4957 }
4958 p.setTransform(mat);
4959 p.drawImage(QPoint(0, 0), sImage);
4960 } else {
4961 bool invertible;
4962 mat = mat.inverted(&invertible); // invert matrix
4963 if (!invertible) // error, return null image
4964 return QImage();
4965
4966 // create target image (some of the code is from QImage::copy())
4968 qsizetype dbpl = dImage.bytesPerLine();
4969 qt_xForm_helper(mat, 0, type, bpp, dImage.bits(), dbpl, 0, hd, sptr, sbpl, ws, hs);
4970 }
4971 copyMetadata(dImage.d, d);
4972
4973 return dImage;
4974}
4975
4998{
4999 const QRectF rect(0, 0, w, h);
5000 const QRect mapped = matrix.mapRect(rect).toAlignedRect();
5001 const QPoint delta = mapped.topLeft();
5002 return matrix * QTransform().translate(-delta.x(), -delta.y());
5003}
5004
5012void QImage::setColorSpace(const QColorSpace &colorSpace)
5013{
5014 if (!d)
5015 return;
5016 if (d->colorSpace == colorSpace)
5017 return;
5019 return;
5020
5021 detachMetadata(false);
5022 if (d)
5023 d->colorSpace = colorSpace;
5024}
5025
5039{
5040 if (!d || !d->colorSpace.isValid())
5041 return;
5042 if (!colorSpace.isValidTarget()) {
5043 qWarning() << "QImage::convertToColorSpace: Output colorspace is not valid";
5044 return;
5045 }
5046 if (d->colorSpace == colorSpace)
5047 return;
5048 if (!qt_compatibleColorModel(pixelFormat().colorModel(), colorSpace.colorModel())) {
5050 return;
5051 }
5052 applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace));
5053 if (d->ref.loadRelaxed() != 1)
5054 detachMetadata(false);
5055 d->colorSpace = colorSpace;
5056}
5057
5071void QImage::convertToColorSpace(const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags)
5072{
5073 if (!d || !d->colorSpace.isValid())
5074 return;
5075 if (!colorSpace.isValidTarget()) {
5076 qWarning() << "QImage::convertToColorSpace: Output colorspace is not valid";
5077 return;
5078 }
5080 qWarning() << "QImage::convertToColorSpace: Color space is not compatible with format";
5081 return;
5082 }
5083
5084 if (d->colorSpace == colorSpace)
5085 return convertTo(format, flags);
5086 applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace), format, flags);
5087 d->colorSpace = colorSpace;
5088}
5089
5105{
5106 if (!d || !d->colorSpace.isValid())
5107 return QImage();
5108 if (!colorSpace.isValidTarget()) {
5109 qWarning() << "QImage::convertedToColorSpace: Output colorspace is not valid";
5110 return QImage();
5111 }
5112 if (d->colorSpace == colorSpace)
5113 return *this;
5114 QImage image = colorTransformed(d->colorSpace.transformationToColorSpace(colorSpace));
5115 image.setColorSpace(colorSpace);
5116 return image;
5117}
5118
5131QImage QImage::convertedToColorSpace(const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags) const
5132{
5133 if (!d || !d->colorSpace.isValid())
5134 return QImage();
5135 if (!colorSpace.isValidTarget()) {
5136 qWarning() << "QImage::convertedToColorSpace: Output colorspace is not valid";
5137 return QImage();
5138 }
5140 qWarning() << "QImage::convertedToColorSpace: Color space is not compatible with format";
5141 return QImage();
5142 }
5143 if (d->colorSpace == colorSpace)
5144 return convertedTo(format, flags);
5145 QImage image = colorTransformed(d->colorSpace.transformationToColorSpace(colorSpace), format, flags);
5146 image.setColorSpace(colorSpace);
5147 return image;
5148}
5149
5156{
5157 if (!d)
5158 return QColorSpace();
5159 return d->colorSpace;
5160}
5161
5168{
5169 if (transform.isIdentity())
5170 return;
5171
5172 if (!qt_compatibleColorModel(pixelFormat().colorModel(), QColorTransformPrivate::get(transform)->colorSpaceIn->colorModel) ||
5173 !qt_compatibleColorModel(pixelFormat().colorModel(), QColorTransformPrivate::get(transform)->colorSpaceOut->colorModel)) {
5174 qWarning() << "QImage::applyColorTransform can not apply format switching transform without switching format";
5175 return;
5176 }
5177
5178 detach();
5179 if (!d)
5180 return;
5181 if (pixelFormat().colorModel() == QPixelFormat::Indexed) {
5182 for (int i = 0; i < d->colortable.size(); ++i)
5183 d->colortable[i] = transform.map(d->colortable[i]);
5184 return;
5185 }
5186 QImage::Format oldFormat = format();
5187 if (qt_fpColorPrecision(oldFormat)) {
5188 if (oldFormat != QImage::Format_RGBX32FPx4 && oldFormat != QImage::Format_RGBA32FPx4
5191 } else if (depth() > 32) {
5192 if (oldFormat != QImage::Format_RGBX64 && oldFormat != QImage::Format_RGBA64
5195 } else if (oldFormat != QImage::Format_ARGB32 && oldFormat != QImage::Format_RGB32
5196 && oldFormat != QImage::Format_ARGB32_Premultiplied && oldFormat != QImage::Format_CMYK8888
5197 && oldFormat != QImage::Format_Grayscale8 && oldFormat != QImage::Format_Grayscale16) {
5198 if (hasAlphaChannel())
5200 else
5202 }
5203
5204 QColorTransformPrivate::TransformFlags flags = QColorTransformPrivate::Unpremultiplied;
5205 switch (format()) {
5210 break;
5211 case Format_Grayscale8:
5212 case Format_Grayscale16:
5213 case Format_RGB32:
5214 case Format_CMYK8888:
5215 case Format_RGBX64:
5216 case Format_RGBX32FPx4:
5218 break;
5219 case Format_ARGB32:
5220 case Format_RGBA64:
5221 case Format_RGBA32FPx4:
5222 break;
5223 default:
5224 Q_UNREACHABLE();
5225 }
5226
5227 std::function<void(int,int)> transformSegment;
5228
5229 if (format() == Format_Grayscale8) {
5230 transformSegment = [&](int yStart, int yEnd) {
5231 for (int y = yStart; y < yEnd; ++y) {
5232 uint8_t *scanline = reinterpret_cast<uint8_t *>(d->data + y * d->bytes_per_line);
5233 QColorTransformPrivate::get(transform)->applyGray(scanline, scanline, width(), flags);
5234 }
5235 };
5236 } else if (format() == Format_Grayscale16) {
5237 transformSegment = [&](int yStart, int yEnd) {
5238 for (int y = yStart; y < yEnd; ++y) {
5239 uint16_t *scanline = reinterpret_cast<uint16_t *>(d->data + y * d->bytes_per_line);
5240 QColorTransformPrivate::get(transform)->applyGray(scanline, scanline, width(), flags);
5241 }
5242 };
5243 } else if (qt_fpColorPrecision(format())) {
5244 transformSegment = [&](int yStart, int yEnd) {
5245 for (int y = yStart; y < yEnd; ++y) {
5246 QRgbaFloat32 *scanline = reinterpret_cast<QRgbaFloat32 *>(d->data + y * d->bytes_per_line);
5247 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5248 }
5249 };
5250 } else if (depth() > 32) {
5251 transformSegment = [&](int yStart, int yEnd) {
5252 for (int y = yStart; y < yEnd; ++y) {
5253 QRgba64 *scanline = reinterpret_cast<QRgba64 *>(d->data + y * d->bytes_per_line);
5254 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5255 }
5256 };
5257 } else if (oldFormat == QImage::Format_CMYK8888) {
5258 transformSegment = [&](int yStart, int yEnd) {
5259 for (int y = yStart; y < yEnd; ++y) {
5260 QCmyk32 *scanline = reinterpret_cast<QCmyk32 *>(d->data + y * d->bytes_per_line);
5261 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5262 }
5263 };
5264 } else {
5265 transformSegment = [&](int yStart, int yEnd) {
5266 for (int y = yStart; y < yEnd; ++y) {
5267 QRgb *scanline = reinterpret_cast<QRgb *>(d->data + y * d->bytes_per_line);
5268 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5269 }
5270 };
5271 }
5272
5273#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
5274 int segments = (qsizetype(width()) * height()) >> 16;
5275 segments = std::min(segments, height());
5277 if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
5278 QSemaphore semaphore;
5279 int y = 0;
5280 for (int i = 0; i < segments; ++i) {
5281 int yn = (height() - y) / (segments - i);
5282 threadPool->start([&, y, yn]() {
5283 transformSegment(y, y + yn);
5284 semaphore.release(1);
5285 });
5286 y += yn;
5287 }
5288 semaphore.acquire(segments);
5289 } else
5290#endif
5291 transformSegment(0, height());
5292
5293 if (oldFormat != format())
5294 *this = std::move(*this).convertToFormat(oldFormat);
5295}
5296
5305void QImage::applyColorTransform(const QColorTransform &transform, QImage::Format toFormat, Qt::ImageConversionFlags flags)
5306{
5307 if (!d)
5308 return;
5309 if (transform.isIdentity())
5310 return convertTo(toFormat, flags);
5311
5312 *this = colorTransformed(transform, toFormat, flags);
5313}
5314
5328{
5329 if (!d)
5330 return QImage();
5331 if (transform.isIdentity())
5332 return *this;
5333
5334 QColorSpace::ColorModel inColorModel = QColorTransformPrivate::get(transform)->colorSpaceIn->colorModel;
5335 QColorSpace::ColorModel outColorModel = QColorTransformPrivate::get(transform)->colorSpaceOut->colorModel;
5336 if (!qt_compatibleColorModel(pixelFormat().colorModel(), inColorModel)) {
5337 qWarning() << "QImage::colorTransformed: Invalid input color space for transform";
5338 return QImage();
5339 }
5340 if (!qt_compatibleColorModel(pixelFormat().colorModel(), outColorModel)) {
5341 // All model switching transforms are opaque in at least one end.
5342 switch (outColorModel) {
5348 return colorTransformed(transform, QImage::Format_CMYK8888);
5350 break;
5351 }
5352 return QImage();
5353 }
5354
5355 QImage image = copy();
5356 image.applyColorTransform(transform);
5357 return image;
5358}
5359
5361{
5362 switch (f) {
5366 return true;
5367 default:
5368 break;
5369 }
5370 return false;
5371}
5372
5374{
5375 switch (f) {
5379 return true;
5380 default:
5381 break;
5382 }
5383 return false;
5384}
5385
5387{
5388 switch (f) {
5392 return true;
5393 default:
5394 break;
5395 }
5396 return false;
5397}
5398
5412QImage QImage::colorTransformed(const QColorTransform &transform, QImage::Format toFormat, Qt::ImageConversionFlags flags) const &
5413{
5414 if (!d)
5415 return QImage();
5416 if (toFormat == QImage::Format_Invalid)
5417 toFormat = format();
5418 if (transform.isIdentity())
5419 return convertedTo(toFormat, flags);
5420
5421 QColorSpace::ColorModel inColorModel = QColorTransformPrivate::get(transform)->colorSpaceIn->colorModel;
5422 QColorSpace::ColorModel outColorModel = QColorTransformPrivate::get(transform)->colorSpaceOut->colorModel;
5423 if (!qt_compatibleColorModel(pixelFormat().colorModel(), inColorModel)) {
5424 qWarning() << "QImage::colorTransformed: Invalid input color space for transform";
5425 return QImage();
5426 }
5427 if (!qt_compatibleColorModel(toPixelFormat(toFormat).colorModel(), outColorModel)) {
5428 qWarning() << "QImage::colorTransformed: Invalid output color space for transform";
5429 return QImage();
5430 }
5431
5432 QImage fromImage = *this;
5433
5434 QImage::Format tmpFormat = toFormat;
5435 switch (toFormat) {
5448 // can be output natively
5449 break;
5457 tmpFormat = QImage::Format_RGB32;
5458 break;
5468 tmpFormat = QImage::Format_ARGB32;
5469 break;
5472 tmpFormat = QImage::Format_RGBX64;
5473 break;
5476 tmpFormat = QImage::Format_RGBA64;
5477 break;
5481 tmpFormat = QImage::Format_RGBA32FPx4;
5482 break;
5484 return convertedTo(QImage::Format_Alpha8);
5487 Q_UNREACHABLE();
5488 break;
5489 }
5490 QColorSpace::ColorModel inColorData = qt_csColorData(pixelFormat().colorModel());
5491 QColorSpace::ColorModel outColorData = qt_csColorData(toPixelFormat(toFormat).colorModel());
5492 // Ensure only precision increasing transforms
5493 if (inColorData != outColorData) {
5494 if (fromImage.format() == QImage::Format_Grayscale8 && outColorData == QColorSpace::ColorModel::Rgb)
5495 tmpFormat = QImage::Format_RGB32;
5496 else if (tmpFormat == QImage::Format_Grayscale8 && qt_highColorPrecision(fromImage.format()))
5497 tmpFormat = QImage::Format_Grayscale16;
5498 else if (fromImage.format() == QImage::Format_Grayscale16 && outColorData == QColorSpace::ColorModel::Rgb)
5499 tmpFormat = QImage::Format_RGBX64;
5500 } else {
5501 if (tmpFormat == QImage::Format_Grayscale8 && fromImage.format() == QImage::Format_Grayscale16)
5502 tmpFormat = QImage::Format_Grayscale16;
5503 else if (qt_fpColorPrecision(fromImage.format()) && !qt_fpColorPrecision(tmpFormat))
5504 tmpFormat = QImage::Format_RGBA32FPx4;
5505 else if (isRgb32Data(tmpFormat) && qt_highColorPrecision(fromImage.format(), true))
5506 tmpFormat = QImage::Format_RGBA64;
5507 }
5508
5509 QImage toImage(size(), tmpFormat);
5510 copyMetadata(&toImage, *this);
5511
5512 std::function<void(int, int)> transformSegment;
5513 QColorTransformPrivate::TransformFlags transFlags = QColorTransformPrivate::Unpremultiplied;
5514
5515 if (inColorData != outColorData) {
5516 // Needs color model switching transform
5517 if (inColorData == QColorSpace::ColorModel::Gray && outColorData == QColorSpace::ColorModel::Rgb) {
5518 // Gray -> RGB
5520 transformSegment = [&](int yStart, int yEnd) {
5521 for (int y = yStart; y < yEnd; ++y) {
5522 const quint8 *in_scanline = reinterpret_cast<const quint8 *>(d->data + y * d->bytes_per_line);
5523 QRgb *out_scanline = reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
5524 QColorTransformPrivate::get(transform)->applyGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5525 }
5526 };
5527 } else {
5528 transformSegment = [&](int yStart, int yEnd) {
5529 for (int y = yStart; y < yEnd; ++y) {
5530 const quint16 *in_scanline = reinterpret_cast<const quint16 *>(d->data + y * d->bytes_per_line);
5531 QRgba64 *out_scanline = reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5532 QColorTransformPrivate::get(transform)->applyGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5533 }
5534 };
5535 }
5536 } else if (inColorData == QColorSpace::ColorModel::Gray && outColorData == QColorSpace::ColorModel::Cmyk) {
5537 // Gray -> CMYK
5539 transformSegment = [&](int yStart, int yEnd) {
5540 for (int y = yStart; y < yEnd; ++y) {
5541 const quint8 *in_scanline = reinterpret_cast<const quint8 *>(d->data + y * d->bytes_per_line);
5542 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5543 QColorTransformPrivate::get(transform)->applyGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5544 }
5545 };
5546 } else {
5547 transformSegment = [&](int yStart, int yEnd) {
5548 for (int y = yStart; y < yEnd; ++y) {
5549 const quint16 *in_scanline = reinterpret_cast<const quint16 *>(d->data + y * d->bytes_per_line);
5550 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5551 QColorTransformPrivate::get(transform)->applyGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5552 }
5553 };
5554 }
5555 } else if (inColorData == QColorSpace::ColorModel::Rgb && outColorData == QColorSpace::ColorModel::Gray) {
5556 // RGB -> Gray
5557 if (tmpFormat == QImage::Format_Grayscale8) {
5559 transformSegment = [&](int yStart, int yEnd) {
5560 for (int y = yStart; y < yEnd; ++y) {
5561 const QRgb *in_scanline = reinterpret_cast<const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5562 quint8 *out_scanline = reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
5563 QColorTransformPrivate::get(transform)->applyReturnGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5564 }
5565 };
5566 } else {
5568 transformSegment = [&](int yStart, int yEnd) {
5569 for (int y = yStart; y < yEnd; ++y) {
5570 const QRgba64 *in_scanline = reinterpret_cast<const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5571 quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5572 QColorTransformPrivate::get(transform)->applyReturnGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5573 }
5574 };
5575 }
5576 } else if (inColorData == QColorSpace::ColorModel::Cmyk && outColorData == QColorSpace::ColorModel::Gray) {
5577 // CMYK -> Gray
5578 if (tmpFormat == QImage::Format_Grayscale8) {
5579 transformSegment = [&](int yStart, int yEnd) {
5580 for (int y = yStart; y < yEnd; ++y) {
5581 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5582 quint8 *out_scanline = reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
5583 QColorTransformPrivate::get(transform)->applyReturnGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5584 }
5585 };
5586 } else {
5587 transformSegment = [&](int yStart, int yEnd) {
5588 for (int y = yStart; y < yEnd; ++y) {
5589 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5590 quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5591 QColorTransformPrivate::get(transform)->applyReturnGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5592 }
5593 };
5594 }
5595 } else if (inColorData == QColorSpace::ColorModel::Cmyk && outColorData == QColorSpace::ColorModel::Rgb) {
5596 // CMYK -> RGB
5597 if (isRgb32Data(tmpFormat) ) {
5598 transformSegment = [&](int yStart, int yEnd) {
5599 for (int y = yStart; y < yEnd; ++y) {
5600 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5601 QRgb *out_scanline = reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
5603 }
5604 };
5605 } else if (isRgb64Data(tmpFormat)) {
5606 transformSegment = [&](int yStart, int yEnd) {
5607 for (int y = yStart; y < yEnd; ++y) {
5608 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5609 QRgba64 *out_scanline = reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5611 }
5612 };
5613 } else {
5614 Q_ASSERT(isRgb32fpx4Data(tmpFormat));
5615 transformSegment = [&](int yStart, int yEnd) {
5616 for (int y = yStart; y < yEnd; ++y) {
5617 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5618 QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5620 }
5621 };
5622 }
5623 } else if (inColorData == QColorSpace::ColorModel::Rgb && outColorData == QColorSpace::ColorModel::Cmyk) {
5624 // RGB -> CMYK
5625 if (!fromImage.hasAlphaChannel())
5627 else if (qPixelLayouts[fromImage.format()].premultiplied)
5629 if (isRgb32Data(fromImage.format()) ) {
5630 transformSegment = [&](int yStart, int yEnd) {
5631 for (int y = yStart; y < yEnd; ++y) {
5632 const QRgb *in_scanline = reinterpret_cast<const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5633 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5634 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5635 }
5636 };
5637 } else if (isRgb64Data(fromImage.format())) {
5638 transformSegment = [&](int yStart, int yEnd) {
5639 for (int y = yStart; y < yEnd; ++y) {
5640 const QRgba64 *in_scanline = reinterpret_cast<const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5641 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5642 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5643 }
5644 };
5645 } else {
5646 Q_ASSERT(isRgb32fpx4Data(fromImage.format()));
5647 transformSegment = [&](int yStart, int yEnd) {
5648 for (int y = yStart; y < yEnd; ++y) {
5649 const QRgbaFloat32 *in_scanline = reinterpret_cast<const QRgbaFloat32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5650 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5651 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5652 }
5653 };
5654 }
5655 } else {
5656 Q_UNREACHABLE();
5657 }
5658 } else {
5659 // Conversion on same color model
5660 if (pixelFormat().colorModel() == QPixelFormat::Indexed) {
5661 for (int i = 0; i < d->colortable.size(); ++i)
5662 fromImage.d->colortable[i] = transform.map(d->colortable[i]);
5663 return fromImage.convertedTo(toFormat, flags);
5664 }
5665
5666 QImage::Format oldFormat = format();
5667 if (qt_fpColorPrecision(oldFormat)) {
5668 if (oldFormat != QImage::Format_RGBX32FPx4 && oldFormat != QImage::Format_RGBA32FPx4
5671 } else if (qt_highColorPrecision(oldFormat, true)) {
5672 if (oldFormat != QImage::Format_RGBX64 && oldFormat != QImage::Format_RGBA64
5675 } else if (oldFormat != QImage::Format_ARGB32 && oldFormat != QImage::Format_RGB32
5676 && oldFormat != QImage::Format_ARGB32_Premultiplied && oldFormat != QImage::Format_CMYK8888
5677 && oldFormat != QImage::Format_Grayscale8 && oldFormat != QImage::Format_Grayscale16) {
5678 if (hasAlphaChannel())
5680 else
5682 }
5683
5684 if (!fromImage.hasAlphaChannel())
5686 else if (qPixelLayouts[fromImage.format()].premultiplied)
5688
5689 if (fromImage.format() == Format_Grayscale8) {
5690 transformSegment = [&](int yStart, int yEnd) {
5691 for (int y = yStart; y < yEnd; ++y) {
5692 const quint8 *in_scanline = reinterpret_cast<const quint8 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5693 if (tmpFormat == Format_Grayscale8) {
5694 quint8 *out_scanline = reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
5695 QColorTransformPrivate::get(transform)->applyGray(out_scanline, in_scanline, width(), transFlags);
5696 } else {
5697 Q_ASSERT(tmpFormat == Format_Grayscale16);
5698 quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5699 QColorTransformPrivate::get(transform)->applyGray(out_scanline, in_scanline, width(), transFlags);
5700 }
5701 }
5702 };
5703 } else if (fromImage.format() == Format_Grayscale16) {
5704 transformSegment = [&](int yStart, int yEnd) {
5705 for (int y = yStart; y < yEnd; ++y) {
5706 const quint16 *in_scanline = reinterpret_cast<const quint16 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5707 quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5708 QColorTransformPrivate::get(transform)->applyGray(out_scanline, in_scanline, width(), transFlags);
5709 }
5710 };
5711 } else if (fromImage.format() == Format_CMYK8888) {
5712 Q_ASSERT(tmpFormat == Format_CMYK8888);
5713 transformSegment = [&](int yStart, int yEnd) {
5714 for (int y = yStart; y < yEnd; ++y) {
5715 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5716 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5717 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5718 }
5719 };
5720 } else if (isRgb32fpx4Data(fromImage.format())) {
5721 Q_ASSERT(isRgb32fpx4Data(tmpFormat));
5722 transformSegment = [&](int yStart, int yEnd) {
5723 for (int y = yStart; y < yEnd; ++y) {
5724 const QRgbaFloat32 *in_scanline = reinterpret_cast<const QRgbaFloat32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5725 QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5726 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5727 }
5728 };
5729 } else if (isRgb64Data(fromImage.format())) {
5730 transformSegment = [&](int yStart, int yEnd) {
5731 for (int y = yStart; y < yEnd; ++y) {
5732 const QRgba64 *in_scanline = reinterpret_cast<const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5733 if (isRgb32fpx4Data(tmpFormat)) {
5734 QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5735 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5736 } else {
5737 Q_ASSERT(isRgb64Data(tmpFormat));
5738 QRgba64 *out_scanline = reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5739 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5740 }
5741 }
5742 };
5743 } else {
5744 transformSegment = [&](int yStart, int yEnd) {
5745 for (int y = yStart; y < yEnd; ++y) {
5746 const QRgb *in_scanline = reinterpret_cast<const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5747 if (isRgb32fpx4Data(tmpFormat)) {
5748 QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5749 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5750 } else if (isRgb64Data(tmpFormat)) {
5751 QRgba64 *out_scanline = reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5752 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5753 } else {
5754 Q_ASSERT(isRgb32Data(tmpFormat));
5755 QRgb *out_scanline = reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
5756 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5757 }
5758 }
5759 };
5760 }
5761 }
5762
5763#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
5764 int segments = (qsizetype(width()) * height()) >> 16;
5765 segments = std::min(segments, height());
5767 if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
5768 QSemaphore semaphore;
5769 int y = 0;
5770 for (int i = 0; i < segments; ++i) {
5771 int yn = (height() - y) / (segments - i);
5772 threadPool->start([&, y, yn]() {
5773 transformSegment(y, y + yn);
5774 semaphore.release(1);
5775 });
5776 y += yn;
5777 }
5778 semaphore.acquire(segments);
5779 } else
5780#endif
5781 transformSegment(0, height());
5782
5783 if (tmpFormat != toFormat)
5784 toImage.convertTo(toFormat);
5785
5786 return toImage;
5787}
5788
5798{
5799 if (!d)
5800 return QImage();
5801
5802 QColorSpace::ColorModel inColorModel = QColorTransformPrivate::get(transform)->colorSpaceIn->colorModel;
5803 QColorSpace::ColorModel outColorModel = QColorTransformPrivate::get(transform)->colorSpaceOut->colorModel;
5804 if (!qt_compatibleColorModel(pixelFormat().colorModel(), inColorModel)) {
5805 qWarning() << "QImage::colorTransformed: Invalid input color space for transform";
5806 return QImage();
5807 }
5808 if (!qt_compatibleColorModel(pixelFormat().colorModel(), outColorModel)) {
5809 // There is currently no inplace conversion of both colorspace and format, so just use the normal version.
5810 switch (outColorModel) {
5816 return colorTransformed(transform, QImage::Format_CMYK8888);
5818 break;
5819 }
5820 return QImage();
5821 }
5822
5823 applyColorTransform(transform);
5824 return std::move(*this);
5825}
5826
5836{
5837 // There is currently no inplace conversion of both colorspace and format, so just use the normal version.
5838 return colorTransformed(transform, format, flags);
5839}
5840
5841bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags flags)
5842{
5843 if (format == newFormat)
5844 return true;
5845
5846 // No in-place conversion if we have to detach
5847 if (ref.loadRelaxed() > 1 || !own_data)
5848 return false;
5849
5851 if (converter)
5852 return converter(this, flags);
5854 // Convert inplace generic, but only if there are no direct converters,
5855 // any direct ones are probably better even if not inplace.
5856 if (qt_highColorPrecision(newFormat, !qPixelLayouts[newFormat].hasAlphaChannel)
5857 && qt_highColorPrecision(format, !qPixelLayouts[format].hasAlphaChannel)) {
5858#if QT_CONFIG(raster_fp)
5860 return convert_generic_inplace_over_rgba32f(this, newFormat, flags);
5861#endif
5862 return convert_generic_inplace_over_rgb64(this, newFormat, flags);
5863 }
5864 return convert_generic_inplace(this, newFormat, flags);
5865 }
5866 return false;
5867}
5868
5879#ifndef QT_NO_DEBUG_STREAM
5881{
5882 QDebugStateSaver saver(dbg);
5883 dbg.nospace();
5884 dbg.noquote();
5885 dbg << "QImage(";
5886 if (i.isNull()) {
5887 dbg << "null";
5888 } else {
5889 dbg << i.size() << ",format=" << i.format() << ",depth=" << i.depth();
5890 if (i.colorCount())
5891 dbg << ",colorCount=" << i.colorCount();
5892 const int bytesPerLine = i.bytesPerLine();
5893 dbg << ",devicePixelRatio=" << i.devicePixelRatio()
5894 << ",bytesPerLine=" << bytesPerLine << ",sizeInBytes=" << i.sizeInBytes();
5895 if (dbg.verbosity() > 2 && i.height() > 0) {
5896 const int outputLength = qMin(bytesPerLine, 24);
5897 dbg << ",line0="
5898 << QByteArray(reinterpret_cast<const char *>(i.scanLine(0)), outputLength).toHex()
5899 << "...";
5900 }
5901 }
5902 dbg << ')';
5903 return dbg;
5904}
5905#endif
5906
5907static constexpr QPixelFormat pixelformats[] = {
5908 //QImage::Format_Invalid:
5909 QPixelFormat(),
5910 //QImage::Format_Mono:
5912 /*RED*/ 1,
5913 /*GREEN*/ 0,
5914 /*BLUE*/ 0,
5915 /*FOURTH*/ 0,
5916 /*FIFTH*/ 0,
5917 /*ALPHA*/ 0,
5918 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5919 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5920 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5921 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5922 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5923 //QImage::Format_MonoLSB:
5925 /*RED*/ 1,
5926 /*GREEN*/ 0,
5927 /*BLUE*/ 0,
5928 /*FOURTH*/ 0,
5929 /*FIFTH*/ 0,
5930 /*ALPHA*/ 0,
5931 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5932 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5933 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5934 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5935 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5936 //QImage::Format_Indexed8:
5938 /*RED*/ 8,
5939 /*GREEN*/ 0,
5940 /*BLUE*/ 0,
5941 /*FOURTH*/ 0,
5942 /*FIFTH*/ 0,
5943 /*ALPHA*/ 0,
5944 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5945 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5946 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5947 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5948 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5949 //QImage::Format_RGB32:
5951 /*RED*/ 8,
5952 /*GREEN*/ 8,
5953 /*BLUE*/ 8,
5954 /*FOURTH*/ 0,
5955 /*FIFTH*/ 0,
5956 /*ALPHA*/ 8,
5957 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5958 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5959 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5960 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5961 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5962 //QImage::Format_ARGB32:
5964 /*RED*/ 8,
5965 /*GREEN*/ 8,
5966 /*BLUE*/ 8,
5967 /*FOURTH*/ 0,
5968 /*FIFTH*/ 0,
5969 /*ALPHA*/ 8,
5970 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5971 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5972 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5973 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5974 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5975 //QImage::Format_ARGB32_Premultiplied:
5977 /*RED*/ 8,
5978 /*GREEN*/ 8,
5979 /*BLUE*/ 8,
5980 /*FOURTH*/ 0,
5981 /*FIFTH*/ 0,
5982 /*ALPHA*/ 8,
5983 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5984 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5985 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5986 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5987 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5988 //QImage::Format_RGB16:
5990 /*RED*/ 5,
5991 /*GREEN*/ 6,
5992 /*BLUE*/ 5,
5993 /*FOURTH*/ 0,
5994 /*FIFTH*/ 0,
5995 /*ALPHA*/ 0,
5996 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5997 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5998 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5999 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6000 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6001 //QImage::Format_ARGB8565_Premultiplied:
6003 /*RED*/ 5,
6004 /*GREEN*/ 6,
6005 /*BLUE*/ 5,
6006 /*FOURTH*/ 0,
6007 /*FIFTH*/ 0,
6008 /*ALPHA*/ 8,
6009 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6010 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6011 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6012 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6013 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6014 //QImage::Format_RGB666:
6016 /*RED*/ 6,
6017 /*GREEN*/ 6,
6018 /*BLUE*/ 6,
6019 /*FOURTH*/ 0,
6020 /*FIFTH*/ 0,
6021 /*ALPHA*/ 0,
6022 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6023 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6024 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6025 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6026 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6027 //QImage::Format_ARGB6666_Premultiplied:
6029 /*RED*/ 6,
6030 /*GREEN*/ 6,
6031 /*BLUE*/ 6,
6032 /*FOURTH*/ 0,
6033 /*FIFTH*/ 0,
6034 /*ALPHA*/ 6,
6035 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6036 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6037 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6038 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6039 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6040 //QImage::Format_RGB555:
6042 /*RED*/ 5,
6043 /*GREEN*/ 5,
6044 /*BLUE*/ 5,
6045 /*FOURTH*/ 0,
6046 /*FIFTH*/ 0,
6047 /*ALPHA*/ 0,
6048 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6049 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6050 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6051 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6052 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6053 //QImage::Format_ARGB8555_Premultiplied:
6055 /*RED*/ 5,
6056 /*GREEN*/ 5,
6057 /*BLUE*/ 5,
6058 /*FOURTH*/ 0,
6059 /*FIFTH*/ 0,
6060 /*ALPHA*/ 8,
6061 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6062 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6063 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6064 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6065 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6066 //QImage::Format_RGB888:
6068 /*RED*/ 8,
6069 /*GREEN*/ 8,
6070 /*BLUE*/ 8,
6071 /*FOURTH*/ 0,
6072 /*FIFTH*/ 0,
6073 /*ALPHA*/ 0,
6074 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6075 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6076 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6077 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6078 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6079 //QImage::Format_RGB444:
6081 /*RED*/ 4,
6082 /*GREEN*/ 4,
6083 /*BLUE*/ 4,
6084 /*FOURTH*/ 0,
6085 /*FIFTH*/ 0,
6086 /*ALPHA*/ 0,
6087 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6088 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6089 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6090 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6091 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6092 //QImage::Format_ARGB4444_Premultiplied:
6094 /*RED*/ 4,
6095 /*GREEN*/ 4,
6096 /*BLUE*/ 4,
6097 /*FOURTH*/ 0,
6098 /*FIFTH*/ 0,
6099 /*ALPHA*/ 4,
6100 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6101 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6102 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6103 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6104 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6105 //QImage::Format_RGBX8888:
6107 /*RED*/ 8,
6108 /*GREEN*/ 8,
6109 /*BLUE*/ 8,
6110 /*FOURTH*/ 0,
6111 /*FIFTH*/ 0,
6112 /*ALPHA*/ 8,
6113 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6114 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6115 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6116 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6117 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6118 //QImage::Format_RGBA8888:
6120 /*RED*/ 8,
6121 /*GREEN*/ 8,
6122 /*BLUE*/ 8,
6123 /*FOURTH*/ 0,
6124 /*FIFTH*/ 0,
6125 /*ALPHA*/ 8,
6126 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6127 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6128 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6129 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6130 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6131 //QImage::Format_RGBA8888_Premultiplied:
6133 /*RED*/ 8,
6134 /*GREEN*/ 8,
6135 /*BLUE*/ 8,
6136 /*FOURTH*/ 0,
6137 /*FIFTH*/ 0,
6138 /*ALPHA*/ 8,
6139 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6140 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6141 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6142 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6143 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6144 //QImage::Format_BGR30:
6146 /*RED*/ 10,
6147 /*GREEN*/ 10,
6148 /*BLUE*/ 10,
6149 /*FOURTH*/ 0,
6150 /*FIFTH*/ 0,
6151 /*ALPHA*/ 2,
6152 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6153 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6154 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6155 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6156 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6157 //QImage::Format_A2BGR30_Premultiplied:
6159 /*RED*/ 10,
6160 /*GREEN*/ 10,
6161 /*BLUE*/ 10,
6162 /*FOURTH*/ 0,
6163 /*FIFTH*/ 0,
6164 /*ALPHA*/ 2,
6165 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6166 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6167 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6168 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6169 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6170 //QImage::Format_RGB30:
6172 /*RED*/ 10,
6173 /*GREEN*/ 10,
6174 /*BLUE*/ 10,
6175 /*FOURTH*/ 0,
6176 /*FIFTH*/ 0,
6177 /*ALPHA*/ 2,
6178 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6179 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6180 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6181 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6182 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6183 //QImage::Format_A2RGB30_Premultiplied:
6185 /*RED*/ 10,
6186 /*GREEN*/ 10,
6187 /*BLUE*/ 10,
6188 /*FOURTH*/ 0,
6189 /*FIFTH*/ 0,
6190 /*ALPHA*/ 2,
6191 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6192 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6193 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6194 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6195 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6196 //QImage::Format_Alpha8:
6198 /*First*/ 0,
6199 /*SECOND*/ 0,
6200 /*THIRD*/ 0,
6201 /*FOURTH*/ 0,
6202 /*FIFTH*/ 0,
6203 /*ALPHA*/ 8,
6204 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6205 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6206 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6207 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6208 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6209 //QImage::Format_Grayscale8:
6211 /*GRAY*/ 8,
6212 /*SECOND*/ 0,
6213 /*THIRD*/ 0,
6214 /*FOURTH*/ 0,
6215 /*FIFTH*/ 0,
6216 /*ALPHA*/ 0,
6217 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6218 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6219 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6220 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6221 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6222 //QImage::Format_RGBX64:
6224 /*RED*/ 16,
6225 /*GREEN*/ 16,
6226 /*BLUE*/ 16,
6227 /*FOURTH*/ 0,
6228 /*FIFTH*/ 0,
6229 /*ALPHA*/ 16,
6230 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6231 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6232 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6233 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6234 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6235 //QImage::Format_RGBA64:
6237 /*RED*/ 16,
6238 /*GREEN*/ 16,
6239 /*BLUE*/ 16,
6240 /*FOURTH*/ 0,
6241 /*FIFTH*/ 0,
6242 /*ALPHA*/ 16,
6243 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6244 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6245 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6246 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6247 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6248 //QImage::Format_RGBA64_Premultiplied:
6250 /*RED*/ 16,
6251 /*GREEN*/ 16,
6252 /*BLUE*/ 16,
6253 /*FOURTH*/ 0,
6254 /*FIFTH*/ 0,
6255 /*ALPHA*/ 16,
6256 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6257 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6258 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6259 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6260 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6261 //QImage::Format_Grayscale16:
6263 /*GRAY*/ 16,
6264 /*SECOND*/ 0,
6265 /*THIRD*/ 0,
6266 /*FOURTH*/ 0,
6267 /*FIFTH*/ 0,
6268 /*ALPHA*/ 0,
6269 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6270 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6271 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6272 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6273 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6274 //QImage::Format_BGR888:
6276 /*RED*/ 8,
6277 /*GREEN*/ 8,
6278 /*BLUE*/ 8,
6279 /*FOURTH*/ 0,
6280 /*FIFTH*/ 0,
6281 /*ALPHA*/ 0,
6282 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6283 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6284 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6285 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6286 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6287 //QImage::Format_RGBX16FPx4:
6289 /*RED*/ 16,
6290 /*GREEN*/ 16,
6291 /*BLUE*/ 16,
6292 /*FOURTH*/ 0,
6293 /*FIFTH*/ 0,
6294 /*ALPHA*/ 16,
6295 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6296 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6297 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6298 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6299 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6300 //QImage::Format_RGBA16FPx4:
6302 /*RED*/ 16,
6303 /*GREEN*/ 16,
6304 /*BLUE*/ 16,
6305 /*FOURTH*/ 0,
6306 /*FIFTH*/ 0,
6307 /*ALPHA*/ 16,
6308 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6309 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6310 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6311 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6312 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6313 //QImage::Format_RGBA16FPx4_Premultiplied:
6315 /*RED*/ 16,
6316 /*GREEN*/ 16,
6317 /*BLUE*/ 16,
6318 /*FOURTH*/ 0,
6319 /*FIFTH*/ 0,
6320 /*ALPHA*/ 16,
6321 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6322 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6323 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6324 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6325 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6326 //QImage::Format_RGBX32FPx4:
6328 /*RED*/ 32,
6329 /*GREEN*/ 32,
6330 /*BLUE*/ 32,
6331 /*FOURTH*/ 0,
6332 /*FIFTH*/ 0,
6333 /*ALPHA*/ 32,
6334 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6335 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6336 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6337 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6338 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6339 //QImage::Format_RGBA32FPx4:
6341 /*RED*/ 32,
6342 /*GREEN*/ 32,
6343 /*BLUE*/ 32,
6344 /*FOURTH*/ 0,
6345 /*FIFTH*/ 0,
6346 /*ALPHA*/ 32,
6347 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6348 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6349 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6350 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6351 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6352 //QImage::Format_RGBA32FPx4_Premultiplied:
6354 /*RED*/ 32,
6355 /*GREEN*/ 32,
6356 /*BLUE*/ 32,
6357 /*FOURTH*/ 0,
6358 /*FIFTH*/ 0,
6359 /*ALPHA*/ 32,
6360 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6361 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6362 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6363 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6364 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6365 //QImage::Format_CMYK8888:
6367 /*RED*/ 8,
6368 /*GREEN*/ 8,
6369 /*BLUE*/ 8,
6370 /*FOURTH*/ 8,
6371 /*FIFTH*/ 0,
6372 /*ALPHA*/ 0,
6373 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6374 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6375 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6376 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6377 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6378};
6379static_assert(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats);
6380
6385{
6386 return toPixelFormat(format());
6387}
6388
6393{
6394 Q_ASSERT(static_cast<int>(format) < NImageFormats && static_cast<int>(format) >= 0);
6395 return pixelformats[format];
6396}
6397
6402{
6403 for (int i = 0; i < NImageFormats; i++) {
6404 if (format == pixelformats[i])
6405 return Format(i);
6406 }
6407 return Format_Invalid;
6408}
6409
6410Q_GUI_EXPORT void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient)
6411{
6413 return;
6415 src = rotated270(src);
6416 } else {
6417 src = std::move(src).mirrored(orient & QImageIOHandler::TransformationMirror,
6420 src = rotated90(src);
6421 }
6422}
6423
6424QMap<QString, QString> qt_getImageText(const QImage &image, const QString &description)
6425{
6426 QMap<QString, QString> text = qt_getImageTextFromDescription(description);
6427 const auto textKeys = image.textKeys();
6428 for (const QString &key : textKeys) {
6429 if (!key.isEmpty() && !text.contains(key))
6430 text.insert(key, image.text(key));
6431 }
6432 return text;
6433}
6434
6435QMap<QString, QString> qt_getImageTextFromDescription(const QString &description)
6436{
6437 QMap<QString, QString> text;
6438 for (const auto &pair : QStringView{description}.tokenize(u"\n\n")) {
6439 int index = pair.indexOf(u':');
6440 if (index >= 0 && pair.indexOf(u' ') < index) {
6441 if (!pair.trimmed().isEmpty())
6442 text.insert("Description"_L1, pair.toString().simplified());
6443 } else {
6444 const auto key = pair.left(index);
6445 if (!key.trimmed().isEmpty())
6446 text.insert(key.toString(), pair.mid(index + 2).toString().simplified());
6447 }
6448 }
6449 return text;
6450}
6451
6453
6454#include "moc_qimage.cpp"
IOBluetoothDevice * device
bool ref() noexcept
\inmodule QtCore \reentrant
Definition qbuffer.h:16
void setData(const QByteArray &data)
Sets the contents of the internal buffer to be data.
Definition qbuffer.cpp:259
\inmodule QtCore
Definition qbytearray.h:57
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
Definition qbytearray.h:409
The QColorSpace class provides a color space abstraction.
Definition qcolorspace.h:21
bool isValid() const noexcept
Returns true if the color space is valid.
ColorModel colorModel() const noexcept
Returns the color model this color space can represent.
bool isValidTarget() const noexcept
static QColorTransformPrivate * get(const QColorTransform &q)
The QColorTransform class is a transformation between color spaces.
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
QRgb rgba() const noexcept
Returns the RGB value of the color, including its alpha.
Definition qcolor.cpp:1376
void setRgbF(float r, float g, float b, float a=1.0)
Sets the color channels of this color to r (red), g (green), b (blue) and a (alpha,...
Definition qcolor.cpp:1317
\inmodule QtCore\reentrant
Definition qdatastream.h:46
\inmodule QtCore
\inmodule QtCore
static QPlatformIntegration * platformIntegration()
\inmodule QtCore \reentrant
Definition qiodevice.h:34
static void executeImageHooks(qint64 key)
The QImageReader class provides a format independent interface for reading images from files or other...
QImage read()
Reads an image from the device.
The QImageWriter class provides a format independent interface for writing images to files or other d...
bool write(const QImage &image)
Writes the image image to the assigned device or file name.
\inmodule QtGui
Definition qimage.h:37
void setDotsPerMeterY(int)
Sets the number of pixels that fit vertically in a physical meter, to y.
Definition qimage.cpp:4138
bool loadFromData(QByteArrayView data, const char *format=nullptr)
Definition qimage.cpp:3799
void detachMetadata(bool invalidateCache=false)
Definition qimage.cpp:1151
int dotsPerMeterX() const
Returns the number of pixels that fit horizontally in a physical meter.
Definition qimage.cpp:4086
int bitPlaneCount() const
Returns the number of bit planes in the image.
Definition qimage.cpp:4611
bool hasAlphaChannel() const
Returns true if the image has a format that respects the alpha channel, otherwise returns false.
Definition qimage.cpp:4589
bool valid(int x, int y) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qimage.cpp:2429
QImage createAlphaMask(Qt::ImageConversionFlags flags=Qt::AutoColor) const
QImage scaled(int w, int h, Qt::AspectRatioMode aspectMode=Qt::IgnoreAspectRatio, Qt::TransformationMode mode=Qt::FastTransformation) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qimage.h:209
void setAlphaChannel(const QImage &alphaChannel)
Sets the alpha channel of this image to the given alphaChannel.
Definition qimage.cpp:4548
QColorSpace colorSpace() const
Definition qimage.cpp:5155
void setText(const QString &key, const QString &value)
Sets the image text to the given text and associate it with the given key.
Definition qimage.cpp:4240
static QPixelFormat toPixelFormat(QImage::Format format) noexcept
Converts format into a QPixelFormat.
Definition qimage.cpp:6392
qsizetype bytesPerLine() const
Returns the number of bytes per image scanline.
Definition qimage.cpp:1560
void setPixel(int x, int y, uint index_or_rgb)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qimage.cpp:2588
QImage colorTransformed(const QColorTransform &transform) const &
Definition qimage.cpp:5327
void setPixelColor(int x, int y, const QColor &c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qimage.cpp:2788
QList< QRgb > colorTable() const
Returns a list of the colors contained in the image's color table, or an empty list if the image does...
Definition qimage.cpp:1466
uchar * scanLine(int)
Returns a pointer to the pixel data at the scanline with index i.
Definition qimage.cpp:1637
QRgb pixel(int x, int y) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qimage.cpp:2493
QImage transformed(const QTransform &matrix, Qt::TransformationMode mode=Qt::FastTransformation) const
void setColorCount(int)
Resizes the color table to contain colorCount entries.
Definition qimage.cpp:2132
QImage copy(const QRect &rect=QRect()) const
Returns a sub-area of the image as a new image.
QImage createHeuristicMask(bool clipTight=true) const
qsizetype sizeInBytes() const
Definition qimage.cpp:1548
bool allGray() const
Returns true if all the colors in the image are shades of gray (i.e.
Definition qimage.cpp:2872
QImage smoothScaled(int w, int h) const
Definition qimage.cpp:4664
void rgbSwapped_inplace()
QRgb color(int i) const
Returns the color in the color table at index i.
Definition qimage.cpp:1577
QSize size() const
Returns the size of the image, i.e.
bool isGrayscale() const
For 32-bit images, this function is equivalent to allGray().
Definition qimage.cpp:2948
void convertTo(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor)
Definition qimage.cpp:2399
bool isDetached() const
Definition qimage.cpp:4523
bool operator==(const QImage &) const
Returns true if this image and the given image have the same contents; otherwise returns false.
Definition qimage.cpp:4005
int width() const
Returns the width of the image.
bool save(const QString &fileName, const char *format=nullptr, int quality=-1) const
Saves the image to the file with the given fileName, using the given image file format and quality fa...
Definition qimage.cpp:3888
uchar * bits()
Returns a pointer to the first pixel data.
Definition qimage.cpp:1698
bool isNull() const
Returns true if it is a null image, otherwise returns false.
Definition qimage.cpp:1222
void applyColorTransform(const QColorTransform &transform)
Definition qimage.cpp:5167
int height() const
Returns the height of the image.
void setColorTable(const QList< QRgb > &colors)
QImage createMaskFromColor(QRgb color, Qt::MaskMode mode=Qt::MaskInColor) const
QPaintEngine * paintEngine() const override
Definition qimage.cpp:4255
bool convertToFormat_inplace(Format format, Qt::ImageConversionFlags flags)
Definition qimage.cpp:2241
Format
The following image formats are available in Qt.
Definition qimage.h:41
@ Format_Grayscale16
Definition qimage.h:70
@ Format_Alpha8
Definition qimage.h:65
@ Format_CMYK8888
Definition qimage.h:78
@ Format_RGBA8888
Definition qimage.h:59
@ Format_RGB30
Definition qimage.h:63
@ Format_RGB888
Definition qimage.h:55
@ Format_RGBA16FPx4
Definition qimage.h:73
@ Format_RGBA32FPx4_Premultiplied
Definition qimage.h:77
@ Format_RGB32
Definition qimage.h:46
@ Format_Invalid
Definition qimage.h:42
@ Format_RGB666
Definition qimage.h:51
@ Format_RGBX32FPx4
Definition qimage.h:75
@ Format_RGBA64_Premultiplied
Definition qimage.h:69
@ Format_ARGB6666_Premultiplied
Definition qimage.h:52
@ Format_ARGB8555_Premultiplied
Definition qimage.h:54
@ Format_RGB444
Definition qimage.h:56
@ Format_MonoLSB
Definition qimage.h:44
@ Format_RGBA8888_Premultiplied
Definition qimage.h:60
@ Format_ARGB8565_Premultiplied
Definition qimage.h:50
@ Format_RGB555
Definition qimage.h:53
@ Format_RGBA64
Definition qimage.h:68
@ Format_RGBA32FPx4
Definition qimage.h:76
@ Format_Mono
Definition qimage.h:43
@ Format_RGBA16FPx4_Premultiplied
Definition qimage.h:74
@ Format_RGBX64
Definition qimage.h:67
@ Format_A2BGR30_Premultiplied
Definition qimage.h:62
@ Format_RGBX16FPx4
Definition qimage.h:72
@ Format_Indexed8
Definition qimage.h:45
@ Format_BGR30
Definition qimage.h:61
@ NImageFormats
Definition qimage.h:80
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
@ Format_A2RGB30_Premultiplied
Definition qimage.h:64
@ Format_ARGB4444_Premultiplied
Definition qimage.h:57
@ Format_RGB16
Definition qimage.h:49
@ Format_BGR888
Definition qimage.h:71
@ Format_ARGB32
Definition qimage.h:47
@ Format_RGBX8888
Definition qimage.h:58
@ Format_Grayscale8
Definition qimage.h:66
virtual int metric(PaintDeviceMetric metric) const override
Definition qimage.cpp:4278
QImage() noexcept
Constructs a null image.
Definition qimage.cpp:791
void fill(uint pixel)
Fills the entire image with the given pixelValue.
Definition qimage.cpp:1758
QImage mirrored(bool horizontally=false, bool vertically=true) const &
Definition qimage.h:219
QPixelFormat pixelFormat() const noexcept
Returns the QImage::Format as a QPixelFormat.
Definition qimage.cpp:6384
QColor pixelColor(int x, int y) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qimage.cpp:2709
void setColorSpace(const QColorSpace &colorSpace)
Definition qimage.cpp:5012
QImage scaledToHeight(int h, Qt::TransformationMode mode=Qt::FastTransformation) const
Returns a scaled copy of the image.
Format format() const
Returns the format of the image.
Definition qimage.cpp:2162
bool operator!=(const QImage &) const
Returns true if this image and the given image have different contents; otherwise returns false.
Definition qimage.cpp:4070
static QImage fromData(QByteArrayView data, const char *format=nullptr)
Definition qimage.cpp:3841
bool load(QIODevice *device, const char *format)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qimage.cpp:3780
const uchar * constScanLine(int) const
Returns a pointer to the pixel data at the scanline with index i.
Definition qimage.cpp:1678
void detach()
Definition qimage.cpp:1128
QStringList textKeys() const
Returns the text keys for this image.
Definition qimage.cpp:4188
void setColor(int i, QRgb c)
Sets the color at the given index in the color table, to the given to colorValue.
Definition qimage.cpp:1595
QRect rect() const
Returns the enclosing rectangle (0, 0, width(), height()) of the image.
void setDevicePixelRatio(qreal scaleFactor)
Sets the device pixel ratio for the image.
Definition qimage.cpp:1510
void mirrored_inplace(bool horizontal, bool vertical)
Definition qimage.cpp:3508
qreal devicePixelRatio() const
Returns the device pixel ratio for the image.
Definition qimage.cpp:1482
void setDotsPerMeterX(int)
Sets the number of pixels that fit horizontally in a physical meter, to x.
Definition qimage.cpp:4116
QImage rgbSwapped_helper() const
int dotsPerMeterY() const
Returns the number of pixels that fit vertically in a physical meter.
Definition qimage.cpp:4099
static QImage::Format toImageFormat(QPixelFormat format) noexcept
Converts format into a QImage::Format.
Definition qimage.cpp:6401
const uchar * constBits() const
Returns a pointer to the first pixel data.
Definition qimage.cpp:1733
int colorCount() const
Returns the depth of the image.
QSizeF deviceIndependentSize() const
Returns the size of the image in device independent pixels.
Definition qimage.cpp:1533
QImage mirrored_helper(bool horizontal, bool vertical) const
Definition qimage.cpp:3480
QString text(const QString &key=QString()) const
Returns the image text associated with the given key.
Definition qimage.cpp:4200
QImage & operator=(const QImage &)
Move-assigns other to this QImage instance.
Definition qimage.cpp:1080
~QImage()
Destroys the image and cleans up.
Definition qimage.cpp:1064
int pixelIndex(int x, int y) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qimage.cpp:2452
QImage convertToFormat_helper(Format format, Qt::ImageConversionFlags flags) const
Definition qimage.cpp:2195
QImage convertedTo(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor) const &
Definition qimage.h:138
InvertMode
This enum type is used to describe how pixel values should be inverted in the invertPixels() function...
Definition qimage.h:40
@ InvertRgba
Definition qimage.h:40
static QTransform trueMatrix(const QTransform &, int w, int h)
Returns a copy of the image that is transformed using the given transformation matrix and transformat...
Definition qimage.cpp:4802
QImage scaledToWidth(int w, Qt::TransformationMode mode=Qt::FastTransformation) const
[9]
Definition qimage.cpp:3013
void convertToColorSpace(const QColorSpace &colorSpace)
Definition qimage.cpp:5038
QPoint offset() const
Returns the number of pixels by which the image is intended to be offset by when positioning relative...
Definition qimage.cpp:4156
bool reinterpretAsFormat(Format f)
Definition qimage.cpp:2365
void setOffset(const QPoint &)
Sets the number of pixels by which the image is intended to be offset by when positioning relative to...
Definition qimage.cpp:4170
QImage convertedToColorSpace(const QColorSpace &colorSpace) const
Definition qimage.cpp:5104
int devType() const override
Definition qimage.cpp:1104
void invertPixels(InvertMode=InvertRgb)
Inverts all pixel values in the image.
Definition qimage.cpp:1987
QImage convertToFormat(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor) const &
Definition qimage.h:125
int depth() const
qint64 cacheKey() const
Returns a number that identifies the contents of this QImage object.
Definition qimage.cpp:4507
@ PdmDevicePixelRatioScaled
static qreal devicePixelRatioFScale()
\inmodule QtGui
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
void setCompositionMode(CompositionMode mode)
Sets the composition mode to the given mode.
void drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect, Qt::ImageConversionFlags flags=Qt::AutoColor)
Draws the rectangular portion source of the given image into the target rectangle in the paint device...
@ SmoothPixmapTransform
Definition qpainter.h:54
@ Antialiasing
Definition qpainter.h:52
@ CompositionMode_Source
Definition qpainter.h:101
@ CompositionMode_DestinationIn
Definition qpainter.h:104
void setRenderHint(RenderHint hint, bool on=true)
Sets the given render hint on the painter if on is true; otherwise clears the render hint.
\inmodule QtGui
The QPlatformIntegration class is the entry for WindowSystem specific functionality.
virtual QPaintEngine * createImagePaintEngine(QPaintDevice *paintDevice) const
Factory function for QPaintEngine.
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:135
The QPolygonF class provides a list of points using floating point precision.
Definition qpolygon.h:96
The QRasterPaintEngine class enables hardware acceleration of painting operations in Qt for Embedded ...
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:242
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
void setAlpha(quint16 _alpha)
Definition qrgba64.h:77
static constexpr QRgba64 fromArgb32(uint rgb)
Definition qrgba64.h:56
static constexpr QRgbaFloat fromArgb32(uint rgb)
Definition qrgbafloat.h:56
constexpr Q_ALWAYS_INLINE QRgbaFloat premultiplied() const
Definition qrgbafloat.h:92
constexpr Q_ALWAYS_INLINE QRgbaFloat unpremultiplied() const
Definition qrgbafloat.h:96
\inmodule QtCore
Definition qsemaphore.h:18
void acquire(int n=1)
Tries to acquire n resources guarded by the semaphore.
void release(int n=1)
Releases n resources guarded by the semaphore.
iterator begin()
Definition qset.h:136
\inmodule QtCore
Definition qsize.h:208
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
constexpr int & rheight() noexcept
Returns a reference to the height.
Definition qsize.h:157
void scale(int w, int h, Qt::AspectRatioMode mode) noexcept
Scales the size to a rectangle with the given width and height, according to the specified mode:
Definition qsize.h:145
constexpr int & rwidth() noexcept
Returns a reference to the width.
Definition qsize.h:154
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString left(qsizetype n) const &
Definition qstring.h:363
qsizetype indexOf(QLatin1StringView s, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4517
void chop(qsizetype n)
Removes n characters from the end of the string.
Definition qstring.cpp:6340
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
QString & insert(qsizetype i, QChar c)
Definition qstring.cpp:3132
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.h:1369
auto tokenize(Needle &&needle, Flags...flags) const &noexcept(noexcept(qTokenize(std::declval< const QString & >(), std::forward< Needle >(needle), flags...))) -> decltype(qTokenize(*this, std::forward< Needle >(needle), flags...))
Definition qstring.h:599
static QThreadPool * qtGuiInstance()
Returns the QThreadPool instance for Qt Gui.
\inmodule QtCore
Definition qthreadpool.h:22
void start(QRunnable *runnable, int priority=0)
Reserves a thread and uses it to run runnable, unless this thread will make the current thread count ...
bool contains(const QThread *thread) const
static QThread * currentThread()
Definition qthread.cpp:1039
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
static QTransform fromScale(qreal dx, qreal dy)
Creates a matrix which corresponds to a scaling of sx horizontally and sy vertically.
QTransform & translate(qreal dx, qreal dy)
Moves the coordinate system dx along the x axis and dy along the y axis, and returns a reference to t...
\inmodule QtCore
Definition qvariant.h:65
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
\keyword 16-bit Floating Point Support\inmodule QtCore \inheaderfile QFloat16
Definition qfloat16.h:47
Format
Definition ddsheader.h:14
#define this
Definition dialogs.cpp:9
QPixmap p2
QPixmap p1
[0]
QString text
QCache< int, Employee > cache
[0]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
QFuture< QtPrivate::MapResultType< Sequence, MapFunctor > > mapped(QThreadPool *pool, Sequence &&sequence, MapFunctor &&map)
TransformationMode
@ SmoothTransformation
AspectRatioMode
GlobalColor
Definition qnamespace.h:27
@ color1
Definition qnamespace.h:29
@ white
Definition qnamespace.h:31
@ black
Definition qnamespace.h:30
@ color0
Definition qnamespace.h:28
QTextStream & ws(QTextStream &stream)
Calls \l {QTextStream::}{skipWhiteSpace()} on stream and returns stream.
@ MaskOutColor
Definition image.cpp:4
static jboolean copy(JNIEnv *, jobject)
#define Q_BASIC_ATOMIC_INITIALIZER(a)
static QT_WARNING_DISABLE_FLOAT_COMPARE ShiftResult shift(const QBezier *orig, QBezier *shifted, qreal offset, qreal threshold)
Definition qbezier.cpp:207
#define Q_FALLTHROUGH()
#define QT_WARNING_DISABLE_MSVC(number)
QList< QString > QStringList
Constructs a string list that contains the given string, str.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
static constexpr int BufferSize
ushort qConvertRgb32To16(uint c)
QRgb qConvertRgb16To32(uint c)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
Q_GUI_EXPORT int qt_defaultDpiX()
Definition qfont.cpp:110
Q_GUI_EXPORT int qt_defaultDpiY()
Definition qfont.cpp:125
#define IWX_MSB(b)
Definition qimage.cpp:4359
static QImage rotated90(const QImage &src)
Definition qimage.cpp:4708
static void copyMetadata(QImageData *dst, const QImageData *src)
Definition qimage.cpp:1172
static void rgbSwapped_generic(int width, int height, const QImage *src, QImage *dst, const QPixelLayout *layout)
Definition qimage.cpp:3545
QDataStream & operator<<(QDataStream &s, const QImage &image)
[0]
Definition qimage.cpp:3947
bool qt_xForm_helper(const QTransform &trueMat, int xoffset, int type, int depth, uchar *dptr, qsizetype dbpl, int p_inc, int dHeight, const uchar *sptr, qsizetype sbpl, int sWidth, int sHeight)
Definition qimage.cpp:4385
QImage Q_TRACE_INSTRUMENT(qtgui) QImage
Definition qimage.cpp:3565
bool qt_read_xpm_image_or_array(QIODevice *device, const char *const *source, QImage &image)
static bool isRgb32fpx4Data(QImage::Format f)
Definition qimage.cpp:5386
static int next_qimage_serial_number()
Definition qimage.cpp:85
#define QIMAGE_SANITYCHECK_MEMORY(image)
Definition qimage.cpp:63
static QImage convertWithPalette(const QImage &src, QImage::Format format, const QList< QRgb > &clut)
Definition qimage.cpp:2273
void do_flip(QImageData *dst, QImageData *src, int w, int h, int depth)
Definition qimage.cpp:3354
static void copyPhysicalMetadata(QImageData *dst, const QImageData *src)
Definition qimage.cpp:1165
#define IWX_LSB(b)
Definition qimage.cpp:4368
Q_GUI_EXPORT void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient)
Definition qimage.cpp:6410
static QImage rotated270(const QImage &src)
Definition qimage.cpp:4752
QMap< QString, QString > qt_getImageText(const QImage &image, const QString &description)
Definition qimage.cpp:6424
void do_mirror(QImageData *dst, QImageData *src, bool horizontal, bool vertical)
Definition qimage.cpp:3385
static int pixel_distance(QRgb p1, QRgb p2)
Definition qimage.cpp:2246
static int closestMatch(QRgb pixel, const QList< QRgb > &clut)
Definition qimage.cpp:2260
static constexpr QPixelFormat pixelformats[]
Definition qimage.cpp:5907
static bool isRgb64Data(QImage::Format f)
Definition qimage.cpp:5373
#define PIX(x, y)
static QImage rotated180(const QImage &src)
Definition qimage.cpp:4734
QDataStream & operator>>(QDataStream &s, QImage &image)
Definition qimage.cpp:3973
static bool isRgb32Data(QImage::Format f)
Definition qimage.cpp:5360
QMap< QString, QString > qt_getImageTextFromDescription(const QString &description)
Definition qimage.cpp:6435
void(* QImageCleanupFunction)(void *)
Definition qimage.h:34
Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats]
static const uchar bitflip[256]
const uchar * qt_get_bitflip_array()
void dither_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags, bool fromalpha)
void convert_generic_over_rgb64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags flags)
bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags)
int qt_depthForFormat(QImage::Format format)
Definition qimage_p.h:142
Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats]
QColorSpace::ColorModel qt_csColorData(QPixelFormat::ColorModel format)
Definition qimage_p.h:440
bool qt_fpColorPrecision(QImage::Format format)
Definition qimage_p.h:424
bool(* InPlace_Image_Converter)(QImageData *data, Qt::ImageConversionFlags)
Definition qimage_p.h:120
bool qt_compatibleColorModel(QPixelFormat::ColorModel data, QColorSpace::ColorModel cs)
Definition qimage_p.h:459
InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats]
QImage::Format qt_alphaVersion(QImage::Format format)
Definition qimage_p.h:267
bool qt_highColorPrecision(QImage::Format format, bool opaque=false)
Definition qimage_p.h:396
void(* Image_Converter)(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
Definition qimage_p.h:119
QImage::Format qt_alphaVersionForPainting(QImage::Format format)
Definition qimage_p.h:543
bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags)
QImage qSmoothScaleImage(const QImage &src, int dw, int dh)
#define qWarning
Definition qlogging.h:166
static ControlElement< T > * ptr(QWidget *widget)
MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3]
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLint GLint GLint GLint dstX0
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum mode
const GLfloat * m
GLenum GLint GLint GLint GLint GLuint GLenum GLint GLint GLint dstY
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLenum GLint GLint GLint srcY
GLenum GLint GLint GLint GLint GLuint GLenum GLint GLint dstX
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLenum src
GLenum GLuint buffer
GLint GLsizei width
GLenum GLint GLint srcX
GLuint color
[2]
GLenum type
GLenum GLenum dst
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbitfield flags
GLint GLint xoffset
GLenum GLuint GLintptr offset
GLboolean GLboolean g
GLint ref
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLfloat n
GLint GLsizei GLsizei GLenum format
GLint GLint GLint GLint GLint dstY0
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
void ** params
GLuint GLenum GLenum transform
GLdouble s
[6]
Definition qopenglext.h:235
GLenum func
Definition qopenglext.h:663
GLuint res
const GLubyte * c
GLint void * img
Definition qopenglext.h:233
GLuint GLenum matrix
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint segments
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLenum GLsizei len
GLenum GLenum GLsizei void * table
QPixelLayout qPixelLayouts[]
QRgba64 qConvertA2rgb30ToRgb64< PixelOrderBGR >(uint rgb)
unsigned int qConvertRgb64ToRgb30< PixelOrderBGR >(QRgba64 c)
QRgb qConvertA2rgb30ToArgb32< PixelOrderBGR >(uint c)
void(QT_FASTCALL * RbSwapFunc)(uchar *dst, const uchar *src, int count)
static quint32 RGBA2ARGB(quint32 x)
uint qConvertRgb32ToRgb30< PixelOrderRGB >(QRgb c)
QRgba64 qConvertA2rgb30ToRgb64< PixelOrderRGB >(uint rgb)
uint qConvertArgb32ToA2rgb30< PixelOrderBGR >(QRgb c)
uint qConvertRgb32ToRgb30< PixelOrderBGR >(QRgb c)
QRgb qConvertA2rgb30ToArgb32< PixelOrderRGB >(uint c)
static quint32 ARGB2RGBA(quint32 x)
unsigned int qConvertRgb64ToRgb30< PixelOrderRGB >(QRgba64 c)
void(* MemRotateFunc)(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
uint qConvertArgb32ToA2rgb30< PixelOrderRGB >(QRgb c)
uint qRgbSwapRgb30(uint c)
#define QT_XFORM_TYPE_LSBFIRST
#define QT_XFORM_TYPE_MSBFIRST
static QT_BEGIN_NAMESPACE const QRgb colors[][14]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
constexpr bool qIsGray(QRgb rgb)
Definition qrgb.h:42
QT_BEGIN_NAMESPACE typedef unsigned int QRgb
Definition qrgb.h:13
constexpr QRgb qRgb(int r, int g, int b)
Definition qrgb.h:30
constexpr int qRed(QRgb rgb)
Definition qrgb.h:18
constexpr int qGreen(QRgb rgb)
Definition qrgb.h:21
constexpr int qBlue(QRgb rgb)
Definition qrgb.h:24
constexpr QRgb qPremultiply(QRgb x)
Definition qrgb.h:45
constexpr int qAlpha(QRgb rgb)
Definition qrgb.h:27
constexpr QRgba64 qRgba64(quint16 r, quint16 g, quint16 b, quint16 a)
Definition qrgba64.h:180
static uint toArgb32(QRgba64 rgba64)
Definition qrgba64_p.h:219
#define qPrintable(string)
Definition qstring.h:1531
#define a2
#define a1
#define QT_CONFIG(feature)
#define Q_TRACE_PARAM_REPLACE(in, out)
Definition qtrace_p.h:231
#define Q_TRACE_METADATA(provider, metadata)
Definition qtrace_p.h:234
#define Q_TRACE_PREFIX(provider, prefix)
Definition qtrace_p.h:233
#define Q_TRACE_SCOPE(x,...)
Definition qtrace_p.h:146
unsigned int quint32
Definition qtypes.h:50
unsigned char uchar
Definition qtypes.h:32
unsigned short quint16
Definition qtypes.h:48
int qint32
Definition qtypes.h:49
unsigned long long quint64
Definition qtypes.h:61
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
unsigned short ushort
Definition qtypes.h:33
double qreal
Definition qtypes.h:187
unsigned char quint8
Definition qtypes.h:46
ReturnedValue read(const char *data)
std::uniform_real_distribution dist(1, 2.5)
[2]
QTextStream out(stdout)
[7]
QObject::connect nullptr
QVBoxLayout * layout
QRect r1(100, 200, 11, 16)
[0]
QRect r2(QPoint(100, 200), QSize(11, 16))
QPainter painter(this)
[7]
int detach_no
Definition qimage_p.h:52
bool checkForAlphaPixels() const
Definition qimage.cpp:172
bool doImageIO(const QImage *image, QImageWriter *io, int quality) const
Definition qimage.cpp:3918
QAtomicInt ref
Definition qimage_p.h:40
int height
Definition qimage_p.h:43
static QImageData * get(QImage &img) noexcept
Definition qimage_p.h:37
uchar * data
Definition qimage_p.h:48
static ImageSizeParameters calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth)
Definition qimage_p.h:89
int ser_no
Definition qimage_p.h:51
uint is_cached
Definition qimage_p.h:61
int width
Definition qimage_p.h:42
bool convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags)
Definition qimage.cpp:5841
void * cleanupInfo
Definition qimage_p.h:64
QList< QRgb > colortable
Definition qimage_p.h:47
uint own_data
Definition qimage_p.h:58
static QImageData * create(const QSize &size, QImage::Format format)
qsizetype bytes_per_line
Definition qimage_p.h:50
int depth
Definition qimage_p.h:44
uint has_alpha_clut
Definition qimage_p.h:60
QPaintEngine * paintEngine
Definition qimage_p.h:76
QImage::Format format
Definition qimage_p.h:49
QImageCleanupFunction cleanupFunction
Definition qimage_p.h:63