QtBase  v6.3.1
qimage.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2021 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qimage.h"
41 
42 #include "qbuffer.h"
43 #include "qdatastream.h"
44 #include "qcolortransform.h"
45 #include "qfloat16.h"
46 #include "qmap.h"
47 #include "qtransform.h"
48 #include "qimagereader.h"
49 #include "qimagewriter.h"
50 #include "qrgbafloat.h"
51 #include "qstringlist.h"
52 #include "qvariant.h"
54 #include <qpa/qplatformintegration.h>
55 #include <private/qguiapplication_p.h>
56 #include <ctype.h>
57 #include <stdlib.h>
58 #include <limits.h>
59 #include <qpa/qplatformpixmap.h>
60 #include <private/qcolortransform_p.h>
61 #include <private/qmemrotate_p.h>
62 #include <private/qimagescale_p.h>
63 #include <private/qpixellayout_p.h>
64 #include <private/qsimd_p.h>
65 
66 #include <qhash.h>
67 
68 #include <private/qpaintengine_raster_p.h>
69 
70 #include <private/qimage_p.h>
71 #include <private/qfont_p.h>
72 
73 #if QT_CONFIG(thread)
74 #include "qsemaphore.h"
75 #include "qthreadpool.h"
76 #endif
77 
78 #include <qtgui_tracepoints_p.h>
79 
80 #include <memory>
81 
83 
84 // MSVC 19.28 does show spurious warning "C4723: potential divide by 0" for code that divides
85 // by height() in release builds. Anyhow, all the code paths in this file are only executed
86 // for valid QImage's, where height() cannot be 0. Therefore disable the warning.
88 
89 #if defined(Q_CC_DEC) && defined(__alpha) && (__DECCXX_VER-0 >= 50190001)
90 #pragma message disable narrowptr
91 #endif
92 
93 
94 #define QIMAGE_SANITYCHECK_MEMORY(image) \
95  if ((image).isNull()) { \
96  qWarning("QImage: out of memory, returning null image"); \
97  return QImage(); \
98  }
99 
100 
101 static QImage rotated90(const QImage &src);
102 static QImage rotated180(const QImage &src);
103 static QImage rotated270(const QImage &src);
104 
105 static int next_qimage_serial_number()
106 {
107  static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
108  return 1 + serial.fetchAndAddRelaxed(1);
109 }
110 
112  : ref(0), width(0), height(0), depth(0), nbytes(0), devicePixelRatio(1.0), data(nullptr),
113  format(QImage::Format_ARGB32), bytes_per_line(0),
114  ser_no(next_qimage_serial_number()),
115  detach_no(0),
116  dpmx(qt_defaultDpiX() * 100 / qreal(2.54)),
117  dpmy(qt_defaultDpiY() * 100 / qreal(2.54)),
118  offset(0, 0), own_data(true), ro_data(false), has_alpha_clut(false),
119  is_cached(false), cleanupFunction(nullptr), cleanupInfo(nullptr),
120  paintEngine(nullptr)
121 {
122 }
123 
132 {
134  return nullptr; // invalid parameter(s)
135 
136  Q_TRACE_SCOPE(QImageData_create, size, format);
137 
138  int width = size.width();
139  int height = size.height();
142  if (!params.isValid())
143  return nullptr;
144 
145  auto d = std::make_unique<QImageData>();
146 
147  switch (format) {
148  case QImage::Format_Mono:
150  d->colortable.resize(2);
151  d->colortable[0] = QColor(Qt::black).rgba();
152  d->colortable[1] = QColor(Qt::white).rgba();
153  break;
154  default:
155  break;
156  }
157 
158  d->width = width;
159  d->height = height;
160  d->depth = depth;
161  d->format = format;
162  d->has_alpha_clut = false;
163  d->is_cached = false;
164 
165  d->bytes_per_line = params.bytesPerLine;
166  d->nbytes = params.totalSize;
167  d->data = (uchar *)malloc(d->nbytes);
168 
169  if (!d->data)
170  return nullptr;
171 
172  d->ref.ref();
173  return d.release();
174 }
175 
177 {
178  if (cleanupFunction)
180  if (is_cached)
182  delete paintEngine;
183  if (data && own_data)
184  free(data);
185  data = nullptr;
186 }
187 
188 #if defined(_M_ARM) && defined(_MSC_VER)
189 #pragma optimize("", off)
190 #endif
191 
193 {
194  bool has_alpha_pixels = false;
195 
196  switch (format) {
197 
198  case QImage::Format_Mono:
201  has_alpha_pixels = has_alpha_clut;
202  break;
204  has_alpha_pixels = true;
205  break;
208  const uchar *bits = data;
209  for (int y=0; y<height && !has_alpha_pixels; ++y) {
210  uint alphaAnd = 0xff000000;
211  for (int x=0; x<width; ++x)
212  alphaAnd &= reinterpret_cast<const uint*>(bits)[x];
213  has_alpha_pixels = (alphaAnd != 0xff000000);
214  bits += bytes_per_line;
215  }
216  } break;
217 
220  const uchar *bits = data;
221  for (int y=0; y<height && !has_alpha_pixels; ++y) {
222  uchar alphaAnd = 0xff;
223  for (int x=0; x<width; ++x)
224  alphaAnd &= bits[x * 4+ 3];
225  has_alpha_pixels = (alphaAnd != 0xff);
226  bits += bytes_per_line;
227  }
228  } break;
229 
232  const uchar *bits = data;
233  for (int y=0; y<height && !has_alpha_pixels; ++y) {
234  uint alphaAnd = 0xc0000000;
235  for (int x=0; x<width; ++x)
236  alphaAnd &= reinterpret_cast<const uint*>(bits)[x];
237  has_alpha_pixels = (alphaAnd != 0xc0000000);
238  bits += bytes_per_line;
239  }
240  } break;
241 
244  const uchar *bits = data;
245  const uchar *end_bits = data + bytes_per_line;
246 
247  for (int y=0; y<height && !has_alpha_pixels; ++y) {
248  uchar alphaAnd = 0xff;
249  while (bits < end_bits) {
250  alphaAnd &= bits[0];
251  bits += 3;
252  }
253  has_alpha_pixels = (alphaAnd != 0xff);
254  bits = end_bits;
255  end_bits += bytes_per_line;
256  }
257  } break;
258 
260  const uchar *bits = data;
261  const uchar *end_bits = data + bytes_per_line;
262 
263  for (int y=0; y<height && !has_alpha_pixels; ++y) {
264  uchar alphaAnd = 0xfc;
265  while (bits < end_bits) {
266  alphaAnd &= bits[0];
267  bits += 3;
268  }
269  has_alpha_pixels = (alphaAnd != 0xfc);
270  bits = end_bits;
271  end_bits += bytes_per_line;
272  }
273  } break;
274 
276  const uchar *bits = data;
277  for (int y=0; y<height && !has_alpha_pixels; ++y) {
278  ushort alphaAnd = 0xf000;
279  for (int x=0; x<width; ++x)
280  alphaAnd &= reinterpret_cast<const ushort*>(bits)[x];
281  has_alpha_pixels = (alphaAnd != 0xf000);
282  bits += bytes_per_line;
283  }
284  } break;
287  uchar *bits = data;
288  for (int y=0; y<height && !has_alpha_pixels; ++y) {
289  for (int x=0; x<width; ++x) {
290  has_alpha_pixels |= !(((QRgba64 *)bits)[x].isOpaque());
291  }
292  bits += bytes_per_line;
293  }
294  } break;
297  uchar *bits = data;
298  for (int y = 0; y < height && !has_alpha_pixels; ++y) {
299  for (int x = 0; x < width; ++x)
300  has_alpha_pixels |= ((qfloat16 *)bits)[x * 4 + 3] < 1.0f;
301  bits += bytes_per_line;
302  }
303  } break;
306  uchar *bits = data;
307  for (int y = 0; y < height && !has_alpha_pixels; ++y) {
308  for (int x = 0; x < width; ++x)
309  has_alpha_pixels |= ((float *)bits)[x * 4 + 3] < 1.0f;
310  bits += bytes_per_line;
311  }
312  } break;
313 
329  break;
332  Q_UNREACHABLE();
333  break;
334  }
335 
336  return has_alpha_pixels;
337 }
338 #if defined(_M_ARM) && defined(_MSC_VER)
339 #pragma optimize("", on)
340 #endif
341 
778 /*****************************************************************************
779  QImage member functions
780  *****************************************************************************/
781 
788 QImage::QImage() noexcept
789  : QPaintDevice()
790 {
791  d = nullptr;
792 }
793 
806 {
807 }
808 
819  : QPaintDevice()
820 {
822 }
823 
824 
825 
826 QImageData *QImageData::create(uchar *data, int width, int height, qsizetype bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
827 {
829  return nullptr;
830 
831  const int depth = qt_depthForFormat(format);
833  if (!params.isValid())
834  return nullptr;
835 
836  if (bpl > 0) {
837  // can't overflow, because has calculateImageParameters already done this multiplication
838  const qsizetype min_bytes_per_line = (qsizetype(width) * depth + 7)/8;
839  if (bpl < min_bytes_per_line)
840  return nullptr;
841 
842  // recalculate the total with this value
843  params.bytesPerLine = bpl;
844  if (mul_overflow<qsizetype>(bpl, height, &params.totalSize))
845  return nullptr;
846  }
847 
848  QImageData *d = new QImageData;
849  d->ref.ref();
850 
851  d->own_data = false;
852  d->ro_data = readOnly;
853  d->data = data;
854  d->width = width;
855  d->height = height;
856  d->depth = depth;
857  d->format = format;
858 
859  d->bytes_per_line = params.bytesPerLine;
860  d->nbytes = params.totalSize;
861 
862  d->cleanupFunction = cleanupFunction;
863  d->cleanupInfo = cleanupInfo;
864 
865  return d;
866 }
867 
885 QImage::QImage(uchar* data, int width, int height, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
886  : QPaintDevice()
887 {
888  d = QImageData::create(data, width, height, 0, format, false, cleanupFunction, cleanupInfo);
889 }
890 
916 QImage::QImage(const uchar* data, int width, int height, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
917  : QPaintDevice()
918 {
919  d = QImageData::create(const_cast<uchar*>(data), width, height, 0, format, true, cleanupFunction, cleanupInfo);
920 }
921 
940 QImage::QImage(uchar *data, int width, int height, qsizetype bytesPerLine, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
941  :QPaintDevice()
942 {
943  d = QImageData::create(data, width, height, bytesPerLine, format, false, cleanupFunction, cleanupInfo);
944 }
945 
971 QImage::QImage(const uchar *data, int width, int height, qsizetype bytesPerLine, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
972  :QPaintDevice()
973 {
974  d = QImageData::create(const_cast<uchar*>(data), width, height, bytesPerLine, format, true, cleanupFunction, cleanupInfo);
975 }
976 
997 QImage::QImage(const QString &fileName, const char *format)
998  : QPaintDevice()
999 {
1000  d = nullptr;
1001  load(fileName, format);
1002 }
1003 
1004 #ifndef QT_NO_IMAGEFORMAT_XPM
1005 extern bool qt_read_xpm_image_or_array(QIODevice *device, const char * const *source, QImage &image);
1006 
1023 QImage::QImage(const char * const xpm[])
1024  : QPaintDevice()
1025 {
1026  d = nullptr;
1027  if (!xpm)
1028  return;
1029  if (!qt_read_xpm_image_or_array(nullptr, xpm, *this))
1030  // Issue: Warning because the constructor may be ambiguous
1031  qWarning("QImage::QImage(), XPM is not supported");
1032 }
1033 #endif // QT_NO_IMAGEFORMAT_XPM
1034 
1045  : QPaintDevice()
1046 {
1047  if (image.paintingActive()) {
1048  d = nullptr;
1049  image.copy().swap(*this);
1050  } else {
1051  d = image.d;
1052  if (d)
1053  d->ref.ref();
1054  }
1055 }
1056 
1062 {
1063  if (d && !d->ref.deref())
1064  delete d;
1065 }
1066 
1078 {
1079  if (image.paintingActive()) {
1080  operator=(image.copy());
1081  } else {
1082  if (image.d)
1083  image.d->ref.ref();
1084  if (d && !d->ref.deref())
1085  delete d;
1086  d = image.d;
1087  }
1088  return *this;
1089 }
1090 
1102 int QImage::devType() const
1103 {
1104  return QInternal::Image;
1105 }
1106 
1110 QImage::operator QVariant() const
1111 {
1112  return QVariant::fromValue(*this);
1113 }
1114 
1127 {
1128  if (d) {
1129  if (d->is_cached && d->ref.loadRelaxed() == 1)
1131 
1132  if (d->ref.loadRelaxed() != 1 || d->ro_data)
1133  *this = copy();
1134 
1135  if (d)
1136  ++d->detach_no;
1137  }
1138 }
1139 
1140 
1141 static void copyPhysicalMetadata(QImageData *dst, const QImageData *src)
1142 {
1143  dst->dpmx = src->dpmx;
1144  dst->dpmy = src->dpmy;
1145  dst->devicePixelRatio = src->devicePixelRatio;
1146 }
1147 
1148 static void copyMetadata(QImageData *dst, const QImageData *src)
1149 {
1150  // Doesn't copy colortable and alpha_clut, or offset.
1151  copyPhysicalMetadata(dst, src);
1152  dst->text = src->text;
1153  dst->colorSpace = src->colorSpace;
1154 }
1155 
1156 static 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 
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 
1319 bool QImage::isNull() const
1320 {
1321  return !d;
1322 }
1323 
1331 int QImage::width() const
1332 {
1333  return d ? d->width : 0;
1334 }
1335 
1343 int QImage::height() const
1344 {
1345  return d ? d->height : 0;
1346 }
1347 
1356 {
1357  return d ? QSize(d->width, d->height) : QSize(0, 0);
1358 }
1359 
1369 {
1370  return d ? QRect(0, 0, d->width, d->height) : QRect();
1371 }
1372 
1385 int QImage::depth() const
1386 {
1387  return d ? d->depth : 0;
1388 }
1389 
1403 {
1404  return d ? d->colortable.size() : 0;
1405 }
1406 
1419 {
1420  if (!d)
1421  return;
1422  detach();
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 
1496  detach();
1497  if (d)
1498  d->devicePixelRatio = scaleFactor;
1499 }
1500 
1510 {
1511  if (!d)
1512  return QSizeF(0, 0);
1513  return QSizeF(d->width, d->height) / d->devicePixelRatio;
1514 }
1515 
1516 
1525 {
1526  return d ? d->nbytes : 0;
1527 }
1528 
1537 {
1538  return d ? d->bytes_per_line : 0;
1539 }
1540 
1541 
1554 {
1555  Q_ASSERT(i < colorCount());
1556  return d ? d->colortable.at(i) : QRgb(uint(-1));
1557 }
1558 
1572 {
1573  if (!d)
1574  return;
1575  if (i < 0 || d->depth > 8 || i >= 1<<d->depth) {
1576  qWarning("QImage::setColor: Index out of bound %d", i);
1577  return;
1578  }
1579  detach();
1580 
1581  // In case detach() run out of memory
1582  if (!d)
1583  return;
1584 
1585  if (i >= d->colortable.size())
1586  setColorCount(i+1);
1587  d->colortable[i] = c;
1588  d->has_alpha_clut |= (qAlpha(c) != 255);
1589 }
1590 
1614 {
1615  if (!d)
1616  return nullptr;
1617 
1618  detach();
1619 
1620  // In case detach() ran out of memory
1621  if (!d)
1622  return nullptr;
1623 
1624  return d->data + i * d->bytes_per_line;
1625 }
1626 
1630 const uchar *QImage::scanLine(int i) const
1631 {
1632  if (!d)
1633  return nullptr;
1634 
1635  Q_ASSERT(i >= 0 && i < height());
1636  return d->data + i * d->bytes_per_line;
1637 }
1638 
1639 
1655 const uchar *QImage::constScanLine(int i) const
1656 {
1657  if (!d)
1658  return nullptr;
1659 
1660  Q_ASSERT(i >= 0 && i < height());
1661  return d->data + i * d->bytes_per_line;
1662 }
1663 
1676 {
1677  if (!d)
1678  return nullptr;
1679  detach();
1680 
1681  // In case detach ran out of memory...
1682  if (!d)
1683  return nullptr;
1684 
1685  return d->data;
1686 }
1687 
1695 const uchar *QImage::bits() const
1696 {
1697  return d ? d->data : nullptr;
1698 }
1699 
1700 
1711 const uchar *QImage::constBits() const
1712 {
1713  return d ? d->data : nullptr;
1714 }
1715 
1736 void QImage::fill(uint pixel)
1737 {
1738  if (!d)
1739  return;
1740 
1741  detach();
1742 
1743  // In case detach() ran out of memory
1744  if (!d)
1745  return;
1746 
1747  if (d->depth == 1 || d->depth == 8) {
1748  int w = d->width;
1749  if (d->depth == 1) {
1750  if (pixel & 1)
1751  pixel = 0xffffffff;
1752  else
1753  pixel = 0;
1754  w = (w + 7) / 8;
1755  } else {
1756  pixel &= 0xff;
1757  }
1758  qt_rectfill<quint8>(d->data, pixel, 0, 0,
1759  w, d->height, d->bytes_per_line);
1760  return;
1761  } else if (d->depth == 16) {
1762  if (d->format == Format_RGB444)
1763  pixel |= 0xf000;
1764  qt_rectfill<quint16>(reinterpret_cast<quint16*>(d->data), pixel,
1765  0, 0, d->width, d->height, d->bytes_per_line);
1766  return;
1767  } else if (d->depth == 24) {
1768  if (d->format == Format_RGB666)
1769  pixel |= 0xfc0000;
1770  qt_rectfill<quint24>(reinterpret_cast<quint24*>(d->data), pixel,
1771  0, 0, d->width, d->height, d->bytes_per_line);
1772  return;
1774  qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), QRgba64::fromArgb32(pixel),
1775  0, 0, d->width, d->height, d->bytes_per_line);
1776  return;
1778  quint64 cu;
1780  ::memcpy(&cu, &cf, sizeof(quint64));
1781  qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), cu,
1782  0, 0, d->width, d->height, d->bytes_per_line);
1783  return;
1786  uchar *data = d->data;
1787  for (int y = 0; y < d->height; ++y) {
1788  QRgbaFloat32 *line = reinterpret_cast<QRgbaFloat32 *>(data);
1789  for (int x = 0; x < d->width; ++x)
1790  line[x] = cf;
1791  data += d->bytes_per_line;
1792  }
1793  return;
1794  }
1795  Q_ASSERT(d->depth == 32);
1796 
1797  if (d->format == Format_RGB32)
1798  pixel |= 0xff000000;
1799  if (d->format == Format_RGBX8888)
1800 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1801  pixel |= 0xff000000;
1802 #else
1803  pixel |= 0x000000ff;
1804 #endif
1805  if (d->format == Format_BGR30 || d->format == Format_RGB30)
1806  pixel |= 0xc0000000;
1807 
1808  qt_rectfill<uint>(reinterpret_cast<uint*>(d->data), pixel,
1809  0, 0, d->width, d->height, d->bytes_per_line);
1810 }
1811 
1812 
1823 {
1824  fill(QColor(color));
1825 }
1826 
1827 
1828 
1847 {
1848  if (!d)
1849  return;
1850  detach();
1851 
1852  // In case we run out of memory
1853  if (!d)
1854  return;
1855 
1856  QRgba64 opaque = color.rgba64();
1857  opaque.setAlpha(65535);
1858  switch (d->format) {
1859  case QImage::Format_RGB32:
1860  case QImage::Format_ARGB32:
1861  fill(color.rgba());
1862  break;
1864  fill(qPremultiply(color.rgba()));
1865  break;
1867  fill(ARGB2RGBA(color.rgba() | 0xff000000));
1868  break;
1870  fill(ARGB2RGBA(color.rgba()));
1871  break;
1873  fill(ARGB2RGBA(qPremultiply(color.rgba())));
1874  break;
1875  case QImage::Format_BGR30:
1877  break;
1878  case QImage::Format_RGB30:
1880  break;
1881  case QImage::Format_RGB16:
1882  fill((uint) qConvertRgb32To16(color.rgba()));
1883  break;
1884  case QImage::Format_Indexed8: {
1885  uint pixel = 0;
1886  for (int i=0; i<d->colortable.size(); ++i) {
1887  if (color.rgba() == d->colortable.at(i)) {
1888  pixel = i;
1889  break;
1890  }
1891  }
1892  fill(pixel);
1893  break;
1894  }
1895  case QImage::Format_Mono:
1897  if (color == Qt::color1)
1898  fill((uint) 1);
1899  else
1900  fill((uint) 0);
1901  break;
1902  case QImage::Format_RGBX64:
1903  qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), opaque,
1904  0, 0, d->width, d->height, d->bytes_per_line);
1905  break;
1906  case QImage::Format_RGBA64:
1907  qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), color.rgba64(),
1908  0, 0, d->width, d->height, d->bytes_per_line);
1909  break;
1911  qt_rectfill<quint64>(reinterpret_cast<quint64 *>(d->data), color.rgba64().premultiplied(),
1912  0, 0, d->width, d->height, d->bytes_per_line);
1913  break;
1914  default: {
1915  QPainter p(this);
1916  p.setCompositionMode(QPainter::CompositionMode_Source);
1917  p.fillRect(rect(), color);
1918  }}
1919 }
1920 
1921 
1922 
1944 {
1945  if (!d)
1946  return;
1947 
1948  detach();
1949 
1950  // In case detach() ran out of memory
1951  if (!d)
1952  return;
1953 
1954  QImage::Format originalFormat = d->format;
1955  // Inverting premultiplied pixels would produce invalid image data.
1963  } else if (depth() > 32) {
1964  if (!d->convertInPlace(QImage::Format_RGBA64, { }))
1966  } else {
1967  if (!d->convertInPlace(QImage::Format_ARGB32, { }))
1969  }
1970  }
1971 
1972  if (depth() < 32) {
1973  // This assumes no alpha-channel as the only formats with non-premultipled alpha are 32bit.
1974  qsizetype bpl = (qsizetype(d->width) * d->depth + 7) / 8;
1975  int pad = d->bytes_per_line - bpl;
1976  uchar *sl = d->data;
1977  for (int y=0; y<d->height; ++y) {
1978  for (qsizetype x=0; x<bpl; ++x)
1979  *sl++ ^= 0xff;
1980  sl += pad;
1981  }
1983  qfloat16 *p = reinterpret_cast<qfloat16 *>(d->data);
1984  qfloat16 *end = reinterpret_cast<qfloat16 *>(d->data + d->nbytes);
1985  while (p < end) {
1986  p[0] = 1.0f - p[0];
1987  p[1] = 1.0f - p[1];
1988  p[2] = 1.0f - p[2];
1989  if (mode == InvertRgba)
1990  p[3] = 1.0f - p[3];
1991  p += 4;
1992  }
1994  uchar *data = d->data;
1995  for (int y = 0; y < d->height; ++y) {
1996  float *p = reinterpret_cast<float *>(data);
1997  for (int x = 0; x < d->width; ++x) {
1998  p[0] = 1.0f - p[0];
1999  p[1] = 1.0f - p[1];
2000  p[2] = 1.0f - p[2];
2001  if (mode == InvertRgba)
2002  p[3] = 1.0f - p[3];
2003  p += 4;
2004  }
2005  data += d->bytes_per_line;
2006  }
2007  } else if (depth() == 64) {
2008  quint16 *p = (quint16*)d->data;
2009  quint16 *end = (quint16*)(d->data + d->nbytes);
2010  quint16 xorbits = 0xffff;
2011  while (p < end) {
2012  *p++ ^= xorbits;
2013  *p++ ^= xorbits;
2014  *p++ ^= xorbits;
2015  if (mode == InvertRgba)
2016  *p++ ^= xorbits;
2017  else
2018  p++;
2019  }
2020  } else {
2021  quint32 *p = (quint32*)d->data;
2022  quint32 *end = (quint32*)(d->data + d->nbytes);
2023  quint32 xorbits = 0xffffffff;
2024  switch (d->format) {
2026  if (mode == InvertRgba)
2027  break;
2028  Q_FALLTHROUGH();
2030 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
2031  xorbits = 0xffffff00;
2032  break;
2033 #else
2034  xorbits = 0x00ffffff;
2035  break;
2036 #endif
2037  case QImage::Format_ARGB32:
2038  if (mode == InvertRgba)
2039  break;
2040  Q_FALLTHROUGH();
2041  case QImage::Format_RGB32:
2042  xorbits = 0x00ffffff;
2043  break;
2044  case QImage::Format_BGR30:
2045  case QImage::Format_RGB30:
2046  xorbits = 0x3fffffff;
2047  break;
2048  default:
2049  Q_UNREACHABLE();
2050  xorbits = 0;
2051  break;
2052  }
2053  while (p < end)
2054  *p++ ^= xorbits;
2055  }
2056 
2057  if (originalFormat != d->format) {
2058  if (!d->convertInPlace(originalFormat, { }))
2059  *this = convertToFormat(originalFormat);
2060  }
2061 }
2062 
2063 // Windows defines these
2064 #if defined(write)
2065 # undef write
2066 #endif
2067 #if defined(close)
2068 # undef close
2069 #endif
2070 #if defined(read)
2071 # undef read
2072 #endif
2073 
2089 void QImage::setColorCount(int colorCount)
2090 {
2091  if (!d) {
2092  qWarning("QImage::setColorCount: null image");
2093  return;
2094  }
2095 
2096  detach();
2097 
2098  // In case detach() ran out of memory
2099  if (!d)
2100  return;
2101 
2102  if (colorCount == d->colortable.size())
2103  return;
2104  if (colorCount <= 0) { // use no color table
2105  d->colortable.clear();
2106  return;
2107  }
2108  int nc = d->colortable.size();
2110  for (int i = nc; i < colorCount; ++i)
2111  d->colortable[i] = 0;
2112 }
2113 
2120 {
2121  return d ? d->format : Format_Invalid;
2122 }
2123 
2152 QImage QImage::convertToFormat_helper(Format format, Qt::ImageConversionFlags flags) const
2153 {
2154  if (!d || d->format == format)
2155  return *this;
2156 
2158  return QImage();
2159 
2160  const QPixelLayout *destLayout = &qPixelLayouts[format];
2162  if (!converter && format > QImage::Format_Indexed8 && d->format > QImage::Format_Indexed8) {
2163  if (qt_highColorPrecision(d->format, !destLayout->hasAlphaChannel)
2165 #if QT_CONFIG(raster_fp)
2167  converter = convert_generic_over_rgba32f;
2168  else
2169 #endif
2170  converter = convert_generic_over_rgb64;
2171  } else
2172  converter = convert_generic;
2173  }
2174  if (converter) {
2175  QImage image(d->width, d->height, format);
2176 
2178 
2179  image.d->offset = offset();
2180  copyMetadata(image.d, d);
2181 
2182  converter(image.d, d, flags);
2183  return image;
2184  }
2185 
2186  // Convert indexed formats over ARGB32 or RGB32 to the final format.
2189 
2190  if (!hasAlphaChannel())
2192 
2194 }
2195 
2199 bool QImage::convertToFormat_inplace(Format format, Qt::ImageConversionFlags flags)
2200 {
2201  return d && d->convertInPlace(format, flags);
2202 }
2203 
2204 static inline int pixel_distance(QRgb p1, QRgb p2) {
2205  int r1 = qRed(p1);
2206  int g1 = qGreen(p1);
2207  int b1 = qBlue(p1);
2208  int a1 = qAlpha(p1);
2209 
2210  int r2 = qRed(p2);
2211  int g2 = qGreen(p2);
2212  int b2 = qBlue(p2);
2213  int a2 = qAlpha(p2);
2214 
2215  return abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2) + abs(a1 - a2);
2216 }
2217 
2218 static inline int closestMatch(QRgb pixel, const QList<QRgb> &clut) {
2219  int idx = 0;
2220  int current_distance = INT_MAX;
2221  for (int i=0; i<clut.size(); ++i) {
2222  int dist = pixel_distance(pixel, clut.at(i));
2223  if (dist < current_distance) {
2224  current_distance = dist;
2225  idx = i;
2226  }
2227  }
2228  return idx;
2229 }
2230 
2231 static QImage convertWithPalette(const QImage &src, QImage::Format format,
2232  const QList<QRgb> &clut) {
2233  QImage dest(src.size(), format);
2234  dest.setColorTable(clut);
2235 
2236  copyMetadata(QImageData::get(dest), QImageData::get(src));
2237 
2238  int h = src.height();
2239  int w = src.width();
2240 
2242 
2244  for (int y=0; y<h; ++y) {
2245  const QRgb *src_pixels = (const QRgb *) src.scanLine(y);
2246  uchar *dest_pixels = (uchar *) dest.scanLine(y);
2247  for (int x=0; x<w; ++x) {
2248  int src_pixel = src_pixels[x];
2249  int value = cache.value(src_pixel, -1);
2250  if (value == -1) {
2251  value = closestMatch(src_pixel, clut);
2252  cache.insert(src_pixel, value);
2253  }
2254  dest_pixels[x] = (uchar) value;
2255  }
2256  }
2257  } else {
2258  QList<QRgb> table = clut;
2259  table.resize(2);
2260  for (int y=0; y<h; ++y) {
2261  const QRgb *src_pixels = (const QRgb *) src.scanLine(y);
2262  for (int x=0; x<w; ++x) {
2263  int src_pixel = src_pixels[x];
2264  int value = cache.value(src_pixel, -1);
2265  if (value == -1) {
2266  value = closestMatch(src_pixel, table);
2267  cache.insert(src_pixel, value);
2268  }
2269  dest.setPixel(x, y, value);
2270  }
2271  }
2272  }
2273 
2274  return dest;
2275 }
2276 
2287 QImage QImage::convertToFormat(Format format, const QList<QRgb> &colorTable, Qt::ImageConversionFlags flags) const
2288 {
2289  if (!d || d->format == format)
2290  return *this;
2291 
2293  return QImage();
2295  return convertWithPalette(convertToFormat(QImage::Format_ARGB32, flags), format, colorTable);
2296 
2297  return convertToFormat(format, flags);
2298 }
2299 
2324 {
2325  if (!d)
2326  return false;
2327  if (d->format == format)
2328  return true;
2330  return false;
2331  if (!isDetached()) { // Detach only if shared, not for read-only data.
2332  QImageData *oldD = d;
2333  detach();
2334  // In case detach() ran out of memory
2335  if (!d) {
2336  d = oldD;
2337  d->ref.ref();
2338  return false;
2339  }
2340  }
2341 
2342  d->format = format;
2343  return true;
2344 }
2345 
2357 void QImage::convertTo(Format format, Qt::ImageConversionFlags flags)
2358 {
2360  return;
2361 
2362  if (d->format == format)
2363  return;
2364 
2365  detach();
2367  return;
2368 
2370 }
2371 
2387 bool QImage::valid(int x, int y) const
2388 {
2389  return d
2390  && x >= 0 && x < d->width
2391  && y >= 0 && y < d->height;
2392 }
2393 
2410 int QImage::pixelIndex(int x, int y) const
2411 {
2412  if (!d || x < 0 || x >= d->width || y < 0 || y >= height()) {
2413  qWarning("QImage::pixelIndex: coordinate (%d,%d) out of range", x, y);
2414  return -12345;
2415  }
2416  const uchar * s = scanLine(y);
2417  switch(d->format) {
2418  case Format_Mono:
2419  return (*(s + (x >> 3)) >> (7- (x & 7))) & 1;
2420  case Format_MonoLSB:
2421  return (*(s + (x >> 3)) >> (x & 7)) & 1;
2422  case Format_Indexed8:
2423  return (int)s[x];
2424  default:
2425  qWarning("QImage::pixelIndex: Not applicable for %d-bpp images (no palette)", d->depth);
2426  }
2427  return 0;
2428 }
2429 
2430 
2451 QRgb QImage::pixel(int x, int y) const
2452 {
2453  if (!d || x < 0 || x >= d->width || y < 0 || y >= d->height) {
2454  qWarning("QImage::pixel: coordinate (%d,%d) out of range", x, y);
2455  return 12345;
2456  }
2457 
2458  const uchar *s = d->data + y * d->bytes_per_line;
2459 
2460  int index = -1;
2461  switch (d->format) {
2462  case Format_Mono:
2463  index = (*(s + (x >> 3)) >> (~x & 7)) & 1;
2464  break;
2465  case Format_MonoLSB:
2466  index = (*(s + (x >> 3)) >> (x & 7)) & 1;
2467  break;
2468  case Format_Indexed8:
2469  index = s[x];
2470  break;
2471  default:
2472  break;
2473  }
2474  if (index >= 0) { // Indexed format
2475  if (index >= d->colortable.size()) {
2476  qWarning("QImage::pixel: color table index %d out of range.", index);
2477  return 0;
2478  }
2479  return d->colortable.at(index);
2480  }
2481 
2482  switch (d->format) {
2483  case Format_RGB32:
2484  return 0xff000000 | reinterpret_cast<const QRgb *>(s)[x];
2485  case Format_ARGB32: // Keep old behaviour.
2487  return reinterpret_cast<const QRgb *>(s)[x];
2488  case Format_RGBX8888:
2489  case Format_RGBA8888: // Match ARGB32 behavior.
2491  return RGBA2ARGB(reinterpret_cast<const quint32 *>(s)[x]);
2492  case Format_BGR30:
2494  return qConvertA2rgb30ToArgb32<PixelOrderBGR>(reinterpret_cast<const quint32 *>(s)[x]);
2495  case Format_RGB30:
2497  return qConvertA2rgb30ToArgb32<PixelOrderRGB>(reinterpret_cast<const quint32 *>(s)[x]);
2498  case Format_RGB16:
2499  return qConvertRgb16To32(reinterpret_cast<const quint16 *>(s)[x]);
2500  case Format_RGBX64:
2501  case Format_RGBA64: // Match ARGB32 behavior.
2503  return reinterpret_cast<const QRgba64 *>(s)[x].toArgb32();
2504  case Format_RGBX16FPx4:
2505  case Format_RGBA16FPx4: // Match ARGB32 behavior.
2507  return reinterpret_cast<const QRgbaFloat16 *>(s)[x].toArgb32();
2508  case Format_RGBX32FPx4:
2509  case Format_RGBA32FPx4: // Match ARGB32 behavior.
2511  return reinterpret_cast<const QRgbaFloat32 *>(s)[x].toArgb32();
2512  default:
2513  break;
2514  }
2515  const QPixelLayout *layout = &qPixelLayouts[d->format];
2516  uint result;
2517  return *layout->fetchToARGB32PM(&result, s, x, 1, nullptr, nullptr);
2518 }
2519 
2546 void QImage::setPixel(int x, int y, uint index_or_rgb)
2547 {
2548  if (!d || x < 0 || x >= width() || y < 0 || y >= height()) {
2549  qWarning("QImage::setPixel: coordinate (%d,%d) out of range", x, y);
2550  return;
2551  }
2552  // detach is called from within scanLine
2553  uchar * s = scanLine(y);
2554  switch(d->format) {
2555  case Format_Mono:
2556  case Format_MonoLSB:
2557  if (index_or_rgb > 1) {
2558  qWarning("QImage::setPixel: Index %d out of range", index_or_rgb);
2559  } else if (format() == Format_MonoLSB) {
2560  if (index_or_rgb==0)
2561  *(s + (x >> 3)) &= ~(1 << (x & 7));
2562  else
2563  *(s + (x >> 3)) |= (1 << (x & 7));
2564  } else {
2565  if (index_or_rgb==0)
2566  *(s + (x >> 3)) &= ~(1 << (7-(x & 7)));
2567  else
2568  *(s + (x >> 3)) |= (1 << (7-(x & 7)));
2569  }
2570  return;
2571  case Format_Indexed8:
2572  if (index_or_rgb >= (uint)d->colortable.size()) {
2573  qWarning("QImage::setPixel: Index %d out of range", index_or_rgb);
2574  return;
2575  }
2576  s[x] = index_or_rgb;
2577  return;
2578  case Format_RGB32:
2579  //make sure alpha is 255, we depend on it in qdrawhelper for cases
2580  // when image is set as a texture pattern on a qbrush
2581  ((uint *)s)[x] = 0xff000000 | index_or_rgb;
2582  return;
2583  case Format_ARGB32:
2585  ((uint *)s)[x] = index_or_rgb;
2586  return;
2587  case Format_RGB16:
2588  ((quint16 *)s)[x] = qConvertRgb32To16(index_or_rgb);
2589  return;
2590  case Format_RGBX8888:
2591  ((uint *)s)[x] = ARGB2RGBA(0xff000000 | index_or_rgb);
2592  return;
2593  case Format_RGBA8888:
2595  ((uint *)s)[x] = ARGB2RGBA(index_or_rgb);
2596  return;
2597  case Format_BGR30:
2598  ((uint *)s)[x] = qConvertRgb32ToRgb30<PixelOrderBGR>(index_or_rgb);
2599  return;
2601  ((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderBGR>(index_or_rgb);
2602  return;
2603  case Format_RGB30:
2604  ((uint *)s)[x] = qConvertRgb32ToRgb30<PixelOrderRGB>(index_or_rgb);
2605  return;
2607  ((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderRGB>(index_or_rgb);
2608  return;
2609  case Format_RGBA64:
2611  ((QRgba64 *)s)[x] = QRgba64::fromArgb32(index_or_rgb);
2612  return;
2613  case Format_RGBX16FPx4:
2614  ((QRgbaFloat16 *)s)[x] = QRgbaFloat16::fromArgb32(index_or_rgb | 0xff000000);
2615  return;
2616  case Format_RGBA16FPx4:
2618  ((QRgbaFloat16 *)s)[x] = QRgbaFloat16::fromArgb32(index_or_rgb);
2619  return;
2620  case Format_RGBX32FPx4:
2621  ((QRgbaFloat32 *)s)[x] = QRgbaFloat32::fromArgb32(index_or_rgb | 0xff000000);
2622  return;
2623  case Format_RGBA32FPx4:
2625  ((QRgbaFloat32 *)s)[x] = QRgbaFloat32::fromArgb32(index_or_rgb);
2626  return;
2627  case Format_Invalid:
2628  case NImageFormats:
2629  Q_ASSERT(false);
2630  return;
2631  default:
2632  break;
2633  }
2634 
2635  const QPixelLayout *layout = &qPixelLayouts[d->format];
2636  if (!hasAlphaChannel())
2637  layout->storeFromRGB32(s, &index_or_rgb, x, 1, nullptr, nullptr);
2638  else
2639  layout->storeFromARGB32PM(s, &index_or_rgb, x, 1, nullptr, nullptr);
2640 }
2641 
2664 QColor QImage::pixelColor(int x, int y) const
2665 {
2666  if (!d || x < 0 || x >= d->width || y < 0 || y >= height()) {
2667  qWarning("QImage::pixelColor: coordinate (%d,%d) out of range", x, y);
2668  return QColor();
2669  }
2670 
2671  QRgba64 c;
2672  const uchar * s = constScanLine(y);
2673  switch (d->format) {
2674  case Format_BGR30:
2676  c = qConvertA2rgb30ToRgb64<PixelOrderBGR>(reinterpret_cast<const quint32 *>(s)[x]);
2677  break;
2678  case Format_RGB30:
2680  c = qConvertA2rgb30ToRgb64<PixelOrderRGB>(reinterpret_cast<const quint32 *>(s)[x]);
2681  break;
2682  case Format_RGBX64:
2683  case Format_RGBA64:
2685  c = reinterpret_cast<const QRgba64 *>(s)[x];
2686  break;
2687  case Format_Grayscale16: {
2688  quint16 v = reinterpret_cast<const quint16 *>(s)[x];
2689  return QColor(qRgba64(v, v, v, 0xffff));
2690  }
2691  case Format_RGBX16FPx4:
2692  case Format_RGBA16FPx4:
2694  QRgbaFloat16 p = reinterpret_cast<const QRgbaFloat16 *>(s)[x];
2696  p = p.unpremultiplied();
2697  QColor color;
2698  color.setRgbF(p.red(), p.green(), p.blue(), p.alpha());
2699  return color;
2700  }
2701  case Format_RGBX32FPx4:
2702  case Format_RGBA32FPx4:
2704  QRgbaFloat32 p = reinterpret_cast<const QRgbaFloat32 *>(s)[x];
2706  p = p.unpremultiplied();
2707  QColor color;
2708  color.setRgbF(p.red(), p.green(), p.blue(), p.alpha());
2709  return color;
2710  }
2711  default:
2712  c = QRgba64::fromArgb32(pixel(x, y));
2713  break;
2714  }
2715  // QColor is always unpremultiplied
2717  c = c.unpremultiplied();
2718  return QColor(c);
2719 }
2720 
2743 void QImage::setPixelColor(int x, int y, const QColor &color)
2744 {
2745  if (!d || x < 0 || x >= width() || y < 0 || y >= height()) {
2746  qWarning("QImage::setPixelColor: coordinate (%d,%d) out of range", x, y);
2747  return;
2748  }
2749 
2750  if (!color.isValid()) {
2751  qWarning("QImage::setPixelColor: color is invalid");
2752  return;
2753  }
2754 
2755  // QColor is always unpremultiplied
2756  QRgba64 c = color.rgba64();
2757  if (!hasAlphaChannel())
2758  c.setAlpha(65535);
2759  else if (qPixelLayouts[d->format].premultiplied)
2760  c = c.premultiplied();
2761  // detach is called from within scanLine
2762  uchar * s = scanLine(y);
2763  switch (d->format) {
2764  case Format_Mono:
2765  case Format_MonoLSB:
2766  case Format_Indexed8:
2767  qWarning("QImage::setPixelColor: called on monochrome or indexed format");
2768  return;
2769  case Format_BGR30:
2770  ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderBGR>(c) | 0xc0000000;
2771  return;
2774  return;
2775  case Format_RGB30:
2776  ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderRGB>(c) | 0xc0000000;
2777  return;
2780  return;
2781  case Format_RGBX64:
2782  case Format_RGBA64:
2784  ((QRgba64 *)s)[x] = c;
2785  return;
2786  case Format_RGBX16FPx4:
2787  case Format_RGBA16FPx4:
2789  float r, g, b, a;
2790  color.getRgbF(&r, &g, &b, &a);
2791  if (d->format == Format_RGBX16FPx4)
2792  a = 1.0f;
2793  QRgbaFloat16 c16f{r, g, b, a};
2795  c16f = c16f.premultiplied();
2796  ((QRgbaFloat16 *)s)[x] = c16f;
2797  return;
2798  }
2799  case Format_RGBX32FPx4:
2800  case Format_RGBA32FPx4:
2802  float r, g, b, a;
2803  color.getRgbF(&r, &g, &b, &a);
2804  if (d->format == Format_RGBX32FPx4)
2805  a = 1.0f;
2806  QRgbaFloat32 c32f{r, g, b, a};
2808  c32f = c32f.premultiplied();
2809  ((QRgbaFloat32 *)s)[x] = c32f;
2810  return;
2811  }
2812  default:
2813  setPixel(x, y, c.toArgb32());
2814  return;
2815  }
2816 }
2817 
2827 bool QImage::allGray() const
2828 {
2829  if (!d)
2830  return true;
2831 
2832  switch (d->format) {
2833  case Format_Mono:
2834  case Format_MonoLSB:
2835  case Format_Indexed8:
2836  for (int i = 0; i < d->colortable.size(); ++i) {
2837  if (!qIsGray(d->colortable.at(i)))
2838  return false;
2839  }
2840  return true;
2841  case Format_Alpha8:
2842  return false;
2843  case Format_Grayscale8:
2844  case Format_Grayscale16:
2845  return true;
2846  case Format_RGB32:
2847  case Format_ARGB32:
2849 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
2850  case Format_RGBX8888:
2851  case Format_RGBA8888:
2853 #endif
2854  for (int j = 0; j < d->height; ++j) {
2855  const QRgb *b = (const QRgb *)constScanLine(j);
2856  for (int i = 0; i < d->width; ++i) {
2857  if (!qIsGray(b[i]))
2858  return false;
2859  }
2860  }
2861  return true;
2862  case Format_RGB16:
2863  for (int j = 0; j < d->height; ++j) {
2864  const quint16 *b = (const quint16 *)constScanLine(j);
2865  for (int i = 0; i < d->width; ++i) {
2866  if (!qIsGray(qConvertRgb16To32(b[i])))
2867  return false;
2868  }
2869  }
2870  return true;
2871  default:
2872  break;
2873  }
2874 
2876  const QPixelLayout *layout = &qPixelLayouts[d->format];
2877  const auto fetch = layout->fetchToARGB32PM;
2878  for (int j = 0; j < d->height; ++j) {
2879  const uchar *b = constScanLine(j);
2880  int x = 0;
2881  while (x < d->width) {
2882  int l = qMin(d->width - x, BufferSize);
2883  const uint *ptr = fetch(buffer, b, x, l, nullptr, nullptr);
2884  for (int i = 0; i < l; ++i) {
2885  if (!qIsGray(ptr[i]))
2886  return false;
2887  }
2888  x += l;
2889  }
2890  }
2891  return true;
2892 }
2893 
2904 {
2905  if (!d)
2906  return false;
2907 
2908  if (d->format == QImage::Format_Alpha8)
2909  return false;
2910 
2912  return true;
2913 
2914  switch (depth()) {
2915  case 32:
2916  case 24:
2917  case 16:
2918  return allGray();
2919  case 8: {
2921  for (int i = 0; i < colorCount(); i++)
2922  if (d->colortable.at(i) != qRgb(i,i,i))
2923  return false;
2924  return true;
2925  }
2926  }
2927  return false;
2928 }
2929 
2969 {
2970  if (!d) {
2971  qWarning("QImage::scaled: Image is a null image");
2972  return QImage();
2973  }
2974  if (s.isEmpty())
2975  return QImage();
2976 
2977  QSize newSize = size();
2978  newSize.scale(s, aspectMode);
2979  newSize.rwidth() = qMax(newSize.width(), 1);
2980  newSize.rheight() = qMax(newSize.height(), 1);
2981  if (newSize == size())
2982  return *this;
2983 
2984  Q_TRACE_SCOPE(QImage_scaled, s, aspectMode, mode);
2985 
2986  QTransform wm = QTransform::fromScale((qreal)newSize.width() / width(), (qreal)newSize.height() / height());
2987  QImage img = transformed(wm, mode);
2988  return img;
2989 }
2990 
3006 {
3007  if (!d) {
3008  qWarning("QImage::scaleWidth: Image is a null image");
3009  return QImage();
3010  }
3011  if (w <= 0)
3012  return QImage();
3013 
3014  Q_TRACE_SCOPE(QImage_scaledToWidth, w, mode);
3015 
3016  qreal factor = (qreal) w / width();
3018  return transformed(wm, mode);
3019 }
3020 
3036 {
3037  if (!d) {
3038  qWarning("QImage::scaleHeight: Image is a null image");
3039  return QImage();
3040  }
3041  if (h <= 0)
3042  return QImage();
3043 
3044  Q_TRACE_SCOPE(QImage_scaledToHeight, h, mode);
3045 
3046  qreal factor = (qreal) h / height();
3048  return transformed(wm, mode);
3049 }
3050 
3068 QImage QImage::createAlphaMask(Qt::ImageConversionFlags flags) const
3069 {
3070  if (!d || d->format == QImage::Format_RGB32)
3071  return QImage();
3072 
3073  if (d->depth == 1) {
3074  // A monochrome pixmap, with alpha channels on those two colors.
3075  // Pretty unlikely, so use less efficient solution.
3077  }
3078 
3080  if (!mask.isNull()) {
3081  dither_to_Mono(mask.d, d, flags, true);
3082  copyPhysicalMetadata(mask.d, d);
3083  }
3084  return mask;
3085 }
3086 
3087 #ifndef QT_NO_IMAGE_HEURISTIC_MASK
3113 {
3114  if (!d)
3115  return QImage();
3116 
3117  if (d->depth != 32) {
3119  return img32.createHeuristicMask(clipTight);
3120  }
3121 
3122 #define PIX(x,y) (*((const QRgb*)scanLine(y)+x) & 0x00ffffff)
3123 
3124  int w = width();
3125  int h = height();
3126  QImage m(w, h, Format_MonoLSB);
3128  m.setColorCount(2);
3129  m.setColor(0, QColor(Qt::color0).rgba());
3130  m.setColor(1, QColor(Qt::color1).rgba());
3131  m.fill(0xff);
3132 
3133  QRgb background = PIX(0,0);
3134  if (background != PIX(w-1,0) &&
3135  background != PIX(0,h-1) &&
3136  background != PIX(w-1,h-1)) {
3137  background = PIX(w-1,0);
3138  if (background != PIX(w-1,h-1) &&
3139  background != PIX(0,h-1) &&
3140  PIX(0,h-1) == PIX(w-1,h-1)) {
3141  background = PIX(w-1,h-1);
3142  }
3143  }
3144 
3145  int x,y;
3146  bool done = false;
3147  uchar *ypp, *ypc, *ypn;
3148  while(!done) {
3149  done = true;
3150  ypn = m.scanLine(0);
3151  ypc = nullptr;
3152  for (y = 0; y < h; y++) {
3153  ypp = ypc;
3154  ypc = ypn;
3155  ypn = (y == h-1) ? nullptr : m.scanLine(y+1);
3156  const QRgb *p = (const QRgb *)scanLine(y);
3157  for (x = 0; x < w; x++) {
3158  // slowness here - it's possible to do six of these tests
3159  // together in one go. oh well.
3160  if ((x == 0 || y == 0 || x == w-1 || y == h-1 ||
3161  !(*(ypc + ((x-1) >> 3)) & (1 << ((x-1) & 7))) ||
3162  !(*(ypc + ((x+1) >> 3)) & (1 << ((x+1) & 7))) ||
3163  !(*(ypp + (x >> 3)) & (1 << (x & 7))) ||
3164  !(*(ypn + (x >> 3)) & (1 << (x & 7)))) &&
3165  ( (*(ypc + (x >> 3)) & (1 << (x & 7)))) &&
3166  ((*p & 0x00ffffff) == background)) {
3167  done = false;
3168  *(ypc + (x >> 3)) &= ~(1 << (x & 7));
3169  }
3170  p++;
3171  }
3172  }
3173  }
3174 
3175  if (!clipTight) {
3176  ypn = m.scanLine(0);
3177  ypc = nullptr;
3178  for (y = 0; y < h; y++) {
3179  ypp = ypc;
3180  ypc = ypn;
3181  ypn = (y == h-1) ? nullptr : m.scanLine(y+1);
3182  const QRgb *p = (const QRgb *)scanLine(y);
3183  for (x = 0; x < w; x++) {
3184  if ((*p & 0x00ffffff) != background) {
3185  if (x > 0)
3186  *(ypc + ((x-1) >> 3)) |= (1 << ((x-1) & 7));
3187  if (x < w-1)
3188  *(ypc + ((x+1) >> 3)) |= (1 << ((x+1) & 7));
3189  if (y > 0)
3190  *(ypp + (x >> 3)) |= (1 << (x & 7));
3191  if (y < h-1)
3192  *(ypn + (x >> 3)) |= (1 << (x & 7));
3193  }
3194  p++;
3195  }
3196  }
3197  }
3198 
3199 #undef PIX
3200 
3201  copyPhysicalMetadata(m.d, d);
3202  return m;
3203 }
3204 #endif //QT_NO_IMAGE_HEURISTIC_MASK
3205 
3217 {
3218  if (!d)
3219  return QImage();
3220  QImage maskImage(size(), QImage::Format_MonoLSB);
3221  QIMAGE_SANITYCHECK_MEMORY(maskImage);
3222  maskImage.fill(0);
3223  uchar *s = maskImage.bits();
3224  if (!s)
3225  return QImage();
3226 
3227  if (depth() == 32) {
3228  for (int h = 0; h < d->height; h++) {
3229  const uint *sl = (const uint *) scanLine(h);
3230  for (int w = 0; w < d->width; w++) {
3231  if (sl[w] == color)
3232  *(s + (w >> 3)) |= (1 << (w & 7));
3233  }
3234  s += maskImage.bytesPerLine();
3235  }
3236  } else {
3237  for (int h = 0; h < d->height; h++) {
3238  for (int w = 0; w < d->width; w++) {
3239  if ((uint) pixel(w, h) == color)
3240  *(s + (w >> 3)) |= (1 << (w & 7));
3241  }
3242  s += maskImage.bytesPerLine();
3243  }
3244  }
3245  if (mode == Qt::MaskOutColor)
3246  maskImage.invertPixels();
3247 
3248  copyPhysicalMetadata(maskImage.d, d);
3249  return maskImage;
3250 }
3251 
3275 template<class T> inline void do_mirror_data(QImageData *dst, QImageData *src,
3276  int dstX0, int dstY0,
3277  int dstXIncr, int dstYIncr,
3278  int w, int h)
3279 {
3280  if (dst == src) {
3281  // When mirroring in-place, stop in the middle for one of the directions, since we
3282  // are swapping the bytes instead of merely copying.
3283  const int srcXEnd = (dstX0 && !dstY0) ? w / 2 : w;
3284  const int srcYEnd = dstY0 ? h / 2 : h;
3285  for (int srcY = 0, dstY = dstY0; srcY < srcYEnd; ++srcY, dstY += dstYIncr) {
3286  T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3287  T *dstPtr = (T *) (dst->data + dstY * dst->bytes_per_line);
3288  for (int srcX = 0, dstX = dstX0; srcX < srcXEnd; ++srcX, dstX += dstXIncr)
3289  std::swap(srcPtr[srcX], dstPtr[dstX]);
3290  }
3291  // If mirroring both ways, the middle line needs to be mirrored horizontally only.
3292  if (dstX0 && dstY0 && (h & 1)) {
3293  int srcY = h / 2;
3294  int srcXEnd2 = w / 2;
3295  T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3296  for (int srcX = 0, dstX = dstX0; srcX < srcXEnd2; ++srcX, dstX += dstXIncr)
3297  std::swap(srcPtr[srcX], srcPtr[dstX]);
3298  }
3299  } else {
3300  for (int srcY = 0, dstY = dstY0; srcY < h; ++srcY, dstY += dstYIncr) {
3301  T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3302  T *dstPtr = (T *) (dst->data + dstY * dst->bytes_per_line);
3303  for (int srcX = 0, dstX = dstX0; srcX < w; ++srcX, dstX += dstXIncr)
3304  dstPtr[dstX] = srcPtr[srcX];
3305  }
3306  }
3307 }
3308 
3309 inline void do_flip(QImageData *dst, QImageData *src, int w, int h, int depth)
3310 {
3311  const int data_bytes_per_line = w * (depth / 8);
3312  if (dst == src) {
3313  uint *srcPtr = reinterpret_cast<uint *>(src->data);
3314  uint *dstPtr = reinterpret_cast<uint *>(dst->data + (h - 1) * dst->bytes_per_line);
3315  h = h / 2;
3316  const int uint_per_line = (data_bytes_per_line + 3) >> 2; // bytes per line must be a multiple of 4
3317  for (int y = 0; y < h; ++y) {
3318  // This is auto-vectorized, no need for SSE2 or NEON versions:
3319  for (int x = 0; x < uint_per_line; x++) {
3320  const uint d = dstPtr[x];
3321  const uint s = srcPtr[x];
3322  dstPtr[x] = s;
3323  srcPtr[x] = d;
3324  }
3325  srcPtr += src->bytes_per_line >> 2;
3326  dstPtr -= dst->bytes_per_line >> 2;
3327  }
3328 
3329  } else {
3330  const uchar *srcPtr = src->data;
3331  uchar *dstPtr = dst->data + (h - 1) * dst->bytes_per_line;
3332  for (int y = 0; y < h; ++y) {
3333  memcpy(dstPtr, srcPtr, data_bytes_per_line);
3334  srcPtr += src->bytes_per_line;
3335  dstPtr -= dst->bytes_per_line;
3336  }
3337  }
3338 }
3339 
3340 inline void do_mirror(QImageData *dst, QImageData *src, bool horizontal, bool vertical)
3341 {
3342  Q_ASSERT(src->width == dst->width && src->height == dst->height && src->depth == dst->depth);
3343  int w = src->width;
3344  int h = src->height;
3345  int depth = src->depth;
3346 
3347  if (src->depth == 1) {
3348  w = (w + 7) / 8; // byte aligned width
3349  depth = 8;
3350  }
3351 
3352  if (vertical && !horizontal) {
3353  // This one is simple and common, so do it a little more optimized
3354  do_flip(dst, src, w, h, depth);
3355  return;
3356  }
3357 
3358  int dstX0 = 0, dstXIncr = 1;
3359  int dstY0 = 0, dstYIncr = 1;
3360  if (horizontal) {
3361  // 0 -> w-1, 1 -> w-2, 2 -> w-3, ...
3362  dstX0 = w - 1;
3363  dstXIncr = -1;
3364  }
3365  if (vertical) {
3366  // 0 -> h-1, 1 -> h-2, 2 -> h-3, ...
3367  dstY0 = h - 1;
3368  dstYIncr = -1;
3369  }
3370 
3371  switch (depth) {
3372  case 128:
3373  do_mirror_data<QRgbaFloat32>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3374  break;
3375  case 64:
3376  do_mirror_data<quint64>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3377  break;
3378  case 32:
3379  do_mirror_data<quint32>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3380  break;
3381  case 24:
3382  do_mirror_data<quint24>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3383  break;
3384  case 16:
3385  do_mirror_data<quint16>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3386  break;
3387  case 8:
3388  do_mirror_data<quint8>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3389  break;
3390  default:
3391  Q_ASSERT(false);
3392  break;
3393  }
3394 
3395  // The bytes are now all in the correct place. In addition, the bits in the individual
3396  // bytes have to be flipped too when horizontally mirroring a 1 bit-per-pixel image.
3397  if (horizontal && dst->depth == 1) {
3398  Q_ASSERT(dst->format == QImage::Format_Mono || dst->format == QImage::Format_MonoLSB);
3399  const int shift = 8 - (dst->width % 8);
3400  const uchar *bitflip = qt_get_bitflip_array();
3401  for (int y = 0; y < h; ++y) {
3402  uchar *begin = dst->data + y * dst->bytes_per_line;
3403  uchar *end = begin + dst->bytes_per_line;
3404  for (uchar *p = begin; p < end; ++p) {
3405  *p = bitflip[*p];
3406  // When the data is non-byte aligned, an extra bit shift (of the number of
3407  // unused bits at the end) is needed for the entire scanline.
3408  if (shift != 8 && p != begin) {
3409  if (dst->format == QImage::Format_Mono) {
3410  for (int i = 0; i < shift; ++i) {
3411  p[-1] <<= 1;
3412  p[-1] |= (*p & (128 >> i)) >> (7 - i);
3413  }
3414  } else {
3415  for (int i = 0; i < shift; ++i) {
3416  p[-1] >>= 1;
3417  p[-1] |= (*p & (1 << i)) << (7 - i);
3418  }
3419  }
3420  }
3421  }
3422  if (shift != 8) {
3423  if (dst->format == QImage::Format_Mono)
3424  end[-1] <<= shift;
3425  else
3426  end[-1] >>= shift;
3427  }
3428  }
3429  }
3430 }
3431 
3435 QImage QImage::mirrored_helper(bool horizontal, bool vertical) const
3436 {
3437  if (!d)
3438  return QImage();
3439 
3440  if ((d->width <= 1 && d->height <= 1) || (!horizontal && !vertical))
3441  return *this;
3442 
3443  // Create result image, copy colormap
3444  QImage result(d->width, d->height, d->format);
3446 
3447  // check if we ran out of of memory..
3448  if (!result.d)
3449  return QImage();
3450 
3451  result.d->colortable = d->colortable;
3452  result.d->has_alpha_clut = d->has_alpha_clut;
3453  copyMetadata(result.d, d);
3454 
3455  do_mirror(result.d, d, horizontal, vertical);
3456 
3457  return result;
3458 }
3459 
3463 void QImage::mirrored_inplace(bool horizontal, bool vertical)
3464 {
3465  if (!d || (d->width <= 1 && d->height <= 1) || (!horizontal && !vertical))
3466  return;
3467 
3468  detach();
3469  if (!d)
3470  return;
3471  if (!d->own_data)
3472  *this = copy();
3473 
3474  do_mirror(d, d, horizontal, vertical);
3475 }
3476 
3500 static inline void rgbSwapped_generic(int width, int height, const QImage *src, QImage *dst, const QPixelLayout* layout)
3501 {
3502  const RbSwapFunc func = layout->rbSwap;
3503  if (!func) {
3504  qWarning("Trying to rb-swap an image format where it doesn't make sense");
3505  if (src != dst)
3506  *dst = *src;
3507  return;
3508  }
3509 
3510  for (int i = 0; i < height; ++i) {
3511  uchar *q = dst->scanLine(i);
3512  const uchar *p = src->constScanLine(i);
3513  func(q, p, width);
3514  }
3515 }
3516 
3521 {
3522  if (isNull())
3523  return *this;
3524 
3525  Q_TRACE_SCOPE(QImage_rgbSwapped_helper);
3526 
3527  QImage res;
3528 
3529  switch (d->format) {
3530  case Format_Invalid:
3531  case NImageFormats:
3532  Q_ASSERT(false);
3533  break;
3534  case Format_Alpha8:
3535  case Format_Grayscale8:
3536  case Format_Grayscale16:
3537  return *this;
3538  case Format_Mono:
3539  case Format_MonoLSB:
3540  case Format_Indexed8:
3541  res = copy();
3542  for (int i = 0; i < res.d->colortable.size(); i++) {
3543  QRgb c = res.d->colortable.at(i);
3544  res.d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
3545  }
3546  break;
3547  case Format_RGBX8888:
3548  case Format_RGBA8888:
3550 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
3551  res = QImage(d->width, d->height, d->format);
3553  for (int i = 0; i < d->height; i++) {
3554  uint *q = (uint*)res.scanLine(i);
3555  const uint *p = (const uint*)constScanLine(i);
3556  const uint *end = p + d->width;
3557  while (p < end) {
3558  uint c = *p;
3559  *q = ((c << 16) & 0xff000000) | ((c >> 16) & 0xff00) | (c & 0x00ff00ff);
3560  p++;
3561  q++;
3562  }
3563  }
3564  break;
3565 #else
3566  // On little-endian rgba8888 is abgr32 and can use same rgb-swap as argb32
3567  Q_FALLTHROUGH();
3568 #endif
3569  case Format_RGB32:
3570  case Format_ARGB32:
3572  res = QImage(d->width, d->height, d->format);
3574  for (int i = 0; i < d->height; i++) {
3575  uint *q = (uint*)res.scanLine(i);
3576  const uint *p = (const uint*)constScanLine(i);
3577  const uint *end = p + d->width;
3578  while (p < end) {
3579  uint c = *p;
3580  *q = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
3581  p++;
3582  q++;
3583  }
3584  }
3585  break;
3586  case Format_RGB16:
3587  res = QImage(d->width, d->height, d->format);
3589  for (int i = 0; i < d->height; i++) {
3590  ushort *q = (ushort*)res.scanLine(i);
3591  const ushort *p = (const ushort*)constScanLine(i);
3592  const ushort *end = p + d->width;
3593  while (p < end) {
3594  ushort c = *p;
3595  *q = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
3596  p++;
3597  q++;
3598  }
3599  }
3600  break;
3601  default:
3602  res = QImage(d->width, d->height, d->format);
3604  rgbSwapped_generic(d->width, d->height, this, &res, &qPixelLayouts[d->format]);
3605  break;
3606  }
3607  copyMetadata(res.d, d);
3608  return res;
3609 }
3610 
3615 {
3616  if (isNull())
3617  return;
3618 
3619  detach();
3620  if (!d)
3621  return;
3622  if (!d->own_data)
3623  *this = copy();
3624 
3625  switch (d->format) {
3626  case Format_Invalid:
3627  case NImageFormats:
3628  Q_ASSERT(false);
3629  break;
3630  case Format_Alpha8:
3631  case Format_Grayscale8:
3632  case Format_Grayscale16:
3633  return;
3634  case Format_Mono:
3635  case Format_MonoLSB:
3636  case Format_Indexed8:
3637  for (int i = 0; i < d->colortable.size(); i++) {
3638  QRgb c = d->colortable.at(i);
3639  d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
3640  }
3641  break;
3642  case Format_RGBX8888:
3643  case Format_RGBA8888:
3645 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
3646  for (int i = 0; i < d->height; i++) {
3647  uint *p = (uint*)scanLine(i);
3648  uint *end = p + d->width;
3649  while (p < end) {
3650  uint c = *p;
3651  *p = ((c << 16) & 0xff000000) | ((c >> 16) & 0xff00) | (c & 0x00ff00ff);
3652  p++;
3653  }
3654  }
3655  break;
3656 #else
3657  // On little-endian rgba8888 is abgr32 and can use same rgb-swap as argb32
3658  Q_FALLTHROUGH();
3659 #endif
3660  case Format_RGB32:
3661  case Format_ARGB32:
3663  for (int i = 0; i < d->height; i++) {
3664  uint *p = (uint*)scanLine(i);
3665  uint *end = p + d->width;
3666  while (p < end) {
3667  uint c = *p;
3668  *p = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
3669  p++;
3670  }
3671  }
3672  break;
3673  case Format_RGB16:
3674  for (int i = 0; i < d->height; i++) {
3675  ushort *p = (ushort*)scanLine(i);
3676  ushort *end = p + d->width;
3677  while (p < end) {
3678  ushort c = *p;
3679  *p = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
3680  p++;
3681  }
3682  }
3683  break;
3684  case Format_BGR30:
3686  case Format_RGB30:
3688  for (int i = 0; i < d->height; i++) {
3689  uint *p = (uint*)scanLine(i);
3690  uint *end = p + d->width;
3691  while (p < end) {
3692  *p = qRgbSwapRgb30(*p);
3693  p++;
3694  }
3695  }
3696  break;
3697  default:
3698  rgbSwapped_generic(d->width, d->height, this, this, &qPixelLayouts[d->format]);
3699  break;
3700  }
3701 }
3702 
3722 bool QImage::load(const QString &fileName, const char* format)
3723 {
3724  *this = QImageReader(fileName, format).read();
3725  return !isNull();
3726 }
3727 
3736 {
3737  *this = QImageReader(device, format).read();
3738  return !isNull();
3739 }
3740 
3755 {
3756  *this = fromData(data, format);
3757  return !isNull();
3758 }
3759 
3768 bool QImage::loadFromData(const uchar *buf, int len, const char *format)
3769 {
3771 }
3772 
3797 {
3798  QByteArray a = QByteArray::fromRawData(data.constData(), data.size());
3799  QBuffer b;
3800  b.setData(a);
3801  b.open(QIODevice::ReadOnly);
3802  return QImageReader(&b, format).read();
3803 }
3804 
3813 QImage QImage::fromData(const uchar *data, int size, const char *format)
3814 {
3815  return fromData(QByteArrayView(data, size), format);
3816 }
3817 
3843 bool QImage::save(const QString &fileName, const char *format, int quality) const
3844 {
3845  if (isNull())
3846  return false;
3847  QImageWriter writer(fileName, format);
3848  return d->doImageIO(this, &writer, quality);
3849 }
3850 
3862 bool QImage::save(QIODevice* device, const char* format, int quality) const
3863 {
3864  if (isNull())
3865  return false; // nothing to save
3866  QImageWriter writer(device, format);
3867  return d->doImageIO(this, &writer, quality);
3868 }
3869 
3870 /* \internal
3871 */
3872 
3873 bool QImageData::doImageIO(const QImage *image, QImageWriter *writer, int quality) const
3874 {
3875  if (quality > 100 || quality < -1)
3876  qWarning("QPixmap::save: Quality out of range [-1, 100]");
3877  if (quality >= 0)
3878  writer->setQuality(qMin(quality,100));
3879  return writer->write(*image);
3880 }
3881 
3882 /*****************************************************************************
3883  QImage stream functions
3884  *****************************************************************************/
3885 #if !defined(QT_NO_DATASTREAM)
3898 {
3899  if (s.version() >= 5) {
3900  if (image.isNull()) {
3901  s << (qint32) 0; // null image marker
3902  return s;
3903  } else {
3904  s << (qint32) 1;
3905  // continue ...
3906  }
3907  }
3908  QImageWriter writer(s.device(), s.version() == 1 ? "bmp" : "png");
3909  writer.write(image);
3910  return s;
3911 }
3912 
3924 {
3925  if (s.version() >= 5) {
3926  qint32 nullMarker;
3927  s >> nullMarker;
3928  if (!nullMarker) {
3929  image = QImage(); // null image
3930  return s;
3931  }
3932  }
3933  image = QImageReader(s.device(), s.version() == 1 ? "bmp" : "png").read();
3934  if (image.isNull() && s.version() >= 5)
3935  s.setStatus(QDataStream::ReadPastEnd);
3936  return s;
3937 }
3938 #endif // QT_NO_DATASTREAM
3939 
3940 
3941 
3955 bool QImage::operator==(const QImage & i) const
3956 {
3957  // same object, or shared?
3958  if (i.d == d)
3959  return true;
3960  if (!i.d || !d)
3961  return false;
3962 
3963  // obviously different stuff?
3964  if (i.d->height != d->height || i.d->width != d->width || i.d->format != d->format)
3965  return false;
3966 
3967  if (d->format != Format_RGB32) {
3968  if (d->format >= Format_ARGB32) { // all bits defined
3969  const int n = d->width * d->depth / 8;
3970  if (n == d->bytes_per_line && n == i.d->bytes_per_line) {
3971  if (memcmp(bits(), i.bits(), d->nbytes))
3972  return false;
3973  } else {
3974  for (int y = 0; y < d->height; ++y) {
3975  if (memcmp(scanLine(y), i.scanLine(y), n))
3976  return false;
3977  }
3978  }
3979  } else {
3980  const int w = width();
3981  const int h = height();
3982  const QList<QRgb> &colortable = d->colortable;
3983  const QList<QRgb> &icolortable = i.d->colortable;
3984  for (int y=0; y<h; ++y) {
3985  for (int x=0; x<w; ++x) {
3986  if (colortable[pixelIndex(x, y)] != icolortable[i.pixelIndex(x, y)])
3987  return false;
3988  }
3989  }
3990  }
3991  } else {
3992  //alpha channel undefined, so we must mask it out
3993  for(int l = 0; l < d->height; l++) {
3994  int w = d->width;
3995  const uint *p1 = reinterpret_cast<const uint*>(scanLine(l));
3996  const uint *p2 = reinterpret_cast<const uint*>(i.scanLine(l));
3997  while (w--) {
3998  if ((*p1++ & 0x00ffffff) != (*p2++ & 0x00ffffff))
3999  return false;
4000  }
4001  }
4002  }
4003  return true;
4004 }
4005 
4006 
4020 bool QImage::operator!=(const QImage & i) const
4021 {
4022  return !(*this == i);
4023 }
4024 
4025 
4026 
4027 
4037 {
4038  return d ? qRound(d->dpmx) : 0;
4039 }
4040 
4050 {
4051  return d ? qRound(d->dpmy) : 0;
4052 }
4053 
4067 {
4068  if (!d || !x)
4069  return;
4070  detach();
4071 
4072  if (d)
4073  d->dpmx = x;
4074 }
4075 
4089 {
4090  if (!d || !y)
4091  return;
4092  detach();
4093 
4094  if (d)
4095  d->dpmy = y;
4096 }
4097 
4107 {
4108  return d ? d->offset : QPoint();
4109 }
4110 
4111 
4121 {
4122  if (!d)
4123  return;
4124  detach();
4125 
4126  if (d)
4127  d->offset = p;
4128 }
4129 
4139 {
4140  return d ? QStringList(d->text.keys()) : QStringList();
4141 }
4142 
4151 {
4152  if (!d)
4153  return QString();
4154 
4155  if (!key.isEmpty())
4156  return d->text.value(key);
4157 
4158  QString tmp;
4159  for (auto it = d->text.begin(), end = d->text.end(); it != end; ++it)
4160  tmp += it.key() + QLatin1String(": ") + it.value().simplified() + QLatin1String("\n\n");
4161  if (!tmp.isEmpty())
4162  tmp.chop(2); // remove final \n\n
4163  return tmp;
4164 }
4165 
4191 {
4192  if (!d)
4193  return;
4194  detach();
4195 
4196  if (d)
4197  d->text.insert(key, value);
4198 }
4199 
4206 {
4207  if (!d)
4208  return nullptr;
4209 
4210  if (!d->paintEngine) {
4211  QPaintDevice *paintDevice = const_cast<QImage *>(this);
4213  if (platformIntegration)
4214  d->paintEngine = platformIntegration->createImagePaintEngine(paintDevice);
4215  if (!d->paintEngine)
4216  d->paintEngine = new QRasterPaintEngine(paintDevice);
4217  }
4218 
4219  return d->paintEngine;
4220 }
4221 
4222 
4229 {
4230  if (!d)
4231  return 0;
4232 
4233  switch (metric) {
4234  case PdmWidth:
4235  return d->width;
4236 
4237  case PdmHeight:
4238  return d->height;
4239 
4240  case PdmWidthMM:
4241  return qRound(d->width * 1000 / d->dpmx);
4242 
4243  case PdmHeightMM:
4244  return qRound(d->height * 1000 / d->dpmy);
4245 
4246  case PdmNumColors:
4247  return d->colortable.size();
4248 
4249  case PdmDepth:
4250  return d->depth;
4251 
4252  case PdmDpiX:
4253  return qRound(d->dpmx * 0.0254);
4254  break;
4255 
4256  case PdmDpiY:
4257  return qRound(d->dpmy * 0.0254);
4258  break;
4259 
4260  case PdmPhysicalDpiX:
4261  return qRound(d->dpmx * 0.0254);
4262  break;
4263 
4264  case PdmPhysicalDpiY:
4265  return qRound(d->dpmy * 0.0254);
4266  break;
4267 
4268  case PdmDevicePixelRatio:
4269  return d->devicePixelRatio;
4270  break;
4271 
4274  break;
4275 
4276  default:
4277  qWarning("QImage::metric(): Unhandled metric type %d", metric);
4278  break;
4279  }
4280  return 0;
4281 }
4282 
4283 
4284 
4285 /*****************************************************************************
4286  QPixmap (and QImage) helper functions
4287  *****************************************************************************/
4288 /*
4289  This internal function contains the common (i.e. platform independent) code
4290  to do a transformation of pixel data. It is used by QPixmap::transform() and by
4291  QImage::transform().
4292 
4293  \a trueMat is the true transformation matrix (see QPixmap::trueMatrix()) and
4294  \a xoffset is an offset to the matrix.
4295 
4296  \a msbfirst specifies for 1bpp images, if the MSB or LSB comes first and \a
4297  depth specifies the colordepth of the data.
4298 
4299  \a dptr is a pointer to the destination data, \a dbpl specifies the bits per
4300  line for the destination data, \a p_inc is the offset that we advance for
4301  every scanline and \a dHeight is the height of the destination image.
4302 
4303  \a sprt is the pointer to the source data, \a sbpl specifies the bits per
4304  line of the source data, \a sWidth and \a sHeight are the width and height of
4305  the source data.
4306 */
4307 
4308 #undef IWX_MSB
4309 #define IWX_MSB(b) if (trigx < maxws && trigy < maxhs) { \
4310  if (*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
4311  (1 << (7-((trigx>>12)&7)))) \
4312  *dptr |= b; \
4313  } \
4314  trigx += m11; \
4315  trigy += m12;
4316  // END OF MACRO
4317 #undef IWX_LSB
4318 #define IWX_LSB(b) if (trigx < maxws && trigy < maxhs) { \
4319  if (*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
4320  (1 << ((trigx>>12)&7))) \
4321  *dptr |= b; \
4322  } \
4323  trigx += m11; \
4324  trigy += m12;
4325  // END OF MACRO
4326 #undef IWX_PIX
4327 #define IWX_PIX(b) if (trigx < maxws && trigy < maxhs) { \
4328  if ((*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
4329  (1 << (7-((trigx>>12)&7)))) == 0) \
4330  *dptr &= ~b; \
4331  } \
4332  trigx += m11; \
4333  trigy += m12;
4334  // END OF MACRO
4335 bool qt_xForm_helper(const QTransform &trueMat, int xoffset, int type, int depth,
4336  uchar *dptr, qsizetype dbpl, int p_inc, int dHeight,
4337  const uchar *sptr, qsizetype sbpl, int sWidth, int sHeight)
4338 {
4339  int m11 = int(trueMat.m11()*4096.0);
4340  int m12 = int(trueMat.m12()*4096.0);
4341  int m21 = int(trueMat.m21()*4096.0);
4342  int m22 = int(trueMat.m22()*4096.0);
4343  int dx = qRound(trueMat.dx()*4096.0);
4344  int dy = qRound(trueMat.dy()*4096.0);
4345 
4346  int m21ydx = dx + (xoffset<<16) + (m11 + m21) / 2;
4347  int m22ydy = dy + (m12 + m22) / 2;
4348  uint trigx;
4349  uint trigy;
4350  uint maxws = sWidth<<12;
4351  uint maxhs = sHeight<<12;
4352 
4353  for (int y=0; y<dHeight; y++) { // for each target scanline
4354  trigx = m21ydx;
4355  trigy = m22ydy;
4356  uchar *maxp = dptr + dbpl;
4357  if (depth != 1) {
4358  switch (depth) {
4359  case 8: // 8 bpp transform
4360  while (dptr < maxp) {
4361  if (trigx < maxws && trigy < maxhs)
4362  *dptr = *(sptr+sbpl*(trigy>>12)+(trigx>>12));
4363  trigx += m11;
4364  trigy += m12;
4365  dptr++;
4366  }
4367  break;
4368 
4369  case 16: // 16 bpp transform
4370  while (dptr < maxp) {
4371  if (trigx < maxws && trigy < maxhs)
4372  *((ushort*)dptr) = *((const ushort *)(sptr+sbpl*(trigy>>12) +
4373  ((trigx>>12)<<1)));
4374  trigx += m11;
4375  trigy += m12;
4376  dptr++;
4377  dptr++;
4378  }
4379  break;
4380 
4381  case 24: // 24 bpp transform
4382  while (dptr < maxp) {
4383  if (trigx < maxws && trigy < maxhs) {
4384  const uchar *p2 = sptr+sbpl*(trigy>>12) + ((trigx>>12)*3);
4385  dptr[0] = p2[0];
4386  dptr[1] = p2[1];
4387  dptr[2] = p2[2];
4388  }
4389  trigx += m11;
4390  trigy += m12;
4391  dptr += 3;
4392  }
4393  break;
4394 
4395  case 32: // 32 bpp transform
4396  while (dptr < maxp) {
4397  if (trigx < maxws && trigy < maxhs)
4398  *((uint*)dptr) = *((const uint *)(sptr+sbpl*(trigy>>12) +
4399  ((trigx>>12)<<2)));
4400  trigx += m11;
4401  trigy += m12;
4402  dptr += 4;
4403  }
4404  break;
4405 
4406  default: {
4407  return false;
4408  }
4409  }
4410  } else {
4411  switch (type) {
4413  while (dptr < maxp) {
4414  IWX_MSB(128);
4415  IWX_MSB(64);
4416  IWX_MSB(32);
4417  IWX_MSB(16);
4418  IWX_MSB(8);
4419  IWX_MSB(4);
4420  IWX_MSB(2);
4421  IWX_MSB(1);
4422  dptr++;
4423  }
4424  break;
4426  while (dptr < maxp) {
4427  IWX_LSB(1);
4428  IWX_LSB(2);
4429  IWX_LSB(4);
4430  IWX_LSB(8);
4431  IWX_LSB(16);
4432  IWX_LSB(32);
4433  IWX_LSB(64);
4434  IWX_LSB(128);
4435  dptr++;
4436  }
4437  break;
4438  }
4439  }
4440  m21ydx += m21;
4441  m22ydy += m22;
4442  dptr += p_inc;
4443  }
4444  return true;
4445 }
4446 #undef IWX_MSB
4447 #undef IWX_LSB
4448 #undef IWX_PIX
4449 
4458 {
4459  if (!d)
4460  return 0;
4461  else
4462  return (((qint64) d->ser_no) << 32) | ((qint64) d->detach_no);
4463 }
4464 
4474 {
4475  return d && d->ref.loadRelaxed() == 1;
4476 }
4477 
4478 
4498 void QImage::setAlphaChannel(const QImage &alphaChannel)
4499 {
4500  if (!d || alphaChannel.isNull())
4501  return;
4502 
4503  if (d->paintEngine && d->paintEngine->isActive()) {
4504  qWarning("QImage::setAlphaChannel: "
4505  "Unable to set alpha channel while image is being painted on");
4506  return;
4507  }
4508 
4509  const Format alphaFormat = qt_alphaVersionForPainting(d->format);
4510  if (d->format == alphaFormat)
4511  detach();
4512  else
4513  convertTo(alphaFormat);
4514 
4515  if (isNull())
4516  return;
4517 
4518  QImage sourceImage;
4519  if (alphaChannel.format() == QImage::Format_Alpha8 || (alphaChannel.d->depth == 8 && alphaChannel.isGrayscale()))
4520  sourceImage = alphaChannel;
4521  else
4522  sourceImage = alphaChannel.convertToFormat(QImage::Format_Grayscale8);
4523  if (!sourceImage.reinterpretAsFormat(QImage::Format_Alpha8))
4524  return;
4525 
4526  QPainter painter(this);
4527  if (sourceImage.size() != size())
4530  painter.drawImage(rect(), sourceImage);
4531 }
4532 
4540 {
4541  if (!d)
4542  return false;
4543  const QPixelFormat format = pixelFormat();
4544  if (format.alphaUsage() == QPixelFormat::UsesAlpha)
4545  return true;
4546  if (format.colorModel() == QPixelFormat::Indexed)
4547  return d->has_alpha_clut;
4548  return false;
4549 }
4550 
4563 {
4564  if (!d)
4565  return 0;
4566  int bpc = 0;
4567  switch (d->format) {
4569  break;
4570  case QImage::Format_BGR30:
4571  case QImage::Format_RGB30:
4572  bpc = 30;
4573  break;
4574  case QImage::Format_RGB32:
4576  bpc = 24;
4577  break;
4578  case QImage::Format_RGB666:
4579  bpc = 18;
4580  break;
4581  case QImage::Format_RGB555:
4582  bpc = 15;
4583  break;
4585  bpc = 23;
4586  break;
4587  case QImage::Format_RGB444:
4588  bpc = 12;
4589  break;
4590  case QImage::Format_RGBX64:
4592  bpc = 48;
4593  break;
4595  bpc = 96;
4596  break;
4597  default:
4598  bpc = qt_depthForFormat(d->format);
4599  break;
4600  }
4601  return bpc;
4602 }
4603 
4616 {
4617  QImage src = *this;
4618  switch (src.format()) {
4619  case QImage::Format_RGB32:
4621 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4623 #endif
4625 #if QT_CONFIG(raster_64bit)
4626  case QImage::Format_RGBX64:
4628  break;
4629  case QImage::Format_RGBA64:
4632  break;
4633 #endif
4634 #if QT_CONFIG(raster_fp)
4637  break;
4639  src.convertTo(QImage::Format_RGBX32FPx4);
4640  break;
4645  break;
4646 #endif
4647  default:
4648  if (src.hasAlphaChannel())
4650  else
4651  src.convertTo(QImage::Format_RGB32);
4652  }
4653  src = qSmoothScaleImage(src, w, h);
4654  if (!src.isNull())
4655  copyMetadata(src.d, d);
4656  return src;
4657 }
4658 
4659 static QImage rotated90(const QImage &image)
4660 {
4661  QImage out(image.height(), image.width(), image.format());
4662  copyMetadata(&out, image);
4663  if (image.colorCount() > 0)
4664  out.setColorTable(image.colorTable());
4665  int w = image.width();
4666  int h = image.height();
4667  const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][2];
4668  if (memrotate) {
4669  memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4670  } else {
4671  for (int y=0; y<h; ++y) {
4672  if (image.colorCount())
4673  for (int x=0; x<w; ++x)
4674  out.setPixel(h-y-1, x, image.pixelIndex(x, y));
4675  else
4676  for (int x=0; x<w; ++x)
4677  out.setPixel(h-y-1, x, image.pixel(x, y));
4678  }
4679  }
4680  return out;
4681 }
4682 
4683 static QImage rotated180(const QImage &image)
4684 {
4685  const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][1];
4686  if (!memrotate)
4687  return image.mirrored(true, true);
4688 
4689  QImage out(image.width(), image.height(), image.format());
4690  copyMetadata(&out, image);
4691  if (image.colorCount() > 0)
4692  out.setColorTable(image.colorTable());
4693  int w = image.width();
4694  int h = image.height();
4695  memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4696  return out;
4697 }
4698 
4699 static QImage rotated270(const QImage &image)
4700 {
4701  QImage out(image.height(), image.width(), image.format());
4702  copyMetadata(&out, image);
4703  if (image.colorCount() > 0)
4704  out.setColorTable(image.colorTable());
4705  int w = image.width();
4706  int h = image.height();
4707  const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][0];
4708  if (memrotate) {
4709  memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4710  } else {
4711  for (int y=0; y<h; ++y) {
4712  if (image.colorCount())
4713  for (int x=0; x<w; ++x)
4714  out.setPixel(y, w-x-1, image.pixelIndex(x, y));
4715  else
4716  for (int x=0; x<w; ++x)
4717  out.setPixel(y, w-x-1, image.pixel(x, y));
4718  }
4719  }
4720  return out;
4721 }
4722 
4748 {
4749  if (!d)
4750  return QImage();
4751 
4752  Q_TRACE_SCOPE(QImage_transformed, matrix, mode);
4753 
4754  // source image data
4755  const int ws = width();
4756  const int hs = height();
4757 
4758  // target image data
4759  int wd;
4760  int hd;
4761 
4762  // compute size of target image
4763  QTransform mat = trueMatrix(matrix, ws, hs);
4764  bool complex_xform = false;
4765  bool scale_xform = false;
4766  bool nonpaintable_scale_xform = false;
4767  if (mat.type() <= QTransform::TxScale) {
4768  if (mat.type() == QTransform::TxNone) // identity matrix
4769  return *this;
4770  else if (mat.m11() == -1. && mat.m22() == -1.)
4771  return rotated180(*this);
4772 
4773  if (mode == Qt::FastTransformation) {
4774  hd = qRound(qAbs(mat.m22()) * hs);
4775  wd = qRound(qAbs(mat.m11()) * ws);
4776  } else {
4777  hd = int(qAbs(mat.m22()) * hs + 0.9999);
4778  wd = int(qAbs(mat.m11()) * ws + 0.9999);
4779  }
4780  scale_xform = true;
4781  // The paint-based scaling is only bilinear, and has problems
4782  // with scaling smoothly more than 2x down.
4783  if (hd * 2 < hs || wd * 2 < ws)
4784  nonpaintable_scale_xform = true;
4785  } else {
4786  if (mat.type() <= QTransform::TxRotate && mat.m11() == 0 && mat.m22() == 0) {
4787  if (mat.m12() == 1. && mat.m21() == -1.)
4788  return rotated90(*this);
4789  else if (mat.m12() == -1. && mat.m21() == 1.)
4790  return rotated270(*this);
4791  }
4792 
4793  QPolygonF a(QRectF(0, 0, ws, hs));
4794  a = mat.map(a);
4795  QRect r = a.boundingRect().toAlignedRect();
4796  wd = r.width();
4797  hd = r.height();
4798  complex_xform = true;
4799  }
4800 
4801  if (wd == 0 || hd == 0)
4802  return QImage();
4803 
4804  if (scale_xform && mode == Qt::SmoothTransformation) {
4805  switch (format()) {
4806  case QImage::Format_RGB32:
4808 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4810 #endif
4812 #if QT_CONFIG(raster_64bit)
4813  case QImage::Format_RGBX64:
4815 #endif
4816  // Use smoothScaled for scaling when we can do so without conversion.
4817  if (mat.m11() > 0.0F && mat.m22() > 0.0F)
4818  return smoothScaled(wd, hd);
4819  break;
4820  default:
4821  break;
4822  }
4823  // Otherwise only use it when the scaling factor demands it, or the image is large enough to scale multi-threaded
4824  if (nonpaintable_scale_xform
4825 #if QT_CONFIG(thread) && !defined(Q_OS_WASM)
4826  || (ws * hs) >= (1<<20)
4827 #endif
4828  ) {
4829  if (mat.m11() < 0.0F && mat.m22() < 0.0F) { // horizontal/vertical flip
4830  return smoothScaled(wd, hd).mirrored(true, true).convertToFormat(format());
4831  } else if (mat.m11() < 0.0F) { // horizontal flip
4832  return smoothScaled(wd, hd).mirrored(true, false).convertToFormat(format());
4833  } else if (mat.m22() < 0.0F) { // vertical flip
4834  return smoothScaled(wd, hd).mirrored(false, true).convertToFormat(format());
4835  } else { // no flipping
4836  return smoothScaled(wd, hd).convertToFormat(format());
4837  }
4838  }
4839  }
4840 
4841  int bpp = depth();
4842 
4843  qsizetype sbpl = bytesPerLine();
4844  const uchar *sptr = bits();
4845 
4846  QImage::Format target_format = d->format;
4847 
4848  if (complex_xform || mode == Qt::SmoothTransformation) {
4849  if (d->format < QImage::Format_RGB32 || (!hasAlphaChannel() && complex_xform)) {
4850  target_format = qt_alphaVersion(d->format);
4851  }
4852  }
4853 
4854  QImage dImage(wd, hd, target_format);
4855  QIMAGE_SANITYCHECK_MEMORY(dImage);
4856 
4857  if (target_format == QImage::Format_MonoLSB
4858  || target_format == QImage::Format_Mono
4859  || target_format == QImage::Format_Indexed8) {
4860  dImage.d->colortable = d->colortable;
4861  dImage.d->has_alpha_clut = d->has_alpha_clut | complex_xform;
4862  }
4863 
4864  // initizialize the data
4865  if (target_format == QImage::Format_Indexed8) {
4866  if (dImage.d->colortable.size() < 256) {
4867  // colors are left in the color table, so pick that one as transparent
4868  dImage.d->colortable.append(0x0);
4869  memset(dImage.bits(), dImage.d->colortable.size() - 1, dImage.d->nbytes);
4870  } else {
4871  memset(dImage.bits(), 0, dImage.d->nbytes);
4872  }
4873  } else
4874  memset(dImage.bits(), 0x00, dImage.d->nbytes);
4875 
4876  if (target_format >= QImage::Format_RGB32) {
4877  // Prevent QPainter from applying devicePixelRatio corrections
4878  const QImage sImage = (devicePixelRatio() != 1) ? QImage(constBits(), width(), height(), format()) : *this;
4879 
4880  Q_ASSERT(sImage.devicePixelRatio() == 1);
4881  Q_ASSERT(sImage.devicePixelRatio() == dImage.devicePixelRatio());
4882 
4883  QPainter p(&dImage);
4884  if (mode == Qt::SmoothTransformation) {
4885  p.setRenderHint(QPainter::Antialiasing);
4886  p.setRenderHint(QPainter::SmoothPixmapTransform);
4887  }
4888  p.setTransform(mat);
4889  p.drawImage(QPoint(0, 0), sImage);
4890  } else {
4891  bool invertible;
4892  mat = mat.inverted(&invertible); // invert matrix
4893  if (!invertible) // error, return null image
4894  return QImage();
4895 
4896  // create target image (some of the code is from QImage::copy())
4898  qsizetype dbpl = dImage.bytesPerLine();
4899  qt_xForm_helper(mat, 0, type, bpp, dImage.bits(), dbpl, 0, hd, sptr, sbpl, ws, hs);
4900  }
4901  copyMetadata(dImage.d, d);
4902 
4903  return dImage;
4904 }
4905 
4928 {
4929  const QRectF rect(0, 0, w, h);
4930  const QRect mapped = matrix.mapRect(rect).toAlignedRect();
4931  const QPoint delta = mapped.topLeft();
4932  return matrix * QTransform().translate(-delta.x(), -delta.y());
4933 }
4934 
4942 void QImage::setColorSpace(const QColorSpace &colorSpace)
4943 {
4944  if (!d)
4945  return;
4946  if (d->colorSpace == colorSpace)
4947  return;
4948  if (!isDetached()) // Detach only if shared, not for read-only data.
4949  detach();
4950  d->colorSpace = colorSpace;
4951 }
4952 
4963 {
4964  if (!d)
4965  return;
4966  if (!d->colorSpace.isValid())
4967  return;
4968  if (!colorSpace.isValid()) {
4969  qWarning() << "QImage::convertToColorSpace: Output colorspace is not valid";
4970  return;
4971  }
4972  if (d->colorSpace == colorSpace)
4973  return;
4975  d->colorSpace = colorSpace;
4976 }
4977 
4988 {
4989  if (!d || !d->colorSpace.isValid() || !colorSpace.isValid())
4990  return QImage();
4991  QImage image = copy();
4992  image.convertToColorSpace(colorSpace);
4993  return image;
4994 }
4995 
5002 {
5003  if (!d)
5004  return QColorSpace();
5005  return d->colorSpace;
5006 }
5007 
5014 {
5015  detach();
5016  if (!d)
5017  return;
5018  if (pixelFormat().colorModel() == QPixelFormat::Indexed) {
5019  for (int i = 0; i < d->colortable.size(); ++i)
5020  d->colortable[i] = transform.map(d->colortable[i]);
5021  return;
5022  }
5023  QImage::Format oldFormat = format();
5024  if (depth() > 32) {
5027  *this = std::move(*this).convertToFormat(QImage::Format_RGBA64);
5030  if (hasAlphaChannel())
5031  *this = std::move(*this).convertToFormat(QImage::Format_ARGB32);
5032  else
5033  *this = std::move(*this).convertToFormat(QImage::Format_RGB32);
5034  }
5035 
5036  QColorTransformPrivate::TransformFlags flags = QColorTransformPrivate::Unpremultiplied;
5037  switch (format()) {
5041  break;
5042  case Format_RGB32:
5043  case Format_RGBX64:
5045  break;
5046  case Format_ARGB32:
5047  case Format_RGBA64:
5048  break;
5049  default:
5050  Q_UNREACHABLE();
5051  }
5052 
5053  std::function<void(int,int)> transformSegment;
5054 
5055  if (depth() > 32) {
5056  transformSegment = [&](int yStart, int yEnd) {
5057  for (int y = yStart; y < yEnd; ++y) {
5058  QRgba64 *scanline = reinterpret_cast<QRgba64 *>(d->data + y * d->bytes_per_line);
5059  transform.d->apply(scanline, scanline, width(), flags);
5060  }
5061  };
5062  } else {
5063  transformSegment = [&](int yStart, int yEnd) {
5064  for (int y = yStart; y < yEnd; ++y) {
5065  QRgb *scanline = reinterpret_cast<QRgb *>(d->data + y * d->bytes_per_line);
5066  transform.d->apply(scanline, scanline, width(), flags);
5067  }
5068  };
5069  }
5070 
5071 #if QT_CONFIG(thread) && !defined(Q_OS_WASM)
5072  int segments = (qsizetype(width()) * height()) >> 16;
5073  segments = std::min(segments, height());
5074  QThreadPool *threadPool = QThreadPool::globalInstance();
5075  if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
5076  QSemaphore semaphore;
5077  int y = 0;
5078  for (int i = 0; i < segments; ++i) {
5079  int yn = (height() - y) / (segments - i);
5080  threadPool->start([&, y, yn]() {
5081  transformSegment(y, y + yn);
5082  semaphore.release(1);
5083  });
5084  y += yn;
5085  }
5086  semaphore.acquire(segments);
5087  } else
5088 #endif
5089  transformSegment(0, height());
5090 
5091  if (oldFormat != format())
5092  *this = std::move(*this).convertToFormat(oldFormat);
5093 }
5094 
5095 
5096 bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags flags)
5097 {
5098  if (format == newFormat)
5099  return true;
5100 
5101  // No in-place conversion if we have to detach
5102  if (ref.loadRelaxed() > 1 || !own_data)
5103  return false;
5104 
5106  if (converter)
5107  return converter(this, flags);
5108  if (format > QImage::Format_Indexed8 && newFormat > QImage::Format_Indexed8 && !qimage_converter_map[format][newFormat]) {
5109  // Convert inplace generic, but only if there are no direct converters,
5110  // any direct ones are probably better even if not inplace.
5111  if (qt_highColorPrecision(newFormat, !qPixelLayouts[newFormat].hasAlphaChannel)
5112  && qt_highColorPrecision(format, !qPixelLayouts[format].hasAlphaChannel)) {
5113 #if QT_CONFIG(raster_fp)
5114  if (qt_fpColorPrecision(format) && qt_fpColorPrecision(newFormat))
5115  return convert_generic_inplace_over_rgba32f(this, newFormat, flags);
5116 #endif
5117  return convert_generic_inplace_over_rgb64(this, newFormat, flags);
5118  }
5119  return convert_generic_inplace(this, newFormat, flags);
5120  }
5121  return false;
5122 }
5123 
5134 #ifndef QT_NO_DEBUG_STREAM
5136 {
5137  QDebugStateSaver saver(dbg);
5138  dbg.nospace();
5139  dbg.noquote();
5140  dbg << "QImage(";
5141  if (i.isNull()) {
5142  dbg << "null";
5143  } else {
5144  dbg << i.size() << ",format=" << i.format() << ",depth=" << i.depth();
5145  if (i.colorCount())
5146  dbg << ",colorCount=" << i.colorCount();
5147  const int bytesPerLine = i.bytesPerLine();
5148  dbg << ",devicePixelRatio=" << i.devicePixelRatio()
5149  << ",bytesPerLine=" << bytesPerLine << ",sizeInBytes=" << i.sizeInBytes();
5150  if (dbg.verbosity() > 2 && i.height() > 0) {
5151  const int outputLength = qMin(bytesPerLine, 24);
5152  dbg << ",line0="
5153  << QByteArray(reinterpret_cast<const char *>(i.scanLine(0)), outputLength).toHex()
5154  << "...";
5155  }
5156  }
5157  dbg << ')';
5158  return dbg;
5159 }
5160 #endif
5161 
5162 static constexpr QPixelFormat pixelformats[] = {
5163  //QImage::Format_Invalid:
5164  QPixelFormat(),
5165  //QImage::Format_Mono:
5167  /*RED*/ 1,
5168  /*GREEN*/ 0,
5169  /*BLUE*/ 0,
5170  /*FOURTH*/ 0,
5171  /*FIFTH*/ 0,
5172  /*ALPHA*/ 0,
5173  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5174  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5175  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5176  /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5177  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5178  //QImage::Format_MonoLSB:
5180  /*RED*/ 1,
5181  /*GREEN*/ 0,
5182  /*BLUE*/ 0,
5183  /*FOURTH*/ 0,
5184  /*FIFTH*/ 0,
5185  /*ALPHA*/ 0,
5186  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5187  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5188  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5189  /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5190  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5191  //QImage::Format_Indexed8:
5193  /*RED*/ 8,
5194  /*GREEN*/ 0,
5195  /*BLUE*/ 0,
5196  /*FOURTH*/ 0,
5197  /*FIFTH*/ 0,
5198  /*ALPHA*/ 0,
5199  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5200  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5201  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5202  /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5203  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5204  //QImage::Format_RGB32:
5206  /*RED*/ 8,
5207  /*GREEN*/ 8,
5208  /*BLUE*/ 8,
5209  /*FOURTH*/ 0,
5210  /*FIFTH*/ 0,
5211  /*ALPHA*/ 8,
5212  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5213  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5214  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5215  /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5216  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5217  //QImage::Format_ARGB32:
5219  /*RED*/ 8,
5220  /*GREEN*/ 8,
5221  /*BLUE*/ 8,
5222  /*FOURTH*/ 0,
5223  /*FIFTH*/ 0,
5224  /*ALPHA*/ 8,
5225  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5226  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5227  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5228  /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5229  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5230  //QImage::Format_ARGB32_Premultiplied:
5232  /*RED*/ 8,
5233  /*GREEN*/ 8,
5234  /*BLUE*/ 8,
5235  /*FOURTH*/ 0,
5236  /*FIFTH*/ 0,
5237  /*ALPHA*/ 8,
5238  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5239  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5240  /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5241  /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5242  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5243  //QImage::Format_RGB16:
5245  /*RED*/ 5,
5246  /*GREEN*/ 6,
5247  /*BLUE*/ 5,
5248  /*FOURTH*/ 0,
5249  /*FIFTH*/ 0,
5250  /*ALPHA*/ 0,
5251  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5252  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5253  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5254  /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5255  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5256  //QImage::Format_ARGB8565_Premultiplied:
5258  /*RED*/ 5,
5259  /*GREEN*/ 6,
5260  /*BLUE*/ 5,
5261  /*FOURTH*/ 0,
5262  /*FIFTH*/ 0,
5263  /*ALPHA*/ 8,
5264  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5265  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5266  /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5267  /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5268  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5269  //QImage::Format_RGB666:
5271  /*RED*/ 6,
5272  /*GREEN*/ 6,
5273  /*BLUE*/ 6,
5274  /*FOURTH*/ 0,
5275  /*FIFTH*/ 0,
5276  /*ALPHA*/ 0,
5277  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5278  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5279  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5280  /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5281  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5282  //QImage::Format_ARGB6666_Premultiplied:
5284  /*RED*/ 6,
5285  /*GREEN*/ 6,
5286  /*BLUE*/ 6,
5287  /*FOURTH*/ 0,
5288  /*FIFTH*/ 0,
5289  /*ALPHA*/ 6,
5290  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5291  /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5292  /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5293  /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5294  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5295  //QImage::Format_RGB555:
5297  /*RED*/ 5,
5298  /*GREEN*/ 5,
5299  /*BLUE*/ 5,
5300  /*FOURTH*/ 0,
5301  /*FIFTH*/ 0,
5302  /*ALPHA*/ 0,
5303  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5304  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5305  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5306  /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5307  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5308  //QImage::Format_ARGB8555_Premultiplied:
5310  /*RED*/ 5,
5311  /*GREEN*/ 5,
5312  /*BLUE*/ 5,
5313  /*FOURTH*/ 0,
5314  /*FIFTH*/ 0,
5315  /*ALPHA*/ 8,
5316  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5317  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5318  /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5319  /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5320  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5321  //QImage::Format_RGB888:
5323  /*RED*/ 8,
5324  /*GREEN*/ 8,
5325  /*BLUE*/ 8,
5326  /*FOURTH*/ 0,
5327  /*FIFTH*/ 0,
5328  /*ALPHA*/ 0,
5329  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5330  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5331  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5332  /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5333  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5334  //QImage::Format_RGB444:
5336  /*RED*/ 4,
5337  /*GREEN*/ 4,
5338  /*BLUE*/ 4,
5339  /*FOURTH*/ 0,
5340  /*FIFTH*/ 0,
5341  /*ALPHA*/ 0,
5342  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5343  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5344  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5345  /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5346  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5347  //QImage::Format_ARGB4444_Premultiplied:
5349  /*RED*/ 4,
5350  /*GREEN*/ 4,
5351  /*BLUE*/ 4,
5352  /*FOURTH*/ 0,
5353  /*FIFTH*/ 0,
5354  /*ALPHA*/ 4,
5355  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5356  /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5357  /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5358  /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5359  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5360  //QImage::Format_RGBX8888:
5362  /*RED*/ 8,
5363  /*GREEN*/ 8,
5364  /*BLUE*/ 8,
5365  /*FOURTH*/ 0,
5366  /*FIFTH*/ 0,
5367  /*ALPHA*/ 8,
5368  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5369  /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5370  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5371  /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5372  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5373  //QImage::Format_RGBA8888:
5375  /*RED*/ 8,
5376  /*GREEN*/ 8,
5377  /*BLUE*/ 8,
5378  /*FOURTH*/ 0,
5379  /*FIFTH*/ 0,
5380  /*ALPHA*/ 8,
5381  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5382  /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5383  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5384  /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5385  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5386  //QImage::Format_RGBA8888_Premultiplied:
5388  /*RED*/ 8,
5389  /*GREEN*/ 8,
5390  /*BLUE*/ 8,
5391  /*FOURTH*/ 0,
5392  /*FIFTH*/ 0,
5393  /*ALPHA*/ 8,
5394  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5395  /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5396  /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5397  /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5398  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5399  //QImage::Format_BGR30:
5401  /*RED*/ 10,
5402  /*GREEN*/ 10,
5403  /*BLUE*/ 10,
5404  /*FOURTH*/ 0,
5405  /*FIFTH*/ 0,
5406  /*ALPHA*/ 2,
5407  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5408  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5409  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5410  /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5411  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5412  //QImage::Format_A2BGR30_Premultiplied:
5414  /*RED*/ 10,
5415  /*GREEN*/ 10,
5416  /*BLUE*/ 10,
5417  /*FOURTH*/ 0,
5418  /*FIFTH*/ 0,
5419  /*ALPHA*/ 2,
5420  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5421  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5422  /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5423  /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5424  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5425  //QImage::Format_RGB30:
5427  /*RED*/ 10,
5428  /*GREEN*/ 10,
5429  /*BLUE*/ 10,
5430  /*FOURTH*/ 0,
5431  /*FIFTH*/ 0,
5432  /*ALPHA*/ 2,
5433  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5434  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5435  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5436  /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5437  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5438  //QImage::Format_A2RGB30_Premultiplied:
5440  /*RED*/ 10,
5441  /*GREEN*/ 10,
5442  /*BLUE*/ 10,
5443  /*FOURTH*/ 0,
5444  /*FIFTH*/ 0,
5445  /*ALPHA*/ 2,
5446  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5447  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5448  /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5449  /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5450  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5451  //QImage::Format_Alpha8:
5453  /*First*/ 0,
5454  /*SECOND*/ 0,
5455  /*THIRD*/ 0,
5456  /*FOURTH*/ 0,
5457  /*FIFTH*/ 0,
5458  /*ALPHA*/ 8,
5459  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5460  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5461  /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5462  /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5463  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5464  //QImage::Format_Grayscale8:
5466  /*GRAY*/ 8,
5467  /*SECOND*/ 0,
5468  /*THIRD*/ 0,
5469  /*FOURTH*/ 0,
5470  /*FIFTH*/ 0,
5471  /*ALPHA*/ 0,
5472  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5473  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5474  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5475  /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5476  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5477  //QImage::Format_RGBX64:
5479  /*RED*/ 16,
5480  /*GREEN*/ 16,
5481  /*BLUE*/ 16,
5482  /*FOURTH*/ 0,
5483  /*FIFTH*/ 0,
5484  /*ALPHA*/ 16,
5485  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5486  /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5487  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5488  /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5489  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5490  //QImage::Format_RGBA64:
5492  /*RED*/ 16,
5493  /*GREEN*/ 16,
5494  /*BLUE*/ 16,
5495  /*FOURTH*/ 0,
5496  /*FIFTH*/ 0,
5497  /*ALPHA*/ 16,
5498  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5499  /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5500  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5501  /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5502  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5503  //QImage::Format_RGBA64_Premultiplied:
5505  /*RED*/ 16,
5506  /*GREEN*/ 16,
5507  /*BLUE*/ 16,
5508  /*FOURTH*/ 0,
5509  /*FIFTH*/ 0,
5510  /*ALPHA*/ 16,
5511  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5512  /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5513  /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5514  /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5515  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5516  //QImage::Format_Grayscale16:
5518  /*GRAY*/ 16,
5519  /*SECOND*/ 0,
5520  /*THIRD*/ 0,
5521  /*FOURTH*/ 0,
5522  /*FIFTH*/ 0,
5523  /*ALPHA*/ 0,
5524  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5525  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5526  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5527  /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
5528  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5529  //QImage::Format_BGR888:
5531  /*RED*/ 8,
5532  /*GREEN*/ 8,
5533  /*BLUE*/ 8,
5534  /*FOURTH*/ 0,
5535  /*FIFTH*/ 0,
5536  /*ALPHA*/ 0,
5537  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5538  /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5539  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5540  /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5541  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5542  //QImage::Format_RGBX16FPx4:
5544  /*RED*/ 16,
5545  /*GREEN*/ 16,
5546  /*BLUE*/ 16,
5547  /*FOURTH*/ 0,
5548  /*FIFTH*/ 0,
5549  /*ALPHA*/ 16,
5550  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5551  /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5552  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5553  /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
5554  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5555  //QImage::Format_RGBA16FPx4:
5557  /*RED*/ 16,
5558  /*GREEN*/ 16,
5559  /*BLUE*/ 16,
5560  /*FOURTH*/ 0,
5561  /*FIFTH*/ 0,
5562  /*ALPHA*/ 16,
5563  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5564  /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5565  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5566  /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
5567  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5568  //QImage::Format_RGBA16FPx4_Premultiplied:
5570  /*RED*/ 16,
5571  /*GREEN*/ 16,
5572  /*BLUE*/ 16,
5573  /*FOURTH*/ 0,
5574  /*FIFTH*/ 0,
5575  /*ALPHA*/ 16,
5576  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5577  /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5578  /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5579  /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
5580  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5581  //QImage::Format_RGBX32FPx4:
5583  /*RED*/ 32,
5584  /*GREEN*/ 32,
5585  /*BLUE*/ 32,
5586  /*FOURTH*/ 0,
5587  /*FIFTH*/ 0,
5588  /*ALPHA*/ 32,
5589  /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5590  /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5591  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5592  /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
5593  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5594  //QImage::Format_RGBA32FPx4:
5596  /*RED*/ 32,
5597  /*GREEN*/ 32,
5598  /*BLUE*/ 32,
5599  /*FOURTH*/ 0,
5600  /*FIFTH*/ 0,
5601  /*ALPHA*/ 32,
5602  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5603  /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5604  /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5605  /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
5606  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5607  //QImage::Format_RGBA32FPx4_Premultiplied:
5609  /*RED*/ 32,
5610  /*GREEN*/ 32,
5611  /*BLUE*/ 32,
5612  /*FOURTH*/ 0,
5613  /*FIFTH*/ 0,
5614  /*ALPHA*/ 32,
5615  /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
5616  /*ALPHA POSITION*/ QPixelFormat::AtEnd,
5617  /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
5618  /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
5619  /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5620 };
5621 static_assert(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats);
5622 
5627 {
5628  return toPixelFormat(format());
5629 }
5630 
5635 {
5636  Q_ASSERT(static_cast<int>(format) < NImageFormats && static_cast<int>(format) >= 0);
5637  return pixelformats[format];
5638 }
5639 
5644 {
5645  for (int i = 0; i < NImageFormats; i++) {
5646  if (format == pixelformats[i])
5647  return Format(i);
5648  }
5649  return Format_Invalid;
5650 }
5651 
5652 Q_GUI_EXPORT void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient)
5653 {
5655  return;
5657  src = rotated270(src);
5658  } else {
5659  src = std::move(src).mirrored(orient & QImageIOHandler::TransformationMirror,
5662  src = rotated90(src);
5663  }
5664 }
5665 
5667 {
5669  const auto textKeys = image.textKeys();
5670  for (const QString &key : textKeys) {
5671  if (!key.isEmpty() && !text.contains(key))
5672  text.insert(key, image.text(key));
5673  }
5674  return text;
5675 }
5676 
5678 {
5680  const auto pairs = QStringView{description}.split(u"\n\n");
5681  for (const auto &pair : pairs) {
5682  int index = pair.indexOf(QLatin1Char(':'));
5683  if (index >= 0 && pair.indexOf(QLatin1Char(' ')) < index) {
5684  if (!pair.trimmed().isEmpty())
5685  text.insert(QLatin1String("Description"), pair.toString().simplified());
5686  } else {
5687  const auto key = pair.left(index);
5688  if (!key.trimmed().isEmpty())
5689  text.insert(key.toString(), pair.mid(index + 2).toString().simplified());
5690  }
5691  }
5692  return text;
5693 }
5694 
5696 
5697 #include "moc_qimage.cpp"
small capitals from c petite p scientific f u
Definition: afcover.h:88
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
FT_UInt idx
Definition: cffcmap.c:135
bool ref() noexcept
Definition: qbasicatomic.h:101
bool deref() noexcept
Definition: qbasicatomic.h:102
T fetchAndAddRelaxed(T valueToAdd) noexcept
Definition: qbasicatomic.h:140
T loadRelaxed() const noexcept
Definition: qbasicatomic.h:90
The QBuffer class provides a QIODevice interface for a QByteArray.
Definition: qbuffer.h:52
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
static QByteArray fromRawData(const char *data, qsizetype size)
Definition: qbytearray.h:396
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
int qAlpha(QRgb rgba)
Definition: qrgb.h:63
int qRed(QRgb rgb)
Definition: qrgb.h:54
QRgb
Definition: qrgb.h:49
QRgb rgba() const noexcept
Definition: qcolor.cpp:1373
int qGreen(QRgb rgb)
Definition: qrgb.h:57
int qBlue(QRgb rgb)
Definition: qrgb.h:60
The QColorSpace class provides a color space abstraction.
Definition: qcolorspace.h:57
QColorTransform transformationToColorSpace(const QColorSpace &colorspace) const
bool isValid() const noexcept
The QColorTransform class is a transformation between color spaces.
The QDataStream class provides serialization of binary data to a QIODevice.
Definition: qdatastream.h:66
operator>>(QDataStream &ds, qfloat16 &f)
Definition: qfloat16.cpp:344
operator<<(QDataStream &ds, qfloat16 f)
Definition: qfloat16.cpp:327
The QDebug class provides an output stream for debugging information.
Definition: qdebug.h:65
QDebug & verbosity(int verbosityLevel)
Definition: qdebug.h:115
QDebug & noquote()
Definition: qdebug.h:124
QDebug & nospace()
Definition: qdebug.h:113
Convenience class for custom QDebug operators.
Definition: qdebug.h:176
static QPlatformIntegration * platformIntegration()
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qhash.h:773
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:70
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:73
void setDotsPerMeterY(int)
Definition: qimage.cpp:4088
bool loadFromData(QByteArrayView data, const char *format=nullptr)
Definition: qimage.cpp:3754
int dotsPerMeterX() const
Definition: qimage.cpp:4036
int bitPlaneCount() const
Definition: qimage.cpp:4562
bool hasAlphaChannel() const
Definition: qimage.cpp:4539
void convertToColorSpace(const QColorSpace &)
Definition: qimage.cpp:4962
bool valid(int x, int y) const
Definition: qimage.cpp:2387
bool isNull() const
Definition: qimage.cpp:1319
QImage createAlphaMask(Qt::ImageConversionFlags flags=Qt::AutoColor) const
Definition: qimage.cpp:3068
QImage scaled(int w, int h, Qt::AspectRatioMode aspectMode=Qt::IgnoreAspectRatio, Qt::TransformationMode mode=Qt::FastTransformation) const
Definition: qimage.h:244
void setAlphaChannel(const QImage &alphaChannel)
Definition: qimage.cpp:4498
QColorSpace colorSpace() const
Definition: qimage.cpp:5001
void setText(const QString &key, const QString &value)
Definition: qimage.cpp:4190
static QPixelFormat toPixelFormat(QImage::Format format) noexcept
Definition: qimage.cpp:5634
qsizetype bytesPerLine() const
Definition: qimage.cpp:1536
void setPixel(int x, int y, uint index_or_rgb)
Definition: qimage.cpp:2546
QImage scaledToWidth(int w, Qt::TransformationMode mode=Qt::FastTransformation) const
[9]
Definition: qimage.cpp:3005
void setPixelColor(int x, int y, const QColor &c)
Definition: qimage.cpp:2743
QList< QRgb > colorTable() const
Definition: qimage.cpp:1444
uchar * scanLine(int)
Definition: qimage.cpp:1613
QRgb pixel(int x, int y) const
Definition: qimage.cpp:2451
QImage transformed(const QTransform &matrix, Qt::TransformationMode mode=Qt::FastTransformation) const
Definition: qimage.cpp:4747
void setColorCount(int)
Definition: qimage.cpp:2089
QImage copy(const QRect &rect=QRect()) const
Definition: qimage.cpp:1197
QImage createHeuristicMask(bool clipTight=true) const
Definition: qimage.cpp:3112
qsizetype sizeInBytes() const
Definition: qimage.cpp:1524
bool allGray() const
Definition: qimage.cpp:2827
QImage smoothScaled(int w, int h) const
Definition: qimage.cpp:4615
void rgbSwapped_inplace()
Definition: qimage.cpp:3614
QRgb color(int i) const
Definition: qimage.cpp:1553
QSize size() const
Definition: qimage.cpp:1355
bool isGrayscale() const
Definition: qimage.cpp:2903
void convertTo(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor)
Definition: qimage.cpp:2357
bool isDetached() const
Definition: qimage.cpp:4473
QImage convertedToColorSpace(const QColorSpace &) const
Definition: qimage.cpp:4987
bool operator==(const QImage &) const
Definition: qimage.cpp:3955
int width() const
Definition: qimage.cpp:1331
bool save(const QString &fileName, const char *format=nullptr, int quality=-1) const
Definition: qimage.cpp:3843
uchar * bits()
Definition: qimage.cpp:1675
void applyColorTransform(const QColorTransform &transform)
Definition: qimage.cpp:5013
int height() const
Definition: qimage.cpp:1343
void setColorTable(const QList< QRgb > &colors)
Definition: qimage.cpp:1418
QImage createMaskFromColor(QRgb color, Qt::MaskMode mode=Qt::MaskInColor) const
Definition: qimage.cpp:3216
QPaintEngine * paintEngine() const override
Definition: qimage.cpp:4205
bool convertToFormat_inplace(Format format, Qt::ImageConversionFlags flags)
Definition: qimage.cpp:2199
Format
Definition: qimage.h:77
@ Format_Grayscale16
Definition: qimage.h:106
@ Format_Alpha8
Definition: qimage.h:101
@ Format_RGBA8888
Definition: qimage.h:95
@ Format_RGB30
Definition: qimage.h:99
@ Format_RGB888
Definition: qimage.h:91
@ Format_RGBA16FPx4
Definition: qimage.h:109
@ Format_RGBA32FPx4_Premultiplied
Definition: qimage.h:113
@ Format_RGB32
Definition: qimage.h:82
@ Format_Invalid
Definition: qimage.h:78
@ Format_RGB666
Definition: qimage.h:87
@ Format_RGBX32FPx4
Definition: qimage.h:111
@ Format_RGBA64_Premultiplied
Definition: qimage.h:105
@ Format_ARGB6666_Premultiplied
Definition: qimage.h:88
@ Format_ARGB8555_Premultiplied
Definition: qimage.h:90
@ Format_RGB444
Definition: qimage.h:92
@ Format_MonoLSB
Definition: qimage.h:80
@ Format_RGBA8888_Premultiplied
Definition: qimage.h:96
@ Format_ARGB8565_Premultiplied
Definition: qimage.h:86
@ Format_RGB555
Definition: qimage.h:89
@ Format_RGBA64
Definition: qimage.h:104
@ Format_RGBA32FPx4
Definition: qimage.h:112
@ Format_Mono
Definition: qimage.h:79
@ Format_RGBA16FPx4_Premultiplied
Definition: qimage.h:110
@ Format_RGBX64
Definition: qimage.h:103
@ Format_A2BGR30_Premultiplied
Definition: qimage.h:98
@ Format_RGBX16FPx4
Definition: qimage.h:108
@ Format_Indexed8
Definition: qimage.h:81
@ Format_BGR30
Definition: qimage.h:97
@ NImageFormats
Definition: qimage.h:115
@ Format_ARGB32_Premultiplied
Definition: qimage.h:84
@ Format_A2RGB30_Premultiplied
Definition: qimage.h:100
@ Format_ARGB4444_Premultiplied
Definition: qimage.h:93
@ Format_RGB16
Definition: qimage.h:85
@ Format_BGR888
Definition: qimage.h:107
@ Format_ARGB32
Definition: qimage.h:83
@ Format_RGBX8888
Definition: qimage.h:94
@ Format_Grayscale8
Definition: qimage.h:102
virtual int metric(PaintDeviceMetric metric) const override
Definition: qimage.cpp:4228
QImage() noexcept
Definition: qimage.cpp:788
void fill(uint pixel)
Definition: qimage.cpp:1736
QImage mirrored(bool horizontally=false, bool vertically=true) const &
Definition: qimage.h:254
QPixelFormat pixelFormat() const noexcept
Definition: qimage.cpp:5626
QColor pixelColor(int x, int y) const
Definition: qimage.cpp:2664
QImage scaledToHeight(int h, Qt::TransformationMode mode=Qt::FastTransformation) const
Definition: qimage.cpp:3035
static QTransform trueMatrix(const QTransform &, int w, int h)
Definition: qimage.cpp:4927
Format format() const
Definition: qimage.cpp:2119
bool operator!=(const QImage &) const
Definition: qimage.cpp:4020
static QImage fromData(QByteArrayView data, const char *format=nullptr)
Definition: qimage.cpp:3796
bool load(QIODevice *device, const char *format)
Definition: qimage.cpp:3735
const uchar * constScanLine(int) const
Definition: qimage.cpp:1655
void detach()
Definition: qimage.cpp:1126
QImageCleanupFunction
QStringList textKeys() const
Definition: qimage.cpp:4138
void setColor(int i, QRgb c)
Definition: qimage.cpp:1571
QRect rect() const
Definition: qimage.cpp:1368
void setDevicePixelRatio(qreal scaleFactor)
Definition: qimage.cpp:1488
void mirrored_inplace(bool horizontal, bool vertical)
Definition: qimage.cpp:3463
qreal devicePixelRatio() const
Definition: qimage.cpp:1460
void setDotsPerMeterX(int)
Definition: qimage.cpp:4066
QImage rgbSwapped_helper() const
Definition: qimage.cpp:3520
int dotsPerMeterY() const
Definition: qimage.cpp:4049
static QImage::Format toImageFormat(QPixelFormat format) noexcept
Definition: qimage.cpp:5643
const uchar * constBits() const
Definition: qimage.cpp:1711
int colorCount() const
Definition: qimage.cpp:1402
QSizeF deviceIndependentSize() const
Definition: qimage.cpp:1509
QImage mirrored_helper(bool horizontal, bool vertical) const
Definition: qimage.cpp:3435
QString text(const QString &key=QString()) const
Definition: qimage.cpp:4150
QImage & operator=(const QImage &)
Definition: qimage.cpp:1077
~QImage()
Definition: qimage.cpp:1061
int pixelIndex(int x, int y) const
Definition: qimage.cpp:2410
QImage convertToFormat_helper(Format format, Qt::ImageConversionFlags flags) const
Definition: qimage.cpp:2152
InvertMode
Definition: qimage.h:76
@ InvertRgba
Definition: qimage.h:76
void setColorSpace(const QColorSpace &)
Definition: qimage.cpp:4942
QPoint offset() const
Definition: qimage.cpp:4106
bool reinterpretAsFormat(Format f)
Definition: qimage.cpp:2323
void setOffset(const QPoint &)
Definition: qimage.cpp:4120
int devType() const override
Definition: qimage.cpp:1102
void invertPixels(InvertMode=InvertRgb)
Definition: qimage.cpp:1943
QImage convertToFormat(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor) const &
Definition: qimage.h:160
int depth() const
Definition: qimage.cpp:1385
qint64 cacheKey() const
Definition: qimage.cpp:4457
static void executeImageHooks(qint64 key)
The QImageReader class provides a format independent interface for reading images from files or other...
Definition: qimagereader.h:59
The QImageWriter class provides a format independent interface for writing images to files or other d...
Definition: qimagewriter.h:57
bool write(const QImage &image)
void setQuality(int quality)
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
QString toString() const
Definition: qstring.h:1159
qsizetype size() const noexcept
Definition: qlist.h:414
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
void resize(qsizetype size)
Definition: qlist.h:420
void append(parameter_type t)
Definition: qlist.h:469
void clear()
Definition: qlist.h:445
iterator insert(const Key &key, const T &value)
Definition: qmap.h:719
T value(const Key &key, const T &defaultValue=T()) const
Definition: qmap.h:392
QList< Key > keys() const
Definition: qmap.h:418
iterator begin()
Definition: qmap.h:633
iterator end()
Definition: qmap.h:637
@ PdmDevicePixelRatioScaled
Definition: qpaintdevice.h:68
static qreal devicePixelRatioFScale()
Definition: qpaintdevice.h:90
The QPaintEngine class provides an abstract definition of how QPainter draws to a given device on a g...
Definition: qpaintengine.h:87
bool isActive() const
Definition: qpaintengine.h:150
The QPainter class performs low-level painting on widgets and other paint devices.
Definition: qpainter.h:82
void setCompositionMode(CompositionMode mode)
Definition: qpainter.cpp:2353
void drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect, Qt::ImageConversionFlags flags=Qt::AutoColor)
Definition: qpainter.cpp:5175
@ SmoothPixmapTransform
Definition: qpainter.h:90
@ Antialiasing
Definition: qpainter.h:88
@ CompositionMode_Source
Definition: qpainter.h:136
@ CompositionMode_DestinationIn
Definition: qpainter.h:139
void setRenderHint(RenderHint hint, bool on=true)
Definition: qpainter.cpp:6845
QPixelFormat is a class for describing different pixel layouts in graphics buffers.
Definition: qpixelformat.h:48
virtual QPaintEngine * createImagePaintEngine(QPaintDevice *paintDevice) const
The QPoint class defines a point in the plane using integer precision.
Definition: qpoint.h:52
constexpr int x() const noexcept
Definition: qpoint.h:155
constexpr int y() const noexcept
Definition: qpoint.h:160
The QPolygonF class provides a list of points using floating point precision. \inmodule QtGui.
Definition: qpolygon.h:128
The QRasterPaintEngine class enables hardware acceleration of painting operations in Qt for Embedded ...
The QRectF class defines a finite rectangle in the plane using floating point precision.
Definition: qrect.h:511
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:59
constexpr int width() const noexcept
Definition: qrect.h:263
constexpr static QRgba64 fromArgb32(uint rgb)
Definition: qrgba64.h:92
void setAlpha(quint16 _alpha)
Definition: qrgba64.h:113
static constexpr QRgbaFloat fromArgb32(uint rgb)
Definition: qrgbafloat.h:84
constexpr Q_ALWAYS_INLINE QRgbaFloat unpremultiplied() const
Definition: qrgbafloat.h:124
The QSemaphore class provides a general counting semaphore.
Definition: qsemaphore.h:55
void acquire(int n=1)
Definition: qsemaphore.cpp:323
void release(int n=1)
Definition: qsemaphore.cpp:351
The QSizeF class defines the size of a two-dimensional object using floating point precision.
Definition: qsize.h:235
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:55
constexpr int height() const noexcept
Definition: qsize.h:160
constexpr int width() const noexcept
Definition: qsize.h:157
constexpr int & rheight() noexcept
Definition: qsize.h:184
void scale(int w, int h, Qt::AspectRatioMode mode) noexcept
Definition: qsize.h:172
constexpr int & rwidth() noexcept
Definition: qsize.h:181
The QString class provides a Unicode character string.
Definition: qstring.h:388
void chop(qsizetype n)
Definition: qstring.cpp:5955
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:7672
QString simplified() const &
Definition: qstring.h:627
bool isEmpty() const
Definition: qstring.h:1216
QString & insert(qsizetype i, QChar c)
Definition: qstring.cpp:3043
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.h:1353
QString left(qsizetype n) const
Definition: qstring.cpp:4951
The QStringList class provides a list of strings.
The QStringView class provides a unified view on UTF-16 strings with a read-only subset of the QStrin...
Definition: qstringview.h:122
static QThread * currentThread()
Definition: qthread.cpp:879
The QThreadPool class manages a collection of QThreads.
Definition: qthreadpool.h:56
void start(QRunnable *runnable, int priority=0)
static QThreadPool * globalInstance()
bool contains(const QThread *thread) const
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:56
qreal m21() const
Definition: qtransform.h:238
static QTransform fromScale(qreal dx, qreal dy)
Definition: qtransform.cpp:503
qreal m12() const
Definition: qtransform.h:230
qreal dx() const
Definition: qtransform.h:262
QPoint map(const QPoint &p) const
qreal m11() const
Definition: qtransform.h:226
QTransform inverted(bool *invertible=nullptr) const
Definition: qtransform.cpp:339
TransformationType type() const
QTransform & translate(qreal dx, qreal dy)
Definition: qtransform.cpp:392
qreal m22() const
Definition: qtransform.h:242
qreal dy() const
Definition: qtransform.h:266
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:95
static auto fromValue(const T &value) -> std::enable_if_t< std::is_copy_constructible_v< T >, QVariant >
Definition: qvariant.h:391
Provides 16-bit floating point support.
Definition: qfloat16.h:75
float factor
QPixmap p2
QPixmap p1
[0]
QString text
[meta data]
QCache< int, Employee > cache
[0]
QColor colorTable[]
Definition: window.cpp:60
for(n=0;n< outline->n_points;n++)
Definition: ftbbox.c:494
#define true
Definition: ftrandom.c:51
auto it unsigned count const
Definition: hb-iter.hh:848
#define bits
Definition: infblock.c:15
int quality
Definition: jpeglib.h:933
QFuture< QtPrivate::MapResultType< Sequence, MapFunctor > > mapped(QThreadPool *pool, Sequence &&sequence, MapFunctor &&map)
TransformationMode
Definition: qnamespace.h:1349
@ FastTransformation
Definition: qnamespace.h:1350
@ SmoothTransformation
Definition: qnamespace.h:1351
AspectRatioMode
Definition: qnamespace.h:1211
GlobalColor
Definition: qnamespace.h:58
@ color1
Definition: qnamespace.h:60
@ white
Definition: qnamespace.h:62
@ black
Definition: qnamespace.h:61
@ color0
Definition: qnamespace.h:59
MaskMode
Definition: qnamespace.h:1325
@ MaskOutColor
Definition: qnamespace.h:1327
Definition: image.cpp:51
void swap(SimpleVector< T > &v1, SimpleVector< T > &v2)
Definition: simplevector.h:331
#define QString()
Definition: parse-defines.h:51
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld endif[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1 beq endif SRC MASK if dst_r_bpp DST_R else add endif PF add sub src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head pixblock_size cache_preload_simple process_pixblock_tail pixinterleave dst_w_basereg irp beq endif process_pixblock_tail_head tst beq irp if pixblock_size chunk_size tst beq pixld SRC pixld MASK if DST_R else pixld DST_R endif if
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp
void
Definition: png.h:1080
#define Q_BASIC_ATOMIC_INITIALIZER(a)
#define Q_FALLTHROUGH()
#define QT_WARNING_DISABLE_MSVC(number)
#define Q_UNREACHABLE()
QList< QString > QStringList
Definition: qcontainerfwd.h:64
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
ushort qConvertRgb32To16(uint c)
QRgb qConvertRgb16To32(uint c)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
QT_BEGIN_NAMESPACE bool done
int qRound(qfloat16 d) noexcept
Definition: qfloat16.h:227
Q_GUI_EXPORT int qt_defaultDpiX()
Definition: qfont.cpp:141
Q_GUI_EXPORT int qt_defaultDpiY()
Definition: qfont.cpp:156
unsigned int quint32
Definition: qglobal.h:288
QT_BEGIN_INCLUDE_NAMESPACE typedef unsigned char uchar
Definition: qglobal.h:332
unsigned short quint16
Definition: qglobal.h:286
int qint32
Definition: qglobal.h:287
QT_END_INCLUDE_NAMESPACE typedef double qreal
Definition: qglobal.h:341
unsigned long long quint64
Definition: qglobal.h:299
ptrdiff_t qsizetype
Definition: qglobal.h:308
unsigned int uint
Definition: qglobal.h:334
long long qint64
Definition: qglobal.h:298
unsigned short ushort
Definition: qglobal.h:333
#define QT_CONFIG(feature)
Definition: qglobal.h:107
#define IWX_MSB(b)
Definition: qimage.cpp:4309
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:4335
bool qt_read_xpm_image_or_array(QIODevice *device, const char *const *source, QImage &image)
#define QIMAGE_SANITYCHECK_MEMORY(image)
Definition: qimage.cpp:94
void do_flip(QImageData *dst, QImageData *src, int w, int h, int depth)
Definition: qimage.cpp:3309
#define IWX_LSB(b)
Definition: qimage.cpp:4318
Q_GUI_EXPORT void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient)
Definition: qimage.cpp:5652
void do_mirror(QImageData *dst, QImageData *src, bool horizontal, bool vertical)
Definition: qimage.cpp:3340
QMap< QString, QString > qt_getImageTextFromDescription(const QString &description)
Definition: qimage.cpp:5677
void do_mirror_data(QImageData *dst, QImageData *src, int dstX0, int dstY0, int dstXIncr, int dstYIncr, int w, int h)
Definition: qimage.cpp:3275
QMap< QString, QString > qt_getImageText(const QImage &image, const QString &description)
Definition: qimage.cpp:5666
#define PIX(x, y)
bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags)
Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats]
InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats]
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)
const uchar * qt_get_bitflip_array()
void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags flags)
bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags flags)
int qt_depthForFormat(QImage::Format format)
Definition: qimage_p.h:176
bool qt_fpColorPrecision(QImage::Format format)
Definition: qimage_p.h:382
bool(* InPlace_Image_Converter)(QImageData *data, Qt::ImageConversionFlags)
Definition: qimage_p.h:154
QImage::Format qt_alphaVersion(QImage::Format format)
Definition: qimage_p.h:297
bool qt_highColorPrecision(QImage::Format format, bool opaque=false)
Definition: qimage_p.h:354
void(* Image_Converter)(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
Definition: qimage_p.h:153
QImage::Format qt_alphaVersionForPainting(QImage::Format format)
Definition: qimage_p.h:413
QImage qSmoothScaleImage(const QImage &src, int dw, int dh)
#define qWarning
Definition: qlogging.h:179
bool int shift
MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3]
Definition: qmemrotate.cpp:397
GLenum type
Definition: qopengl.h:270
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
GLboolean r
[2]
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[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
GLuint color
[2]
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
GLeglImageOES image
GLuint GLenum GLenum transform
Definition: qopenglext.h:11564
GLenum func
Definition: qopenglext.h:663
GLuint res
Definition: qopenglext.h:8867
const GLubyte * c
Definition: qopenglext.h:12701
GLint void * img
Definition: qopenglext.h:233
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
Definition: qopenglext.h:6904
GLenum GLsizei len
Definition: qopenglext.h:3292
GLuint GLenum matrix
Definition: qopenglext.h:11564
GLdouble GLdouble GLdouble GLdouble q
Definition: qopenglext.h:259
GLuint segments
Definition: qopenglext.h:9598
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLdouble s
[6]
Definition: qopenglext.h:235
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
GLenum GLenum GLsizei void * table
Definition: qopenglext.h:2745
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)
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)
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
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
constexpr bool qIsGray(QRgb rgb)
Definition: qrgb.h:78
QT_BEGIN_NAMESPACE typedef unsigned int QRgb
Definition: qrgb.h:49
constexpr QRgb qRgb(int r, int g, int b)
Definition: qrgb.h:66
constexpr QRgb qPremultiply(QRgb x)
Definition: qrgb.h:81
constexpr int qAlpha(QRgb rgb)
Definition: qrgb.h:63
constexpr QRgba64 qRgba64(quint16 r, quint16 g, quint16 b, quint16 a)
Definition: qrgba64.h:216
QPointF qAbs(const QPointF &p)
Definition: qscroller.cpp:119
#define a2
#define a1
#define Q_TRACE_SCOPE(x,...)
Definition: qtrace_p.h:138
const int BufferSize
Definition: semaphores.cpp:59
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]
QStringList::Iterator it
int detach_no
Definition: qimage_p.h:86
qreal dpmx
Definition: qimage_p.h:88
bool checkForAlphaPixels() const
Definition: qimage.cpp:192
qreal devicePixelRatio
Definition: qimage_p.h:80
~QImageData()
Definition: qimage.cpp:176
bool doImageIO(const QImage *image, QImageWriter *io, int quality) const
Definition: qimage.cpp:3873
QImageData()
Definition: qimage.cpp:111
QAtomicInt ref
Definition: qimage_p.h:74
int height
Definition: qimage_p.h:77
QColorSpace colorSpace
Definition: qimage_p.h:112
uchar * data
Definition: qimage_p.h:82
static ImageSizeParameters calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth)
Definition: qimage_p.h:123
int ser_no
Definition: qimage_p.h:85
uint is_cached
Definition: qimage_p.h:95
int width
Definition: qimage_p.h:76
static QImageData * get(QImage &img) noexcept
Definition: qimage_p.h:71
bool convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags)
Definition: qimage.cpp:5096
void * cleanupInfo
Definition: qimage_p.h:98
QList< QRgb > colortable
Definition: qimage_p.h:81
uint ro_data
Definition: qimage_p.h:93
uint own_data
Definition: qimage_p.h:92
static QImageData * create(const QSize &size, QImage::Format format)
Definition: qimage.cpp:131
qsizetype bytes_per_line
Definition: qimage_p.h:84
qsizetype nbytes
Definition: qimage_p.h:79
qreal dpmy
Definition: qimage_p.h:89
int depth
Definition: qimage_p.h:78
uint has_alpha_clut
Definition: qimage_p.h:94
QPaintEngine * paintEngine
Definition: qimage_p.h:110
QImage::Format format
Definition: qimage_p.h:83
QMap< QString, QString > text
Definition: qimage_p.h:106
QPoint offset
Definition: qimage_p.h:90
QImageCleanupFunction cleanupFunction
Definition: qimage_p.h:97
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:53
Definition: main.cpp:38