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
4327 Q_FALLTHROUGH();
4329 return QPaintDevice::encodeMetricF(metric, d->devicePixelRatio);
4330 break;
4331
4332 default:
4333 qWarning("QImage::metric(): Unhandled metric type %d", metric);
4334 break;
4335 }
4336 return 0;
4337}
4338
4339
4340
4341/*****************************************************************************
4342 QPixmap (and QImage) helper functions
4343 *****************************************************************************/
4344/*
4345 This internal function contains the common (i.e. platform independent) code
4346 to do a transformation of pixel data. It is used by QPixmap::transform() and by
4347 QImage::transform().
4348
4349 \a trueMat is the true transformation matrix (see QPixmap::trueMatrix()) and
4350 \a xoffset is an offset to the matrix.
4351
4352 \a msbfirst specifies for 1bpp images, if the MSB or LSB comes first and \a
4353 depth specifies the colordepth of the data.
4354
4355 \a dptr is a pointer to the destination data, \a dbpl specifies the bits per
4356 line for the destination data, \a p_inc is the offset that we advance for
4357 every scanline and \a dHeight is the height of the destination image.
4358
4359 \a sprt is the pointer to the source data, \a sbpl specifies the bits per
4360 line of the source data, \a sWidth and \a sHeight are the width and height of
4361 the source data.
4362*/
4363
4364#undef IWX_MSB
4365#define IWX_MSB(b) if (trigx < maxws && trigy < maxhs) { \
4366 if (*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
4367 (1 << (7-((trigx>>12)&7)))) \
4368 *dptr |= b; \
4369 } \
4370 trigx += m11; \
4371 trigy += m12;
4372 // END OF MACRO
4373#undef IWX_LSB
4374#define IWX_LSB(b) if (trigx < maxws && trigy < maxhs) { \
4375 if (*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
4376 (1 << ((trigx>>12)&7))) \
4377 *dptr |= b; \
4378 } \
4379 trigx += m11; \
4380 trigy += m12;
4381 // END OF MACRO
4382#undef IWX_PIX
4383#define IWX_PIX(b) if (trigx < maxws && trigy < maxhs) { \
4384 if ((*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
4385 (1 << (7-((trigx>>12)&7)))) == 0) \
4386 *dptr &= ~b; \
4387 } \
4388 trigx += m11; \
4389 trigy += m12;
4390 // END OF MACRO
4391bool qt_xForm_helper(const QTransform &trueMat, int xoffset, int type, int depth,
4392 uchar *dptr, qsizetype dbpl, int p_inc, int dHeight,
4393 const uchar *sptr, qsizetype sbpl, int sWidth, int sHeight)
4394{
4395 int m11 = int(trueMat.m11()*4096.0);
4396 int m12 = int(trueMat.m12()*4096.0);
4397 int m21 = int(trueMat.m21()*4096.0);
4398 int m22 = int(trueMat.m22()*4096.0);
4399 int dx = qRound(trueMat.dx()*4096.0);
4400 int dy = qRound(trueMat.dy()*4096.0);
4401
4402 int m21ydx = dx + (xoffset<<16) + (m11 + m21) / 2;
4403 int m22ydy = dy + (m12 + m22) / 2;
4404 uint trigx;
4405 uint trigy;
4406 uint maxws = sWidth<<12;
4407 uint maxhs = sHeight<<12;
4408
4409 for (int y=0; y<dHeight; y++) { // for each target scanline
4410 trigx = m21ydx;
4411 trigy = m22ydy;
4412 uchar *maxp = dptr + dbpl;
4413 if (depth != 1) {
4414 switch (depth) {
4415 case 8: // 8 bpp transform
4416 while (dptr < maxp) {
4417 if (trigx < maxws && trigy < maxhs)
4418 *dptr = *(sptr+sbpl*(trigy>>12)+(trigx>>12));
4419 trigx += m11;
4420 trigy += m12;
4421 dptr++;
4422 }
4423 break;
4424
4425 case 16: // 16 bpp transform
4426 while (dptr < maxp) {
4427 if (trigx < maxws && trigy < maxhs)
4428 *((ushort*)dptr) = *((const ushort *)(sptr+sbpl*(trigy>>12) +
4429 ((trigx>>12)<<1)));
4430 trigx += m11;
4431 trigy += m12;
4432 dptr++;
4433 dptr++;
4434 }
4435 break;
4436
4437 case 24: // 24 bpp transform
4438 while (dptr < maxp) {
4439 if (trigx < maxws && trigy < maxhs) {
4440 const uchar *p2 = sptr+sbpl*(trigy>>12) + ((trigx>>12)*3);
4441 dptr[0] = p2[0];
4442 dptr[1] = p2[1];
4443 dptr[2] = p2[2];
4444 }
4445 trigx += m11;
4446 trigy += m12;
4447 dptr += 3;
4448 }
4449 break;
4450
4451 case 32: // 32 bpp transform
4452 while (dptr < maxp) {
4453 if (trigx < maxws && trigy < maxhs)
4454 *((uint*)dptr) = *((const uint *)(sptr+sbpl*(trigy>>12) +
4455 ((trigx>>12)<<2)));
4456 trigx += m11;
4457 trigy += m12;
4458 dptr += 4;
4459 }
4460 break;
4461
4462 default: {
4463 return false;
4464 }
4465 }
4466 } else {
4467 switch (type) {
4469 while (dptr < maxp) {
4470 IWX_MSB(128);
4471 IWX_MSB(64);
4472 IWX_MSB(32);
4473 IWX_MSB(16);
4474 IWX_MSB(8);
4475 IWX_MSB(4);
4476 IWX_MSB(2);
4477 IWX_MSB(1);
4478 dptr++;
4479 }
4480 break;
4482 while (dptr < maxp) {
4483 IWX_LSB(1);
4484 IWX_LSB(2);
4485 IWX_LSB(4);
4486 IWX_LSB(8);
4487 IWX_LSB(16);
4488 IWX_LSB(32);
4489 IWX_LSB(64);
4490 IWX_LSB(128);
4491 dptr++;
4492 }
4493 break;
4494 }
4495 }
4496 m21ydx += m21;
4497 m22ydy += m22;
4498 dptr += p_inc;
4499 }
4500 return true;
4501}
4502#undef IWX_MSB
4503#undef IWX_LSB
4504#undef IWX_PIX
4505
4514{
4515 if (!d)
4516 return 0;
4517 else
4518 return (((qint64) d->ser_no) << 32) | ((qint64) d->detach_no);
4519}
4520
4530{
4531 return d && d->ref.loadRelaxed() == 1;
4532}
4533
4534
4554void QImage::setAlphaChannel(const QImage &alphaChannel)
4555{
4556 if (!d || alphaChannel.isNull())
4557 return;
4558
4559 if (d->paintEngine && d->paintEngine->isActive()) {
4560 qWarning("QImage::setAlphaChannel: "
4561 "Unable to set alpha channel while image is being painted on");
4562 return;
4563 }
4564
4565 const Format alphaFormat = qt_alphaVersionForPainting(d->format);
4566 if (d->format == alphaFormat)
4567 detach();
4568 else
4569 convertTo(alphaFormat);
4570
4571 if (isNull())
4572 return;
4573
4574 QImage sourceImage;
4575 if (alphaChannel.format() == QImage::Format_Alpha8 || (alphaChannel.d->depth == 8 && alphaChannel.isGrayscale()))
4576 sourceImage = alphaChannel;
4577 else
4578 sourceImage = alphaChannel.convertToFormat(QImage::Format_Grayscale8);
4579 if (!sourceImage.reinterpretAsFormat(QImage::Format_Alpha8))
4580 return;
4581
4582 QPainter painter(this);
4583 if (sourceImage.size() != size())
4586 painter.drawImage(rect(), sourceImage);
4587}
4588
4596{
4597 if (!d)
4598 return false;
4600 if (format.alphaUsage() == QPixelFormat::UsesAlpha)
4601 return true;
4602 if (format.colorModel() == QPixelFormat::Indexed)
4603 return d->has_alpha_clut;
4604 return false;
4605}
4606
4618{
4619 if (!d)
4620 return 0;
4621 int bpc = 0;
4622 switch (d->format) {
4624 break;
4627 bpc = 30;
4628 break;
4631 bpc = 24;
4632 break;
4634 bpc = 18;
4635 break;
4637 bpc = 15;
4638 break;
4640 bpc = 23;
4641 break;
4643 bpc = 12;
4644 break;
4647 bpc = 48;
4648 break;
4650 bpc = 96;
4651 break;
4652 default:
4653 bpc = qt_depthForFormat(d->format);
4654 break;
4655 }
4656 return bpc;
4657}
4658
4671{
4672 QImage src = *this;
4673 switch (src.format()) {
4676#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4678#endif
4680#if QT_CONFIG(raster_64bit)
4683 break;
4687 break;
4688#endif
4689#if QT_CONFIG(raster_fp)
4692 break;
4694 src.convertTo(QImage::Format_RGBX32FPx4);
4695 break;
4700 break;
4701#endif
4703 break;
4704 default:
4705 if (src.hasAlphaChannel())
4707 else
4708 src.convertTo(QImage::Format_RGB32);
4709 }
4711 if (!src.isNull())
4712 copyMetadata(src.d, d);
4713 return src;
4714}
4715
4717{
4718 QImage out(image.height(), image.width(), image.format());
4719 if (out.isNull())
4720 return out;
4722 if (image.colorCount() > 0)
4723 out.setColorTable(image.colorTable());
4724 int w = image.width();
4725 int h = image.height();
4726 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][2];
4727 if (memrotate) {
4728 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4729 } else {
4730 for (int y=0; y<h; ++y) {
4731 if (image.colorCount())
4732 for (int x=0; x<w; ++x)
4733 out.setPixel(h-y-1, x, image.pixelIndex(x, y));
4734 else
4735 for (int x=0; x<w; ++x)
4736 out.setPixel(h-y-1, x, image.pixel(x, y));
4737 }
4738 }
4739 return out;
4740}
4741
4743{
4744 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][1];
4745 if (!memrotate)
4746 return image.mirrored(true, true);
4747
4748 QImage out(image.width(), image.height(), image.format());
4749 if (out.isNull())
4750 return out;
4752 if (image.colorCount() > 0)
4753 out.setColorTable(image.colorTable());
4754 int w = image.width();
4755 int h = image.height();
4756 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4757 return out;
4758}
4759
4761{
4762 QImage out(image.height(), image.width(), image.format());
4763 if (out.isNull())
4764 return out;
4766 if (image.colorCount() > 0)
4767 out.setColorTable(image.colorTable());
4768 int w = image.width();
4769 int h = image.height();
4770 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][0];
4771 if (memrotate) {
4772 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4773 } else {
4774 for (int y=0; y<h; ++y) {
4775 if (image.colorCount())
4776 for (int x=0; x<w; ++x)
4777 out.setPixel(y, w-x-1, image.pixelIndex(x, y));
4778 else
4779 for (int x=0; x<w; ++x)
4780 out.setPixel(y, w-x-1, image.pixel(x, y));
4781 }
4782 }
4783 return out;
4784}
4785
4811{
4812 if (!d)
4813 return QImage();
4814
4815 Q_TRACE_PARAM_REPLACE(const QTransform &, double[9]);
4816 Q_TRACE_SCOPE(QImage_transformed, QList<double>({matrix.m11(), matrix.m12(), matrix.m13(),
4817 matrix.m21(), matrix.m22(), matrix.m23(),
4818 matrix.m31(), matrix.m32(), matrix.m33()}).data(), mode);
4819
4820 // source image data
4821 const int ws = width();
4822 const int hs = height();
4823
4824 // target image data
4825 int wd;
4826 int hd;
4827
4828 // compute size of target image
4829 QTransform mat = trueMatrix(matrix, ws, hs);
4830 bool complex_xform = false;
4831 bool scale_xform = false;
4832 bool nonpaintable_scale_xform = false;
4833 if (mat.type() <= QTransform::TxScale) {
4834 if (mat.type() == QTransform::TxNone) // identity matrix
4835 return *this;
4836 else if (mat.m11() == -1. && mat.m22() == -1.)
4837 return rotated180(*this);
4838
4839 hd = qRound(qAbs(mat.m22()) * hs);
4840 wd = qRound(qAbs(mat.m11()) * ws);
4841 scale_xform = true;
4842 // The paint-based scaling is only bilinear, and has problems
4843 // with scaling smoothly more than 2x down.
4844 if (hd * 2 < hs || wd * 2 < ws)
4845 nonpaintable_scale_xform = true;
4846 // We cannot paint on a CMYK image, so don't try to do so
4848 nonpaintable_scale_xform = true;
4849 } else {
4850 if (mat.type() <= QTransform::TxRotate && mat.m11() == 0 && mat.m22() == 0) {
4851 if (mat.m12() == 1. && mat.m21() == -1.)
4852 return rotated90(*this);
4853 else if (mat.m12() == -1. && mat.m21() == 1.)
4854 return rotated270(*this);
4855 }
4856
4857 QPolygonF a(QRectF(0, 0, ws, hs));
4858 a = mat.map(a);
4859 QRect r = a.boundingRect().toAlignedRect();
4860 wd = r.width();
4861 hd = r.height();
4862 complex_xform = true;
4863 }
4864
4865 if (wd == 0 || hd == 0)
4866 return QImage();
4867
4868 if (scale_xform && mode == Qt::SmoothTransformation) {
4869 switch (format()) {
4872#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4874#endif
4876#if QT_CONFIG(raster_64bit)
4879#endif
4881 // Use smoothScaled for scaling when we can do so without conversion.
4882 if (mat.m11() > 0.0F && mat.m22() > 0.0F)
4883 return smoothScaled(wd, hd);
4884 break;
4885 default:
4886 break;
4887 }
4888 // Otherwise only use it when the scaling factor demands it, or the image is large enough to scale multi-threaded
4889 if (nonpaintable_scale_xform
4890#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
4891 || (ws * hs) >= (1<<20)
4892#endif
4893 ) {
4894 QImage scaledImage;
4895 if (mat.m11() < 0.0F && mat.m22() < 0.0F) { // horizontal/vertical flip
4896 scaledImage = smoothScaled(wd, hd).mirrored(true, true);
4897 } else if (mat.m11() < 0.0F) { // horizontal flip
4898 scaledImage = smoothScaled(wd, hd).mirrored(true, false);
4899 } else if (mat.m22() < 0.0F) { // vertical flip
4900 scaledImage = smoothScaled(wd, hd).mirrored(false, true);
4901 } else { // no flipping
4902 scaledImage = smoothScaled(wd, hd);
4903 }
4904
4905 switch (format()) {
4909 return scaledImage;
4910 default:
4911 return scaledImage.convertToFormat(format());
4912 }
4913 }
4914 }
4915
4916 int bpp = depth();
4917
4918 qsizetype sbpl = bytesPerLine();
4919 const uchar *sptr = bits();
4920
4921 QImage::Format target_format = d->format;
4922
4923 if (complex_xform || mode == Qt::SmoothTransformation) {
4924 if (d->format < QImage::Format_RGB32 || (!hasAlphaChannel() && complex_xform)) {
4925 target_format = qt_alphaVersion(d->format);
4926 }
4927 }
4928
4929 QImage dImage(wd, hd, target_format);
4931
4932 if (target_format == QImage::Format_MonoLSB
4933 || target_format == QImage::Format_Mono
4934 || target_format == QImage::Format_Indexed8) {
4935 dImage.d->colortable = d->colortable;
4936 dImage.d->has_alpha_clut = d->has_alpha_clut | complex_xform;
4937 }
4938
4939 // initizialize the data
4940 if (target_format == QImage::Format_Indexed8) {
4941 if (dImage.d->colortable.size() < 256) {
4942 // colors are left in the color table, so pick that one as transparent
4943 dImage.d->colortable.append(0x0);
4944 memset(dImage.bits(), dImage.d->colortable.size() - 1, dImage.d->nbytes);
4945 } else {
4946 memset(dImage.bits(), 0, dImage.d->nbytes);
4947 }
4948 } else
4949 memset(dImage.bits(), 0x00, dImage.d->nbytes);
4950
4951 if (target_format >= QImage::Format_RGB32 && target_format != QImage::Format_CMYK8888) {
4952 // Prevent QPainter from applying devicePixelRatio corrections
4953 QImage sImage = (devicePixelRatio() != 1) ? QImage(constBits(), width(), height(), format()) : *this;
4954 if (sImage.d != d
4955 && (d->format == QImage::Format_MonoLSB
4956 || d->format == QImage::Format_Mono
4957 || d->format == QImage::Format_Indexed8)) {
4958 sImage.d->colortable = d->colortable;
4959 sImage.d->has_alpha_clut = d->has_alpha_clut;
4960 }
4961
4962 Q_ASSERT(sImage.devicePixelRatio() == 1);
4963 Q_ASSERT(sImage.devicePixelRatio() == dImage.devicePixelRatio());
4964
4965 QPainter p(&dImage);
4967 p.setRenderHint(QPainter::Antialiasing);
4968 p.setRenderHint(QPainter::SmoothPixmapTransform);
4969 }
4970 p.setTransform(mat);
4971 p.drawImage(QPoint(0, 0), sImage);
4972 } else {
4973 bool invertible;
4974 mat = mat.inverted(&invertible); // invert matrix
4975 if (!invertible) // error, return null image
4976 return QImage();
4977
4978 // create target image (some of the code is from QImage::copy())
4980 qsizetype dbpl = dImage.bytesPerLine();
4981 qt_xForm_helper(mat, 0, type, bpp, dImage.bits(), dbpl, 0, hd, sptr, sbpl, ws, hs);
4982 }
4983 copyMetadata(dImage.d, d);
4984
4985 return dImage;
4986}
4987
5010{
5011 const QRectF rect(0, 0, w, h);
5012 const QRect mapped = matrix.mapRect(rect).toAlignedRect();
5013 const QPoint delta = mapped.topLeft();
5014 return matrix * QTransform().translate(-delta.x(), -delta.y());
5015}
5016
5024void QImage::setColorSpace(const QColorSpace &colorSpace)
5025{
5026 if (!d)
5027 return;
5028 if (d->colorSpace == colorSpace)
5029 return;
5031 return;
5032
5033 detachMetadata(false);
5034 if (d)
5035 d->colorSpace = colorSpace;
5036}
5037
5051{
5052 if (!d || !d->colorSpace.isValid())
5053 return;
5054 if (!colorSpace.isValidTarget()) {
5055 qWarning() << "QImage::convertToColorSpace: Output colorspace is not valid";
5056 return;
5057 }
5058 if (d->colorSpace == colorSpace)
5059 return;
5062 return;
5063 }
5064 applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace));
5065 if (d->ref.loadRelaxed() != 1)
5066 detachMetadata(false);
5067 d->colorSpace = colorSpace;
5068}
5069
5083void QImage::convertToColorSpace(const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags)
5084{
5085 if (!d || !d->colorSpace.isValid())
5086 return;
5087 if (!colorSpace.isValidTarget()) {
5088 qWarning() << "QImage::convertToColorSpace: Output colorspace is not valid";
5089 return;
5090 }
5092 qWarning() << "QImage::convertToColorSpace: Color space is not compatible with format";
5093 return;
5094 }
5095
5096 if (d->colorSpace == colorSpace)
5097 return convertTo(format, flags);
5098 applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace), format, flags);
5099 d->colorSpace = colorSpace;
5100}
5101
5117{
5118 if (!d || !d->colorSpace.isValid())
5119 return QImage();
5120 if (!colorSpace.isValidTarget()) {
5121 qWarning() << "QImage::convertedToColorSpace: Output colorspace is not valid";
5122 return QImage();
5123 }
5124 if (d->colorSpace == colorSpace)
5125 return *this;
5126 QImage image = colorTransformed(d->colorSpace.transformationToColorSpace(colorSpace));
5127 image.setColorSpace(colorSpace);
5128 return image;
5129}
5130
5143QImage QImage::convertedToColorSpace(const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags) const
5144{
5145 if (!d || !d->colorSpace.isValid())
5146 return QImage();
5147 if (!colorSpace.isValidTarget()) {
5148 qWarning() << "QImage::convertedToColorSpace: Output colorspace is not valid";
5149 return QImage();
5150 }
5152 qWarning() << "QImage::convertedToColorSpace: Color space is not compatible with format";
5153 return QImage();
5154 }
5155 if (d->colorSpace == colorSpace)
5156 return convertedTo(format, flags);
5157 QImage image = colorTransformed(d->colorSpace.transformationToColorSpace(colorSpace), format, flags);
5158 image.setColorSpace(colorSpace);
5159 return image;
5160}
5161
5168{
5169 if (!d)
5170 return QColorSpace();
5171 return d->colorSpace;
5172}
5173
5180{
5181 if (transform.isIdentity())
5182 return;
5183
5184 if (!qt_compatibleColorModelSource(pixelFormat().colorModel(), QColorTransformPrivate::get(transform)->colorSpaceIn->colorModel) ||
5185 !qt_compatibleColorModelTarget(pixelFormat().colorModel(), QColorTransformPrivate::get(transform)->colorSpaceOut->colorModel,
5186 QColorTransformPrivate::get(transform)->colorSpaceOut->transformModel)) {
5187 qWarning() << "QImage::applyColorTransform can not apply format switching transform without switching format";
5188 return;
5189 }
5190
5191 detach();
5192 if (!d)
5193 return;
5194 if (pixelFormat().colorModel() == QPixelFormat::Indexed) {
5195 for (int i = 0; i < d->colortable.size(); ++i)
5196 d->colortable[i] = transform.map(d->colortable[i]);
5197 return;
5198 }
5199 QImage::Format oldFormat = format();
5200 if (qt_fpColorPrecision(oldFormat)) {
5201 if (oldFormat != QImage::Format_RGBX32FPx4 && oldFormat != QImage::Format_RGBA32FPx4
5204 } else if (depth() > 32) {
5205 if (oldFormat != QImage::Format_RGBX64 && oldFormat != QImage::Format_RGBA64
5208 } else if (oldFormat != QImage::Format_ARGB32 && oldFormat != QImage::Format_RGB32
5209 && oldFormat != QImage::Format_ARGB32_Premultiplied && oldFormat != QImage::Format_CMYK8888
5210 && oldFormat != QImage::Format_Grayscale8 && oldFormat != QImage::Format_Grayscale16) {
5211 if (hasAlphaChannel())
5213 else
5215 }
5216
5217 QColorTransformPrivate::TransformFlags flags = QColorTransformPrivate::Unpremultiplied;
5218 switch (format()) {
5223 break;
5224 case Format_Grayscale8:
5225 case Format_Grayscale16:
5226 case Format_RGB32:
5227 case Format_CMYK8888:
5228 case Format_RGBX64:
5229 case Format_RGBX32FPx4:
5231 break;
5232 case Format_ARGB32:
5233 case Format_RGBA64:
5234 case Format_RGBA32FPx4:
5235 break;
5236 default:
5237 Q_UNREACHABLE();
5238 }
5239
5240 std::function<void(int,int)> transformSegment;
5241
5242 if (format() == Format_Grayscale8) {
5243 transformSegment = [&](int yStart, int yEnd) {
5244 for (int y = yStart; y < yEnd; ++y) {
5245 uint8_t *scanline = reinterpret_cast<uint8_t *>(d->data + y * d->bytes_per_line);
5246 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5247 }
5248 };
5249 } else if (format() == Format_Grayscale16) {
5250 transformSegment = [&](int yStart, int yEnd) {
5251 for (int y = yStart; y < yEnd; ++y) {
5252 uint16_t *scanline = reinterpret_cast<uint16_t *>(d->data + y * d->bytes_per_line);
5253 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5254 }
5255 };
5256 } else if (qt_fpColorPrecision(format())) {
5257 transformSegment = [&](int yStart, int yEnd) {
5258 for (int y = yStart; y < yEnd; ++y) {
5259 QRgbaFloat32 *scanline = reinterpret_cast<QRgbaFloat32 *>(d->data + y * d->bytes_per_line);
5260 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5261 }
5262 };
5263 } else if (depth() > 32) {
5264 transformSegment = [&](int yStart, int yEnd) {
5265 for (int y = yStart; y < yEnd; ++y) {
5266 QRgba64 *scanline = reinterpret_cast<QRgba64 *>(d->data + y * d->bytes_per_line);
5267 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5268 }
5269 };
5270 } else if (oldFormat == QImage::Format_CMYK8888) {
5271 transformSegment = [&](int yStart, int yEnd) {
5272 for (int y = yStart; y < yEnd; ++y) {
5273 QCmyk32 *scanline = reinterpret_cast<QCmyk32 *>(d->data + y * d->bytes_per_line);
5274 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5275 }
5276 };
5277 } else {
5278 transformSegment = [&](int yStart, int yEnd) {
5279 for (int y = yStart; y < yEnd; ++y) {
5280 QRgb *scanline = reinterpret_cast<QRgb *>(d->data + y * d->bytes_per_line);
5281 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5282 }
5283 };
5284 }
5285
5286#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
5287 int segments = (qsizetype(width()) * height()) >> 16;
5288 segments = std::min(segments, height());
5290 if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
5291 QSemaphore semaphore;
5292 int y = 0;
5293 for (int i = 0; i < segments; ++i) {
5294 int yn = (height() - y) / (segments - i);
5295 threadPool->start([&, y, yn]() {
5296 transformSegment(y, y + yn);
5297 semaphore.release(1);
5298 });
5299 y += yn;
5300 }
5301 semaphore.acquire(segments);
5302 } else
5303#endif
5304 transformSegment(0, height());
5305
5306 if (oldFormat != format())
5307 *this = std::move(*this).convertToFormat(oldFormat);
5308}
5309
5318void QImage::applyColorTransform(const QColorTransform &transform, QImage::Format toFormat, Qt::ImageConversionFlags flags)
5319{
5320 if (!d)
5321 return;
5322 if (transform.isIdentity())
5323 return convertTo(toFormat, flags);
5324
5325 *this = colorTransformed(transform, toFormat, flags);
5326}
5327
5341{
5342 if (!d)
5343 return QImage();
5344 if (transform.isIdentity())
5345 return *this;
5346
5347 const QColorSpacePrivate *inColorSpace = QColorTransformPrivate::get(transform)->colorSpaceIn.constData();
5348 const QColorSpacePrivate *outColorSpace = QColorTransformPrivate::get(transform)->colorSpaceOut.constData();
5349 if (!qt_compatibleColorModelSource(pixelFormat().colorModel(), inColorSpace->colorModel)) {
5350 qWarning() << "QImage::colorTransformed: Invalid input color space for transform";
5351 return QImage();
5352 }
5353 if (!qt_compatibleColorModelTarget(pixelFormat().colorModel(), outColorSpace->colorModel, outColorSpace->transformModel)) {
5354 // All model switching transforms are opaque in at least one end.
5355 switch (outColorSpace->colorModel) {
5361 return colorTransformed(transform, QImage::Format_CMYK8888);
5363 break;
5364 }
5365 return QImage();
5366 }
5367
5368 QImage image = copy();
5369 image.applyColorTransform(transform);
5370 return image;
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
5400{
5401 switch (f) {
5405 return true;
5406 default:
5407 break;
5408 }
5409 return false;
5410}
5411
5425QImage QImage::colorTransformed(const QColorTransform &transform, QImage::Format toFormat, Qt::ImageConversionFlags flags) const &
5426{
5427 if (!d)
5428 return QImage();
5429 if (toFormat == QImage::Format_Invalid)
5430 toFormat = format();
5431 if (transform.isIdentity())
5432 return convertedTo(toFormat, flags);
5433
5434 const QColorSpacePrivate *inColorSpace = QColorTransformPrivate::get(transform)->colorSpaceIn.constData();
5435 const QColorSpacePrivate *outColorSpace = QColorTransformPrivate::get(transform)->colorSpaceOut.constData();
5436 if (!qt_compatibleColorModelSource(pixelFormat().colorModel(), inColorSpace->colorModel)) {
5437 qWarning() << "QImage::colorTransformed: Invalid input color space for transform";
5438 return QImage();
5439 }
5440 if (!qt_compatibleColorModelTarget(toPixelFormat(toFormat).colorModel(), outColorSpace->colorModel, outColorSpace->transformModel)) {
5441 qWarning() << "QImage::colorTransformed: Invalid output color space for transform";
5442 return QImage();
5443 }
5444
5445 QImage fromImage = *this;
5446
5447 QImage::Format tmpFormat = toFormat;
5448 switch (toFormat) {
5461 // can be output natively
5462 break;
5470 tmpFormat = QImage::Format_RGB32;
5471 break;
5481 tmpFormat = QImage::Format_ARGB32;
5482 break;
5485 tmpFormat = QImage::Format_RGBX64;
5486 break;
5489 tmpFormat = QImage::Format_RGBA64;
5490 break;
5494 tmpFormat = QImage::Format_RGBA32FPx4;
5495 break;
5497 return convertedTo(QImage::Format_Alpha8);
5500 Q_UNREACHABLE();
5501 break;
5502 }
5503 QColorSpace::ColorModel inColorData = qt_csColorData(pixelFormat().colorModel());
5504 QColorSpace::ColorModel outColorData = qt_csColorData(toPixelFormat(toFormat).colorModel());
5505 // Ensure only precision increasing transforms
5506 if (inColorData != outColorData) {
5507 if (fromImage.format() == QImage::Format_Grayscale8 && outColorData == QColorSpace::ColorModel::Rgb)
5508 tmpFormat = QImage::Format_RGB32;
5509 else if (tmpFormat == QImage::Format_Grayscale8 && qt_highColorPrecision(fromImage.format()))
5510 tmpFormat = QImage::Format_Grayscale16;
5511 else if (fromImage.format() == QImage::Format_Grayscale16 && outColorData == QColorSpace::ColorModel::Rgb)
5512 tmpFormat = QImage::Format_RGBX64;
5513 } else {
5514 if (tmpFormat == QImage::Format_Grayscale8 && fromImage.format() == QImage::Format_Grayscale16)
5515 tmpFormat = QImage::Format_Grayscale16;
5516 else if (qt_fpColorPrecision(fromImage.format()) && !qt_fpColorPrecision(tmpFormat))
5517 tmpFormat = QImage::Format_RGBA32FPx4;
5518 else if (isRgb32Data(tmpFormat) && qt_highColorPrecision(fromImage.format(), true))
5519 tmpFormat = QImage::Format_RGBA64;
5520 }
5521
5522 QImage toImage(size(), tmpFormat);
5523 copyMetadata(&toImage, *this);
5524
5525 std::function<void(int, int)> transformSegment;
5526 QColorTransformPrivate::TransformFlags transFlags = QColorTransformPrivate::Unpremultiplied;
5527
5528 if (inColorData != outColorData) {
5529 // Needs color model switching transform
5530 if (inColorData == QColorSpace::ColorModel::Gray && outColorData == QColorSpace::ColorModel::Rgb) {
5531 // Gray -> RGB
5533 transformSegment = [&](int yStart, int yEnd) {
5534 for (int y = yStart; y < yEnd; ++y) {
5535 const quint8 *in_scanline = reinterpret_cast<const quint8 *>(d->data + y * d->bytes_per_line);
5536 QRgb *out_scanline = reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
5538 }
5539 };
5540 } else {
5541 transformSegment = [&](int yStart, int yEnd) {
5542 for (int y = yStart; y < yEnd; ++y) {
5543 const quint16 *in_scanline = reinterpret_cast<const quint16 *>(d->data + y * d->bytes_per_line);
5544 QRgba64 *out_scanline = reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5546 }
5547 };
5548 }
5549 } else if (inColorData == QColorSpace::ColorModel::Gray && outColorData == QColorSpace::ColorModel::Cmyk) {
5550 // Gray -> CMYK
5552 transformSegment = [&](int yStart, int yEnd) {
5553 for (int y = yStart; y < yEnd; ++y) {
5554 const quint8 *in_scanline = reinterpret_cast<const quint8 *>(d->data + y * d->bytes_per_line);
5555 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5557 }
5558 };
5559 } else {
5560 transformSegment = [&](int yStart, int yEnd) {
5561 for (int y = yStart; y < yEnd; ++y) {
5562 const quint16 *in_scanline = reinterpret_cast<const quint16 *>(d->data + y * d->bytes_per_line);
5563 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5565 }
5566 };
5567 }
5568 } else if (inColorData == QColorSpace::ColorModel::Rgb && outColorData == QColorSpace::ColorModel::Gray) {
5569 // RGB -> Gray
5570 if (tmpFormat == QImage::Format_Grayscale8) {
5572 transformSegment = [&](int yStart, int yEnd) {
5573 for (int y = yStart; y < yEnd; ++y) {
5574 const QRgb *in_scanline = reinterpret_cast<const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5575 quint8 *out_scanline = reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
5577 }
5578 };
5579 } else {
5581 transformSegment = [&](int yStart, int yEnd) {
5582 for (int y = yStart; y < yEnd; ++y) {
5583 const QRgba64 *in_scanline = reinterpret_cast<const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5584 quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5586 }
5587 };
5588 }
5589 } else if (inColorData == QColorSpace::ColorModel::Cmyk && outColorData == QColorSpace::ColorModel::Gray) {
5590 // CMYK -> Gray
5591 if (tmpFormat == QImage::Format_Grayscale8) {
5592 transformSegment = [&](int yStart, int yEnd) {
5593 for (int y = yStart; y < yEnd; ++y) {
5594 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5595 quint8 *out_scanline = reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
5597 }
5598 };
5599 } else {
5600 transformSegment = [&](int yStart, int yEnd) {
5601 for (int y = yStart; y < yEnd; ++y) {
5602 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5603 quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5605 }
5606 };
5607 }
5608 } else if (inColorData == QColorSpace::ColorModel::Cmyk && outColorData == QColorSpace::ColorModel::Rgb) {
5609 // CMYK -> RGB
5610 if (isRgb32Data(tmpFormat) ) {
5611 transformSegment = [&](int yStart, int yEnd) {
5612 for (int y = yStart; y < yEnd; ++y) {
5613 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5614 QRgb *out_scanline = reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
5616 }
5617 };
5618 } else if (isRgb64Data(tmpFormat)) {
5619 transformSegment = [&](int yStart, int yEnd) {
5620 for (int y = yStart; y < yEnd; ++y) {
5621 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5622 QRgba64 *out_scanline = reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5624 }
5625 };
5626 } else {
5627 Q_ASSERT(isRgb32fpx4Data(tmpFormat));
5628 transformSegment = [&](int yStart, int yEnd) {
5629 for (int y = yStart; y < yEnd; ++y) {
5630 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5631 QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5633 }
5634 };
5635 }
5636 } else if (inColorData == QColorSpace::ColorModel::Rgb && outColorData == QColorSpace::ColorModel::Cmyk) {
5637 // RGB -> CMYK
5638 if (!fromImage.hasAlphaChannel())
5640 else if (qPixelLayouts[fromImage.format()].premultiplied)
5642 if (isRgb32Data(fromImage.format()) ) {
5643 transformSegment = [&](int yStart, int yEnd) {
5644 for (int y = yStart; y < yEnd; ++y) {
5645 const QRgb *in_scanline = reinterpret_cast<const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5646 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5647 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5648 }
5649 };
5650 } else if (isRgb64Data(fromImage.format())) {
5651 transformSegment = [&](int yStart, int yEnd) {
5652 for (int y = yStart; y < yEnd; ++y) {
5653 const QRgba64 *in_scanline = reinterpret_cast<const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5654 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5655 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5656 }
5657 };
5658 } else {
5659 Q_ASSERT(isRgb32fpx4Data(fromImage.format()));
5660 transformSegment = [&](int yStart, int yEnd) {
5661 for (int y = yStart; y < yEnd; ++y) {
5662 const QRgbaFloat32 *in_scanline = reinterpret_cast<const QRgbaFloat32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5663 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5664 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5665 }
5666 };
5667 }
5668 } else {
5669 Q_UNREACHABLE();
5670 }
5671 } else {
5672 // Conversion on same color model
5673 if (pixelFormat().colorModel() == QPixelFormat::Indexed) {
5674 for (int i = 0; i < d->colortable.size(); ++i)
5675 fromImage.d->colortable[i] = transform.map(d->colortable[i]);
5676 return fromImage.convertedTo(toFormat, flags);
5677 }
5678
5679 QImage::Format oldFormat = format();
5680 if (qt_fpColorPrecision(oldFormat)) {
5681 if (oldFormat != QImage::Format_RGBX32FPx4 && oldFormat != QImage::Format_RGBA32FPx4
5684 } else if (qt_highColorPrecision(oldFormat, true)) {
5685 if (oldFormat != QImage::Format_RGBX64 && oldFormat != QImage::Format_RGBA64
5688 } else if (oldFormat != QImage::Format_ARGB32 && oldFormat != QImage::Format_RGB32
5689 && oldFormat != QImage::Format_ARGB32_Premultiplied && oldFormat != QImage::Format_CMYK8888
5690 && oldFormat != QImage::Format_Grayscale8 && oldFormat != QImage::Format_Grayscale16) {
5691 if (hasAlphaChannel())
5693 else
5695 }
5696
5697 if (!fromImage.hasAlphaChannel())
5699 else if (qPixelLayouts[fromImage.format()].premultiplied)
5701
5702 if (fromImage.format() == Format_Grayscale8) {
5703 transformSegment = [&](int yStart, int yEnd) {
5704 for (int y = yStart; y < yEnd; ++y) {
5705 const quint8 *in_scanline = reinterpret_cast<const quint8 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5706 if (tmpFormat == Format_Grayscale8) {
5707 quint8 *out_scanline = reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
5708 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5709 } else {
5710 Q_ASSERT(tmpFormat == Format_Grayscale16);
5711 quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5712 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5713 }
5714 }
5715 };
5716 } else if (fromImage.format() == Format_Grayscale16) {
5717 transformSegment = [&](int yStart, int yEnd) {
5718 for (int y = yStart; y < yEnd; ++y) {
5719 const quint16 *in_scanline = reinterpret_cast<const quint16 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5720 quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5721 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5722 }
5723 };
5724 } else if (fromImage.format() == Format_CMYK8888) {
5725 Q_ASSERT(tmpFormat == Format_CMYK8888);
5726 transformSegment = [&](int yStart, int yEnd) {
5727 for (int y = yStart; y < yEnd; ++y) {
5728 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5729 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5730 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5731 }
5732 };
5733 } else if (isRgb32fpx4Data(fromImage.format())) {
5734 Q_ASSERT(isRgb32fpx4Data(tmpFormat));
5735 transformSegment = [&](int yStart, int yEnd) {
5736 for (int y = yStart; y < yEnd; ++y) {
5737 const QRgbaFloat32 *in_scanline = reinterpret_cast<const QRgbaFloat32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5738 QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5739 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5740 }
5741 };
5742 } else if (isRgb64Data(fromImage.format())) {
5743 transformSegment = [&](int yStart, int yEnd) {
5744 for (int y = yStart; y < yEnd; ++y) {
5745 const QRgba64 *in_scanline = reinterpret_cast<const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5746 if (isRgb32fpx4Data(tmpFormat)) {
5747 QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5748 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5749 } else {
5750 Q_ASSERT(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 }
5754 }
5755 };
5756 } else {
5757 transformSegment = [&](int yStart, int yEnd) {
5758 for (int y = yStart; y < yEnd; ++y) {
5759 const QRgb *in_scanline = reinterpret_cast<const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5760 if (isRgb32fpx4Data(tmpFormat)) {
5761 QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5762 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5763 } else if (isRgb64Data(tmpFormat)) {
5764 QRgba64 *out_scanline = reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5765 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5766 } else {
5767 Q_ASSERT(isRgb32Data(tmpFormat));
5768 QRgb *out_scanline = reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
5769 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5770 }
5771 }
5772 };
5773 }
5774 }
5775
5776#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
5777 int segments = (qsizetype(width()) * height()) >> 16;
5778 segments = std::min(segments, height());
5780 if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
5781 QSemaphore semaphore;
5782 int y = 0;
5783 for (int i = 0; i < segments; ++i) {
5784 int yn = (height() - y) / (segments - i);
5785 threadPool->start([&, y, yn]() {
5786 transformSegment(y, y + yn);
5787 semaphore.release(1);
5788 });
5789 y += yn;
5790 }
5791 semaphore.acquire(segments);
5792 } else
5793#endif
5794 transformSegment(0, height());
5795
5796 if (tmpFormat != toFormat)
5797 toImage.convertTo(toFormat);
5798
5799 return toImage;
5800}
5801
5811{
5812 if (!d)
5813 return QImage();
5814
5815 const QColorSpacePrivate *inColorSpace = QColorTransformPrivate::get(transform)->colorSpaceIn.constData();
5816 const QColorSpacePrivate *outColorSpace = QColorTransformPrivate::get(transform)->colorSpaceOut.constData();
5817 if (!qt_compatibleColorModelSource(pixelFormat().colorModel(), inColorSpace->colorModel)) {
5818 qWarning() << "QImage::colorTransformed: Invalid input color space for transform";
5819 return QImage();
5820 }
5821 if (!qt_compatibleColorModelTarget(pixelFormat().colorModel(), outColorSpace->colorModel, outColorSpace->transformModel)) {
5822 // There is currently no inplace conversion of both colorspace and format, so just use the normal version.
5823 switch (outColorSpace->colorModel) {
5829 return colorTransformed(transform, QImage::Format_CMYK8888);
5831 break;
5832 }
5833 return QImage();
5834 }
5835
5836 applyColorTransform(transform);
5837 return std::move(*this);
5838}
5839
5849{
5850 // There is currently no inplace conversion of both colorspace and format, so just use the normal version.
5851 return colorTransformed(transform, format, flags);
5852}
5853
5854bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags flags)
5855{
5856 if (format == newFormat)
5857 return true;
5858
5859 // No in-place conversion if we have to detach
5860 if (ref.loadRelaxed() > 1 || !own_data)
5861 return false;
5862
5864 if (converter)
5865 return converter(this, flags);
5867 // Convert inplace generic, but only if there are no direct converters,
5868 // any direct ones are probably better even if not inplace.
5869 if (qt_highColorPrecision(newFormat, !qPixelLayouts[newFormat].hasAlphaChannel)
5870 && qt_highColorPrecision(format, !qPixelLayouts[format].hasAlphaChannel)) {
5871#if QT_CONFIG(raster_fp)
5873 return convert_generic_inplace_over_rgba32f(this, newFormat, flags);
5874#endif
5875 return convert_generic_inplace_over_rgb64(this, newFormat, flags);
5876 }
5877 return convert_generic_inplace(this, newFormat, flags);
5878 }
5879 return false;
5880}
5881
5892#ifndef QT_NO_DEBUG_STREAM
5894{
5895 QDebugStateSaver saver(dbg);
5896 dbg.nospace();
5897 dbg.noquote();
5898 dbg << "QImage(";
5899 if (i.isNull()) {
5900 dbg << "null";
5901 } else {
5902 dbg << i.size() << ",format=" << i.format() << ",depth=" << i.depth();
5903 if (i.colorCount())
5904 dbg << ",colorCount=" << i.colorCount();
5905 const int bytesPerLine = i.bytesPerLine();
5906 dbg << ",devicePixelRatio=" << i.devicePixelRatio()
5907 << ",bytesPerLine=" << bytesPerLine << ",sizeInBytes=" << i.sizeInBytes();
5908 if (dbg.verbosity() > 2 && i.height() > 0) {
5909 const int outputLength = qMin(bytesPerLine, 24);
5910 dbg << ",line0="
5911 << QByteArray(reinterpret_cast<const char *>(i.scanLine(0)), outputLength).toHex()
5912 << "...";
5913 }
5914 }
5915 dbg << ')';
5916 return dbg;
5917}
5918#endif
5919
5920static constexpr QPixelFormat pixelformats[] = {
5921 //QImage::Format_Invalid:
5922 QPixelFormat(),
5923 //QImage::Format_Mono:
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_MonoLSB:
5938 /*RED*/ 1,
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_Indexed8:
5951 /*RED*/ 8,
5952 /*GREEN*/ 0,
5953 /*BLUE*/ 0,
5954 /*FOURTH*/ 0,
5955 /*FIFTH*/ 0,
5956 /*ALPHA*/ 0,
5957 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5958 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5959 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5960 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5961 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5962 //QImage::Format_RGB32:
5964 /*RED*/ 8,
5965 /*GREEN*/ 8,
5966 /*BLUE*/ 8,
5967 /*FOURTH*/ 0,
5968 /*FIFTH*/ 0,
5969 /*ALPHA*/ 8,
5970 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5971 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5972 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5973 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5974 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5975 //QImage::Format_ARGB32:
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::NotPremultiplied,
5986 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5987 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5988 //QImage::Format_ARGB32_Premultiplied:
5990 /*RED*/ 8,
5991 /*GREEN*/ 8,
5992 /*BLUE*/ 8,
5993 /*FOURTH*/ 0,
5994 /*FIFTH*/ 0,
5995 /*ALPHA*/ 8,
5996 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5997 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5998 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5999 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6000 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6001 //QImage::Format_RGB16:
6003 /*RED*/ 5,
6004 /*GREEN*/ 6,
6005 /*BLUE*/ 5,
6006 /*FOURTH*/ 0,
6007 /*FIFTH*/ 0,
6008 /*ALPHA*/ 0,
6009 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6010 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6011 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6012 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6013 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6014 //QImage::Format_ARGB8565_Premultiplied:
6016 /*RED*/ 5,
6017 /*GREEN*/ 6,
6018 /*BLUE*/ 5,
6019 /*FOURTH*/ 0,
6020 /*FIFTH*/ 0,
6021 /*ALPHA*/ 8,
6022 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6023 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6024 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6025 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6026 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6027 //QImage::Format_RGB666:
6029 /*RED*/ 6,
6030 /*GREEN*/ 6,
6031 /*BLUE*/ 6,
6032 /*FOURTH*/ 0,
6033 /*FIFTH*/ 0,
6034 /*ALPHA*/ 0,
6035 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6036 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6037 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6038 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6039 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6040 //QImage::Format_ARGB6666_Premultiplied:
6042 /*RED*/ 6,
6043 /*GREEN*/ 6,
6044 /*BLUE*/ 6,
6045 /*FOURTH*/ 0,
6046 /*FIFTH*/ 0,
6047 /*ALPHA*/ 6,
6048 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6049 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6050 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6051 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6052 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6053 //QImage::Format_RGB555:
6055 /*RED*/ 5,
6056 /*GREEN*/ 5,
6057 /*BLUE*/ 5,
6058 /*FOURTH*/ 0,
6059 /*FIFTH*/ 0,
6060 /*ALPHA*/ 0,
6061 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6062 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6063 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6064 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6065 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6066 //QImage::Format_ARGB8555_Premultiplied:
6068 /*RED*/ 5,
6069 /*GREEN*/ 5,
6070 /*BLUE*/ 5,
6071 /*FOURTH*/ 0,
6072 /*FIFTH*/ 0,
6073 /*ALPHA*/ 8,
6074 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6075 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6076 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6077 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6078 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6079 //QImage::Format_RGB888:
6081 /*RED*/ 8,
6082 /*GREEN*/ 8,
6083 /*BLUE*/ 8,
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::UnsignedByte,
6091 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6092 //QImage::Format_RGB444:
6094 /*RED*/ 4,
6095 /*GREEN*/ 4,
6096 /*BLUE*/ 4,
6097 /*FOURTH*/ 0,
6098 /*FIFTH*/ 0,
6099 /*ALPHA*/ 0,
6100 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6101 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6102 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6103 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6104 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6105 //QImage::Format_ARGB4444_Premultiplied:
6107 /*RED*/ 4,
6108 /*GREEN*/ 4,
6109 /*BLUE*/ 4,
6110 /*FOURTH*/ 0,
6111 /*FIFTH*/ 0,
6112 /*ALPHA*/ 4,
6113 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6114 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6115 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6116 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6117 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6118 //QImage::Format_RGBX8888:
6120 /*RED*/ 8,
6121 /*GREEN*/ 8,
6122 /*BLUE*/ 8,
6123 /*FOURTH*/ 0,
6124 /*FIFTH*/ 0,
6125 /*ALPHA*/ 8,
6126 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6127 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6128 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6129 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6130 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6131 //QImage::Format_RGBA8888:
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::NotPremultiplied,
6142 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6143 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6144 //QImage::Format_RGBA8888_Premultiplied:
6146 /*RED*/ 8,
6147 /*GREEN*/ 8,
6148 /*BLUE*/ 8,
6149 /*FOURTH*/ 0,
6150 /*FIFTH*/ 0,
6151 /*ALPHA*/ 8,
6152 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6153 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6154 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6155 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6156 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6157 //QImage::Format_BGR30:
6159 /*RED*/ 10,
6160 /*GREEN*/ 10,
6161 /*BLUE*/ 10,
6162 /*FOURTH*/ 0,
6163 /*FIFTH*/ 0,
6164 /*ALPHA*/ 2,
6165 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6166 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6167 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6168 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6169 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6170 //QImage::Format_A2BGR30_Premultiplied:
6172 /*RED*/ 10,
6173 /*GREEN*/ 10,
6174 /*BLUE*/ 10,
6175 /*FOURTH*/ 0,
6176 /*FIFTH*/ 0,
6177 /*ALPHA*/ 2,
6178 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6179 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6180 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6181 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6182 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6183 //QImage::Format_RGB30:
6185 /*RED*/ 10,
6186 /*GREEN*/ 10,
6187 /*BLUE*/ 10,
6188 /*FOURTH*/ 0,
6189 /*FIFTH*/ 0,
6190 /*ALPHA*/ 2,
6191 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6192 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6193 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6194 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6195 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6196 //QImage::Format_A2RGB30_Premultiplied:
6198 /*RED*/ 10,
6199 /*GREEN*/ 10,
6200 /*BLUE*/ 10,
6201 /*FOURTH*/ 0,
6202 /*FIFTH*/ 0,
6203 /*ALPHA*/ 2,
6204 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6205 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6206 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6207 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6208 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6209 //QImage::Format_Alpha8:
6211 /*First*/ 0,
6212 /*SECOND*/ 0,
6213 /*THIRD*/ 0,
6214 /*FOURTH*/ 0,
6215 /*FIFTH*/ 0,
6216 /*ALPHA*/ 8,
6217 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6218 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6219 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6220 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6221 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6222 //QImage::Format_Grayscale8:
6224 /*GRAY*/ 8,
6225 /*SECOND*/ 0,
6226 /*THIRD*/ 0,
6227 /*FOURTH*/ 0,
6228 /*FIFTH*/ 0,
6229 /*ALPHA*/ 0,
6230 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6231 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6232 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6233 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6234 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6235 //QImage::Format_RGBX64:
6237 /*RED*/ 16,
6238 /*GREEN*/ 16,
6239 /*BLUE*/ 16,
6240 /*FOURTH*/ 0,
6241 /*FIFTH*/ 0,
6242 /*ALPHA*/ 16,
6243 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6244 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6245 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6246 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6247 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6248 //QImage::Format_RGBA64:
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::NotPremultiplied,
6259 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6260 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6261 //QImage::Format_RGBA64_Premultiplied:
6263 /*RED*/ 16,
6264 /*GREEN*/ 16,
6265 /*BLUE*/ 16,
6266 /*FOURTH*/ 0,
6267 /*FIFTH*/ 0,
6268 /*ALPHA*/ 16,
6269 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6270 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6271 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6272 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6273 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6274 //QImage::Format_Grayscale16:
6276 /*GRAY*/ 16,
6277 /*SECOND*/ 0,
6278 /*THIRD*/ 0,
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::UnsignedShort,
6286 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6287 //QImage::Format_BGR888:
6289 /*RED*/ 8,
6290 /*GREEN*/ 8,
6291 /*BLUE*/ 8,
6292 /*FOURTH*/ 0,
6293 /*FIFTH*/ 0,
6294 /*ALPHA*/ 0,
6295 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6296 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6297 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6298 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6299 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6300 //QImage::Format_RGBX16FPx4:
6302 /*RED*/ 16,
6303 /*GREEN*/ 16,
6304 /*BLUE*/ 16,
6305 /*FOURTH*/ 0,
6306 /*FIFTH*/ 0,
6307 /*ALPHA*/ 16,
6308 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6309 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6310 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6311 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6312 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6313 //QImage::Format_RGBA16FPx4:
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::NotPremultiplied,
6324 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6325 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6326 //QImage::Format_RGBA16FPx4_Premultiplied:
6328 /*RED*/ 16,
6329 /*GREEN*/ 16,
6330 /*BLUE*/ 16,
6331 /*FOURTH*/ 0,
6332 /*FIFTH*/ 0,
6333 /*ALPHA*/ 16,
6334 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6335 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6336 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6337 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6338 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6339 //QImage::Format_RGBX32FPx4:
6341 /*RED*/ 32,
6342 /*GREEN*/ 32,
6343 /*BLUE*/ 32,
6344 /*FOURTH*/ 0,
6345 /*FIFTH*/ 0,
6346 /*ALPHA*/ 32,
6347 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6348 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6349 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6350 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6351 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6352 //QImage::Format_RGBA32FPx4:
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::NotPremultiplied,
6363 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6364 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6365 //QImage::Format_RGBA32FPx4_Premultiplied:
6367 /*RED*/ 32,
6368 /*GREEN*/ 32,
6369 /*BLUE*/ 32,
6370 /*FOURTH*/ 0,
6371 /*FIFTH*/ 0,
6372 /*ALPHA*/ 32,
6373 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6374 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6375 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6376 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6377 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6378 //QImage::Format_CMYK8888:
6380 /*RED*/ 8,
6381 /*GREEN*/ 8,
6382 /*BLUE*/ 8,
6383 /*FOURTH*/ 8,
6384 /*FIFTH*/ 0,
6385 /*ALPHA*/ 0,
6386 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6387 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6388 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6389 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6390 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6391};
6392static_assert(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats);
6393
6398{
6399 return toPixelFormat(format());
6400}
6401
6406{
6407 Q_ASSERT(static_cast<int>(format) < NImageFormats && static_cast<int>(format) >= 0);
6408 return pixelformats[format];
6409}
6410
6415{
6416 for (int i = 0; i < NImageFormats; i++) {
6417 if (format == pixelformats[i])
6418 return Format(i);
6419 }
6420 return Format_Invalid;
6421}
6422
6423Q_GUI_EXPORT void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient)
6424{
6426 return;
6428 src = rotated270(src);
6429 } else {
6430 src = std::move(src).mirrored(orient & QImageIOHandler::TransformationMirror,
6433 src = rotated90(src);
6434 }
6435}
6436
6437QMap<QString, QString> qt_getImageText(const QImage &image, const QString &description)
6438{
6439 QMap<QString, QString> text = qt_getImageTextFromDescription(description);
6440 const auto textKeys = image.textKeys();
6441 for (const QString &key : textKeys) {
6442 if (!key.isEmpty() && !text.contains(key))
6443 text.insert(key, image.text(key));
6444 }
6445 return text;
6446}
6447
6448QMap<QString, QString> qt_getImageTextFromDescription(const QString &description)
6449{
6450 QMap<QString, QString> text;
6451 for (const auto &pair : QStringView{description}.tokenize(u"\n\n")) {
6452 int index = pair.indexOf(u':');
6453 if (index >= 0 && pair.indexOf(u' ') < index) {
6454 if (!pair.trimmed().isEmpty())
6455 text.insert("Description"_L1, pair.toString().simplified());
6456 } else {
6457 const auto key = pair.left(index);
6458 if (!key.trimmed().isEmpty())
6459 text.insert(key.toString(), pair.mid(index + 2).toString().simplified());
6460 }
6461 }
6462 return text;
6463}
6464
6466
6467#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:410
The QColorSpace class provides a color space abstraction.
Definition qcolorspace.h:21
TransformModel transformModel() const noexcept
Returns the transfrom processing model used for this color space.
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:47
\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:4617
bool hasAlphaChannel() const
Returns true if the image has a format that respects the alpha channel, otherwise returns false.
Definition qimage.cpp:4595
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:4554
QColorSpace colorSpace() const
Definition qimage.cpp:5167
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:6405
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:5340
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:4670
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:4529
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:5179
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:6397
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:5024
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:6414
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:4810
QImage scaledToWidth(int w, Qt::TransformationMode mode=Qt::FastTransformation) const
[9]
Definition qimage.cpp:3013
void convertToColorSpace(const QColorSpace &colorSpace)
Definition qimage.cpp:5050
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:5116
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:4513
@ PdmDevicePixelRatioF_EncodedB
@ PdmDevicePixelRatioF_EncodedA
@ PdmDevicePixelRatioScaled
static int encodeMetricF(PaintDeviceMetric metric, double value)
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:137
\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:4522
void chop(qsizetype n)
Removes n characters from the end of the string.
Definition qstring.cpp:6351
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:3134
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:537
\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:4365
static QImage rotated90(const QImage &src)
Definition qimage.cpp:4716
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:4391
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:5399
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:4374
Q_GUI_EXPORT void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient)
Definition qimage.cpp:6423
static QImage rotated270(const QImage &src)
Definition qimage.cpp:4760
QMap< QString, QString > qt_getImageText(const QImage &image, const QString &description)
Definition qimage.cpp:6437
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:5920
static bool isRgb64Data(QImage::Format f)
Definition qimage.cpp:5386
#define PIX(x, y)
static QImage rotated180(const QImage &src)
Definition qimage.cpp:4742
QDataStream & operator>>(QDataStream &s, QImage &image)
Definition qimage.cpp:3973
static bool isRgb32Data(QImage::Format f)
Definition qimage.cpp:5373
QMap< QString, QString > qt_getImageTextFromDescription(const QString &description)
Definition qimage.cpp:6448
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:145
Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats]
QColorSpace::ColorModel qt_csColorData(QPixelFormat::ColorModel format)
Definition qimage_p.h:443
bool qt_fpColorPrecision(QImage::Format format)
Definition qimage_p.h:427
bool(* InPlace_Image_Converter)(QImageData *data, Qt::ImageConversionFlags)
Definition qimage_p.h:123
InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats]
QImage::Format qt_alphaVersion(QImage::Format format)
Definition qimage_p.h:270
bool qt_compatibleColorModelTarget(QPixelFormat::ColorModel data, QColorSpace::ColorModel cs, QColorSpace::TransformModel tm)
Definition qimage_p.h:486
bool qt_highColorPrecision(QImage::Format format, bool opaque=false)
Definition qimage_p.h:399
void(* Image_Converter)(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
Definition qimage_p.h:122
QImage::Format qt_alphaVersionForPainting(QImage::Format format)
Definition qimage_p.h:562
bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags)
bool qt_compatibleColorModelSource(QPixelFormat::ColorModel data, QColorSpace::ColorModel cs)
Definition qimage_p.h:475
QImage qSmoothScaleImage(const QImage &src, int dw, int dh)
#define qWarning
Definition qlogging.h:167
static ControlElement< T > * ptr(QWidget *widget)
MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3]
QT_BEGIN_NAMESPACE constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:19
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:21
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:226
#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:55
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:43
int height
Definition qimage_p.h:46
static QImageData * get(QImage &img) noexcept
Definition qimage_p.h:40
uchar * data
Definition qimage_p.h:51
static ImageSizeParameters calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth)
Definition qimage_p.h:92
int ser_no
Definition qimage_p.h:54
uint is_cached
Definition qimage_p.h:64
int width
Definition qimage_p.h:45
bool convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags)
Definition qimage.cpp:5854
void * cleanupInfo
Definition qimage_p.h:67
QList< QRgb > colortable
Definition qimage_p.h:50
uint own_data
Definition qimage_p.h:61
static QImageData * create(const QSize &size, QImage::Format format)
qsizetype bytes_per_line
Definition qimage_p.h:53
int depth
Definition qimage_p.h:47
uint has_alpha_clut
Definition qimage_p.h:63
QPaintEngine * paintEngine
Definition qimage_p.h:79
QImage::Format format
Definition qimage_p.h:52
QImageCleanupFunction cleanupFunction
Definition qimage_p.h:66