Qt 6.x
The Qt SDK
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/qcolortransform_p.h>
25#include <private/qmemrotate_p.h>
26#include <private/qimagescale_p.h>
27#include <private/qpixellayout_p.h>
28#include <private/qsimd_p.h>
29
30#include <qhash.h>
31
32#include <private/qpaintengine_raster_p.h>
33
34#include <private/qimage_p.h>
35#include <private/qfont_p.h>
36
37#if QT_CONFIG(thread)
38#include <qsemaphore.h>
39#include <qthreadpool.h>
40#include <private/qthreadpool_p.h>
41#endif
42
43#include <qtgui_tracepoints_p.h>
44
45#include <memory>
46
48
49using namespace Qt::StringLiterals;
50
51// MSVC 19.28 does show spurious warning "C4723: potential divide by 0" for code that divides
52// by height() in release builds. Anyhow, all the code paths in this file are only executed
53// for valid QImage's, where height() cannot be 0. Therefore disable the warning.
55
56#if defined(Q_CC_DEC) && defined(__alpha) && (__DECCXX_VER-0 >= 50190001)
57#pragma message disable narrowptr
58#endif
59
60
61#define QIMAGE_SANITYCHECK_MEMORY(image) \
62 if ((image).isNull()) { \
63 qWarning("QImage: out of memory, returning null image"); \
64 return QImage(); \
65 }
66
68 "#include <qimagereader.h>"
69);
70
72"ENUM { } QImage::Format;" \
73"FLAGS { } Qt::ImageConversionFlags;"
74);
75
78
79static QImage rotated90(const QImage &src);
80static QImage rotated180(const QImage &src);
81static QImage rotated270(const QImage &src);
82
84{
85 Q_CONSTINIT static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
86 return 1 + serial.fetchAndAddRelaxed(1);
87}
88
90 : ref(0), width(0), height(0), depth(0), nbytes(0), devicePixelRatio(1.0), data(nullptr),
91 format(QImage::Format_ARGB32), bytes_per_line(0),
93 detach_no(0),
94 dpmx(qt_defaultDpiX() * 100 / qreal(2.54)),
95 dpmy(qt_defaultDpiY() * 100 / qreal(2.54)),
96 offset(0, 0), own_data(true), ro_data(false), has_alpha_clut(false),
97 is_cached(false), cleanupFunction(nullptr), cleanupInfo(nullptr),
98 paintEngine(nullptr)
99{
100}
101
110{
111 if (size.isEmpty() || format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
112 return nullptr; // invalid parameter(s)
113
114 Q_TRACE_SCOPE(QImageData_create, size, format);
115
116 int width = size.width();
117 int height = size.height();
120 if (!params.isValid())
121 return nullptr;
122
123 auto d = std::make_unique<QImageData>();
124
125 switch (format) {
128 d->colortable.resize(2);
129 d->colortable[0] = QColor(Qt::black).rgba();
130 d->colortable[1] = QColor(Qt::white).rgba();
131 break;
132 default:
133 break;
134 }
135
136 d->width = width;
137 d->height = height;
138 d->depth = depth;
139 d->format = format;
140 d->has_alpha_clut = false;
141 d->is_cached = false;
142
143 d->bytes_per_line = params.bytesPerLine;
144 d->nbytes = params.totalSize;
145 d->data = (uchar *)malloc(d->nbytes);
146
147 if (!d->data)
148 return nullptr;
149
150 d->ref.ref();
151 return d.release();
152}
153
155{
156 if (cleanupFunction)
158 if (is_cached)
160 delete paintEngine;
161 if (data && own_data)
162 free(data);
163 data = nullptr;
164}
165
166#if defined(_M_ARM) && defined(_MSC_VER)
167#pragma optimize("", off)
168#endif
169
171{
172 bool has_alpha_pixels = false;
173
174 switch (format) {
175
179 has_alpha_pixels = has_alpha_clut;
180 break;
182 has_alpha_pixels = true;
183 break;
186 const uchar *bits = data;
187 for (int y=0; y<height && !has_alpha_pixels; ++y) {
188 uint alphaAnd = 0xff000000;
189 for (int x=0; x<width; ++x)
190 alphaAnd &= reinterpret_cast<const uint*>(bits)[x];
191 has_alpha_pixels = (alphaAnd != 0xff000000);
193 }
194 } break;
195
198 const uchar *bits = data;
199 for (int y=0; y<height && !has_alpha_pixels; ++y) {
200 uchar alphaAnd = 0xff;
201 for (int x=0; x<width; ++x)
202 alphaAnd &= bits[x * 4+ 3];
203 has_alpha_pixels = (alphaAnd != 0xff);
205 }
206 } break;
207
210 const uchar *bits = data;
211 for (int y=0; y<height && !has_alpha_pixels; ++y) {
212 uint alphaAnd = 0xc0000000;
213 for (int x=0; x<width; ++x)
214 alphaAnd &= reinterpret_cast<const uint*>(bits)[x];
215 has_alpha_pixels = (alphaAnd != 0xc0000000);
217 }
218 } break;
219
222 const uchar *bits = data;
223 const uchar *end_bits = data + bytes_per_line;
224
225 for (int y=0; y<height && !has_alpha_pixels; ++y) {
226 uchar alphaAnd = 0xff;
227 while (bits < end_bits) {
228 alphaAnd &= bits[0];
229 bits += 3;
230 }
231 has_alpha_pixels = (alphaAnd != 0xff);
232 bits = end_bits;
233 end_bits += bytes_per_line;
234 }
235 } break;
236
238 const uchar *bits = data;
239 const uchar *end_bits = data + bytes_per_line;
240
241 for (int y=0; y<height && !has_alpha_pixels; ++y) {
242 uchar alphaAnd = 0xfc;
243 while (bits < end_bits) {
244 alphaAnd &= bits[0];
245 bits += 3;
246 }
247 has_alpha_pixels = (alphaAnd != 0xfc);
248 bits = end_bits;
249 end_bits += bytes_per_line;
250 }
251 } break;
252
254 const uchar *bits = data;
255 for (int y=0; y<height && !has_alpha_pixels; ++y) {
256 ushort alphaAnd = 0xf000;
257 for (int x=0; x<width; ++x)
258 alphaAnd &= reinterpret_cast<const ushort*>(bits)[x];
259 has_alpha_pixels = (alphaAnd != 0xf000);
261 }
262 } break;
265 uchar *bits = data;
266 for (int y=0; y<height && !has_alpha_pixels; ++y) {
267 for (int x=0; x<width; ++x) {
268 has_alpha_pixels |= !(((QRgba64 *)bits)[x].isOpaque());
269 }
271 }
272 } break;
275 uchar *bits = data;
276 for (int y = 0; y < height && !has_alpha_pixels; ++y) {
277 for (int x = 0; x < width; ++x)
278 has_alpha_pixels |= ((qfloat16 *)bits)[x * 4 + 3] < 1.0f;
280 }
281 } break;
284 uchar *bits = data;
285 for (int y = 0; y < height && !has_alpha_pixels; ++y) {
286 for (int x = 0; x < width; ++x)
287 has_alpha_pixels |= ((float *)bits)[x * 4 + 3] < 1.0f;
289 }
290 } break;
291
307 break;
310 Q_UNREACHABLE();
311 break;
312 }
313
314 return has_alpha_pixels;
315}
316#if defined(_M_ARM) && defined(_MSC_VER)
317#pragma optimize("", on)
318#endif
319
756/*****************************************************************************
757 QImage member functions
758 *****************************************************************************/
759
767 : QPaintDevice()
768{
769 d = nullptr;
770}
771
784{
785}
786
797 : QPaintDevice()
798{
800}
801
802
803
804QImageData *QImageData::create(uchar *data, int width, int height, qsizetype bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
805{
806 if (width <= 0 || height <= 0 || !data || format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
807 return nullptr;
808
809 const int depth = qt_depthForFormat(format);
811 if (!params.isValid())
812 return nullptr;
813
814 if (bpl > 0) {
815 // can't overflow, because has calculateImageParameters already done this multiplication
816 const qsizetype min_bytes_per_line = (qsizetype(width) * depth + 7)/8;
817 if (bpl < min_bytes_per_line)
818 return nullptr;
819
820 // recalculate the total with this value
821 params.bytesPerLine = bpl;
822 if (qMulOverflow<qsizetype>(bpl, height, &params.totalSize))
823 return nullptr;
824 }
825
826 QImageData *d = new QImageData;
827 d->ref.ref();
828
829 d->own_data = false;
830 d->ro_data = readOnly;
831 d->data = data;
832 d->width = width;
833 d->height = height;
834 d->depth = depth;
835 d->format = format;
836
837 d->bytes_per_line = params.bytesPerLine;
838 d->nbytes = params.totalSize;
839
840 d->cleanupFunction = cleanupFunction;
841 d->cleanupInfo = cleanupInfo;
842
843 return d;
844}
845
863QImage::QImage(uchar* data, int width, int height, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
864 : QPaintDevice()
865{
866 d = QImageData::create(data, width, height, 0, format, false, cleanupFunction, cleanupInfo);
867}
868
894QImage::QImage(const uchar* data, int width, int height, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
895 : QPaintDevice()
896{
897 d = QImageData::create(const_cast<uchar*>(data), width, height, 0, format, true, cleanupFunction, cleanupInfo);
898}
899
918QImage::QImage(uchar *data, int width, int height, qsizetype bytesPerLine, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
919 :QPaintDevice()
920{
921 d = QImageData::create(data, width, height, bytesPerLine, format, false, cleanupFunction, cleanupInfo);
922}
923
949QImage::QImage(const uchar *data, int width, int height, qsizetype bytesPerLine, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
950 :QPaintDevice()
951{
952 d = QImageData::create(const_cast<uchar*>(data), width, height, bytesPerLine, format, true, cleanupFunction, cleanupInfo);
953}
954
976 : QPaintDevice()
977{
978 d = nullptr;
980}
981
982#ifndef QT_NO_IMAGEFORMAT_XPM
983extern bool qt_read_xpm_image_or_array(QIODevice *device, const char * const *source, QImage &image);
984
1001QImage::QImage(const char * const xpm[])
1002 : QPaintDevice()
1003{
1004 d = nullptr;
1005 if (!xpm)
1006 return;
1007 if (!qt_read_xpm_image_or_array(nullptr, xpm, *this))
1008 // Issue: Warning because the constructor may be ambiguous
1009 qWarning("QImage::QImage(), XPM is not supported");
1010}
1011#endif // QT_NO_IMAGEFORMAT_XPM
1012
1023 : QPaintDevice()
1024{
1025 if (image.paintingActive()) {
1026 d = nullptr;
1027 image.copy().swap(*this);
1028 } else {
1029 d = image.d;
1030 if (d)
1031 d->ref.ref();
1032 }
1033}
1034
1040{
1041 if (d && !d->ref.deref())
1042 delete d;
1043}
1044
1056{
1057 if (image.paintingActive()) {
1058 operator=(image.copy());
1059 } else {
1060 if (image.d)
1061 image.d->ref.ref();
1062 if (d && !d->ref.deref())
1063 delete d;
1064 d = image.d;
1065 }
1066 return *this;
1067}
1068
1081{
1082 return QInternal::Image;
1083}
1084
1088QImage::operator QVariant() const
1089{
1090 return QVariant::fromValue(*this);
1091}
1092
1105{
1106 if (d) {
1107 if (d->is_cached && d->ref.loadRelaxed() == 1)
1109
1110 if (d->ref.loadRelaxed() != 1 || d->ro_data)
1111 *this = copy();
1112
1113 if (d)
1114 ++d->detach_no;
1115 }
1116}
1117
1118
1127void QImage::detachMetadata(bool invalidateCache)
1128{
1129 if (d) {
1130 if (d->is_cached && d->ref.loadRelaxed() == 1)
1132
1133 if (d->ref.loadRelaxed() != 1)
1134 *this = copy();
1135
1136 if (d && invalidateCache)
1137 ++d->detach_no;
1138 }
1139}
1140
1142{
1143 dst->dpmx = src->dpmx;
1144 dst->dpmy = src->dpmy;
1145 dst->devicePixelRatio = src->devicePixelRatio;
1146}
1147
1149{
1150 // Doesn't copy colortable and alpha_clut, or offset.
1152 dst->text = src->text;
1153 dst->colorSpace = src->colorSpace;
1154}
1155
1156static void copyMetadata(QImage *dst, const QImage &src)
1157{
1158 dst->setDotsPerMeterX(src.dotsPerMeterX());
1159 dst->setDotsPerMeterY(src.dotsPerMeterY());
1160 dst->setDevicePixelRatio(src.devicePixelRatio());
1161 const auto textKeys = src.textKeys();
1162 for (const auto &key: textKeys)
1163 dst->setText(key, src.text(key));
1164
1165}
1166
1197QImage Q_TRACE_INSTRUMENT(qtgui) QImage::copy(const QRect& r) const
1198{
1199 Q_TRACE_SCOPE(QImage_copy, r);
1200 if (!d)
1201 return QImage();
1202
1203 if (r.isNull()) {
1204 QImage image(d->width, d->height, d->format);
1205 if (image.isNull())
1206 return image;
1207
1208 // Qt for Embedded Linux can create images with non-default bpl
1209 // make sure we don't crash.
1210 if (image.d->nbytes != d->nbytes) {
1211 qsizetype bpl = qMin(bytesPerLine(), image.bytesPerLine());
1212 for (int i = 0; i < height(); i++)
1213 memcpy(image.scanLine(i), scanLine(i), bpl);
1214 } else
1215 memcpy(image.bits(), bits(), d->nbytes);
1216 image.d->colortable = d->colortable;
1217 image.d->offset = d->offset;
1218 image.d->has_alpha_clut = d->has_alpha_clut;
1219 copyMetadata(image.d, d);
1220 return image;
1221 }
1222
1223 int x = r.x();
1224 int y = r.y();
1225 int w = r.width();
1226 int h = r.height();
1227
1228 int dx = 0;
1229 int dy = 0;
1230 if (w <= 0 || h <= 0)
1231 return QImage();
1232
1233 QImage image(w, h, d->format);
1234 if (image.isNull())
1235 return image;
1236
1237 if (x < 0 || y < 0 || x + w > d->width || y + h > d->height) {
1238 // bitBlt will not cover entire image - clear it.
1239 image.fill(0);
1240 if (x < 0) {
1241 dx = -x;
1242 x = 0;
1243 }
1244 if (y < 0) {
1245 dy = -y;
1246 y = 0;
1247 }
1248 }
1249
1250 image.d->colortable = d->colortable;
1251
1252 int pixels_to_copy = qMax(w - dx, 0);
1253 if (x > d->width)
1254 pixels_to_copy = 0;
1255 else if (pixels_to_copy > d->width - x)
1256 pixels_to_copy = d->width - x;
1257 int lines_to_copy = qMax(h - dy, 0);
1258 if (y > d->height)
1259 lines_to_copy = 0;
1260 else if (lines_to_copy > d->height - y)
1261 lines_to_copy = d->height - y;
1262
1263 bool byteAligned = true;
1264 if (d->format == Format_Mono || d->format == Format_MonoLSB)
1265 byteAligned = !(dx & 7) && !(x & 7) && !(pixels_to_copy & 7);
1266
1267 if (byteAligned) {
1268 const uchar *src = d->data + ((x * d->depth) >> 3) + y * d->bytes_per_line;
1269 uchar *dest = image.d->data + ((dx * d->depth) >> 3) + dy * image.d->bytes_per_line;
1270 const qsizetype bytes_to_copy = (qsizetype(pixels_to_copy) * d->depth) >> 3;
1271 for (int i = 0; i < lines_to_copy; ++i) {
1272 memcpy(dest, src, bytes_to_copy);
1273 src += d->bytes_per_line;
1274 dest += image.d->bytes_per_line;
1275 }
1276 } else if (d->format == Format_Mono) {
1277 const uchar *src = d->data + y * d->bytes_per_line;
1278 uchar *dest = image.d->data + dy * image.d->bytes_per_line;
1279 for (int i = 0; i < lines_to_copy; ++i) {
1280 for (int j = 0; j < pixels_to_copy; ++j) {
1281 if (src[(x + j) >> 3] & (0x80 >> ((x + j) & 7)))
1282 dest[(dx + j) >> 3] |= (0x80 >> ((dx + j) & 7));
1283 else
1284 dest[(dx + j) >> 3] &= ~(0x80 >> ((dx + j) & 7));
1285 }
1286 src += d->bytes_per_line;
1287 dest += image.d->bytes_per_line;
1288 }
1289 } else { // Format_MonoLSB
1291 const uchar *src = d->data + y * d->bytes_per_line;
1292 uchar *dest = image.d->data + dy * image.d->bytes_per_line;
1293 for (int i = 0; i < lines_to_copy; ++i) {
1294 for (int j = 0; j < pixels_to_copy; ++j) {
1295 if (src[(x + j) >> 3] & (0x1 << ((x + j) & 7)))
1296 dest[(dx + j) >> 3] |= (0x1 << ((dx + j) & 7));
1297 else
1298 dest[(dx + j) >> 3] &= ~(0x1 << ((dx + j) & 7));
1299 }
1300 src += d->bytes_per_line;
1301 dest += image.d->bytes_per_line;
1302 }
1303 }
1304
1305 copyMetadata(image.d, d);
1306 image.d->offset = offset();
1307 image.d->has_alpha_clut = d->has_alpha_clut;
1308 return image;
1309}
1310
1311
1319bool QImage::isNull() const
1320{
1321 return !d;
1322}
1323
1331int QImage::width() const
1332{
1333 return d ? d->width : 0;
1334}
1335
1343int QImage::height() const
1344{
1345 return d ? d->height : 0;
1346}
1347
1355QSize QImage::size() const
1356{
1357 return d ? QSize(d->width, d->height) : QSize(0, 0);
1358}
1359
1368QRect QImage::rect() const
1369{
1370 return d ? QRect(0, 0, d->width, d->height) : QRect();
1371}
1372
1385int QImage::depth() const
1386{
1387 return d ? d->depth : 0;
1388}
1389
1402int QImage::colorCount() const
1403{
1404 return d ? d->colortable.size() : 0;
1405}
1406
1419{
1420 if (!d)
1421 return;
1422 detachMetadata(true);
1423
1424 // In case detach() ran out of memory
1425 if (!d)
1426 return;
1427
1428 d->colortable = colors;
1429 d->has_alpha_clut = false;
1430 for (int i = 0; i < d->colortable.size(); ++i) {
1431 if (qAlpha(d->colortable.at(i)) != 255) {
1432 d->has_alpha_clut = true;
1433 break;
1434 }
1435 }
1436}
1437
1445{
1446 return d ? d->colortable : QList<QRgb>();
1447}
1448
1461{
1462 if (!d)
1463 return 1.0;
1464 return d->devicePixelRatio;
1465}
1466
1489{
1490 if (!d)
1491 return;
1492
1493 if (scaleFactor == d->devicePixelRatio)
1494 return;
1495
1497 if (d)
1498 d->devicePixelRatio = scaleFactor;
1499}
1500
1512{
1513 if (!d)
1514 return QSizeF(0, 0);
1515 return QSizeF(d->width, d->height) / d->devicePixelRatio;
1516}
1517
1518
1527{
1528 return d ? d->nbytes : 0;
1529}
1530
1539{
1540 return d ? d->bytes_per_line : 0;
1541}
1542
1543
1556{
1557 Q_ASSERT(i < colorCount());
1558 return d ? d->colortable.at(i) : QRgb(uint(-1));
1559}
1560
1574{
1575 if (!d)
1576 return;
1577 if (i < 0 || d->depth > 8 || i >= 1<<d->depth) {
1578 qWarning("QImage::setColor: Index out of bound %d", i);
1579 return;
1580 }
1581 detachMetadata(true);
1582
1583 // In case detach() run out of memory
1584 if (!d)
1585 return;
1586
1587 if (i >= d->colortable.size())
1588 setColorCount(i+1);
1589 d->colortable[i] = c;
1590 d->has_alpha_clut |= (qAlpha(c) != 255);
1591}
1592
1616{
1617 if (!d)
1618 return nullptr;
1619
1620 detach();
1621
1622 // In case detach() ran out of memory
1623 if (!d)
1624 return nullptr;
1625
1626 return d->data + i * d->bytes_per_line;
1627}
1628
1632const uchar *QImage::scanLine(int i) const
1633{
1634 if (!d)
1635 return nullptr;
1636
1637 Q_ASSERT(i >= 0 && i < height());
1638 return d->data + i * d->bytes_per_line;
1639}
1640
1641
1658{
1659 if (!d)
1660 return nullptr;
1661
1662 Q_ASSERT(i >= 0 && i < height());
1663 return d->data + i * d->bytes_per_line;
1664}
1665
1678{
1679 if (!d)
1680 return nullptr;
1681 detach();
1682
1683 // In case detach ran out of memory...
1684 if (!d)
1685 return nullptr;
1686
1687 return d->data;
1688}
1689
1697const uchar *QImage::bits() const
1698{
1699 return d ? d->data : nullptr;
1700}
1701
1702
1714{
1715 return d ? d->data : nullptr;
1716}
1717
1739{
1740 if (!d)
1741 return;
1742
1743 detach();
1744
1745 // In case detach() ran out of memory
1746 if (!d)
1747 return;
1748
1749 if (d->depth == 1 || d->depth == 8) {
1750 int w = d->width;
1751 if (d->depth == 1) {
1752 if (pixel & 1)
1753 pixel = 0xffffffff;
1754 else
1755 pixel = 0;
1756 w = (w + 7) / 8;
1757 } else {
1758 pixel &= 0xff;
1759 }
1760 qt_rectfill<quint8>(d->data, pixel, 0, 0,
1761 w, d->height, d->bytes_per_line);
1762 return;
1763 } else if (d->depth == 16) {
1764 if (d->format == Format_RGB444)
1765 pixel |= 0xf000;
1766 qt_rectfill<quint16>(reinterpret_cast<quint16*>(d->data), pixel,
1767 0, 0, d->width, d->height, d->bytes_per_line);
1768 return;
1769 } else if (d->depth == 24) {
1770 if (d->format == Format_RGB666)
1771 pixel |= 0xfc0000;
1772 qt_rectfill<quint24>(reinterpret_cast<quint24*>(d->data), pixel,
1773 0, 0, d->width, d->height, d->bytes_per_line);
1774 return;
1776 qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), QRgba64::fromArgb32(pixel),
1777 0, 0, d->width, d->height, d->bytes_per_line);
1778 return;
1780 quint64 cu;
1782 ::memcpy(&cu, &cf, sizeof(quint64));
1783 qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), cu,
1784 0, 0, d->width, d->height, d->bytes_per_line);
1785 return;
1788 uchar *data = d->data;
1789 for (int y = 0; y < d->height; ++y) {
1790 QRgbaFloat32 *line = reinterpret_cast<QRgbaFloat32 *>(data);
1791 for (int x = 0; x < d->width; ++x)
1792 line[x] = cf;
1793 data += d->bytes_per_line;
1794 }
1795 return;
1796 }
1797 Q_ASSERT(d->depth == 32);
1798
1799 if (d->format == Format_RGB32)
1800 pixel |= 0xff000000;
1801 if (d->format == Format_RGBX8888)
1802#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1803 pixel |= 0xff000000;
1804#else
1805 pixel |= 0x000000ff;
1806#endif
1807 if (d->format == Format_BGR30 || d->format == Format_RGB30)
1808 pixel |= 0xc0000000;
1809
1810 qt_rectfill<uint>(reinterpret_cast<uint*>(d->data), pixel,
1811 0, 0, d->width, d->height, d->bytes_per_line);
1812}
1813
1814
1825{
1826 fill(QColor(color));
1827}
1828
1829
1830
1849{
1850 if (!d)
1851 return;
1852 detach();
1853
1854 // In case we run out of memory
1855 if (!d)
1856 return;
1857
1858 QRgba64 opaque = color.rgba64();
1859 opaque.setAlpha(65535);
1860 switch (d->format) {
1863 fill(color.rgba());
1864 break;
1866 fill(qPremultiply(color.rgba()));
1867 break;
1869 fill(ARGB2RGBA(color.rgba() | 0xff000000));
1870 break;
1872 fill(ARGB2RGBA(color.rgba()));
1873 break;
1875 fill(ARGB2RGBA(qPremultiply(color.rgba())));
1876 break;
1879 break;
1882 break;
1884 fill((uint) qConvertRgb32To16(color.rgba()));
1885 break;
1887 uint pixel = 0;
1888 for (int i=0; i<d->colortable.size(); ++i) {
1889 if (color.rgba() == d->colortable.at(i)) {
1890 pixel = i;
1891 break;
1892 }
1893 }
1894 fill(pixel);
1895 break;
1896 }
1899 if (color == Qt::color1)
1900 fill((uint) 1);
1901 else
1902 fill((uint) 0);
1903 break;
1905 qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), opaque,
1906 0, 0, d->width, d->height, d->bytes_per_line);
1907 break;
1909 qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), color.rgba64(),
1910 0, 0, d->width, d->height, d->bytes_per_line);
1911 break;
1913 qt_rectfill<quint64>(reinterpret_cast<quint64 *>(d->data), color.rgba64().premultiplied(),
1914 0, 0, d->width, d->height, d->bytes_per_line);
1915 break;
1922 float r, g, b, a;
1923 color.getRgbF(&r, &g, &b, &a);
1924 if (!hasAlphaChannel())
1925 a = 1.0f;
1926 if (depth() == 64) {
1929 c16 = c16.premultiplied();
1930 qt_rectfill<QRgbaFloat16>(reinterpret_cast<QRgbaFloat16 *>(d->data), c16,
1931 0, 0, d->width, d->height, d->bytes_per_line);
1932 } else {
1933 QRgbaFloat32 c32{r, g, b, a};
1935 c32 = c32.premultiplied();
1936 qt_rectfill<QRgbaFloat32>(reinterpret_cast<QRgbaFloat32 *>(d->data), c32,
1937 0, 0, d->width, d->height, d->bytes_per_line);
1938 }
1939 break;
1940 }
1941 default: {
1942 QPainter p(this);
1943 p.setCompositionMode(QPainter::CompositionMode_Source);
1944 p.fillRect(rect(), color);
1945 }}
1946}
1947
1948
1949
1971{
1972 if (!d)
1973 return;
1974
1975 detach();
1976
1977 // In case detach() ran out of memory
1978 if (!d)
1979 return;
1980
1981 QImage::Format originalFormat = d->format;
1982 // Inverting premultiplied pixels would produce invalid image data.
1990 } else if (depth() > 32) {
1993 } else {
1996 }
1997 }
1998
1999 if (depth() < 32) {
2000 // This assumes no alpha-channel as the only formats with non-premultipled alpha are 32bit.
2001 qsizetype bpl = (qsizetype(d->width) * d->depth + 7) / 8;
2002 int pad = d->bytes_per_line - bpl;
2003 uchar *sl = d->data;
2004 for (int y=0; y<d->height; ++y) {
2005 for (qsizetype x=0; x<bpl; ++x)
2006 *sl++ ^= 0xff;
2007 sl += pad;
2008 }
2010 qfloat16 *p = reinterpret_cast<qfloat16 *>(d->data);
2011 qfloat16 *end = reinterpret_cast<qfloat16 *>(d->data + d->nbytes);
2012 while (p < end) {
2013 p[0] = qfloat16(1) - p[0];
2014 p[1] = qfloat16(1) - p[1];
2015 p[2] = qfloat16(1) - p[2];
2016 if (mode == InvertRgba)
2017 p[3] = qfloat16(1) - p[3];
2018 p += 4;
2019 }
2021 uchar *data = d->data;
2022 for (int y = 0; y < d->height; ++y) {
2023 float *p = reinterpret_cast<float *>(data);
2024 for (int x = 0; x < d->width; ++x) {
2025 p[0] = 1.0f - p[0];
2026 p[1] = 1.0f - p[1];
2027 p[2] = 1.0f - p[2];
2028 if (mode == InvertRgba)
2029 p[3] = 1.0f - p[3];
2030 p += 4;
2031 }
2032 data += d->bytes_per_line;
2033 }
2034 } else if (depth() == 64) {
2035 quint16 *p = (quint16*)d->data;
2036 quint16 *end = (quint16*)(d->data + d->nbytes);
2037 quint16 xorbits = 0xffff;
2038 while (p < end) {
2039 *p++ ^= xorbits;
2040 *p++ ^= xorbits;
2041 *p++ ^= xorbits;
2042 if (mode == InvertRgba)
2043 *p++ ^= xorbits;
2044 else
2045 p++;
2046 }
2047 } else {
2048 quint32 *p = (quint32*)d->data;
2049 quint32 *end = (quint32*)(d->data + d->nbytes);
2050 quint32 xorbits = 0xffffffff;
2051 switch (d->format) {
2053 if (mode == InvertRgba)
2054 break;
2055 Q_FALLTHROUGH();
2057#if Q_BYTE_ORDER == Q_BIG_ENDIAN
2058 xorbits = 0xffffff00;
2059 break;
2060#else
2061 xorbits = 0x00ffffff;
2062 break;
2063#endif
2065 if (mode == InvertRgba)
2066 break;
2067 Q_FALLTHROUGH();
2069 xorbits = 0x00ffffff;
2070 break;
2073 xorbits = 0x3fffffff;
2074 break;
2075 default:
2076 Q_UNREACHABLE();
2077 xorbits = 0;
2078 break;
2079 }
2080 while (p < end)
2081 *p++ ^= xorbits;
2082 }
2083
2084 if (originalFormat != d->format) {
2085 if (!d->convertInPlace(originalFormat, { }))
2086 *this = convertToFormat(originalFormat);
2087 }
2088}
2089
2090// Windows defines these
2091#if defined(write)
2092# undef write
2093#endif
2094#if defined(close)
2095# undef close
2096#endif
2097#if defined(read)
2098# undef read
2099#endif
2100
2116void QImage::setColorCount(int colorCount)
2117{
2118 if (!d) {
2119 qWarning("QImage::setColorCount: null image");
2120 return;
2121 }
2122
2123 detachMetadata(true);
2124
2125 // In case detach() ran out of memory
2126 if (!d)
2127 return;
2128
2129 if (colorCount == d->colortable.size())
2130 return;
2131 if (colorCount <= 0) { // use no color table
2132 d->colortable.clear();
2133 return;
2134 }
2135 int nc = d->colortable.size();
2137 for (int i = nc; i < colorCount; ++i)
2138 d->colortable[i] = 0;
2139}
2140
2147{
2148 return d ? d->format : Format_Invalid;
2149}
2150
2180{
2181 if (!d || d->format == format)
2182 return *this;
2183
2184 if (d->format == Format_Invalid || format <= Format_Invalid || format >= NImageFormats)
2185 return QImage();
2186
2187 const QPixelLayout *destLayout = &qPixelLayouts[format];
2189 if (!converter && format > QImage::Format_Indexed8 && d->format > QImage::Format_Indexed8) {
2190 if (qt_highColorPrecision(d->format, !destLayout->hasAlphaChannel)
2192#if QT_CONFIG(raster_fp)
2194 converter = convert_generic_over_rgba32f;
2195 else
2196#endif
2197 converter = convert_generic_over_rgb64;
2198 } else
2199 converter = convert_generic;
2200 }
2201 if (converter) {
2202 QImage image(d->width, d->height, format);
2203
2205
2206 image.d->offset = offset();
2207 copyMetadata(image.d, d);
2208
2209 converter(image.d, d, flags);
2210 return image;
2211 }
2212
2213 // Convert indexed formats over ARGB32 or RGB32 to the final format.
2216
2217 if (!hasAlphaChannel())
2219
2221}
2222
2227{
2228 return d && d->convertInPlace(format, flags);
2229}
2230
2231static inline int pixel_distance(QRgb p1, QRgb p2) {
2232 int r1 = qRed(p1);
2233 int g1 = qGreen(p1);
2234 int b1 = qBlue(p1);
2235 int a1 = qAlpha(p1);
2236
2237 int r2 = qRed(p2);
2238 int g2 = qGreen(p2);
2239 int b2 = qBlue(p2);
2240 int a2 = qAlpha(p2);
2241
2242 return abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2) + abs(a1 - a2);
2243}
2244
2245static inline int closestMatch(QRgb pixel, const QList<QRgb> &clut) {
2246 int idx = 0;
2247 int current_distance = INT_MAX;
2248 for (int i=0; i<clut.size(); ++i) {
2249 int dist = pixel_distance(pixel, clut.at(i));
2250 if (dist < current_distance) {
2251 current_distance = dist;
2252 idx = i;
2253 }
2254 }
2255 return idx;
2256}
2257
2259 const QList<QRgb> &clut) {
2260 QImage dest(src.size(), format);
2261 dest.setColorTable(clut);
2262
2264
2265 int h = src.height();
2266 int w = src.width();
2267
2269
2271 for (int y=0; y<h; ++y) {
2272 const QRgb *src_pixels = (const QRgb *) src.scanLine(y);
2273 uchar *dest_pixels = (uchar *) dest.scanLine(y);
2274 for (int x=0; x<w; ++x) {
2275 int src_pixel = src_pixels[x];
2276 int value = cache.value(src_pixel, -1);
2277 if (value == -1) {
2278 value = closestMatch(src_pixel, clut);
2279 cache.insert(src_pixel, value);
2280 }
2281 dest_pixels[x] = (uchar) value;
2282 }
2283 }
2284 } else {
2285 QList<QRgb> table = clut;
2286 table.resize(2);
2287 for (int y=0; y<h; ++y) {
2288 const QRgb *src_pixels = (const QRgb *) src.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, table);
2294 cache.insert(src_pixel, value);
2295 }
2296 dest.setPixel(x, y, value);
2297 }
2298 }
2299 }
2300
2301 return dest;
2302}
2303
2314QImage QImage::convertToFormat(Format format, const QList<QRgb> &colorTable, Qt::ImageConversionFlags flags) const
2315{
2316 if (!d || d->format == format)
2317 return *this;
2318
2319 if (format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
2320 return QImage();
2323
2324 return convertToFormat(format, flags);
2325}
2326
2351{
2352 if (!d)
2353 return false;
2354 if (d->format == format)
2355 return true;
2357 return false;
2358 if (!isDetached()) { // Detach only if shared, not for read-only data.
2359 QImageData *oldD = d;
2360 detach();
2361 // In case detach() ran out of memory
2362 if (!d) {
2363 d = oldD;
2364 d->ref.ref();
2365 return false;
2366 }
2367 }
2368
2369 d->format = format;
2370 return true;
2371}
2372
2384void QImage::convertTo(Format format, Qt::ImageConversionFlags flags)
2385{
2386 if (!d || format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
2387 return;
2388
2389 if (d->format == format)
2390 return;
2391
2392 detach();
2394 return;
2395
2397}
2398
2414bool QImage::valid(int x, int y) const
2415{
2416 return d
2417 && x >= 0 && x < d->width
2418 && y >= 0 && y < d->height;
2419}
2420
2437int QImage::pixelIndex(int x, int y) const
2438{
2439 if (!d || x < 0 || x >= d->width || y < 0 || y >= height()) {
2440 qWarning("QImage::pixelIndex: coordinate (%d,%d) out of range", x, y);
2441 return -12345;
2442 }
2443 const uchar * s = scanLine(y);
2444 switch(d->format) {
2445 case Format_Mono:
2446 return (*(s + (x >> 3)) >> (7- (x & 7))) & 1;
2447 case Format_MonoLSB:
2448 return (*(s + (x >> 3)) >> (x & 7)) & 1;
2449 case Format_Indexed8:
2450 return (int)s[x];
2451 default:
2452 qWarning("QImage::pixelIndex: Not applicable for %d-bpp images (no palette)", d->depth);
2453 }
2454 return 0;
2455}
2456
2457
2478QRgb QImage::pixel(int x, int y) const
2479{
2480 if (!d || x < 0 || x >= d->width || y < 0 || y >= d->height) {
2481 qWarning("QImage::pixel: coordinate (%d,%d) out of range", x, y);
2482 return 12345;
2483 }
2484
2485 const uchar *s = d->data + y * d->bytes_per_line;
2486
2487 int index = -1;
2488 switch (d->format) {
2489 case Format_Mono:
2490 index = (*(s + (x >> 3)) >> (~x & 7)) & 1;
2491 break;
2492 case Format_MonoLSB:
2493 index = (*(s + (x >> 3)) >> (x & 7)) & 1;
2494 break;
2495 case Format_Indexed8:
2496 index = s[x];
2497 break;
2498 default:
2499 break;
2500 }
2501 if (index >= 0) { // Indexed format
2502 if (index >= d->colortable.size()) {
2503 qWarning("QImage::pixel: color table index %d out of range.", index);
2504 return 0;
2505 }
2506 return d->colortable.at(index);
2507 }
2508
2509 switch (d->format) {
2510 case Format_RGB32:
2511 return 0xff000000 | reinterpret_cast<const QRgb *>(s)[x];
2512 case Format_ARGB32: // Keep old behaviour.
2514 return reinterpret_cast<const QRgb *>(s)[x];
2515 case Format_RGBX8888:
2516 case Format_RGBA8888: // Match ARGB32 behavior.
2518 return RGBA2ARGB(reinterpret_cast<const quint32 *>(s)[x]);
2519 case Format_BGR30:
2521 return qConvertA2rgb30ToArgb32<PixelOrderBGR>(reinterpret_cast<const quint32 *>(s)[x]);
2522 case Format_RGB30:
2524 return qConvertA2rgb30ToArgb32<PixelOrderRGB>(reinterpret_cast<const quint32 *>(s)[x]);
2525 case Format_RGB16:
2526 return qConvertRgb16To32(reinterpret_cast<const quint16 *>(s)[x]);
2527 case Format_RGBX64:
2528 case Format_RGBA64: // Match ARGB32 behavior.
2530 return reinterpret_cast<const QRgba64 *>(s)[x].toArgb32();
2531 case Format_RGBX16FPx4:
2532 case Format_RGBA16FPx4: // Match ARGB32 behavior.
2534 return reinterpret_cast<const QRgbaFloat16 *>(s)[x].toArgb32();
2535 case Format_RGBX32FPx4:
2536 case Format_RGBA32FPx4: // Match ARGB32 behavior.
2538 return reinterpret_cast<const QRgbaFloat32 *>(s)[x].toArgb32();
2539 default:
2540 break;
2541 }
2543 uint result;
2544 return *layout->fetchToARGB32PM(&result, s, x, 1, nullptr, nullptr);
2545}
2546
2573void QImage::setPixel(int x, int y, uint index_or_rgb)
2574{
2575 if (!d || x < 0 || x >= width() || y < 0 || y >= height()) {
2576 qWarning("QImage::setPixel: coordinate (%d,%d) out of range", x, y);
2577 return;
2578 }
2579 // detach is called from within scanLine
2580 uchar * s = scanLine(y);
2581 switch(d->format) {
2582 case Format_Mono:
2583 case Format_MonoLSB:
2584 if (index_or_rgb > 1) {
2585 qWarning("QImage::setPixel: Index %d out of range", index_or_rgb);
2586 } else if (format() == Format_MonoLSB) {
2587 if (index_or_rgb==0)
2588 *(s + (x >> 3)) &= ~(1 << (x & 7));
2589 else
2590 *(s + (x >> 3)) |= (1 << (x & 7));
2591 } else {
2592 if (index_or_rgb==0)
2593 *(s + (x >> 3)) &= ~(1 << (7-(x & 7)));
2594 else
2595 *(s + (x >> 3)) |= (1 << (7-(x & 7)));
2596 }
2597 return;
2598 case Format_Indexed8:
2599 if (index_or_rgb >= (uint)d->colortable.size()) {
2600 qWarning("QImage::setPixel: Index %d out of range", index_or_rgb);
2601 return;
2602 }
2603 s[x] = index_or_rgb;
2604 return;
2605 case Format_RGB32:
2606 //make sure alpha is 255, we depend on it in qdrawhelper for cases
2607 // when image is set as a texture pattern on a qbrush
2608 ((uint *)s)[x] = 0xff000000 | index_or_rgb;
2609 return;
2610 case Format_ARGB32:
2612 ((uint *)s)[x] = index_or_rgb;
2613 return;
2614 case Format_RGB16:
2615 ((quint16 *)s)[x] = qConvertRgb32To16(index_or_rgb);
2616 return;
2617 case Format_RGBX8888:
2618 ((uint *)s)[x] = ARGB2RGBA(0xff000000 | index_or_rgb);
2619 return;
2620 case Format_RGBA8888:
2622 ((uint *)s)[x] = ARGB2RGBA(index_or_rgb);
2623 return;
2624 case Format_BGR30:
2625 ((uint *)s)[x] = qConvertRgb32ToRgb30<PixelOrderBGR>(index_or_rgb);
2626 return;
2628 ((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderBGR>(index_or_rgb);
2629 return;
2630 case Format_RGB30:
2631 ((uint *)s)[x] = qConvertRgb32ToRgb30<PixelOrderRGB>(index_or_rgb);
2632 return;
2634 ((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderRGB>(index_or_rgb);
2635 return;
2636 case Format_RGBA64:
2638 ((QRgba64 *)s)[x] = QRgba64::fromArgb32(index_or_rgb);
2639 return;
2640 case Format_RGBX16FPx4:
2641 ((QRgbaFloat16 *)s)[x] = QRgbaFloat16::fromArgb32(index_or_rgb | 0xff000000);
2642 return;
2643 case Format_RGBA16FPx4:
2645 ((QRgbaFloat16 *)s)[x] = QRgbaFloat16::fromArgb32(index_or_rgb);
2646 return;
2647 case Format_RGBX32FPx4:
2648 ((QRgbaFloat32 *)s)[x] = QRgbaFloat32::fromArgb32(index_or_rgb | 0xff000000);
2649 return;
2650 case Format_RGBA32FPx4:
2652 ((QRgbaFloat32 *)s)[x] = QRgbaFloat32::fromArgb32(index_or_rgb);
2653 return;
2654 case Format_Invalid:
2655 case NImageFormats:
2656 Q_ASSERT(false);
2657 return;
2658 default:
2659 break;
2660 }
2661
2663 if (!hasAlphaChannel())
2664 layout->storeFromRGB32(s, &index_or_rgb, x, 1, nullptr, nullptr);
2665 else
2666 layout->storeFromARGB32PM(s, &index_or_rgb, x, 1, nullptr, nullptr);
2667}
2668
2692{
2693 if (!d || x < 0 || x >= d->width || y < 0 || y >= height()) {
2694 qWarning("QImage::pixelColor: coordinate (%d,%d) out of range", x, y);
2695 return QColor();
2696 }
2697
2698 QRgba64 c;
2699 const uchar * s = constScanLine(y);
2700 switch (d->format) {
2701 case Format_BGR30:
2703 c = qConvertA2rgb30ToRgb64<PixelOrderBGR>(reinterpret_cast<const quint32 *>(s)[x]);
2704 break;
2705 case Format_RGB30:
2707 c = qConvertA2rgb30ToRgb64<PixelOrderRGB>(reinterpret_cast<const quint32 *>(s)[x]);
2708 break;
2709 case Format_RGBX64:
2710 case Format_RGBA64:
2712 c = reinterpret_cast<const QRgba64 *>(s)[x];
2713 break;
2714 case Format_Grayscale16: {
2715 quint16 v = reinterpret_cast<const quint16 *>(s)[x];
2716 return QColor(qRgba64(v, v, v, 0xffff));
2717 }
2718 case Format_RGBX16FPx4:
2719 case Format_RGBA16FPx4:
2721 QRgbaFloat16 p = reinterpret_cast<const QRgbaFloat16 *>(s)[x];
2723 p = p.unpremultiplied();
2724 QColor color;
2725 color.setRgbF(p.red(), p.green(), p.blue(), p.alpha());
2726 return color;
2727 }
2728 case Format_RGBX32FPx4:
2729 case Format_RGBA32FPx4:
2731 QRgbaFloat32 p = reinterpret_cast<const QRgbaFloat32 *>(s)[x];
2733 p = p.unpremultiplied();
2734 QColor color;
2735 color.setRgbF(p.red(), p.green(), p.blue(), p.alpha());
2736 return color;
2737 }
2738 default:
2740 break;
2741 }
2742 // QColor is always unpremultiplied
2744 c = c.unpremultiplied();
2745 return QColor(c);
2746}
2747
2770void QImage::setPixelColor(int x, int y, const QColor &color)
2771{
2772 if (!d || x < 0 || x >= width() || y < 0 || y >= height()) {
2773 qWarning("QImage::setPixelColor: coordinate (%d,%d) out of range", x, y);
2774 return;
2775 }
2776
2777 if (!color.isValid()) {
2778 qWarning("QImage::setPixelColor: color is invalid");
2779 return;
2780 }
2781
2782 // QColor is always unpremultiplied
2783 QRgba64 c = color.rgba64();
2784 if (!hasAlphaChannel())
2785 c.setAlpha(65535);
2786 else if (qPixelLayouts[d->format].premultiplied)
2787 c = c.premultiplied();
2788 // detach is called from within scanLine
2789 uchar * s = scanLine(y);
2790 switch (d->format) {
2791 case Format_Mono:
2792 case Format_MonoLSB:
2793 case Format_Indexed8:
2794 qWarning("QImage::setPixelColor: called on monochrome or indexed format");
2795 return;
2796 case Format_BGR30:
2797 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderBGR>(c) | 0xc0000000;
2798 return;
2801 return;
2802 case Format_RGB30:
2803 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderRGB>(c) | 0xc0000000;
2804 return;
2807 return;
2808 case Format_RGBX64:
2809 case Format_RGBA64:
2811 ((QRgba64 *)s)[x] = c;
2812 return;
2813 case Format_RGBX16FPx4:
2814 case Format_RGBA16FPx4:
2816 float r, g, b, a;
2817 color.getRgbF(&r, &g, &b, &a);
2818 if (d->format == Format_RGBX16FPx4)
2819 a = 1.0f;
2822 c16f = c16f.premultiplied();
2823 ((QRgbaFloat16 *)s)[x] = c16f;
2824 return;
2825 }
2826 case Format_RGBX32FPx4:
2827 case Format_RGBA32FPx4:
2829 float r, g, b, a;
2830 color.getRgbF(&r, &g, &b, &a);
2831 if (d->format == Format_RGBX32FPx4)
2832 a = 1.0f;
2833 QRgbaFloat32 c32f{r, g, b, a};
2835 c32f = c32f.premultiplied();
2836 ((QRgbaFloat32 *)s)[x] = c32f;
2837 return;
2838 }
2839 default:
2840 setPixel(x, y, c.toArgb32());
2841 return;
2842 }
2843}
2844
2855{
2856 if (!d)
2857 return true;
2858
2859 switch (d->format) {
2860 case Format_Mono:
2861 case Format_MonoLSB:
2862 case Format_Indexed8:
2863 for (int i = 0; i < d->colortable.size(); ++i) {
2864 if (!qIsGray(d->colortable.at(i)))
2865 return false;
2866 }
2867 return true;
2868 case Format_Alpha8:
2869 return false;
2870 case Format_Grayscale8:
2871 case Format_Grayscale16:
2872 return true;
2873 case Format_RGB32:
2874 case Format_ARGB32:
2876#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
2877 case Format_RGBX8888:
2878 case Format_RGBA8888:
2880#endif
2881 for (int j = 0; j < d->height; ++j) {
2882 const QRgb *b = (const QRgb *)constScanLine(j);
2883 for (int i = 0; i < d->width; ++i) {
2884 if (!qIsGray(b[i]))
2885 return false;
2886 }
2887 }
2888 return true;
2889 case Format_RGB16:
2890 for (int j = 0; j < d->height; ++j) {
2891 const quint16 *b = (const quint16 *)constScanLine(j);
2892 for (int i = 0; i < d->width; ++i) {
2893 if (!qIsGray(qConvertRgb16To32(b[i])))
2894 return false;
2895 }
2896 }
2897 return true;
2898 default:
2899 break;
2900 }
2901
2904 const auto fetch = layout->fetchToARGB32PM;
2905 for (int j = 0; j < d->height; ++j) {
2906 const uchar *b = constScanLine(j);
2907 int x = 0;
2908 while (x < d->width) {
2909 int l = qMin(d->width - x, BufferSize);
2910 const uint *ptr = fetch(buffer, b, x, l, nullptr, nullptr);
2911 for (int i = 0; i < l; ++i) {
2912 if (!qIsGray(ptr[i]))
2913 return false;
2914 }
2915 x += l;
2916 }
2917 }
2918 return true;
2919}
2920
2931{
2932 if (!d)
2933 return false;
2934
2935 if (d->format == QImage::Format_Alpha8)
2936 return false;
2937
2939 return true;
2940
2941 switch (depth()) {
2942 case 32:
2943 case 24:
2944 case 16:
2945 return allGray();
2946 case 8: {
2948 for (int i = 0; i < colorCount(); i++)
2949 if (d->colortable.at(i) != qRgb(i,i,i))
2950 return false;
2951 return true;
2952 }
2953 }
2954 return false;
2955}
2956
2996{
2997 if (!d) {
2998 qWarning("QImage::scaled: Image is a null image");
2999 return QImage();
3000 }
3001 if (s.isEmpty())
3002 return QImage();
3003
3004 QSize newSize = size();
3005 newSize.scale(s, aspectMode);
3006 newSize.rwidth() = qMax(newSize.width(), 1);
3007 newSize.rheight() = qMax(newSize.height(), 1);
3008 if (newSize == size())
3009 return *this;
3010
3011 Q_TRACE_SCOPE(QImage_scaled, s, aspectMode, mode);
3012
3013 QTransform wm = QTransform::fromScale((qreal)newSize.width() / width(), (qreal)newSize.height() / height());
3014 QImage img = transformed(wm, mode);
3015 return img;
3016}
3017
3033{
3034 if (!d) {
3035 qWarning("QImage::scaleWidth: Image is a null image");
3036 return QImage();
3037 }
3038 if (w <= 0)
3039 return QImage();
3040
3041 Q_TRACE_SCOPE(QImage_scaledToWidth, w, mode);
3042
3043 qreal factor = (qreal) w / width();
3044 QTransform wm = QTransform::fromScale(factor, factor);
3045 return transformed(wm, mode);
3046}
3047
3063{
3064 if (!d) {
3065 qWarning("QImage::scaleHeight: Image is a null image");
3066 return QImage();
3067 }
3068 if (h <= 0)
3069 return QImage();
3070
3071 Q_TRACE_SCOPE(QImage_scaledToHeight, h, mode);
3072
3073 qreal factor = (qreal) h / height();
3074 QTransform wm = QTransform::fromScale(factor, factor);
3075 return transformed(wm, mode);
3076}
3077
3095QImage Q_TRACE_INSTRUMENT(qtgui) QImage::createAlphaMask(Qt::ImageConversionFlags flags) const
3096{
3097 if (!d || d->format == QImage::Format_RGB32)
3098 return QImage();
3099
3100 if (d->depth == 1) {
3101 // A monochrome pixmap, with alpha channels on those two colors.
3102 // Pretty unlikely, so use less efficient solution.
3104 }
3105
3107 if (!mask.isNull()) {
3108 dither_to_Mono(mask.d, d, flags, true);
3110 }
3111 return mask;
3112}
3113
3114#ifndef QT_NO_IMAGE_HEURISTIC_MASK
3139QImage QImage::createHeuristicMask(bool clipTight) const
3140{
3141 if (!d)
3142 return QImage();
3143
3144 if (d->depth != 32) {
3146 return img32.createHeuristicMask(clipTight);
3147 }
3148
3149#define PIX(x,y) (*((const QRgb*)scanLine(y)+x) & 0x00ffffff)
3150
3151 int w = width();
3152 int h = height();
3155 m.setColorCount(2);
3156 m.setColor(0, QColor(Qt::color0).rgba());
3157 m.setColor(1, QColor(Qt::color1).rgba());
3158 m.fill(0xff);
3159
3160 QRgb background = PIX(0,0);
3161 if (background != PIX(w-1,0) &&
3162 background != PIX(0,h-1) &&
3163 background != PIX(w-1,h-1)) {
3164 background = PIX(w-1,0);
3165 if (background != PIX(w-1,h-1) &&
3166 background != PIX(0,h-1) &&
3167 PIX(0,h-1) == PIX(w-1,h-1)) {
3168 background = PIX(w-1,h-1);
3169 }
3170 }
3171
3172 int x,y;
3173 bool done = false;
3174 uchar *ypp, *ypc, *ypn;
3175 while(!done) {
3176 done = true;
3177 ypn = m.scanLine(0);
3178 ypc = nullptr;
3179 for (y = 0; y < h; y++) {
3180 ypp = ypc;
3181 ypc = ypn;
3182 ypn = (y == h-1) ? nullptr : m.scanLine(y+1);
3183 const QRgb *p = (const QRgb *)scanLine(y);
3184 for (x = 0; x < w; x++) {
3185 // slowness here - it's possible to do six of these tests
3186 // together in one go. oh well.
3187 if ((x == 0 || y == 0 || x == w-1 || y == h-1 ||
3188 !(*(ypc + ((x-1) >> 3)) & (1 << ((x-1) & 7))) ||
3189 !(*(ypc + ((x+1) >> 3)) & (1 << ((x+1) & 7))) ||
3190 !(*(ypp + (x >> 3)) & (1 << (x & 7))) ||
3191 !(*(ypn + (x >> 3)) & (1 << (x & 7)))) &&
3192 ( (*(ypc + (x >> 3)) & (1 << (x & 7)))) &&
3193 ((*p & 0x00ffffff) == background)) {
3194 done = false;
3195 *(ypc + (x >> 3)) &= ~(1 << (x & 7));
3196 }
3197 p++;
3198 }
3199 }
3200 }
3201
3202 if (!clipTight) {
3203 ypn = m.scanLine(0);
3204 ypc = nullptr;
3205 for (y = 0; y < h; y++) {
3206 ypp = ypc;
3207 ypc = ypn;
3208 ypn = (y == h-1) ? nullptr : m.scanLine(y+1);
3209 const QRgb *p = (const QRgb *)scanLine(y);
3210 for (x = 0; x < w; x++) {
3211 if ((*p & 0x00ffffff) != background) {
3212 if (x > 0)
3213 *(ypc + ((x-1) >> 3)) |= (1 << ((x-1) & 7));
3214 if (x < w-1)
3215 *(ypc + ((x+1) >> 3)) |= (1 << ((x+1) & 7));
3216 if (y > 0)
3217 *(ypp + (x >> 3)) |= (1 << (x & 7));
3218 if (y < h-1)
3219 *(ypn + (x >> 3)) |= (1 << (x & 7));
3220 }
3221 p++;
3222 }
3223 }
3224 }
3225
3226#undef PIX
3227
3228 copyPhysicalMetadata(m.d, d);
3229 return m;
3230}
3231#endif //QT_NO_IMAGE_HEURISTIC_MASK
3232
3244{
3245 if (!d)
3246 return QImage();
3247 QImage maskImage(size(), QImage::Format_MonoLSB);
3248 QIMAGE_SANITYCHECK_MEMORY(maskImage);
3249 maskImage.fill(0);
3250 uchar *s = maskImage.bits();
3251 if (!s)
3252 return QImage();
3253
3254 if (depth() == 32) {
3255 for (int h = 0; h < d->height; h++) {
3256 const uint *sl = (const uint *) scanLine(h);
3257 for (int w = 0; w < d->width; w++) {
3258 if (sl[w] == color)
3259 *(s + (w >> 3)) |= (1 << (w & 7));
3260 }
3261 s += maskImage.bytesPerLine();
3262 }
3263 } else {
3264 for (int h = 0; h < d->height; h++) {
3265 for (int w = 0; w < d->width; w++) {
3266 if ((uint) pixel(w, h) == color)
3267 *(s + (w >> 3)) |= (1 << (w & 7));
3268 }
3269 s += maskImage.bytesPerLine();
3270 }
3271 }
3272 if (mode == Qt::MaskOutColor)
3273 maskImage.invertPixels();
3274
3275 copyPhysicalMetadata(maskImage.d, d);
3276 return maskImage;
3277}
3278
3302template<class T> inline void do_mirror_data(QImageData *dst, QImageData *src,
3303 int dstX0, int dstY0,
3304 int dstXIncr, int dstYIncr,
3305 int w, int h)
3306{
3307 if (dst == src) {
3308 // When mirroring in-place, stop in the middle for one of the directions, since we
3309 // are swapping the bytes instead of merely copying.
3310 const int srcXEnd = (dstX0 && !dstY0) ? w / 2 : w;
3311 const int srcYEnd = dstY0 ? h / 2 : h;
3312 for (int srcY = 0, dstY = dstY0; srcY < srcYEnd; ++srcY, dstY += dstYIncr) {
3313 T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3314 T *dstPtr = (T *) (dst->data + dstY * dst->bytes_per_line);
3315 for (int srcX = 0, dstX = dstX0; srcX < srcXEnd; ++srcX, dstX += dstXIncr)
3316 std::swap(srcPtr[srcX], dstPtr[dstX]);
3317 }
3318 // If mirroring both ways, the middle line needs to be mirrored horizontally only.
3319 if (dstX0 && dstY0 && (h & 1)) {
3320 int srcY = h / 2;
3321 int srcXEnd2 = w / 2;
3322 T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3323 for (int srcX = 0, dstX = dstX0; srcX < srcXEnd2; ++srcX, dstX += dstXIncr)
3324 std::swap(srcPtr[srcX], srcPtr[dstX]);
3325 }
3326 } else {
3327 for (int srcY = 0, dstY = dstY0; srcY < h; ++srcY, dstY += dstYIncr) {
3328 T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3329 T *dstPtr = (T *) (dst->data + dstY * dst->bytes_per_line);
3330 for (int srcX = 0, dstX = dstX0; srcX < w; ++srcX, dstX += dstXIncr)
3331 dstPtr[dstX] = srcPtr[srcX];
3332 }
3333 }
3334}
3335
3336inline void do_flip(QImageData *dst, QImageData *src, int w, int h, int depth)
3337{
3338 const int data_bytes_per_line = w * (depth / 8);
3339 if (dst == src) {
3340 uint *srcPtr = reinterpret_cast<uint *>(src->data);
3341 uint *dstPtr = reinterpret_cast<uint *>(dst->data + (h - 1) * dst->bytes_per_line);
3342 h = h / 2;
3343 const int uint_per_line = (data_bytes_per_line + 3) >> 2; // bytes per line must be a multiple of 4
3344 for (int y = 0; y < h; ++y) {
3345 // This is auto-vectorized, no need for SSE2 or NEON versions:
3346 for (int x = 0; x < uint_per_line; x++) {
3347 const uint d = dstPtr[x];
3348 const uint s = srcPtr[x];
3349 dstPtr[x] = s;
3350 srcPtr[x] = d;
3351 }
3352 srcPtr += src->bytes_per_line >> 2;
3353 dstPtr -= dst->bytes_per_line >> 2;
3354 }
3355
3356 } else {
3357 const uchar *srcPtr = src->data;
3358 uchar *dstPtr = dst->data + (h - 1) * dst->bytes_per_line;
3359 for (int y = 0; y < h; ++y) {
3360 memcpy(dstPtr, srcPtr, data_bytes_per_line);
3361 srcPtr += src->bytes_per_line;
3362 dstPtr -= dst->bytes_per_line;
3363 }
3364 }
3365}
3366
3367inline void do_mirror(QImageData *dst, QImageData *src, bool horizontal, bool vertical)
3368{
3369 Q_ASSERT(src->width == dst->width && src->height == dst->height && src->depth == dst->depth);
3370 int w = src->width;
3371 int h = src->height;
3372 int depth = src->depth;
3373
3374 if (src->depth == 1) {
3375 w = (w + 7) / 8; // byte aligned width
3376 depth = 8;
3377 }
3378
3379 if (vertical && !horizontal) {
3380 // This one is simple and common, so do it a little more optimized
3381 do_flip(dst, src, w, h, depth);
3382 return;
3383 }
3384
3385 int dstX0 = 0, dstXIncr = 1;
3386 int dstY0 = 0, dstYIncr = 1;
3387 if (horizontal) {
3388 // 0 -> w-1, 1 -> w-2, 2 -> w-3, ...
3389 dstX0 = w - 1;
3390 dstXIncr = -1;
3391 }
3392 if (vertical) {
3393 // 0 -> h-1, 1 -> h-2, 2 -> h-3, ...
3394 dstY0 = h - 1;
3395 dstYIncr = -1;
3396 }
3397
3398 switch (depth) {
3399 case 128:
3400 do_mirror_data<QRgbaFloat32>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3401 break;
3402 case 64:
3403 do_mirror_data<quint64>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3404 break;
3405 case 32:
3406 do_mirror_data<quint32>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3407 break;
3408 case 24:
3409 do_mirror_data<quint24>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3410 break;
3411 case 16:
3412 do_mirror_data<quint16>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3413 break;
3414 case 8:
3415 do_mirror_data<quint8>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3416 break;
3417 default:
3418 Q_ASSERT(false);
3419 break;
3420 }
3421
3422 // The bytes are now all in the correct place. In addition, the bits in the individual
3423 // bytes have to be flipped too when horizontally mirroring a 1 bit-per-pixel image.
3424 if (horizontal && dst->depth == 1) {
3425 Q_ASSERT(dst->format == QImage::Format_Mono || dst->format == QImage::Format_MonoLSB);
3426 const int shift = 8 - (dst->width % 8);
3428 for (int y = 0; y < h; ++y) {
3429 uchar *begin = dst->data + y * dst->bytes_per_line;
3430 uchar *end = begin + dst->bytes_per_line;
3431 for (uchar *p = begin; p < end; ++p) {
3432 *p = bitflip[*p];
3433 // When the data is non-byte aligned, an extra bit shift (of the number of
3434 // unused bits at the end) is needed for the entire scanline.
3435 if (shift != 8 && p != begin) {
3436 if (dst->format == QImage::Format_Mono) {
3437 for (int i = 0; i < shift; ++i) {
3438 p[-1] <<= 1;
3439 p[-1] |= (*p & (128 >> i)) >> (7 - i);
3440 }
3441 } else {
3442 for (int i = 0; i < shift; ++i) {
3443 p[-1] >>= 1;
3444 p[-1] |= (*p & (1 << i)) << (7 - i);
3445 }
3446 }
3447 }
3448 }
3449 if (shift != 8) {
3450 if (dst->format == QImage::Format_Mono)
3451 end[-1] <<= shift;
3452 else
3453 end[-1] >>= shift;
3454 }
3455 }
3456 }
3457}
3458
3462QImage QImage::mirrored_helper(bool horizontal, bool vertical) const
3463{
3464 if (!d)
3465 return QImage();
3466
3467 if ((d->width <= 1 && d->height <= 1) || (!horizontal && !vertical))
3468 return *this;
3469
3470 // Create result image, copy colormap
3471 QImage result(d->width, d->height, d->format);
3473
3474 // check if we ran out of of memory..
3475 if (!result.d)
3476 return QImage();
3477
3478 result.d->colortable = d->colortable;
3479 result.d->has_alpha_clut = d->has_alpha_clut;
3480 copyMetadata(result.d, d);
3481
3482 do_mirror(result.d, d, horizontal, vertical);
3483
3484 return result;
3485}
3486
3490void QImage::mirrored_inplace(bool horizontal, bool vertical)
3491{
3492 if (!d || (d->width <= 1 && d->height <= 1) || (!horizontal && !vertical))
3493 return;
3494
3495 detach();
3496 if (!d)
3497 return;
3498 if (!d->own_data)
3499 *this = copy();
3500
3501 do_mirror(d, d, horizontal, vertical);
3502}
3503
3527static inline void rgbSwapped_generic(int width, int height, const QImage *src, QImage *dst, const QPixelLayout* layout)
3528{
3529 const RbSwapFunc func = layout->rbSwap;
3530 if (!func) {
3531 qWarning("Trying to rb-swap an image format where it doesn't make sense");
3532 if (src != dst)
3533 *dst = *src;
3534 return;
3535 }
3536
3537 for (int i = 0; i < height; ++i) {
3538 uchar *q = dst->scanLine(i);
3539 const uchar *p = src->constScanLine(i);
3540 func(q, p, width);
3541 }
3542}
3543
3548{
3549 if (isNull())
3550 return *this;
3551
3552 Q_TRACE_SCOPE(QImage_rgbSwapped_helper);
3553
3554 QImage res;
3555
3556 switch (d->format) {
3557 case Format_Invalid:
3558 case NImageFormats:
3559 Q_ASSERT(false);
3560 break;
3561 case Format_Alpha8:
3562 case Format_Grayscale8:
3563 case Format_Grayscale16:
3564 return *this;
3565 case Format_Mono:
3566 case Format_MonoLSB:
3567 case Format_Indexed8:
3568 res = copy();
3569 for (int i = 0; i < res.d->colortable.size(); i++) {
3570 QRgb c = res.d->colortable.at(i);
3571 res.d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
3572 }
3573 break;
3574 case Format_RGBX8888:
3575 case Format_RGBA8888:
3577#if Q_BYTE_ORDER == Q_BIG_ENDIAN
3578 res = QImage(d->width, d->height, d->format);
3580 for (int i = 0; i < d->height; i++) {
3581 uint *q = (uint*)res.scanLine(i);
3582 const uint *p = (const uint*)constScanLine(i);
3583 const uint *end = p + d->width;
3584 while (p < end) {
3585 uint c = *p;
3586 *q = ((c << 16) & 0xff000000) | ((c >> 16) & 0xff00) | (c & 0x00ff00ff);
3587 p++;
3588 q++;
3589 }
3590 }
3591 break;
3592#else
3593 // On little-endian rgba8888 is abgr32 and can use same rgb-swap as argb32
3594 Q_FALLTHROUGH();
3595#endif
3596 case Format_RGB32:
3597 case Format_ARGB32:
3599 res = QImage(d->width, d->height, d->format);
3601 for (int i = 0; i < d->height; i++) {
3602 uint *q = (uint*)res.scanLine(i);
3603 const uint *p = (const uint*)constScanLine(i);
3604 const uint *end = p + d->width;
3605 while (p < end) {
3606 uint c = *p;
3607 *q = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
3608 p++;
3609 q++;
3610 }
3611 }
3612 break;
3613 case Format_RGB16:
3614 res = QImage(d->width, d->height, d->format);
3616 for (int i = 0; i < d->height; i++) {
3617 ushort *q = (ushort*)res.scanLine(i);
3618 const ushort *p = (const ushort*)constScanLine(i);
3619 const ushort *end = p + d->width;
3620 while (p < end) {
3621 ushort c = *p;
3622 *q = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
3623 p++;
3624 q++;
3625 }
3626 }
3627 break;
3628 default:
3629 res = QImage(d->width, d->height, d->format);
3631 rgbSwapped_generic(d->width, d->height, this, &res, &qPixelLayouts[d->format]);
3632 break;
3633 }
3634 copyMetadata(res.d, d);
3635 return res;
3636}
3637
3642{
3643 if (isNull())
3644 return;
3645
3646 detach();
3647 if (!d)
3648 return;
3649 if (!d->own_data)
3650 *this = copy();
3651
3652 switch (d->format) {
3653 case Format_Invalid:
3654 case NImageFormats:
3655 Q_ASSERT(false);
3656 break;
3657 case Format_Alpha8:
3658 case Format_Grayscale8:
3659 case Format_Grayscale16:
3660 return;
3661 case Format_Mono:
3662 case Format_MonoLSB:
3663 case Format_Indexed8:
3664 for (int i = 0; i < d->colortable.size(); i++) {
3665 QRgb c = d->colortable.at(i);
3666 d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
3667 }
3668 break;
3669 case Format_RGBX8888:
3670 case Format_RGBA8888:
3672#if Q_BYTE_ORDER == Q_BIG_ENDIAN
3673 for (int i = 0; i < d->height; i++) {
3674 uint *p = (uint*)scanLine(i);
3675 uint *end = p + d->width;
3676 while (p < end) {
3677 uint c = *p;
3678 *p = ((c << 16) & 0xff000000) | ((c >> 16) & 0xff00) | (c & 0x00ff00ff);
3679 p++;
3680 }
3681 }
3682 break;
3683#else
3684 // On little-endian rgba8888 is abgr32 and can use same rgb-swap as argb32
3685 Q_FALLTHROUGH();
3686#endif
3687 case Format_RGB32:
3688 case Format_ARGB32:
3690 for (int i = 0; i < d->height; i++) {
3691 uint *p = (uint*)scanLine(i);
3692 uint *end = p + d->width;
3693 while (p < end) {
3694 uint c = *p;
3695 *p = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
3696 p++;
3697 }
3698 }
3699 break;
3700 case Format_RGB16:
3701 for (int i = 0; i < d->height; i++) {
3702 ushort *p = (ushort*)scanLine(i);
3703 ushort *end = p + d->width;
3704 while (p < end) {
3705 ushort c = *p;
3706 *p = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
3707 p++;
3708 }
3709 }
3710 break;
3711 case Format_BGR30:
3713 case Format_RGB30:
3715 for (int i = 0; i < d->height; i++) {
3716 uint *p = (uint*)scanLine(i);
3717 uint *end = p + d->width;
3718 while (p < end) {
3719 *p = qRgbSwapRgb30(*p);
3720 p++;
3721 }
3722 }
3723 break;
3724 default:
3725 rgbSwapped_generic(d->width, d->height, this, this, &qPixelLayouts[d->format]);
3726 break;
3727 }
3728}
3729
3749bool QImage::load(const QString &fileName, const char* format)
3750{
3751 *this = QImageReader(fileName, format).read();
3752 return !isNull();
3753}
3754
3763{
3764 *this = QImageReader(device, format).read();
3765 return !isNull();
3766}
3767
3782{
3783 *this = fromData(data, format);
3784 return !isNull();
3785}
3786
3795bool QImage::loadFromData(const uchar *buf, int len, const char *format)
3796{
3798}
3799
3824{
3825 QByteArray a = QByteArray::fromRawData(data.constData(), data.size());
3826 QBuffer b;
3827 b.setData(a);
3828 b.open(QIODevice::ReadOnly);
3829 return QImageReader(&b, format).read();
3830}
3831
3840QImage QImage::fromData(const uchar *data, int size, const char *format)
3841{
3843}
3844
3870bool QImage::save(const QString &fileName, const char *format, int quality) const
3871{
3872 if (isNull())
3873 return false;
3874 QImageWriter writer(fileName, format);
3875 return d->doImageIO(this, &writer, quality);
3876}
3877
3889bool QImage::save(QIODevice* device, const char* format, int quality) const
3890{
3891 if (isNull())
3892 return false; // nothing to save
3893 QImageWriter writer(device, format);
3894 return d->doImageIO(this, &writer, quality);
3895}
3896
3897/* \internal
3898*/
3899
3900bool QImageData::doImageIO(const QImage *image, QImageWriter *writer, int quality) const
3901{
3902 if (quality > 100 || quality < -1)
3903 qWarning("QImage::save: Quality out of range [-1, 100]");
3904 if (quality >= 0)
3905 writer->setQuality(qMin(quality,100));
3906 const bool result = writer->write(*image);
3907#ifdef QT_DEBUG
3908 if (!result)
3909 qWarning("QImage::save: failed to write image - %s", qPrintable(writer->errorString()));
3910#endif
3911 return result;
3912}
3913
3914/*****************************************************************************
3915 QImage stream functions
3916 *****************************************************************************/
3917#if !defined(QT_NO_DATASTREAM)
3930{
3931 if (s.version() >= 5) {
3932 if (image.isNull()) {
3933 s << (qint32) 0; // null image marker
3934 return s;
3935 } else {
3936 s << (qint32) 1;
3937 // continue ...
3938 }
3939 }
3940 QImageWriter writer(s.device(), s.version() == 1 ? "bmp" : "png");
3941 writer.write(image);
3942 return s;
3943}
3944
3956{
3957 if (s.version() >= 5) {
3958 qint32 nullMarker;
3959 s >> nullMarker;
3960 if (!nullMarker) {
3961 image = QImage(); // null image
3962 return s;
3963 }
3964 }
3965 image = QImageReader(s.device(), s.version() == 1 ? "bmp" : "png").read();
3966 if (image.isNull() && s.version() >= 5)
3967 s.setStatus(QDataStream::ReadPastEnd);
3968 return s;
3969}
3970#endif // QT_NO_DATASTREAM
3971
3972
3973
3987bool QImage::operator==(const QImage & i) const
3988{
3989 // same object, or shared?
3990 if (i.d == d)
3991 return true;
3992 if (!i.d || !d)
3993 return false;
3994
3995 // obviously different stuff?
3996 if (i.d->height != d->height || i.d->width != d->width || i.d->format != d->format || i.d->colorSpace != d->colorSpace)
3997 return false;
3998
3999 if (d->format != Format_RGB32) {
4000 if (d->format >= Format_ARGB32) { // all bits defined
4001 const int n = d->width * d->depth / 8;
4002 if (n == d->bytes_per_line && n == i.d->bytes_per_line) {
4003 if (memcmp(bits(), i.bits(), d->nbytes))
4004 return false;
4005 } else {
4006 for (int y = 0; y < d->height; ++y) {
4007 if (memcmp(scanLine(y), i.scanLine(y), n))
4008 return false;
4009 }
4010 }
4011 } else {
4012 const int w = width();
4013 const int h = height();
4014 const QList<QRgb> &colortable = d->colortable;
4015 const QList<QRgb> &icolortable = i.d->colortable;
4016 for (int y=0; y<h; ++y) {
4017 for (int x=0; x<w; ++x) {
4018 if (colortable[pixelIndex(x, y)] != icolortable[i.pixelIndex(x, y)])
4019 return false;
4020 }
4021 }
4022 }
4023 } else {
4024 //alpha channel undefined, so we must mask it out
4025 for(int l = 0; l < d->height; l++) {
4026 int w = d->width;
4027 const uint *p1 = reinterpret_cast<const uint*>(scanLine(l));
4028 const uint *p2 = reinterpret_cast<const uint*>(i.scanLine(l));
4029 while (w--) {
4030 if ((*p1++ & 0x00ffffff) != (*p2++ & 0x00ffffff))
4031 return false;
4032 }
4033 }
4034 }
4035 return true;
4036}
4037
4038
4052bool QImage::operator!=(const QImage & i) const
4053{
4054 return !(*this == i);
4055}
4056
4057
4058
4059
4069{
4070 return d ? qRound(d->dpmx) : 0;
4071}
4072
4082{
4083 return d ? qRound(d->dpmy) : 0;
4084}
4085
4099{
4100 if (!d || !x || d->dpmx == x)
4101 return;
4103
4104 if (d)
4105 d->dpmx = x;
4106}
4107
4121{
4122 if (!d || !y || d->dpmy == y)
4123 return;
4125
4126 if (d)
4127 d->dpmy = y;
4128}
4129
4139{
4140 return d ? d->offset : QPoint();
4141}
4142
4143
4153{
4154 if (!d || d->offset == p)
4155 return;
4157
4158 if (d)
4159 d->offset = p;
4160}
4161
4171{
4172 return d ? QStringList(d->text.keys()) : QStringList();
4173}
4174
4183{
4184 if (!d)
4185 return QString();
4186
4187 if (!key.isEmpty())
4188 return d->text.value(key);
4189
4190 QString tmp;
4191 for (auto it = d->text.begin(), end = d->text.end(); it != end; ++it)
4192 tmp += it.key() + ": "_L1 + it.value().simplified() + "\n\n"_L1;
4193 if (!tmp.isEmpty())
4194 tmp.chop(2); // remove final \n\n
4195 return tmp;
4196}
4197
4223{
4224 if (!d)
4225 return;
4227
4228 if (d)
4229 d->text.insert(key, value);
4230}
4231
4238{
4239 if (!d)
4240 return nullptr;
4241
4242 if (!d->paintEngine) {
4243 QPaintDevice *paintDevice = const_cast<QImage *>(this);
4245 if (platformIntegration)
4246 d->paintEngine = platformIntegration->createImagePaintEngine(paintDevice);
4247 if (!d->paintEngine)
4248 d->paintEngine = new QRasterPaintEngine(paintDevice);
4249 }
4250
4251 return d->paintEngine;
4252}
4253
4254
4261{
4262 if (!d)
4263 return 0;
4264
4265 switch (metric) {
4266 case PdmWidth:
4267 return d->width;
4268
4269 case PdmHeight:
4270 return d->height;
4271
4272 case PdmWidthMM:
4273 return qRound(d->width * 1000 / d->dpmx);
4274
4275 case PdmHeightMM:
4276 return qRound(d->height * 1000 / d->dpmy);
4277
4278 case PdmNumColors:
4279 return d->colortable.size();
4280
4281 case PdmDepth:
4282 return d->depth;
4283
4284 case PdmDpiX:
4285 return qRound(d->dpmx * 0.0254);
4286 break;
4287
4288 case PdmDpiY:
4289 return qRound(d->dpmy * 0.0254);
4290 break;
4291
4292 case PdmPhysicalDpiX:
4293 return qRound(d->dpmx * 0.0254);
4294 break;
4295
4296 case PdmPhysicalDpiY:
4297 return qRound(d->dpmy * 0.0254);
4298 break;
4299
4301 return d->devicePixelRatio;
4302 break;
4303
4306 break;
4307
4308 default:
4309 qWarning("QImage::metric(): Unhandled metric type %d", metric);
4310 break;
4311 }
4312 return 0;
4313}
4314
4315
4316
4317/*****************************************************************************
4318 QPixmap (and QImage) helper functions
4319 *****************************************************************************/
4320/*
4321 This internal function contains the common (i.e. platform independent) code
4322 to do a transformation of pixel data. It is used by QPixmap::transform() and by
4323 QImage::transform().
4324
4325 \a trueMat is the true transformation matrix (see QPixmap::trueMatrix()) and
4326 \a xoffset is an offset to the matrix.
4327
4328 \a msbfirst specifies for 1bpp images, if the MSB or LSB comes first and \a
4329 depth specifies the colordepth of the data.
4330
4331 \a dptr is a pointer to the destination data, \a dbpl specifies the bits per
4332 line for the destination data, \a p_inc is the offset that we advance for
4333 every scanline and \a dHeight is the height of the destination image.
4334
4335 \a sprt is the pointer to the source data, \a sbpl specifies the bits per
4336 line of the source data, \a sWidth and \a sHeight are the width and height of
4337 the source data.
4338*/
4339
4340#undef IWX_MSB
4341#define IWX_MSB(b) if (trigx < maxws && trigy < maxhs) { \
4342 if (*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
4343 (1 << (7-((trigx>>12)&7)))) \
4344 *dptr |= b; \
4345 } \
4346 trigx += m11; \
4347 trigy += m12;
4348 // END OF MACRO
4349#undef IWX_LSB
4350#define IWX_LSB(b) if (trigx < maxws && trigy < maxhs) { \
4351 if (*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
4352 (1 << ((trigx>>12)&7))) \
4353 *dptr |= b; \
4354 } \
4355 trigx += m11; \
4356 trigy += m12;
4357 // END OF MACRO
4358#undef IWX_PIX
4359#define IWX_PIX(b) if (trigx < maxws && trigy < maxhs) { \
4360 if ((*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
4361 (1 << (7-((trigx>>12)&7)))) == 0) \
4362 *dptr &= ~b; \
4363 } \
4364 trigx += m11; \
4365 trigy += m12;
4366 // END OF MACRO
4367bool qt_xForm_helper(const QTransform &trueMat, int xoffset, int type, int depth,
4368 uchar *dptr, qsizetype dbpl, int p_inc, int dHeight,
4369 const uchar *sptr, qsizetype sbpl, int sWidth, int sHeight)
4370{
4371 int m11 = int(trueMat.m11()*4096.0);
4372 int m12 = int(trueMat.m12()*4096.0);
4373 int m21 = int(trueMat.m21()*4096.0);
4374 int m22 = int(trueMat.m22()*4096.0);
4375 int dx = qRound(trueMat.dx()*4096.0);
4376 int dy = qRound(trueMat.dy()*4096.0);
4377
4378 int m21ydx = dx + (xoffset<<16) + (m11 + m21) / 2;
4379 int m22ydy = dy + (m12 + m22) / 2;
4380 uint trigx;
4381 uint trigy;
4382 uint maxws = sWidth<<12;
4383 uint maxhs = sHeight<<12;
4384
4385 for (int y=0; y<dHeight; y++) { // for each target scanline
4386 trigx = m21ydx;
4387 trigy = m22ydy;
4388 uchar *maxp = dptr + dbpl;
4389 if (depth != 1) {
4390 switch (depth) {
4391 case 8: // 8 bpp transform
4392 while (dptr < maxp) {
4393 if (trigx < maxws && trigy < maxhs)
4394 *dptr = *(sptr+sbpl*(trigy>>12)+(trigx>>12));
4395 trigx += m11;
4396 trigy += m12;
4397 dptr++;
4398 }
4399 break;
4400
4401 case 16: // 16 bpp transform
4402 while (dptr < maxp) {
4403 if (trigx < maxws && trigy < maxhs)
4404 *((ushort*)dptr) = *((const ushort *)(sptr+sbpl*(trigy>>12) +
4405 ((trigx>>12)<<1)));
4406 trigx += m11;
4407 trigy += m12;
4408 dptr++;
4409 dptr++;
4410 }
4411 break;
4412
4413 case 24: // 24 bpp transform
4414 while (dptr < maxp) {
4415 if (trigx < maxws && trigy < maxhs) {
4416 const uchar *p2 = sptr+sbpl*(trigy>>12) + ((trigx>>12)*3);
4417 dptr[0] = p2[0];
4418 dptr[1] = p2[1];
4419 dptr[2] = p2[2];
4420 }
4421 trigx += m11;
4422 trigy += m12;
4423 dptr += 3;
4424 }
4425 break;
4426
4427 case 32: // 32 bpp transform
4428 while (dptr < maxp) {
4429 if (trigx < maxws && trigy < maxhs)
4430 *((uint*)dptr) = *((const uint *)(sptr+sbpl*(trigy>>12) +
4431 ((trigx>>12)<<2)));
4432 trigx += m11;
4433 trigy += m12;
4434 dptr += 4;
4435 }
4436 break;
4437
4438 default: {
4439 return false;
4440 }
4441 }
4442 } else {
4443 switch (type) {
4445 while (dptr < maxp) {
4446 IWX_MSB(128);
4447 IWX_MSB(64);
4448 IWX_MSB(32);
4449 IWX_MSB(16);
4450 IWX_MSB(8);
4451 IWX_MSB(4);
4452 IWX_MSB(2);
4453 IWX_MSB(1);
4454 dptr++;
4455 }
4456 break;
4458 while (dptr < maxp) {
4459 IWX_LSB(1);
4460 IWX_LSB(2);
4461 IWX_LSB(4);
4462 IWX_LSB(8);
4463 IWX_LSB(16);
4464 IWX_LSB(32);
4465 IWX_LSB(64);
4466 IWX_LSB(128);
4467 dptr++;
4468 }
4469 break;
4470 }
4471 }
4472 m21ydx += m21;
4473 m22ydy += m22;
4474 dptr += p_inc;
4475 }
4476 return true;
4477}
4478#undef IWX_MSB
4479#undef IWX_LSB
4480#undef IWX_PIX
4481
4490{
4491 if (!d)
4492 return 0;
4493 else
4494 return (((qint64) d->ser_no) << 32) | ((qint64) d->detach_no);
4495}
4496
4506{
4507 return d && d->ref.loadRelaxed() == 1;
4508}
4509
4510
4530void QImage::setAlphaChannel(const QImage &alphaChannel)
4531{
4532 if (!d || alphaChannel.isNull())
4533 return;
4534
4535 if (d->paintEngine && d->paintEngine->isActive()) {
4536 qWarning("QImage::setAlphaChannel: "
4537 "Unable to set alpha channel while image is being painted on");
4538 return;
4539 }
4540
4541 const Format alphaFormat = qt_alphaVersionForPainting(d->format);
4542 if (d->format == alphaFormat)
4543 detach();
4544 else
4545 convertTo(alphaFormat);
4546
4547 if (isNull())
4548 return;
4549
4550 QImage sourceImage;
4551 if (alphaChannel.format() == QImage::Format_Alpha8 || (alphaChannel.d->depth == 8 && alphaChannel.isGrayscale()))
4552 sourceImage = alphaChannel;
4553 else
4554 sourceImage = alphaChannel.convertToFormat(QImage::Format_Grayscale8);
4556 return;
4557
4558 QPainter painter(this);
4559 if (sourceImage.size() != size())
4562 painter.drawImage(rect(), sourceImage);
4563}
4564
4572{
4573 if (!d)
4574 return false;
4576 if (format.alphaUsage() == QPixelFormat::UsesAlpha)
4577 return true;
4578 if (format.colorModel() == QPixelFormat::Indexed)
4579 return d->has_alpha_clut;
4580 return false;
4581}
4582
4595{
4596 if (!d)
4597 return 0;
4598 int bpc = 0;
4599 switch (d->format) {
4601 break;
4604 bpc = 30;
4605 break;
4608 bpc = 24;
4609 break;
4611 bpc = 18;
4612 break;
4614 bpc = 15;
4615 break;
4617 bpc = 23;
4618 break;
4620 bpc = 12;
4621 break;
4624 bpc = 48;
4625 break;
4627 bpc = 96;
4628 break;
4629 default:
4630 bpc = qt_depthForFormat(d->format);
4631 break;
4632 }
4633 return bpc;
4634}
4635
4648{
4649 QImage src = *this;
4650 switch (src.format()) {
4653#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4655#endif
4657#if QT_CONFIG(raster_64bit)
4660 break;
4664 break;
4665#endif
4666#if QT_CONFIG(raster_fp)
4669 break;
4671 src.convertTo(QImage::Format_RGBX32FPx4);
4672 break;
4677 break;
4678#endif
4679 default:
4680 if (src.hasAlphaChannel())
4682 else
4683 src.convertTo(QImage::Format_RGB32);
4684 }
4686 if (!src.isNull())
4687 copyMetadata(src.d, d);
4688 return src;
4689}
4690
4692{
4693 QImage out(image.height(), image.width(), image.format());
4694 if (out.isNull())
4695 return out;
4697 if (image.colorCount() > 0)
4698 out.setColorTable(image.colorTable());
4699 int w = image.width();
4700 int h = image.height();
4701 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][2];
4702 if (memrotate) {
4703 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4704 } else {
4705 for (int y=0; y<h; ++y) {
4706 if (image.colorCount())
4707 for (int x=0; x<w; ++x)
4708 out.setPixel(h-y-1, x, image.pixelIndex(x, y));
4709 else
4710 for (int x=0; x<w; ++x)
4711 out.setPixel(h-y-1, x, image.pixel(x, y));
4712 }
4713 }
4714 return out;
4715}
4716
4718{
4719 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][1];
4720 if (!memrotate)
4721 return image.mirrored(true, true);
4722
4723 QImage out(image.width(), image.height(), image.format());
4724 if (out.isNull())
4725 return out;
4727 if (image.colorCount() > 0)
4728 out.setColorTable(image.colorTable());
4729 int w = image.width();
4730 int h = image.height();
4731 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4732 return out;
4733}
4734
4736{
4737 QImage out(image.height(), image.width(), image.format());
4738 if (out.isNull())
4739 return out;
4741 if (image.colorCount() > 0)
4742 out.setColorTable(image.colorTable());
4743 int w = image.width();
4744 int h = image.height();
4745 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][0];
4746 if (memrotate) {
4747 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4748 } else {
4749 for (int y=0; y<h; ++y) {
4750 if (image.colorCount())
4751 for (int x=0; x<w; ++x)
4752 out.setPixel(y, w-x-1, image.pixelIndex(x, y));
4753 else
4754 for (int x=0; x<w; ++x)
4755 out.setPixel(y, w-x-1, image.pixel(x, y));
4756 }
4757 }
4758 return out;
4759}
4760
4786{
4787 if (!d)
4788 return QImage();
4789
4790 Q_TRACE_PARAM_REPLACE(const QTransform &, double[9]);
4791 Q_TRACE_SCOPE(QImage_transformed, QList<double>({matrix.m11(), matrix.m12(), matrix.m13(),
4792 matrix.m21(), matrix.m22(), matrix.m23(),
4793 matrix.m31(), matrix.m32(), matrix.m33()}).data(), mode);
4794
4795 // source image data
4796 const int ws = width();
4797 const int hs = height();
4798
4799 // target image data
4800 int wd;
4801 int hd;
4802
4803 // compute size of target image
4804 QTransform mat = trueMatrix(matrix, ws, hs);
4805 bool complex_xform = false;
4806 bool scale_xform = false;
4807 bool nonpaintable_scale_xform = false;
4808 if (mat.type() <= QTransform::TxScale) {
4809 if (mat.type() == QTransform::TxNone) // identity matrix
4810 return *this;
4811 else if (mat.m11() == -1. && mat.m22() == -1.)
4812 return rotated180(*this);
4813
4814 hd = qRound(qAbs(mat.m22()) * hs);
4815 wd = qRound(qAbs(mat.m11()) * ws);
4816 scale_xform = true;
4817 // The paint-based scaling is only bilinear, and has problems
4818 // with scaling smoothly more than 2x down.
4819 if (hd * 2 < hs || wd * 2 < ws)
4820 nonpaintable_scale_xform = true;
4821 } else {
4822 if (mat.type() <= QTransform::TxRotate && mat.m11() == 0 && mat.m22() == 0) {
4823 if (mat.m12() == 1. && mat.m21() == -1.)
4824 return rotated90(*this);
4825 else if (mat.m12() == -1. && mat.m21() == 1.)
4826 return rotated270(*this);
4827 }
4828
4829 QPolygonF a(QRectF(0, 0, ws, hs));
4830 a = mat.map(a);
4831 QRect r = a.boundingRect().toAlignedRect();
4832 wd = r.width();
4833 hd = r.height();
4834 complex_xform = true;
4835 }
4836
4837 if (wd == 0 || hd == 0)
4838 return QImage();
4839
4840 if (scale_xform && mode == Qt::SmoothTransformation) {
4841 switch (format()) {
4844#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4846#endif
4848#if QT_CONFIG(raster_64bit)
4851#endif
4852 // Use smoothScaled for scaling when we can do so without conversion.
4853 if (mat.m11() > 0.0F && mat.m22() > 0.0F)
4854 return smoothScaled(wd, hd);
4855 break;
4856 default:
4857 break;
4858 }
4859 // Otherwise only use it when the scaling factor demands it, or the image is large enough to scale multi-threaded
4860 if (nonpaintable_scale_xform
4861#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
4862 || (ws * hs) >= (1<<20)
4863#endif
4864 ) {
4865 if (mat.m11() < 0.0F && mat.m22() < 0.0F) { // horizontal/vertical flip
4866 return smoothScaled(wd, hd).mirrored(true, true).convertToFormat(format());
4867 } else if (mat.m11() < 0.0F) { // horizontal flip
4868 return smoothScaled(wd, hd).mirrored(true, false).convertToFormat(format());
4869 } else if (mat.m22() < 0.0F) { // vertical flip
4870 return smoothScaled(wd, hd).mirrored(false, true).convertToFormat(format());
4871 } else { // no flipping
4872 return smoothScaled(wd, hd).convertToFormat(format());
4873 }
4874 }
4875 }
4876
4877 int bpp = depth();
4878
4879 qsizetype sbpl = bytesPerLine();
4880 const uchar *sptr = bits();
4881
4882 QImage::Format target_format = d->format;
4883
4884 if (complex_xform || mode == Qt::SmoothTransformation) {
4885 if (d->format < QImage::Format_RGB32 || (!hasAlphaChannel() && complex_xform)) {
4886 target_format = qt_alphaVersion(d->format);
4887 }
4888 }
4889
4890 QImage dImage(wd, hd, target_format);
4892
4893 if (target_format == QImage::Format_MonoLSB
4894 || target_format == QImage::Format_Mono
4895 || target_format == QImage::Format_Indexed8) {
4896 dImage.d->colortable = d->colortable;
4897 dImage.d->has_alpha_clut = d->has_alpha_clut | complex_xform;
4898 }
4899
4900 // initizialize the data
4901 if (target_format == QImage::Format_Indexed8) {
4902 if (dImage.d->colortable.size() < 256) {
4903 // colors are left in the color table, so pick that one as transparent
4904 dImage.d->colortable.append(0x0);
4905 memset(dImage.bits(), dImage.d->colortable.size() - 1, dImage.d->nbytes);
4906 } else {
4907 memset(dImage.bits(), 0, dImage.d->nbytes);
4908 }
4909 } else
4910 memset(dImage.bits(), 0x00, dImage.d->nbytes);
4911
4912 if (target_format >= QImage::Format_RGB32) {
4913 // Prevent QPainter from applying devicePixelRatio corrections
4914 const QImage sImage = (devicePixelRatio() != 1) ? QImage(constBits(), width(), height(), format()) : *this;
4915
4916 Q_ASSERT(sImage.devicePixelRatio() == 1);
4917 Q_ASSERT(sImage.devicePixelRatio() == dImage.devicePixelRatio());
4918
4919 QPainter p(&dImage);
4921 p.setRenderHint(QPainter::Antialiasing);
4922 p.setRenderHint(QPainter::SmoothPixmapTransform);
4923 }
4924 p.setTransform(mat);
4925 p.drawImage(QPoint(0, 0), sImage);
4926 } else {
4927 bool invertible;
4928 mat = mat.inverted(&invertible); // invert matrix
4929 if (!invertible) // error, return null image
4930 return QImage();
4931
4932 // create target image (some of the code is from QImage::copy())
4934 qsizetype dbpl = dImage.bytesPerLine();
4935 qt_xForm_helper(mat, 0, type, bpp, dImage.bits(), dbpl, 0, hd, sptr, sbpl, ws, hs);
4936 }
4937 copyMetadata(dImage.d, d);
4938
4939 return dImage;
4940}
4941
4964{
4965 const QRectF rect(0, 0, w, h);
4966 const QRect mapped = matrix.mapRect(rect).toAlignedRect();
4967 const QPoint delta = mapped.topLeft();
4968 return matrix * QTransform().translate(-delta.x(), -delta.y());
4969}
4970
4978void QImage::setColorSpace(const QColorSpace &colorSpace)
4979{
4980 if (!d)
4981 return;
4982 if (d->colorSpace == colorSpace)
4983 return;
4984 detachMetadata(false);
4985 if (d)
4987}
4988
4999{
5000 if (!d)
5001 return;
5002 if (!d->colorSpace.isValid())
5003 return;
5004 if (!colorSpace.isValid()) {
5005 qWarning() << "QImage::convertToColorSpace: Output colorspace is not valid";
5006 return;
5007 }
5008 if (d->colorSpace == colorSpace)
5009 return;
5012}
5013
5024{
5025 if (!d || !d->colorSpace.isValid() || !colorSpace.isValid())
5026 return QImage();
5027 if (d->colorSpace == colorSpace)
5028 return *this;
5029 QImage image = copy();
5030 image.convertToColorSpace(colorSpace);
5031 return image;
5032}
5033
5040{
5041 if (!d)
5042 return QColorSpace();
5043 return d->colorSpace;
5044}
5045
5052{
5053 if (transform.isIdentity())
5054 return;
5055 detach();
5056 if (!d)
5057 return;
5058 if (pixelFormat().colorModel() == QPixelFormat::Indexed) {
5059 for (int i = 0; i < d->colortable.size(); ++i)
5060 d->colortable[i] = transform.map(d->colortable[i]);
5061 return;
5062 }
5063 QImage::Format oldFormat = format();
5064 if (qt_fpColorPrecision(oldFormat)) {
5065 if (oldFormat != QImage::Format_RGBX32FPx4 && oldFormat != QImage::Format_RGBA32FPx4
5068 } else if (depth() > 32) {
5069 if (oldFormat != QImage::Format_RGBX64 && oldFormat != QImage::Format_RGBA64
5072 } else if (oldFormat != QImage::Format_ARGB32 && oldFormat != QImage::Format_RGB32
5073 && oldFormat != QImage::Format_ARGB32_Premultiplied) {
5074 if (hasAlphaChannel())
5076 else
5078 }
5079
5080 QColorTransformPrivate::TransformFlags flags = QColorTransformPrivate::Unpremultiplied;
5081 switch (format()) {
5086 break;
5087 case Format_RGB32:
5088 case Format_RGBX64:
5089 case Format_RGBX32FPx4:
5091 break;
5092 case Format_ARGB32:
5093 case Format_RGBA64:
5094 case Format_RGBA32FPx4:
5095 break;
5096 default:
5097 Q_UNREACHABLE();
5098 }
5099
5100 std::function<void(int,int)> transformSegment;
5101
5102 if (qt_fpColorPrecision(format())) {
5103 transformSegment = [&](int yStart, int yEnd) {
5104 for (int y = yStart; y < yEnd; ++y) {
5105 QRgbaFloat32 *scanline = reinterpret_cast<QRgbaFloat32 *>(d->data + y * d->bytes_per_line);
5106 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5107 }
5108 };
5109 } else if (depth() > 32) {
5110 transformSegment = [&](int yStart, int yEnd) {
5111 for (int y = yStart; y < yEnd; ++y) {
5112 QRgba64 *scanline = reinterpret_cast<QRgba64 *>(d->data + y * d->bytes_per_line);
5113 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5114 }
5115 };
5116 } else {
5117 transformSegment = [&](int yStart, int yEnd) {
5118 for (int y = yStart; y < yEnd; ++y) {
5119 QRgb *scanline = reinterpret_cast<QRgb *>(d->data + y * d->bytes_per_line);
5120 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5121 }
5122 };
5123 }
5124
5125#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
5126 int segments = (qsizetype(width()) * height()) >> 16;
5127 segments = std::min(segments, height());
5129 if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
5130 QSemaphore semaphore;
5131 int y = 0;
5132 for (int i = 0; i < segments; ++i) {
5133 int yn = (height() - y) / (segments - i);
5134 threadPool->start([&, y, yn]() {
5135 transformSegment(y, y + yn);
5136 semaphore.release(1);
5137 });
5138 y += yn;
5139 }
5140 semaphore.acquire(segments);
5141 } else
5142#endif
5143 transformSegment(0, height());
5144
5145 if (oldFormat != format())
5146 *this = std::move(*this).convertToFormat(oldFormat);
5147}
5148
5157{
5158 if (!d || !d->colorSpace.isValid())
5159 return QImage();
5160 if (transform.isIdentity())
5161 return *this;
5162 QImage image = copy();
5163 image.applyColorTransform(transform);
5164 return image;
5165}
5166
5176{
5177 if (!d || !d->colorSpace.isValid())
5178 return QImage();
5179 applyColorTransform(transform);
5180 return std::move(*this);
5181}
5182
5183bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags flags)
5184{
5185 if (format == newFormat)
5186 return true;
5187
5188 // No in-place conversion if we have to detach
5189 if (ref.loadRelaxed() > 1 || !own_data)
5190 return false;
5191
5193 if (converter)
5194 return converter(this, flags);
5196 // Convert inplace generic, but only if there are no direct converters,
5197 // any direct ones are probably better even if not inplace.
5198 if (qt_highColorPrecision(newFormat, !qPixelLayouts[newFormat].hasAlphaChannel)
5199 && qt_highColorPrecision(format, !qPixelLayouts[format].hasAlphaChannel)) {
5200#if QT_CONFIG(raster_fp)
5202 return convert_generic_inplace_over_rgba32f(this, newFormat, flags);
5203#endif
5204 return convert_generic_inplace_over_rgb64(this, newFormat, flags);
5205 }
5206 return convert_generic_inplace(this, newFormat, flags);
5207 }
5208 return false;
5209}
5210
5221#ifndef QT_NO_DEBUG_STREAM
5223{
5224 QDebugStateSaver saver(dbg);
5225 dbg.nospace();
5226 dbg.noquote();
5227 dbg << "QImage(";
5228 if (i.isNull()) {
5229 dbg << "null";
5230 } else {
5231 dbg << i.size() << ",format=" << i.format() << ",depth=" << i.depth();
5232 if (i.colorCount())
5233 dbg << ",colorCount=" << i.colorCount();
5234 const int bytesPerLine = i.bytesPerLine();
5235 dbg << ",devicePixelRatio=" << i.devicePixelRatio()
5236 << ",bytesPerLine=" << bytesPerLine << ",sizeInBytes=" << i.sizeInBytes();
5237 if (dbg.verbosity() > 2 && i.height() > 0) {
5238 const int outputLength = qMin(bytesPerLine, 24);
5239 dbg << ",line0="
5240 << QByteArray(reinterpret_cast<const char *>(i.scanLine(0)), outputLength).toHex()
5241 << "...";
5242 }
5243 }
5244 dbg << ')';
5245 return dbg;
5246}
5247#endif
5248
5249static constexpr QPixelFormat pixelformats[] = {
5250 //QImage::Format_Invalid:
5251 QPixelFormat(),
5252 //QImage::Format_Mono:
5254 /*RED*/ 1,
5255 /*GREEN*/ 0,
5256 /*BLUE*/ 0,
5257 /*FOURTH*/ 0,
5258 /*FIFTH*/ 0,
5259 /*ALPHA*/ 0,
5260 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5261 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5262 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5263 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5264 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5265 //QImage::Format_MonoLSB:
5267 /*RED*/ 1,
5268 /*GREEN*/ 0,
5269 /*BLUE*/ 0,
5270 /*FOURTH*/ 0,
5271 /*FIFTH*/ 0,
5272 /*ALPHA*/ 0,
5273 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5274 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5275 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5276 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5277 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5278 //QImage::Format_Indexed8:
5280 /*RED*/ 8,
5281 /*GREEN*/ 0,
5282 /*BLUE*/ 0,
5283 /*FOURTH*/ 0,
5284 /*FIFTH*/ 0,
5285 /*ALPHA*/ 0,
5286 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5287 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5288 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5289 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5290 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5291 //QImage::Format_RGB32:
5293 /*RED*/ 8,
5294 /*GREEN*/ 8,
5295 /*BLUE*/ 8,
5296 /*FOURTH*/ 0,
5297 /*FIFTH*/ 0,
5298 /*ALPHA*/ 8,
5299 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5300 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5301 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5302 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5303 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5304 //QImage::Format_ARGB32:
5306 /*RED*/ 8,
5307 /*GREEN*/ 8,
5308 /*BLUE*/ 8,
5309 /*FOURTH*/ 0,
5310 /*FIFTH*/ 0,
5311 /*ALPHA*/ 8,
5312 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5313 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5314 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5315 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5316 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5317 //QImage::Format_ARGB32_Premultiplied:
5319 /*RED*/ 8,
5320 /*GREEN*/ 8,
5321 /*BLUE*/ 8,
5322 /*FOURTH*/ 0,
5323 /*FIFTH*/ 0,
5324 /*ALPHA*/ 8,
5325 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5326 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5327 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5328 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5329 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5330 //QImage::Format_RGB16:
5332 /*RED*/ 5,
5333 /*GREEN*/ 6,
5334 /*BLUE*/ 5,
5335 /*FOURTH*/ 0,
5336 /*FIFTH*/ 0,
5337 /*ALPHA*/ 0,
5338 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5339 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5340 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5341 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5342 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5343 //QImage::Format_ARGB8565_Premultiplied:
5345 /*RED*/ 5,
5346 /*GREEN*/ 6,
5347 /*BLUE*/ 5,
5348 /*FOURTH*/ 0,
5349 /*FIFTH*/ 0,
5350 /*ALPHA*/ 8,
5351 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5352 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5353 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5354 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5355 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5356 //QImage::Format_RGB666:
5358 /*RED*/ 6,
5359 /*GREEN*/ 6,
5360 /*BLUE*/ 6,
5361 /*FOURTH*/ 0,
5362 /*FIFTH*/ 0,
5363 /*ALPHA*/ 0,
5364 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5365 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5366 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5367 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5368 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5369 //QImage::Format_ARGB6666_Premultiplied:
5371 /*RED*/ 6,
5372 /*GREEN*/ 6,
5373 /*BLUE*/ 6,
5374 /*FOURTH*/ 0,
5375 /*FIFTH*/ 0,
5376 /*ALPHA*/ 6,
5377 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5378 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5379 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5380 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5381 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5382 //QImage::Format_RGB555:
5384 /*RED*/ 5,
5385 /*GREEN*/ 5,
5386 /*BLUE*/ 5,
5387 /*FOURTH*/ 0,
5388 /*FIFTH*/ 0,
5389 /*ALPHA*/ 0,
5390 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5391 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5392 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5393 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5394 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5395 //QImage::Format_ARGB8555_Premultiplied:
5397 /*RED*/ 5,
5398 /*GREEN*/ 5,
5399 /*BLUE*/ 5,
5400 /*FOURTH*/ 0,
5401 /*FIFTH*/ 0,
5402 /*ALPHA*/ 8,
5403 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5404 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5405 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5406 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5407 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5408 //QImage::Format_RGB888:
5410 /*RED*/ 8,
5411 /*GREEN*/ 8,
5412 /*BLUE*/ 8,
5413 /*FOURTH*/ 0,
5414 /*FIFTH*/ 0,
5415 /*ALPHA*/ 0,
5416 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5417 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5418 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5419 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5420 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5421 //QImage::Format_RGB444:
5423 /*RED*/ 4,
5424 /*GREEN*/ 4,
5425 /*BLUE*/ 4,
5426 /*FOURTH*/ 0,
5427 /*FIFTH*/ 0,
5428 /*ALPHA*/ 0,
5429 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5430 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5431 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5432 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5433 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5434 //QImage::Format_ARGB4444_Premultiplied:
5436 /*RED*/ 4,
5437 /*GREEN*/ 4,
5438 /*BLUE*/ 4,
5439 /*FOURTH*/ 0,
5440 /*FIFTH*/ 0,
5441 /*ALPHA*/ 4,
5442 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5443 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5444 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5445 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5446 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5447 //QImage::Format_RGBX8888:
5449 /*RED*/ 8,
5450 /*GREEN*/ 8,
5451 /*BLUE*/ 8,
5452 /*FOURTH*/ 0,
5453 /*FIFTH*/ 0,
5454 /*ALPHA*/ 8,
5455 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5456 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5457 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5458 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5459 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5460 //QImage::Format_RGBA8888:
5462 /*RED*/ 8,
5463 /*GREEN*/ 8,
5464 /*BLUE*/ 8,
5465 /*FOURTH*/ 0,
5466 /*FIFTH*/ 0,
5467 /*ALPHA*/ 8,
5468 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5469 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5470 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5471 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5472 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5473 //QImage::Format_RGBA8888_Premultiplied:
5475 /*RED*/ 8,
5476 /*GREEN*/ 8,
5477 /*BLUE*/ 8,
5478 /*FOURTH*/ 0,
5479 /*FIFTH*/ 0,
5480 /*ALPHA*/ 8,
5481 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5482 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5483 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5484 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5485 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5486 //QImage::Format_BGR30:
5488 /*RED*/ 10,
5489 /*GREEN*/ 10,
5490 /*BLUE*/ 10,
5491 /*FOURTH*/ 0,
5492 /*FIFTH*/ 0,
5493 /*ALPHA*/ 2,
5494 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5495 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5496 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5497 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5498 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5499 //QImage::Format_A2BGR30_Premultiplied:
5501 /*RED*/ 10,
5502 /*GREEN*/ 10,
5503 /*BLUE*/ 10,
5504 /*FOURTH*/ 0,
5505 /*FIFTH*/ 0,
5506 /*ALPHA*/ 2,
5507 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5508 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5509 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5510 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5511 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5512 //QImage::Format_RGB30:
5514 /*RED*/ 10,
5515 /*GREEN*/ 10,
5516 /*BLUE*/ 10,
5517 /*FOURTH*/ 0,
5518 /*FIFTH*/ 0,
5519 /*ALPHA*/ 2,
5520 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5521 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5522 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5523 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5524 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5525 //QImage::Format_A2RGB30_Premultiplied:
5527 /*RED*/ 10,
5528 /*GREEN*/ 10,
5529 /*BLUE*/ 10,
5530 /*FOURTH*/ 0,
5531 /*FIFTH*/ 0,
5532 /*ALPHA*/ 2,
5533 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5534 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5535 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5536 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5537 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5538 //QImage::Format_Alpha8:
5540 /*First*/ 0,
5541 /*SECOND*/ 0,
5542 /*THIRD*/ 0,
5543 /*FOURTH*/ 0,
5544 /*FIFTH*/ 0,
5545 /*ALPHA*/ 8,
5546 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5547 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5548 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5549 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5550 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5551 //QImage::Format_Grayscale8:
5553 /*GRAY*/ 8,
5554 /*SECOND*/ 0,
5555 /*THIRD*/ 0,
5556 /*FOURTH*/ 0,
5557 /*FIFTH*/ 0,
5558 /*ALPHA*/ 0,
5559 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5560 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5561 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5562 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5563 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5564 //QImage::Format_RGBX64:
5566 /*RED*/ 16,
5567 /*GREEN*/ 16,
5568 /*BLUE*/ 16,
5569 /*FOURTH*/ 0,
5570 /*FIFTH*/ 0,
5571 /*ALPHA*/ 16,
5572 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5573 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5574 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5575 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5576 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5577 //QImage::Format_RGBA64:
5579 /*RED*/ 16,
5580 /*GREEN*/ 16,
5581 /*BLUE*/ 16,
5582 /*FOURTH*/ 0,
5583 /*FIFTH*/ 0,
5584 /*ALPHA*/ 16,
5585 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5586 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5587 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5588 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5589 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5590 //QImage::Format_RGBA64_Premultiplied:
5592 /*RED*/ 16,
5593 /*GREEN*/ 16,
5594 /*BLUE*/ 16,
5595 /*FOURTH*/ 0,
5596 /*FIFTH*/ 0,
5597 /*ALPHA*/ 16,
5598 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5599 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5600 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5601 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5602 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5603 //QImage::Format_Grayscale16:
5605 /*GRAY*/ 16,
5606 /*SECOND*/ 0,
5607 /*THIRD*/ 0,
5608 /*FOURTH*/ 0,
5609 /*FIFTH*/ 0,
5610 /*ALPHA*/ 0,
5611 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5612 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5613 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5614 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5615 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5616 //QImage::Format_BGR888:
5618 /*RED*/ 8,
5619 /*GREEN*/ 8,
5620 /*BLUE*/ 8,
5621 /*FOURTH*/ 0,
5622 /*FIFTH*/ 0,
5623 /*ALPHA*/ 0,
5624 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5625 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5626 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5627 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5628 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5629 //QImage::Format_RGBX16FPx4:
5631 /*RED*/ 16,
5632 /*GREEN*/ 16,
5633 /*BLUE*/ 16,
5634 /*FOURTH*/ 0,
5635 /*FIFTH*/ 0,
5636 /*ALPHA*/ 16,
5637 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5638 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5639 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5640 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
5641 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5642 //QImage::Format_RGBA16FPx4:
5644 /*RED*/ 16,
5645 /*GREEN*/ 16,
5646 /*BLUE*/ 16,
5647 /*FOURTH*/ 0,
5648 /*FIFTH*/ 0,
5649 /*ALPHA*/ 16,
5650 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5651 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5652 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5653 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
5654 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5655 //QImage::Format_RGBA16FPx4_Premultiplied:
5657 /*RED*/ 16,
5658 /*GREEN*/ 16,
5659 /*BLUE*/ 16,
5660 /*FOURTH*/ 0,
5661 /*FIFTH*/ 0,
5662 /*ALPHA*/ 16,
5663 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5664 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5665 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5666 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
5667 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5668 //QImage::Format_RGBX32FPx4:
5670 /*RED*/ 32,
5671 /*GREEN*/ 32,
5672 /*BLUE*/ 32,
5673 /*FOURTH*/ 0,
5674 /*FIFTH*/ 0,
5675 /*ALPHA*/ 32,
5676 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5677 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5678 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5679 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
5680 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5681 //QImage::Format_RGBA32FPx4:
5683 /*RED*/ 32,
5684 /*GREEN*/ 32,
5685 /*BLUE*/ 32,
5686 /*FOURTH*/ 0,
5687 /*FIFTH*/ 0,
5688 /*ALPHA*/ 32,
5689 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5690 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5691 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5692 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
5693 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5694 //QImage::Format_RGBA32FPx4_Premultiplied:
5696 /*RED*/ 32,
5697 /*GREEN*/ 32,
5698 /*BLUE*/ 32,
5699 /*FOURTH*/ 0,
5700 /*FIFTH*/ 0,
5701 /*ALPHA*/ 32,
5702 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5703 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5704 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5705 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
5706 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5707};
5708static_assert(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats);
5709
5714{
5715 return toPixelFormat(format());
5716}
5717
5722{
5723 Q_ASSERT(static_cast<int>(format) < NImageFormats && static_cast<int>(format) >= 0);
5724 return pixelformats[format];
5725}
5726
5731{
5732 for (int i = 0; i < NImageFormats; i++) {
5733 if (format == pixelformats[i])
5734 return Format(i);
5735 }
5736 return Format_Invalid;
5737}
5738
5739Q_GUI_EXPORT void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient)
5740{
5742 return;
5744 src = rotated270(src);
5745 } else {
5746 src = std::move(src).mirrored(orient & QImageIOHandler::TransformationMirror,
5749 src = rotated90(src);
5750 }
5751}
5752
5754{
5756 const auto textKeys = image.textKeys();
5757 for (const QString &key : textKeys) {
5758 if (!key.isEmpty() && !text.contains(key))
5759 text.insert(key, image.text(key));
5760 }
5761 return text;
5762}
5763
5765{
5767 const auto pairs = QStringView{description}.split(u"\n\n");
5768 for (const auto &pair : pairs) {
5769 int index = pair.indexOf(u':');
5770 if (index >= 0 && pair.indexOf(u' ') < index) {
5771 if (!pair.trimmed().isEmpty())
5772 text.insert("Description"_L1, pair.toString().simplified());
5773 } else {
5774 const auto key = pair.left(index);
5775 if (!key.trimmed().isEmpty())
5776 text.insert(key.toString(), pair.mid(index + 2).toString().simplified());
5777 }
5778 }
5779 return text;
5780}
5781
5783
5784#include "moc_qimage.cpp"
IOBluetoothDevice * device
bool ref() noexcept
bool deref() noexcept
T loadRelaxed() const noexcept
\inmodule QtCore \reentrant
Definition qbuffer.h:16
\inmodule QtCore
Definition qbytearray.h:57
QByteArray toHex(char separator='\0') const
Returns a hex encoded copy of the byte array.
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
Definition qbytearray.h:394
The QColorSpace class provides a color space abstraction.
Definition qcolorspace.h:21
QColorTransform transformationToColorSpace(const QColorSpace &colorspace) const
Generates and returns a color space transformation from this color space to colorspace.
bool isValid() const noexcept
Returns true if the color space is valid.
void apply(QRgb *dst, const QRgb *src, qsizetype count, TransformFlags flags=Unpremultiplied) const
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
\inmodule QtCore\reentrant
Definition qdatastream.h:30
\inmodule QtCore
\inmodule QtCore
static QPlatformIntegration * platformIntegration()
\inmodule QtCore
Definition qhash.h:818
\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...
QString errorString() const
Returns a human readable description of the last error that occurred.
bool write(const QImage &image)
Writes the image image to the assigned device or file name.
void setQuality(int quality)
Sets the quality setting of the image format to quality.
\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:4120
bool loadFromData(QByteArrayView data, const char *format=nullptr)
Definition qimage.cpp:3781
void detachMetadata(bool invalidateCache=false)
Definition qimage.cpp:1127
int dotsPerMeterX() const
Returns the number of pixels that fit horizontally in a physical meter.
Definition qimage.cpp:4068
int bitPlaneCount() const
Definition qimage.cpp:4594
bool hasAlphaChannel() const
Returns true if the image has a format that respects the alpha channel, otherwise returns false.
Definition qimage.cpp:4571
void convertToColorSpace(const QColorSpace &)
Definition qimage.cpp:4998
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:2414
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:208
void setAlphaChannel(const QImage &alphaChannel)
Sets the alpha channel of this image to the given alphaChannel.
Definition qimage.cpp:4530
QColorSpace colorSpace() const
Definition qimage.cpp:5039
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:4222
static QPixelFormat toPixelFormat(QImage::Format format) noexcept
Converts format into a QPixelFormat.
Definition qimage.cpp:5721
qsizetype bytesPerLine() const
Returns the number of bytes per image scanline.
Definition qimage.cpp:1538
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:2573
QImage colorTransformed(const QColorTransform &transform) const &
Definition qimage.cpp:5156
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:2770
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:1444
uchar * scanLine(int)
Returns a pointer to the pixel data at the scanline with index i.
Definition qimage.cpp:1615
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:2478
QImage transformed(const QTransform &matrix, Qt::TransformationMode mode=Qt::FastTransformation) const
void setColorCount(int)
Definition qimage.cpp:2116
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:1526
bool allGray() const
Returns true if all the colors in the image are shades of gray (i.e.
Definition qimage.cpp:2854
QImage smoothScaled(int w, int h) const
Definition qimage.cpp:4647
void rgbSwapped_inplace()
QRgb color(int i) const
Returns the color in the color table at index i.
Definition qimage.cpp:1555
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:2930
void convertTo(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor)
Definition qimage.cpp:2384
bool isDetached() const
Definition qimage.cpp:4505
QImage convertedToColorSpace(const QColorSpace &) const
Definition qimage.cpp:5023
bool operator==(const QImage &) const
Returns true if this image and the given image have the same contents; otherwise returns false.
Definition qimage.cpp:3987
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:3870
uchar * bits()
Returns a pointer to the first pixel data.
Definition qimage.cpp:1677
bool isNull() const
Returns true if it is a null image, otherwise returns false.
Definition qimage.cpp:1197
void applyColorTransform(const QColorTransform &transform)
Definition qimage.cpp:5051
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:4237
bool convertToFormat_inplace(Format format, Qt::ImageConversionFlags flags)
Definition qimage.cpp:2226
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_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:79
@ 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:4260
QImage() noexcept
Constructs a null image.
Definition qimage.cpp:766
void fill(uint pixel)
Fills the entire image with the given pixelValue.
Definition qimage.cpp:1738
QImage mirrored(bool horizontally=false, bool vertically=true) const &
Definition qimage.h:218
QPixelFormat pixelFormat() const noexcept
Returns the QImage::Format as a QPixelFormat.
Definition qimage.cpp:5713
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:2691
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:2146
bool operator!=(const QImage &) const
Returns true if this image and the given image have different contents; otherwise returns false.
Definition qimage.cpp:4052
static QImage fromData(QByteArrayView data, const char *format=nullptr)
Definition qimage.cpp:3823
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:3762
const uchar * constScanLine(int) const
Returns a pointer to the pixel data at the scanline with index i.
Definition qimage.cpp:1657
void detach()
Definition qimage.cpp:1104
QStringList textKeys() const
Returns the text keys for this image.
Definition qimage.cpp:4170
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:1573
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:1488
void mirrored_inplace(bool horizontal, bool vertical)
Definition qimage.cpp:3490
qreal devicePixelRatio() const
Returns the device pixel ratio for the image.
Definition qimage.cpp:1460
void setDotsPerMeterX(int)
Sets the number of pixels that fit horizontally in a physical meter, to x.
Definition qimage.cpp:4098
QImage rgbSwapped_helper() const
int dotsPerMeterY() const
Returns the number of pixels that fit vertically in a physical meter.
Definition qimage.cpp:4081
static QImage::Format toImageFormat(QPixelFormat format) noexcept
Converts format into a QImage::Format.
Definition qimage.cpp:5730
const uchar * constBits() const
Returns a pointer to the first pixel data.
Definition qimage.cpp:1713
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:1511
QImage mirrored_helper(bool horizontal, bool vertical) const
Definition qimage.cpp:3462
QString text(const QString &key=QString()) const
Returns the image text associated with the given key.
Definition qimage.cpp:4182
QImage & operator=(const QImage &)
Move-assigns other to this QImage instance.
Definition qimage.cpp:1055
~QImage()
Destroys the image and cleans up.
Definition qimage.cpp:1039
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:2437
QImage convertToFormat_helper(Format format, Qt::ImageConversionFlags flags) const
Definition qimage.cpp:2179
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:4785
QImage scaledToWidth(int w, Qt::TransformationMode mode=Qt::FastTransformation) const
[9]
Definition qimage.cpp:2995
void setColorSpace(const QColorSpace &)
Definition qimage.cpp:4978
QPoint offset() const
Returns the number of pixels by which the image is intended to be offset by when positioning relative...
Definition qimage.cpp:4138
bool reinterpretAsFormat(Format f)
Definition qimage.cpp:2350
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:4152
int devType() const override
Definition qimage.cpp:1080
void invertPixels(InvertMode=InvertRgb)
Inverts all pixel values in the image.
Definition qimage.cpp:1970
QImage convertToFormat(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor) const &
Definition qimage.h:124
int depth() const
qint64 cacheKey() const
Returns a number that identifies the contents of this QImage object.
Definition qimage.cpp:4489
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void resize(qsizetype size)
Definition qlist.h:392
void clear()
Definition qlist.h:417
Definition qmap.h:186
iterator insert(const Key &key, const T &value)
Definition qmap.h:687
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:356
QList< Key > keys() const
Definition qmap.h:382
iterator begin()
Definition qmap.h:597
iterator end()
Definition qmap.h:601
@ PdmDevicePixelRatioScaled
static qreal devicePixelRatioFScale()
\inmodule QtGui
bool isActive() const
Returns true if the paint engine is actively drawing; otherwise returns false.
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:23
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:127
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:132
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:483
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:235
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 unpremultiplied() const
Definition qrgbafloat.h:96
\inmodule QtCore
Definition qsemaphore.h:16
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.
\inmodule QtCore
Definition qsize.h:207
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
constexpr int & rheight() noexcept
Returns a reference to the height.
Definition qsize.h:156
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:144
constexpr int & rwidth() noexcept
Returns a reference to the width.
Definition qsize.h:153
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
void chop(qsizetype n)
Removes n characters from the end of the string.
Definition qstring.cpp:6180
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the string into substrings wherever sep occurs, and returns the list of those strings.
Definition qstring.cpp:7956
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QString & insert(qsizetype i, QChar c)
Definition qstring.cpp:3110
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.h:1217
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
Definition qstring.cpp:5161
static QThreadPool * qtGuiInstance()
Returns the QThreadPool instance for Qt Gui.
\inmodule QtCore
Definition qthreadpool.h:20
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:966
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
qreal m21() const
Returns the horizontal shearing factor.
Definition qtransform.h:211
static QTransform fromScale(qreal dx, qreal dy)
Creates a matrix which corresponds to a scaling of sx horizontally and sy vertically.
qreal m12() const
Returns the vertical shearing factor.
Definition qtransform.h:203
qreal dx() const
Returns the horizontal translation factor.
Definition qtransform.h:235
QPoint map(const QPoint &p) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
qreal m11() const
Returns the horizontal scaling factor.
Definition qtransform.h:199
QTransform inverted(bool *invertible=nullptr) const
Returns an inverted copy of this matrix.
TransformationType type() const
Returns the transformation type of this matrix.
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...
qreal m22() const
Returns the vertical scaling factor.
Definition qtransform.h:215
qreal dy() const
Returns the vertical translation factor.
Definition qtransform.h:239
\inmodule QtCore
Definition qvariant.h:64
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:531
\keyword 16-bit Floating Point Support\inmodule QtCore \inheaderfile QFloat16
Definition qfloat16.h:46
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:26
@ color1
Definition qnamespace.h:28
@ white
Definition qnamespace.h:30
@ black
Definition qnamespace.h:29
@ color0
Definition qnamespace.h:27
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:309
#define Q_FALLTHROUGH()
#define QT_WARNING_DISABLE_MSVC(number)
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)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:281
Q_GUI_EXPORT int qt_defaultDpiX()
Definition qfont.cpp:107
Q_GUI_EXPORT int qt_defaultDpiY()
Definition qfont.cpp:122
#define IWX_MSB(b)
Definition qimage.cpp:4341
static QImage rotated90(const QImage &src)
Definition qimage.cpp:4691
static void copyMetadata(QImageData *dst, const QImageData *src)
Definition qimage.cpp:1148
static void rgbSwapped_generic(int width, int height, const QImage *src, QImage *dst, const QPixelLayout *layout)
Definition qimage.cpp:3527
QDataStream & operator<<(QDataStream &s, const QImage &image)
[0]
Definition qimage.cpp:3929
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:4367
QImage Q_TRACE_INSTRUMENT(qtgui) QImage
Definition qimage.cpp:3547
bool qt_read_xpm_image_or_array(QIODevice *device, const char *const *source, QImage &image)
static int next_qimage_serial_number()
Definition qimage.cpp:83
#define QIMAGE_SANITYCHECK_MEMORY(image)
Definition qimage.cpp:61
static QImage convertWithPalette(const QImage &src, QImage::Format format, const QList< QRgb > &clut)
Definition qimage.cpp:2258
void do_flip(QImageData *dst, QImageData *src, int w, int h, int depth)
Definition qimage.cpp:3336
static void copyPhysicalMetadata(QImageData *dst, const QImageData *src)
Definition qimage.cpp:1141
#define IWX_LSB(b)
Definition qimage.cpp:4350
Q_GUI_EXPORT void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient)
Definition qimage.cpp:5739
static QImage rotated270(const QImage &src)
Definition qimage.cpp:4735
QMap< QString, QString > qt_getImageText(const QImage &image, const QString &description)
Definition qimage.cpp:5753
void do_mirror(QImageData *dst, QImageData *src, bool horizontal, bool vertical)
Definition qimage.cpp:3367
static int pixel_distance(QRgb p1, QRgb p2)
Definition qimage.cpp:2231
static int closestMatch(QRgb pixel, const QList< QRgb > &clut)
Definition qimage.cpp:2245
static constexpr QPixelFormat pixelformats[]
Definition qimage.cpp:5249
#define PIX(x, y)
static QImage rotated180(const QImage &src)
Definition qimage.cpp:4717
QDataStream & operator>>(QDataStream &s, QImage &image)
Definition qimage.cpp:3955
QMap< QString, QString > qt_getImageTextFromDescription(const QString &description)
Definition qimage.cpp:5764
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:140
Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats]
bool qt_fpColorPrecision(QImage::Format format)
Definition qimage_p.h:346
bool(* InPlace_Image_Converter)(QImageData *data, Qt::ImageConversionFlags)
Definition qimage_p.h:118
InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats]
QImage::Format qt_alphaVersion(QImage::Format format)
Definition qimage_p.h:261
bool qt_highColorPrecision(QImage::Format format, bool opaque=false)
Definition qimage_p.h:318
void(* Image_Converter)(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
Definition qimage_p.h:117
QImage::Format qt_alphaVersionForPainting(QImage::Format format)
Definition qimage_p.h:377
bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags)
QImage qSmoothScaleImage(const QImage &src, int dw, int dh)
#define qWarning
Definition qlogging.h:162
static ControlElement< T > * ptr(QWidget *widget)
MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3]
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLint GLint GLint GLint dstX0
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum mode
const GLfloat * m
GLenum GLint GLint GLint GLint GLuint GLenum GLint GLint GLint dstY
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLenum GLint GLint GLint srcY
GLenum GLint GLint GLint GLint GLuint GLenum GLint GLint dstX
GLenum src
GLenum GLuint buffer
GLint GLsizei width
GLenum GLint GLint srcX
GLenum type
GLenum GLenum dst
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbitfield flags
GLint GLint xoffset
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
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
GLenum func
Definition qopenglext.h:663
GLuint res
const GLubyte * c
GLint void * img
Definition qopenglext.h:233
GLenum GLsizei len
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]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLenum GLenum GLsizei void * table
QPixelLayout qPixelLayouts[QImage::NImageFormats]
QRgba64 qConvertA2rgb30ToRgb64< PixelOrderBGR >(uint rgb)
unsigned int qConvertRgb64ToRgb30< PixelOrderBGR >(QRgba64 c)
QRgb qConvertA2rgb30ToArgb32< PixelOrderBGR >(uint c)
void(QT_FASTCALL * RbSwapFunc)(uchar *dst, const uchar *src, int count)
static quint32 RGBA2ARGB(quint32 x)
uint qConvertRgb32ToRgb30< PixelOrderRGB >(QRgb c)
QRgba64 qConvertA2rgb30ToRgb64< PixelOrderRGB >(uint rgb)
uint qConvertArgb32ToA2rgb30< PixelOrderBGR >(QRgb c)
uint qConvertRgb32ToRgb30< PixelOrderBGR >(QRgb c)
QRgb qConvertA2rgb30ToArgb32< PixelOrderRGB >(uint c)
static quint32 ARGB2RGBA(quint32 x)
unsigned int qConvertRgb64ToRgb30< PixelOrderRGB >(QRgba64 c)
void(* MemRotateFunc)(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
uint qConvertArgb32ToA2rgb30< PixelOrderRGB >(QRgb c)
uint qRgbSwapRgb30(uint c)
#define QT_XFORM_TYPE_LSBFIRST
#define QT_XFORM_TYPE_MSBFIRST
static QT_BEGIN_NAMESPACE const QRgb colors[][14]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
constexpr bool qIsGray(QRgb rgb)
Definition qrgb.h:42
QT_BEGIN_NAMESPACE typedef unsigned int QRgb
Definition qrgb.h:13
constexpr QRgb qRgb(int r, int g, int b)
Definition qrgb.h:30
constexpr int qRed(QRgb rgb)
Definition qrgb.h:18
constexpr int qGreen(QRgb rgb)
Definition qrgb.h:21
constexpr int qBlue(QRgb rgb)
Definition qrgb.h:24
constexpr QRgb qPremultiply(QRgb x)
Definition qrgb.h:45
constexpr int qAlpha(QRgb rgb)
Definition qrgb.h:27
constexpr QRgba64 qRgba64(quint16 r, quint16 g, quint16 b, quint16 a)
Definition qrgba64.h:180
static uint toArgb32(QRgba64 rgba64)
Definition qrgba64_p.h:219
#define qPrintable(string)
Definition qstring.h:1391
#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:45
unsigned char uchar
Definition qtypes.h:27
unsigned short quint16
Definition qtypes.h:43
int qint32
Definition qtypes.h:44
unsigned long long quint64
Definition qtypes.h:56
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
long long qint64
Definition qtypes.h:55
unsigned short ushort
Definition qtypes.h:28
double qreal
Definition qtypes.h:92
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:50
qreal dpmx
Definition qimage_p.h:52
bool checkForAlphaPixels() const
Definition qimage.cpp:170
qreal devicePixelRatio
Definition qimage_p.h:44
bool doImageIO(const QImage *image, QImageWriter *io, int quality) const
Definition qimage.cpp:3900
QAtomicInt ref
Definition qimage_p.h:38
int height
Definition qimage_p.h:41
static QImageData * get(QImage &img) noexcept
Definition qimage_p.h:35
QColorSpace colorSpace
Definition qimage_p.h:76
uchar * data
Definition qimage_p.h:46
static ImageSizeParameters calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth)
Definition qimage_p.h:87
int ser_no
Definition qimage_p.h:49
uint is_cached
Definition qimage_p.h:59
int width
Definition qimage_p.h:40
bool convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags)
Definition qimage.cpp:5183
void * cleanupInfo
Definition qimage_p.h:62
QList< QRgb > colortable
Definition qimage_p.h:45
uint ro_data
Definition qimage_p.h:57
uint own_data
Definition qimage_p.h:56
static QImageData * create(const QSize &size, QImage::Format format)
qsizetype bytes_per_line
Definition qimage_p.h:48
qsizetype nbytes
Definition qimage_p.h:43
qreal dpmy
Definition qimage_p.h:53
int depth
Definition qimage_p.h:42
uint has_alpha_clut
Definition qimage_p.h:58
QPaintEngine * paintEngine
Definition qimage_p.h:74
QImage::Format format
Definition qimage_p.h:47
QMap< QString, QString > text
Definition qimage_p.h:70
QPoint offset
Definition qimage_p.h:54
QImageCleanupFunction cleanupFunction
Definition qimage_p.h:61