1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qimage.h"
5
6#include "qbuffer.h"
7#include "qdatastream.h"
8#include "qcolortransform.h"
9#include "qfloat16.h"
10#include "qmap.h"
11#include "qtransform.h"
12#include "qimagereader.h"
13#include "qimagewriter.h"
14#include "qrgbafloat.h"
15#include "qstringlist.h"
16#include "qvariant.h"
17#include "qimagepixmapcleanuphooks_p.h"
18#include <qpa/qplatformintegration.h>
19#include <private/qguiapplication_p.h>
20#include <ctype.h>
21#include <stdlib.h>
22#include <limits.h>
23#include <qpa/qplatformpixmap.h>
24#include <private/qcolorspace_p.h>
25#include <private/qcolortransform_p.h>
26#include <private/qmemrotate_p.h>
27#include <private/qimagescale_p.h>
28#include <private/qpixellayout_p.h>
29#include <private/qsimd_p.h>
30
31#include <qhash.h>
32
33#include <private/qpaintengine_raster_p.h>
34
35#include <private/qimage_p.h>
36#include <private/qfont_p.h>
37
38#if QT_CONFIG(thread)
39#include <qsemaphore.h>
40#include <qthreadpool.h>
41#include <private/qthreadpool_p.h>
42#endif
43
44#include <qtgui_tracepoints_p.h>
45
46#include <memory>
47
48QT_BEGIN_NAMESPACE
49class QCmyk32;
50
51using namespace Qt::StringLiterals;
52
53// MSVC 19.28 does show spurious warning "C4723: potential divide by 0" for code that divides
54// by height() in release builds. Anyhow, all the code paths in this file are only executed
55// for valid QImage's, where height() cannot be 0. Therefore disable the warning.
56QT_WARNING_DISABLE_MSVC(4723)
57
58#if defined(Q_CC_DEC) && defined(__alpha) && (__DECCXX_VER-0 >= 50190001)
59#pragma message disable narrowptr
60#endif
61
62
63#define QIMAGE_SANITYCHECK_MEMORY(image) \
64 if ((image).isNull()) { \
65 qWarning("QImage: out of memory, returning null image"); \
66 return QImage(); \
67 }
68
69Q_TRACE_PREFIX(qtgui,
70 "#include <qimagereader.h>"
71);
72
73Q_TRACE_METADATA(qtgui,
74"ENUM { } QImage::Format;" \
75"FLAGS { } Qt::ImageConversionFlags;"
76);
77
78Q_TRACE_PARAM_REPLACE(Qt::AspectRatioMode, int);
79Q_TRACE_PARAM_REPLACE(Qt::TransformationMode, int);
80
81static QImage rotated90(const QImage &src);
82static QImage rotated180(const QImage &src);
83static QImage rotated270(const QImage &src);
84
85static int next_qimage_serial_number()
86{
87 Q_CONSTINIT static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
88 return 1 + serial.fetchAndAddRelaxed(valueToAdd: 1);
89}
90
91QImageData::QImageData()
92 : ref(0), width(0), height(0), depth(0), nbytes(0), devicePixelRatio(1.0), data(nullptr),
93 format(QImage::Format_ARGB32), bytes_per_line(0),
94 ser_no(next_qimage_serial_number()),
95 detach_no(0),
96 dpmx(qt_defaultDpiX() * 100 / qreal(2.54)),
97 dpmy(qt_defaultDpiY() * 100 / qreal(2.54)),
98 offset(0, 0), own_data(true), ro_data(false), has_alpha_clut(false),
99 is_cached(false), cleanupFunction(nullptr), cleanupInfo(nullptr),
100 paintEngine(nullptr)
101{
102}
103
104/*! \fn QImageData * QImageData::create(const QSize &size, QImage::Format format)
105
106 \internal
107
108 Creates a new image data.
109 Returns \nullptr if invalid parameters are give or anything else failed.
110*/
111QImageData * Q_TRACE_INSTRUMENT(qtgui) QImageData::create(const QSize &size, QImage::Format format)
112{
113 if (size.isEmpty() || format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
114 return nullptr; // invalid parameter(s)
115
116 Q_TRACE_SCOPE(QImageData_create, size, format);
117
118 int width = size.width();
119 int height = size.height();
120 int depth = qt_depthForFormat(format);
121 auto params = calculateImageParameters(width, height, depth);
122 if (!params.isValid())
123 return nullptr;
124
125 auto d = std::make_unique<QImageData>();
126
127 switch (format) {
128 case QImage::Format_Mono:
129 case QImage::Format_MonoLSB:
130 d->colortable.resize(size: 2);
131 d->colortable[0] = QColor(Qt::black).rgba();
132 d->colortable[1] = QColor(Qt::white).rgba();
133 break;
134 default:
135 break;
136 }
137
138 d->width = width;
139 d->height = height;
140 d->depth = depth;
141 d->format = format;
142 d->has_alpha_clut = false;
143 d->is_cached = false;
144
145 d->bytes_per_line = params.bytesPerLine;
146 d->nbytes = params.totalSize;
147 d->data = (uchar *)malloc(size: d->nbytes);
148
149 if (!d->data)
150 return nullptr;
151
152 d->ref.ref();
153 return d.release();
154}
155
156QImageData::~QImageData()
157{
158 if (cleanupFunction)
159 cleanupFunction(cleanupInfo);
160 if (is_cached)
161 QImagePixmapCleanupHooks::executeImageHooks(key: (((qint64) ser_no) << 32) | ((qint64) detach_no));
162 delete paintEngine;
163 if (data && own_data)
164 free(ptr: data);
165 data = nullptr;
166}
167
168#if defined(_M_ARM) && defined(_MSC_VER)
169#pragma optimize("", off)
170#endif
171
172bool QImageData::checkForAlphaPixels() const
173{
174 bool has_alpha_pixels = false;
175
176 switch (format) {
177
178 case QImage::Format_Mono:
179 case QImage::Format_MonoLSB:
180 case QImage::Format_Indexed8:
181 has_alpha_pixels = has_alpha_clut;
182 break;
183 case QImage::Format_Alpha8:
184 has_alpha_pixels = true;
185 break;
186 case QImage::Format_ARGB32:
187 case QImage::Format_ARGB32_Premultiplied: {
188 const uchar *bits = data;
189 for (int y=0; y<height && !has_alpha_pixels; ++y) {
190 uint alphaAnd = 0xff000000;
191 for (int x=0; x<width; ++x)
192 alphaAnd &= reinterpret_cast<const uint*>(bits)[x];
193 has_alpha_pixels = (alphaAnd != 0xff000000);
194 bits += bytes_per_line;
195 }
196 } break;
197
198 case QImage::Format_RGBA8888:
199 case QImage::Format_RGBA8888_Premultiplied: {
200 const uchar *bits = data;
201 for (int y=0; y<height && !has_alpha_pixels; ++y) {
202 uchar alphaAnd = 0xff;
203 for (int x=0; x<width; ++x)
204 alphaAnd &= bits[x * 4+ 3];
205 has_alpha_pixels = (alphaAnd != 0xff);
206 bits += bytes_per_line;
207 }
208 } break;
209
210 case QImage::Format_A2BGR30_Premultiplied:
211 case QImage::Format_A2RGB30_Premultiplied: {
212 const uchar *bits = data;
213 for (int y=0; y<height && !has_alpha_pixels; ++y) {
214 uint alphaAnd = 0xc0000000;
215 for (int x=0; x<width; ++x)
216 alphaAnd &= reinterpret_cast<const uint*>(bits)[x];
217 has_alpha_pixels = (alphaAnd != 0xc0000000);
218 bits += bytes_per_line;
219 }
220 } break;
221
222 case QImage::Format_ARGB8555_Premultiplied:
223 case QImage::Format_ARGB8565_Premultiplied: {
224 const uchar *bits = data;
225 const uchar *end_bits = data + bytes_per_line;
226
227 for (int y=0; y<height && !has_alpha_pixels; ++y) {
228 uchar alphaAnd = 0xff;
229 while (bits < end_bits) {
230 alphaAnd &= bits[0];
231 bits += 3;
232 }
233 has_alpha_pixels = (alphaAnd != 0xff);
234 bits = end_bits;
235 end_bits += bytes_per_line;
236 }
237 } break;
238
239 case QImage::Format_ARGB6666_Premultiplied: {
240 const uchar *bits = data;
241 const uchar *end_bits = data + bytes_per_line;
242
243 for (int y=0; y<height && !has_alpha_pixels; ++y) {
244 uchar alphaAnd = 0xfc;
245 while (bits < end_bits) {
246 alphaAnd &= bits[0];
247 bits += 3;
248 }
249 has_alpha_pixels = (alphaAnd != 0xfc);
250 bits = end_bits;
251 end_bits += bytes_per_line;
252 }
253 } break;
254
255 case QImage::Format_ARGB4444_Premultiplied: {
256 const uchar *bits = data;
257 for (int y=0; y<height && !has_alpha_pixels; ++y) {
258 ushort alphaAnd = 0xf000;
259 for (int x=0; x<width; ++x)
260 alphaAnd &= reinterpret_cast<const ushort*>(bits)[x];
261 has_alpha_pixels = (alphaAnd != 0xf000);
262 bits += bytes_per_line;
263 }
264 } break;
265 case QImage::Format_RGBA64:
266 case QImage::Format_RGBA64_Premultiplied: {
267 uchar *bits = data;
268 for (int y=0; y<height && !has_alpha_pixels; ++y) {
269 for (int x=0; x<width; ++x) {
270 has_alpha_pixels |= !(((QRgba64 *)bits)[x].isOpaque());
271 }
272 bits += bytes_per_line;
273 }
274 } break;
275 case QImage::Format_RGBA16FPx4:
276 case QImage::Format_RGBA16FPx4_Premultiplied: {
277 uchar *bits = data;
278 for (int y = 0; y < height && !has_alpha_pixels; ++y) {
279 for (int x = 0; x < width; ++x)
280 has_alpha_pixels |= ((qfloat16 *)bits)[x * 4 + 3] < 1.0f;
281 bits += bytes_per_line;
282 }
283 } break;
284 case QImage::Format_RGBA32FPx4:
285 case QImage::Format_RGBA32FPx4_Premultiplied: {
286 uchar *bits = data;
287 for (int y = 0; y < height && !has_alpha_pixels; ++y) {
288 for (int x = 0; x < width; ++x)
289 has_alpha_pixels |= ((float *)bits)[x * 4 + 3] < 1.0f;
290 bits += bytes_per_line;
291 }
292 } break;
293
294 case QImage::Format_RGB32:
295 case QImage::Format_RGB16:
296 case QImage::Format_RGB444:
297 case QImage::Format_RGB555:
298 case QImage::Format_RGB666:
299 case QImage::Format_RGB888:
300 case QImage::Format_BGR888:
301 case QImage::Format_RGBX8888:
302 case QImage::Format_BGR30:
303 case QImage::Format_RGB30:
304 case QImage::Format_Grayscale8:
305 case QImage::Format_Grayscale16:
306 case QImage::Format_RGBX64:
307 case QImage::Format_RGBX16FPx4:
308 case QImage::Format_RGBX32FPx4:
309 case QImage::Format_CMYK8888:
310 break;
311 case QImage::Format_Invalid:
312 case QImage::NImageFormats:
313 Q_UNREACHABLE();
314 break;
315 }
316
317 return has_alpha_pixels;
318}
319#if defined(_M_ARM) && defined(_MSC_VER)
320#pragma optimize("", on)
321#endif
322
323/*!
324 \class QImage
325
326 \inmodule QtGui
327 \ingroup painting
328 \ingroup shared
329
330 \reentrant
331
332 \brief The QImage class provides a hardware-independent image
333 representation that allows direct access to the pixel data, and
334 can be used as a paint device.
335
336 Qt provides four classes for handling image data: QImage, QPixmap,
337 QBitmap and QPicture. QImage is designed and optimized for I/O,
338 and for direct pixel access and manipulation, while QPixmap is
339 designed and optimized for showing images on screen. QBitmap is
340 only a convenience class that inherits QPixmap, ensuring a
341 depth of 1. Finally, the QPicture class is a paint device that
342 records and replays QPainter commands.
343
344 Because QImage is a QPaintDevice subclass, QPainter can be used to
345 draw directly onto images. When using QPainter on a QImage, the
346 painting can be performed in another thread than the current GUI
347 thread.
348
349 The QImage class supports several image formats described by the
350 \l Format enum. These include monochrome, 8-bit, 32-bit and
351 alpha-blended images which are available in all versions of Qt
352 4.x.
353
354 QImage provides a collection of functions that can be used to
355 obtain a variety of information about the image. There are also
356 several functions that enables transformation of the image.
357
358 QImage objects can be passed around by value since the QImage
359 class uses \l{Implicit Data Sharing}{implicit data
360 sharing}. QImage objects can also be streamed and compared.
361
362 \note If you would like to load QImage objects in a static build of Qt,
363 refer to the \l{How to Create Qt Plugins}{Plugin HowTo}.
364
365 \warning Painting on a QImage with the format
366 QImage::Format_Indexed8 or QImage::Format_CMYK8888 is not supported.
367
368 \section1 Reading and Writing Image Files
369
370 QImage provides several ways of loading an image file: The file
371 can be loaded when constructing the QImage object, or by using the
372 load() or loadFromData() functions later on. QImage also provides
373 the static fromData() function, constructing a QImage from the
374 given data. When loading an image, the file name can either refer
375 to an actual file on disk or to one of the application's embedded
376 resources. See \l{The Qt Resource System} overview for details
377 on how to embed images and other resource files in the
378 application's executable.
379
380 Simply call the save() function to save a QImage object.
381
382 The complete list of supported file formats are available through
383 the QImageReader::supportedImageFormats() and
384 QImageWriter::supportedImageFormats() functions. New file formats
385 can be added as plugins. By default, Qt supports the following
386 formats:
387
388 \table
389 \header \li Format \li Description \li Qt's support
390 \row \li BMP \li Windows Bitmap \li Read/write
391 \row \li GIF \li Graphic Interchange Format (optional) \li Read
392 \row \li JPG \li Joint Photographic Experts Group \li Read/write
393 \row \li JPEG \li Joint Photographic Experts Group \li Read/write
394 \row \li PNG \li Portable Network Graphics \li Read/write
395 \row \li PBM \li Portable Bitmap \li Read
396 \row \li PGM \li Portable Graymap \li Read
397 \row \li PPM \li Portable Pixmap \li Read/write
398 \row \li XBM \li X11 Bitmap \li Read/write
399 \row \li XPM \li X11 Pixmap \li Read/write
400 \endtable
401
402 \section1 Image Information
403
404 QImage provides a collection of functions that can be used to
405 obtain a variety of information about the image:
406
407 \table
408 \header
409 \li \li Available Functions
410
411 \row
412 \li Geometry
413 \li
414
415 The size(), width(), height(), dotsPerMeterX(), and
416 dotsPerMeterY() functions provide information about the image size
417 and aspect ratio.
418
419 The rect() function returns the image's enclosing rectangle. The
420 valid() function tells if a given pair of coordinates is within
421 this rectangle. The offset() function returns the number of pixels
422 by which the image is intended to be offset by when positioned
423 relative to other images, which also can be manipulated using the
424 setOffset() function.
425
426 \row
427 \li Colors
428 \li
429
430 The color of a pixel can be retrieved by passing its coordinates
431 to the pixel() function. The pixel() function returns the color
432 as a QRgb value independent of the image's format.
433
434 In case of monochrome and 8-bit images, the colorCount() and
435 colorTable() functions provide information about the color
436 components used to store the image data: The colorTable() function
437 returns the image's entire color table. To obtain a single entry,
438 use the pixelIndex() function to retrieve the pixel index for a
439 given pair of coordinates, then use the color() function to
440 retrieve the color. Note that if you create an 8-bit image
441 manually, you have to set a valid color table on the image as
442 well.
443
444 The hasAlphaChannel() function tells if the image's format
445 respects the alpha channel, or not. The allGray() and
446 isGrayscale() functions tell whether an image's colors are all
447 shades of gray.
448
449 See also the \l {QImage#Pixel Manipulation}{Pixel Manipulation}
450 and \l {QImage#Image Transformations}{Image Transformations}
451 sections.
452
453 \row
454 \li Text
455 \li
456
457 The text() function returns the image text associated with the
458 given text key. An image's text keys can be retrieved using the
459 textKeys() function. Use the setText() function to alter an
460 image's text.
461
462 \row
463 \li Low-level information
464 \li
465
466 The depth() function returns the depth of the image. The supported
467 depths are 1 (monochrome), 8, 16, 24 and 32 bits. The
468 bitPlaneCount() function tells how many of those bits that are
469 used. For more information see the
470 \l {QImage#Image Formats}{Image Formats} section.
471
472 The format(), bytesPerLine(), and sizeInBytes() functions provide
473 low-level information about the data stored in the image.
474
475 The cacheKey() function returns a number that uniquely
476 identifies the contents of this QImage object.
477 \endtable
478
479 \section1 Pixel Manipulation
480
481 The functions used to manipulate an image's pixels depend on the
482 image format. The reason is that monochrome and 8-bit images are
483 index-based and use a color lookup table, while 32-bit images
484 store ARGB values directly. For more information on image formats,
485 see the \l {Image Formats} section.
486
487 In case of a 32-bit image, the setPixel() function can be used to
488 alter the color of the pixel at the given coordinates to any other
489 color specified as an ARGB quadruplet. To make a suitable QRgb
490 value, use the qRgb() (adding a default alpha component to the
491 given RGB values, i.e. creating an opaque color) or qRgba()
492 function. For example:
493
494 \table
495 \header
496 \li {2,1}32-bit
497 \row
498 \li \inlineimage qimage-32bit_scaled.png
499 \li
500 \snippet code/src_gui_image_qimage.cpp 0
501 \endtable
502
503 In case of a 8-bit and monchrome images, the pixel value is only
504 an index from the image's color table. So the setPixel() function
505 can only be used to alter the color of the pixel at the given
506 coordinates to a predefined color from the image's color table,
507 i.e. it can only change the pixel's index value. To alter or add a
508 color to an image's color table, use the setColor() function.
509
510 An entry in the color table is an ARGB quadruplet encoded as an
511 QRgb value. Use the qRgb() and qRgba() functions to make a
512 suitable QRgb value for use with the setColor() function. For
513 example:
514
515 \table
516 \header
517 \li {2,1} 8-bit
518 \row
519 \li \inlineimage qimage-8bit_scaled.png
520 \li
521 \snippet code/src_gui_image_qimage.cpp 1
522 \endtable
523
524 For images with more than 8-bit per color-channel. The methods
525 setPixelColor() and pixelColor() can be used to set and get
526 with QColor values.
527
528 QImage also provide the scanLine() function which returns a
529 pointer to the pixel data at the scanline with the given index,
530 and the bits() function which returns a pointer to the first pixel
531 data (this is equivalent to \c scanLine(0)).
532
533 \section1 Image Formats
534
535 Each pixel stored in a QImage is represented by an integer. The
536 size of the integer varies depending on the format. QImage
537 supports several image formats described by the \l Format
538 enum.
539
540 Monochrome images are stored using 1-bit indexes into a color table
541 with at most two colors. There are two different types of
542 monochrome images: big endian (MSB first) or little endian (LSB
543 first) bit order.
544
545 8-bit images are stored using 8-bit indexes into a color table,
546 i.e. they have a single byte per pixel. The color table is a
547 QList<QRgb>, and the QRgb typedef is equivalent to an unsigned
548 int containing an ARGB quadruplet on the format 0xAARRGGBB.
549
550 32-bit images have no color table; instead, each pixel contains an
551 QRgb value. There are three different types of 32-bit images
552 storing RGB (i.e. 0xffRRGGBB), ARGB and premultiplied ARGB
553 values respectively. In the premultiplied format the red, green,
554 and blue channels are multiplied by the alpha component divided by
555 255.
556
557 An image's format can be retrieved using the format()
558 function. Use the convertToFormat() functions to convert an image
559 into another format. The allGray() and isGrayscale() functions
560 tell whether a color image can safely be converted to a grayscale
561 image.
562
563 \section1 Image Transformations
564
565 QImage supports a number of functions for creating a new image
566 that is a transformed version of the original: The
567 createAlphaMask() function builds and returns a 1-bpp mask from
568 the alpha buffer in this image, and the createHeuristicMask()
569 function creates and returns a 1-bpp heuristic mask for this
570 image. The latter function works by selecting a color from one of
571 the corners, then chipping away pixels of that color starting at
572 all the edges.
573
574 The mirrored() function returns a mirror of the image in the
575 desired direction, the scaled() returns a copy of the image scaled
576 to a rectangle of the desired measures, and the rgbSwapped() function
577 constructs a BGR image from a RGB image.
578
579 The scaledToWidth() and scaledToHeight() functions return scaled
580 copies of the image.
581
582 The transformed() function returns a copy of the image that is
583 transformed with the given transformation matrix and
584 transformation mode: Internally, the transformation matrix is
585 adjusted to compensate for unwanted translation,
586 i.e. transformed() returns the smallest image containing all
587 transformed points of the original image. The static trueMatrix()
588 function returns the actual matrix used for transforming the
589 image.
590
591 There are also functions for changing attributes of an image
592 in-place:
593
594 \table
595 \header \li Function \li Description
596 \row
597 \li setDotsPerMeterX()
598 \li Defines the aspect ratio by setting the number of pixels that fit
599 horizontally in a physical meter.
600 \row
601 \li setDotsPerMeterY()
602 \li Defines the aspect ratio by setting the number of pixels that fit
603 vertically in a physical meter.
604 \row
605 \li fill()
606 \li Fills the entire image with the given pixel value.
607 \row
608 \li invertPixels()
609 \li Inverts all pixel values in the image using the given InvertMode value.
610 \row
611 \li setColorTable()
612 \li Sets the color table used to translate color indexes. Only
613 monochrome and 8-bit formats.
614 \row
615 \li setColorCount()
616 \li Resizes the color table. Only monochrome and 8-bit formats.
617
618 \endtable
619
620 \sa QImageReader, QImageWriter, QPixmap, QSvgRenderer,
621 {Image Composition Example}, {Scribble Example}
622*/
623
624/*!
625 \fn QImage::QImage(QImage &&other)
626
627 Move-constructs a QImage instance, making it point at the same
628 object that \a other was pointing to.
629
630 \since 5.2
631*/
632
633/*!
634 \fn QImage &QImage::operator=(QImage &&other)
635
636 Move-assigns \a other to this QImage instance.
637
638 \since 5.2
639*/
640
641/*!
642 \typedef QImageCleanupFunction
643 \relates QImage
644 \since 5.0
645
646 A function with the following signature that can be used to
647 implement basic image memory management:
648
649 \code
650 void myImageCleanupHandler(void *info);
651 \endcode
652*/
653
654/*!
655 \enum QImage::InvertMode
656
657 This enum type is used to describe how pixel values should be
658 inverted in the invertPixels() function.
659
660 \value InvertRgb Invert only the RGB values and leave the alpha
661 channel unchanged.
662
663 \value InvertRgba Invert all channels, including the alpha channel.
664
665 \sa invertPixels()
666*/
667
668/*!
669 \enum QImage::Format
670
671 The following image formats are available in Qt.
672 See the notes after the table.
673
674 \value Format_Invalid The image is invalid.
675 \value Format_Mono The image is stored using 1-bit per pixel. Bytes are
676 packed with the most significant bit (MSB) first.
677 \value Format_MonoLSB The image is stored using 1-bit per pixel. Bytes are
678 packed with the less significant bit (LSB) first.
679
680 \value Format_Indexed8 The image is stored using 8-bit indexes
681 into a colormap.
682
683 \value Format_RGB32 The image is stored using a 32-bit RGB format (0xffRRGGBB).
684
685 \value Format_ARGB32 The image is stored using a 32-bit ARGB
686 format (0xAARRGGBB).
687
688 \value Format_ARGB32_Premultiplied The image is stored using a premultiplied 32-bit
689 ARGB format (0xAARRGGBB), i.e. the red,
690 green, and blue channels are multiplied
691 by the alpha component divided by 255. (If RR, GG, or BB
692 has a higher value than the alpha channel, the results are
693 undefined.) Certain operations (such as image composition
694 using alpha blending) are faster using premultiplied ARGB32
695 than with plain ARGB32.
696
697 \value Format_RGB16 The image is stored using a 16-bit RGB format (5-6-5).
698
699 \value Format_ARGB8565_Premultiplied The image is stored using a
700 premultiplied 24-bit ARGB format (8-5-6-5).
701 \value Format_RGB666 The image is stored using a 24-bit RGB format (6-6-6).
702 The unused most significant bits is always zero.
703 \value Format_ARGB6666_Premultiplied The image is stored using a
704 premultiplied 24-bit ARGB format (6-6-6-6).
705 \value Format_RGB555 The image is stored using a 16-bit RGB format (5-5-5).
706 The unused most significant bit is always zero.
707 \value Format_ARGB8555_Premultiplied The image is stored using a
708 premultiplied 24-bit ARGB format (8-5-5-5).
709 \value Format_RGB888 The image is stored using a 24-bit RGB format (8-8-8).
710 \value Format_RGB444 The image is stored using a 16-bit RGB format (4-4-4).
711 The unused bits are always zero.
712 \value Format_ARGB4444_Premultiplied The image is stored using a
713 premultiplied 16-bit ARGB format (4-4-4-4).
714 \value [since 5.2]
715 Format_RGBX8888 The image is stored using a 32-bit byte-ordered RGB(x) format (8-8-8-8).
716 This is the same as the Format_RGBA8888 except alpha must always be 255.
717 \value [since 5.2]
718 Format_RGBA8888 The image is stored using a 32-bit byte-ordered RGBA format (8-8-8-8).
719 Unlike ARGB32 this is a byte-ordered format, which means the 32bit
720 encoding differs between big endian and little endian architectures,
721 being respectively (0xRRGGBBAA) and (0xAABBGGRR). The order of the colors
722 is the same on any architecture if read as bytes 0xRR,0xGG,0xBB,0xAA.
723 \value [since 5.2]
724 Format_RGBA8888_Premultiplied The image is stored using a
725 premultiplied 32-bit byte-ordered RGBA format (8-8-8-8).
726 \value [since 5.4]
727 Format_BGR30 The image is stored using a 32-bit BGR format (x-10-10-10).
728 \value [since 5.4]
729 Format_A2BGR30_Premultiplied The image is stored using a 32-bit premultiplied ABGR format (2-10-10-10).
730 \value [since 5.4]
731 Format_RGB30 The image is stored using a 32-bit RGB format (x-10-10-10).
732 \value [since 5.4]
733 Format_A2RGB30_Premultiplied The image is stored using a 32-bit premultiplied ARGB format (2-10-10-10).
734 \value [since 5.5]
735 Format_Alpha8 The image is stored using an 8-bit alpha only format.
736 \value [since 5.5]
737 Format_Grayscale8 The image is stored using an 8-bit grayscale format.
738 \value [since 5.13]
739 Format_Grayscale16 The image is stored using an 16-bit grayscale format.
740 \value [since 5.12]
741 Format_RGBX64 The image is stored using a 64-bit halfword-ordered RGB(x) format (16-16-16-16).
742 This is the same as the Format_RGBA64 except alpha must always be 65535.
743 \value [since 5.12]
744 Format_RGBA64 The image is stored using a 64-bit halfword-ordered RGBA format (16-16-16-16).
745 \value [since 5.12]
746 Format_RGBA64_Premultiplied The image is stored using a premultiplied 64-bit halfword-ordered
747 RGBA format (16-16-16-16).
748 \value [since 5.14]
749 Format_BGR888 The image is stored using a 24-bit BGR format.
750 \value [since 6.2]
751 Format_RGBX16FPx4 The image is stored using a four 16-bit halfword floating point RGBx format (16FP-16FP-16FP-16FP).
752 This is the same as the Format_RGBA16FPx4 except alpha must always be 1.0.
753 \value [since 6.2]
754 Format_RGBA16FPx4 The image is stored using a four 16-bit halfword floating point RGBA format (16FP-16FP-16FP-16FP).
755 \value [since 6.2]
756 Format_RGBA16FPx4_Premultiplied The image is stored using a premultiplied four 16-bit halfword floating point
757 RGBA format (16FP-16FP-16FP-16FP).
758 \value [since 6.2]
759 Format_RGBX32FPx4 The image is stored using a four 32-bit floating point RGBx format (32FP-32FP-32FP-32FP).
760 This is the same as the Format_RGBA32FPx4 except alpha must always be 1.0.
761 \value [since 6.2]
762 Format_RGBA32FPx4 The image is stored using a four 32-bit floating point RGBA format (32FP-32FP-32FP-32FP).
763 \value [since 6.2]
764 Format_RGBA32FPx4_Premultiplied The image is stored using a premultiplied four 32-bit floating point
765 RGBA format (32FP-32FP-32FP-32FP).
766 \value [since 6.8]
767 Format_CMYK8888 The image is stored using a 32-bit byte-ordered CMYK format.
768
769 \note Drawing into a QImage with format QImage::Format_Indexed8 or QImage::Format_CMYK8888 is not
770 supported.
771
772 \note Avoid most rendering directly to most of these formats using QPainter. Rendering
773 is best optimized to the \c Format_RGB32 and \c Format_ARGB32_Premultiplied formats, and secondarily for rendering to the
774 \c Format_RGB16, \c Format_RGBX8888, \c Format_RGBA8888_Premultiplied, \c Format_RGBX64 and \c Format_RGBA64_Premultiplied formats
775
776 \sa format(), convertToFormat()
777*/
778
779/*****************************************************************************
780 QImage member functions
781 *****************************************************************************/
782
783/*!
784 Constructs a null image.
785
786 \sa isNull()
787*/
788
789QImage::QImage() noexcept
790 : QPaintDevice()
791{
792 d = nullptr;
793}
794
795/*!
796 Constructs an image with the given \a width, \a height and \a
797 format.
798
799 A \l{isNull()}{null} image will be returned if memory cannot be allocated.
800
801 \warning This will create a QImage with uninitialized data. Call
802 fill() to fill the image with an appropriate pixel value before
803 drawing onto it with QPainter.
804*/
805QImage::QImage(int width, int height, Format format)
806 : QImage(QSize(width, height), format)
807{
808}
809
810/*!
811 Constructs an image with the given \a size and \a format.
812
813 A \l{isNull()}{null} image is returned if memory cannot be allocated.
814
815 \warning This will create a QImage with uninitialized data. Call
816 fill() to fill the image with an appropriate pixel value before
817 drawing onto it with QPainter.
818*/
819QImage::QImage(const QSize &size, Format format)
820 : QPaintDevice()
821{
822 d = QImageData::create(size, format);
823}
824
825
826
827QImageData *QImageData::create(uchar *data, int width, int height, qsizetype bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
828{
829 if (width <= 0 || height <= 0 || !data || format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
830 return nullptr;
831
832 const int depth = qt_depthForFormat(format);
833 auto params = calculateImageParameters(width, height, depth);
834 if (!params.isValid())
835 return nullptr;
836
837 if (bpl > 0) {
838 // can't overflow, because has calculateImageParameters already done this multiplication
839 const qsizetype min_bytes_per_line = (qsizetype(width) * depth + 7)/8;
840 if (bpl < min_bytes_per_line)
841 return nullptr;
842
843 // recalculate the total with this value
844 params.bytesPerLine = bpl;
845 if (qMulOverflow<qsizetype>(v1: bpl, v2: height, r: &params.totalSize))
846 return nullptr;
847 }
848
849 QImageData *d = new QImageData;
850 d->ref.ref();
851
852 d->own_data = false;
853 d->ro_data = readOnly;
854 d->data = data;
855 d->width = width;
856 d->height = height;
857 d->depth = depth;
858 d->format = format;
859
860 d->bytes_per_line = params.bytesPerLine;
861 d->nbytes = params.totalSize;
862
863 d->cleanupFunction = cleanupFunction;
864 d->cleanupInfo = cleanupInfo;
865
866 return d;
867}
868
869/*!
870 Constructs an image with the given \a width, \a height and \a
871 format, that uses an existing memory buffer, \a data. The \a width
872 and \a height must be specified in pixels, \a data must be 32-bit aligned,
873 and each scanline of data in the image must also be 32-bit aligned.
874
875 The buffer must remain valid throughout the life of the QImage and
876 all copies that have not been modified or otherwise detached from
877 the original buffer. The image does not delete the buffer at destruction.
878 You can provide a function pointer \a cleanupFunction along with an
879 extra pointer \a cleanupInfo that will be called when the last copy
880 is destroyed.
881
882 If \a format is an indexed color format, the image color table is
883 initially empty and must be sufficiently expanded with
884 setColorCount() or setColorTable() before the image is used.
885*/
886QImage::QImage(uchar* data, int width, int height, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
887 : QPaintDevice()
888{
889 d = QImageData::create(data, width, height, bpl: 0, format, readOnly: false, cleanupFunction, cleanupInfo);
890}
891
892/*!
893 Constructs an image with the given \a width, \a height and \a
894 format, that uses an existing read-only memory buffer, \a
895 data. The \a width and \a height must be specified in pixels, \a
896 data must be 32-bit aligned, and each scanline of data in the
897 image must also be 32-bit aligned.
898
899 The buffer must remain valid throughout the life of the QImage and
900 all copies that have not been modified or otherwise detached from
901 the original buffer. The image does not delete the buffer at destruction.
902 You can provide a function pointer \a cleanupFunction along with an
903 extra pointer \a cleanupInfo that will be called when the last copy
904 is destroyed.
905
906 If \a format is an indexed color format, the image color table is
907 initially empty and must be sufficiently expanded with
908 setColorCount() or setColorTable() before the image is used.
909
910 Unlike the similar QImage constructor that takes a non-const data buffer,
911 this version will never alter the contents of the buffer. For example,
912 calling QImage::bits() will return a deep copy of the image, rather than
913 the buffer passed to the constructor. This allows for the efficiency of
914 constructing a QImage from raw data, without the possibility of the raw
915 data being changed.
916*/
917QImage::QImage(const uchar* data, int width, int height, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
918 : QPaintDevice()
919{
920 d = QImageData::create(data: const_cast<uchar*>(data), width, height, bpl: 0, format, readOnly: true, cleanupFunction, cleanupInfo);
921}
922
923/*!
924 Constructs an image with the given \a width, \a height and \a
925 format, that uses an existing memory buffer, \a data. The \a width
926 and \a height must be specified in pixels. \a bytesPerLine
927 specifies the number of bytes per line (stride).
928
929 The buffer must remain valid throughout the life of the QImage and
930 all copies that have not been modified or otherwise detached from
931 the original buffer. The image does not delete the buffer at destruction.
932 You can provide a function pointer \a cleanupFunction along with an
933 extra pointer \a cleanupInfo that will be called when the last copy
934 is destroyed.
935
936 If \a format is an indexed color format, the image color table is
937 initially empty and must be sufficiently expanded with
938 setColorCount() or setColorTable() before the image is used.
939*/
940
941QImage::QImage(uchar *data, int width, int height, qsizetype bytesPerLine, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
942 :QPaintDevice()
943{
944 d = QImageData::create(data, width, height, bpl: bytesPerLine, format, readOnly: false, cleanupFunction, cleanupInfo);
945}
946
947/*!
948 Constructs an image with the given \a width, \a height and \a
949 format, that uses an existing memory buffer, \a data. The \a width
950 and \a height must be specified in pixels. \a bytesPerLine
951 specifies the number of bytes per line (stride).
952
953 The buffer must remain valid throughout the life of the QImage and
954 all copies that have not been modified or otherwise detached from
955 the original buffer. The image does not delete the buffer at destruction.
956 You can provide a function pointer \a cleanupFunction along with an
957 extra pointer \a cleanupInfo that will be called when the last copy
958 is destroyed.
959
960 If \a format is an indexed color format, the image color table is
961 initially empty and must be sufficiently expanded with
962 setColorCount() or setColorTable() before the image is used.
963
964 Unlike the similar QImage constructor that takes a non-const data buffer,
965 this version will never alter the contents of the buffer. For example,
966 calling QImage::bits() will return a deep copy of the image, rather than
967 the buffer passed to the constructor. This allows for the efficiency of
968 constructing a QImage from raw data, without the possibility of the raw
969 data being changed.
970*/
971
972QImage::QImage(const uchar *data, int width, int height, qsizetype bytesPerLine, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
973 :QPaintDevice()
974{
975 d = QImageData::create(data: const_cast<uchar*>(data), width, height, bpl: bytesPerLine, format, readOnly: true, cleanupFunction, cleanupInfo);
976}
977
978/*!
979 Constructs an image and tries to load the image from the file with
980 the given \a fileName.
981
982 The loader attempts to read the image using the specified \a
983 format. If the \a format is not specified (which is the default),
984 it is auto-detected based on the file's suffix and header. For
985 details, see {QImageReader::setAutoDetectImageFormat()}{QImageReader}.
986
987 If the loading of the image failed, this object is a null image.
988
989 The file name can either refer to an actual file on disk or to one
990 of the application's embedded resources. See the
991 \l{resources.html}{Resource System} overview for details on how to
992 embed images and other resource files in the application's
993 executable.
994
995 \sa isNull(), {QImage#Reading and Writing Image Files}{Reading and Writing Image Files}
996*/
997
998QImage::QImage(const QString &fileName, const char *format)
999 : QPaintDevice()
1000{
1001 d = nullptr;
1002 load(fileName, format);
1003}
1004
1005#ifndef QT_NO_IMAGEFORMAT_XPM
1006extern bool qt_read_xpm_image_or_array(QIODevice *device, const char * const *source, QImage &image);
1007
1008/*!
1009 Constructs an image from the given \a xpm image.
1010
1011 Make sure that the image is a valid XPM image. Errors are silently
1012 ignored.
1013
1014 Note that it's possible to squeeze the XPM variable a little bit
1015 by using an unusual declaration:
1016
1017 \snippet code/src_gui_image_qimage.cpp 2
1018
1019 The extra \c const makes the entire definition read-only, which is
1020 slightly more efficient (e.g., when the code is in a shared
1021 library) and able to be stored in ROM with the application.
1022*/
1023
1024QImage::QImage(const char * const xpm[])
1025 : QPaintDevice()
1026{
1027 d = nullptr;
1028 if (!xpm)
1029 return;
1030 if (!qt_read_xpm_image_or_array(device: nullptr, source: xpm, image&: *this))
1031 // Issue: Warning because the constructor may be ambiguous
1032 qWarning(msg: "QImage::QImage(), XPM is not supported");
1033}
1034#endif // QT_NO_IMAGEFORMAT_XPM
1035
1036/*!
1037 Constructs a shallow copy of the given \a image.
1038
1039 For more information about shallow copies, see the \l {Implicit
1040 Data Sharing} documentation.
1041
1042 \sa copy()
1043*/
1044
1045QImage::QImage(const QImage &image)
1046 : QPaintDevice()
1047{
1048 if (image.paintingActive()) {
1049 d = nullptr;
1050 image.copy().swap(other&: *this);
1051 } else {
1052 d = image.d;
1053 if (d)
1054 d->ref.ref();
1055 }
1056}
1057
1058/*!
1059 Destroys the image and cleans up.
1060*/
1061
1062QImage::~QImage()
1063{
1064 if (d && !d->ref.deref())
1065 delete d;
1066}
1067
1068/*!
1069 Assigns a shallow copy of the given \a image to this image and
1070 returns a reference to this image.
1071
1072 For more information about shallow copies, see the \l {Implicit
1073 Data Sharing} documentation.
1074
1075 \sa copy(), QImage()
1076*/
1077
1078QImage &QImage::operator=(const QImage &image)
1079{
1080 if (image.paintingActive()) {
1081 operator=(other: image.copy());
1082 } else {
1083 if (image.d)
1084 image.d->ref.ref();
1085 if (d && !d->ref.deref())
1086 delete d;
1087 d = image.d;
1088 }
1089 return *this;
1090}
1091
1092/*!
1093 \fn void QImage::swap(QImage &other)
1094
1095 Swaps image \a other with this image. This operation is very
1096 fast and never fails.
1097*/
1098
1099/*!
1100 \internal
1101*/
1102int QImage::devType() const
1103{
1104 return QInternal::Image;
1105}
1106
1107/*!
1108 Returns the image as a QVariant.
1109*/
1110QImage::operator QVariant() const
1111{
1112 return QVariant::fromValue(value: *this);
1113}
1114
1115/*!
1116 \internal
1117
1118 If multiple images share common data, this image makes a copy of
1119 the data and detaches itself from the sharing mechanism, making
1120 sure that this image is the only one referring to the data.
1121
1122 Nothing is done if there is just a single reference.
1123
1124 \sa copy(), {QImage::isDetached()}{isDetached()}, {Implicit Data Sharing}
1125*/
1126void QImage::detach()
1127{
1128 if (d) {
1129 if (d->is_cached && d->ref.loadRelaxed() == 1)
1130 QImagePixmapCleanupHooks::executeImageHooks(key: cacheKey());
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/*!
1142 \internal
1143
1144 A variant for metadata-only detach, which will not detach readonly image data,
1145 and only invalidate caches of the image data if asked to.
1146
1147 \sa detach(), isDetached()
1148*/
1149void QImage::detachMetadata(bool invalidateCache)
1150{
1151 if (d) {
1152 if (d->is_cached && d->ref.loadRelaxed() == 1)
1153 QImagePixmapCleanupHooks::executeImageHooks(key: cacheKey());
1154
1155 if (d->ref.loadRelaxed() != 1)
1156 *this = copy();
1157
1158 if (d && invalidateCache)
1159 ++d->detach_no;
1160 }
1161}
1162
1163static void copyPhysicalMetadata(QImageData *dst, const QImageData *src)
1164{
1165 dst->dpmx = src->dpmx;
1166 dst->dpmy = src->dpmy;
1167 dst->devicePixelRatio = src->devicePixelRatio;
1168}
1169
1170static void copyMetadata(QImageData *dst, const QImageData *src)
1171{
1172 // Doesn't copy colortable and alpha_clut.
1173 copyPhysicalMetadata(dst, src);
1174 dst->text = src->text;
1175 dst->offset = src->offset;
1176 dst->colorSpace = src->colorSpace;
1177}
1178
1179static void copyMetadata(QImage *dst, const QImage &src)
1180{
1181 dst->setDotsPerMeterX(src.dotsPerMeterX());
1182 dst->setDotsPerMeterY(src.dotsPerMeterY());
1183 dst->setDevicePixelRatio(src.devicePixelRatio());
1184 const auto textKeys = src.textKeys();
1185 for (const auto &key: textKeys)
1186 dst->setText(key, value: src.text(key));
1187
1188}
1189
1190/*!
1191 \fn QImage QImage::copy(int x, int y, int width, int height) const
1192 \overload
1193
1194 The returned image is copied from the position (\a x, \a y) in
1195 this image, and will always have the given \a width and \a height.
1196 In areas beyond this image, pixels are set to 0.
1197
1198*/
1199
1200/*!
1201 \fn QImage QImage::copy(const QRect& rectangle) const
1202
1203 Returns a sub-area of the image as a new image.
1204
1205 The returned image is copied from the position (\a
1206 {rectangle}.x(), \a{rectangle}.y()) in this image, and will always
1207 have the size of the given \a rectangle.
1208
1209 In areas beyond this image, pixels are set to 0. For 32-bit RGB
1210 images, this means black; for 32-bit ARGB images, this means
1211 transparent black; for 8-bit images, this means the color with
1212 index 0 in the color table which can be anything; for 1-bit
1213 images, this means Qt::color0.
1214
1215 If the given \a rectangle is a null rectangle the entire image is
1216 copied.
1217
1218 \sa QImage()
1219*/
1220QImage Q_TRACE_INSTRUMENT(qtgui) QImage::copy(const QRect& r) const
1221{
1222 Q_TRACE_SCOPE(QImage_copy, r);
1223 if (!d)
1224 return QImage();
1225
1226 if (r.isNull()) {
1227 QImage image(d->width, d->height, d->format);
1228 if (image.isNull())
1229 return image;
1230
1231 // Qt for Embedded Linux can create images with non-default bpl
1232 // make sure we don't crash.
1233 if (image.d->nbytes != d->nbytes) {
1234 qsizetype bpl = qMin(a: bytesPerLine(), b: image.bytesPerLine());
1235 for (int i = 0; i < height(); i++)
1236 memcpy(dest: image.scanLine(i), src: scanLine(i), n: bpl);
1237 } else
1238 memcpy(dest: image.bits(), src: bits(), n: d->nbytes);
1239 image.d->colortable = d->colortable;
1240 image.d->has_alpha_clut = d->has_alpha_clut;
1241 copyMetadata(dst: image.d, src: d);
1242 return image;
1243 }
1244
1245 int x = r.x();
1246 int y = r.y();
1247 int w = r.width();
1248 int h = r.height();
1249
1250 int dx = 0;
1251 int dy = 0;
1252 if (w <= 0 || h <= 0)
1253 return QImage();
1254
1255 QImage image(w, h, d->format);
1256 if (image.isNull())
1257 return image;
1258
1259 if (x < 0 || y < 0 || x + w > d->width || y + h > d->height) {
1260 // bitBlt will not cover entire image - clear it.
1261 image.fill(pixel: 0);
1262 if (x < 0) {
1263 dx = -x;
1264 x = 0;
1265 }
1266 if (y < 0) {
1267 dy = -y;
1268 y = 0;
1269 }
1270 }
1271
1272 image.d->colortable = d->colortable;
1273
1274 int pixels_to_copy = qMax(a: w - dx, b: 0);
1275 if (x > d->width)
1276 pixels_to_copy = 0;
1277 else if (pixels_to_copy > d->width - x)
1278 pixels_to_copy = d->width - x;
1279 int lines_to_copy = qMax(a: h - dy, b: 0);
1280 if (y > d->height)
1281 lines_to_copy = 0;
1282 else if (lines_to_copy > d->height - y)
1283 lines_to_copy = d->height - y;
1284
1285 bool byteAligned = true;
1286 if (d->format == Format_Mono || d->format == Format_MonoLSB)
1287 byteAligned = !(dx & 7) && !(x & 7) && !(pixels_to_copy & 7);
1288
1289 if (byteAligned) {
1290 const uchar *src = d->data + ((x * d->depth) >> 3) + y * d->bytes_per_line;
1291 uchar *dest = image.d->data + ((dx * d->depth) >> 3) + dy * image.d->bytes_per_line;
1292 const qsizetype bytes_to_copy = (qsizetype(pixels_to_copy) * d->depth) >> 3;
1293 for (int i = 0; i < lines_to_copy; ++i) {
1294 memcpy(dest: dest, src: src, n: bytes_to_copy);
1295 src += d->bytes_per_line;
1296 dest += image.d->bytes_per_line;
1297 }
1298 } else if (d->format == Format_Mono) {
1299 const uchar *src = d->data + y * d->bytes_per_line;
1300 uchar *dest = image.d->data + dy * image.d->bytes_per_line;
1301 for (int i = 0; i < lines_to_copy; ++i) {
1302 for (int j = 0; j < pixels_to_copy; ++j) {
1303 if (src[(x + j) >> 3] & (0x80 >> ((x + j) & 7)))
1304 dest[(dx + j) >> 3] |= (0x80 >> ((dx + j) & 7));
1305 else
1306 dest[(dx + j) >> 3] &= ~(0x80 >> ((dx + j) & 7));
1307 }
1308 src += d->bytes_per_line;
1309 dest += image.d->bytes_per_line;
1310 }
1311 } else { // Format_MonoLSB
1312 Q_ASSERT(d->format == Format_MonoLSB);
1313 const uchar *src = d->data + y * d->bytes_per_line;
1314 uchar *dest = image.d->data + dy * image.d->bytes_per_line;
1315 for (int i = 0; i < lines_to_copy; ++i) {
1316 for (int j = 0; j < pixels_to_copy; ++j) {
1317 if (src[(x + j) >> 3] & (0x1 << ((x + j) & 7)))
1318 dest[(dx + j) >> 3] |= (0x1 << ((dx + j) & 7));
1319 else
1320 dest[(dx + j) >> 3] &= ~(0x1 << ((dx + j) & 7));
1321 }
1322 src += d->bytes_per_line;
1323 dest += image.d->bytes_per_line;
1324 }
1325 }
1326
1327 copyMetadata(dst: image.d, src: d);
1328 image.d->has_alpha_clut = d->has_alpha_clut;
1329 return image;
1330}
1331
1332
1333/*!
1334 \fn bool QImage::isNull() const
1335
1336 Returns \c true if it is a null image, otherwise returns \c false.
1337
1338 A null image has all parameters set to zero and no allocated data.
1339*/
1340bool QImage::isNull() const
1341{
1342 return !d;
1343}
1344
1345/*!
1346 \fn int QImage::width() const
1347
1348 Returns the width of the image.
1349
1350 \sa {QImage#Image Information}{Image Information}
1351*/
1352int QImage::width() const
1353{
1354 return d ? d->width : 0;
1355}
1356
1357/*!
1358 \fn int QImage::height() const
1359
1360 Returns the height of the image.
1361
1362 \sa {QImage#Image Information}{Image Information}
1363*/
1364int QImage::height() const
1365{
1366 return d ? d->height : 0;
1367}
1368
1369/*!
1370 \fn QSize QImage::size() const
1371
1372 Returns the size of the image, i.e. its width() and height().
1373
1374 \sa {QImage#Image Information}{Image Information}, deviceIndependentSize()
1375*/
1376QSize QImage::size() const
1377{
1378 return d ? QSize(d->width, d->height) : QSize(0, 0);
1379}
1380
1381/*!
1382 \fn QRect QImage::rect() const
1383
1384 Returns the enclosing rectangle (0, 0, width(), height()) of the
1385 image.
1386
1387 \sa {QImage#Image Information}{Image Information}
1388*/
1389QRect QImage::rect() const
1390{
1391 return d ? QRect(0, 0, d->width, d->height) : QRect();
1392}
1393
1394/*!
1395 Returns the depth of the image.
1396
1397 The image depth is the number of bits used to store a single
1398 pixel, also called bits per pixel (bpp).
1399
1400 The supported depths are 1, 8, 16, 24, 32 and 64.
1401
1402 \sa bitPlaneCount(), convertToFormat(), {QImage#Image Formats}{Image Formats},
1403 {QImage#Image Information}{Image Information}
1404
1405*/
1406int QImage::depth() const
1407{
1408 return d ? d->depth : 0;
1409}
1410
1411/*!
1412 \fn int QImage::colorCount() const
1413
1414 Returns the size of the color table for the image.
1415
1416 Notice that colorCount() returns 0 for 32-bpp images because these
1417 images do not use color tables, but instead encode pixel values as
1418 ARGB quadruplets.
1419
1420 \sa setColorCount(), {QImage#Image Information}{Image Information}
1421*/
1422int QImage::colorCount() const
1423{
1424 return d ? d->colortable.size() : 0;
1425}
1426
1427/*!
1428 Sets the color table used to translate color indexes to QRgb
1429 values, to the specified \a colors.
1430
1431 When the image is used, the color table must be large enough to
1432 have entries for all the pixel/index values present in the image,
1433 otherwise the results are undefined.
1434
1435 \sa colorTable(), setColor(), {QImage#Image Transformations}{Image
1436 Transformations}
1437*/
1438void QImage::setColorTable(const QList<QRgb> &colors)
1439{
1440 if (!d)
1441 return;
1442 detachMetadata(invalidateCache: true);
1443
1444 // In case detach() ran out of memory
1445 if (!d)
1446 return;
1447
1448 d->colortable = colors;
1449 d->has_alpha_clut = false;
1450 for (int i = 0; i < d->colortable.size(); ++i) {
1451 if (qAlpha(rgb: d->colortable.at(i)) != 255) {
1452 d->has_alpha_clut = true;
1453 break;
1454 }
1455 }
1456}
1457
1458/*!
1459 Returns a list of the colors contained in the image's color table,
1460 or an empty list if the image does not have a color table
1461
1462 \sa setColorTable(), colorCount(), color()
1463*/
1464QList<QRgb> QImage::colorTable() const
1465{
1466 return d ? d->colortable : QList<QRgb>();
1467}
1468
1469/*!
1470 Returns the device pixel ratio for the image. This is the
1471 ratio between \e{device pixels} and \e{device independent pixels}.
1472
1473 Use this function when calculating layout geometry based on
1474 the image size: QSize layoutSize = image.size() / image.devicePixelRatio()
1475
1476 The default value is 1.0.
1477
1478 \sa setDevicePixelRatio(), QImageReader
1479*/
1480qreal QImage::devicePixelRatio() const
1481{
1482 if (!d)
1483 return 1.0;
1484 return d->devicePixelRatio;
1485}
1486
1487/*!
1488 Sets the device pixel ratio for the image. This is the
1489 ratio between image pixels and device-independent pixels.
1490
1491 The default \a scaleFactor is 1.0. Setting it to something else has
1492 two effects:
1493
1494 QPainters that are opened on the image will be scaled. For
1495 example, painting on a 200x200 image if with a ratio of 2.0
1496 will result in effective (device-independent) painting bounds
1497 of 100x100.
1498
1499 Code paths in Qt that calculate layout geometry based on the
1500 image size will take the ratio into account:
1501 QSize layoutSize = image.size() / image.devicePixelRatio()
1502 The net effect of this is that the image is displayed as
1503 high-DPI image rather than a large image
1504 (see \l{Drawing High Resolution Versions of Pixmaps and Images}).
1505
1506 \sa devicePixelRatio(), deviceIndependentSize()
1507*/
1508void QImage::setDevicePixelRatio(qreal scaleFactor)
1509{
1510 if (!d)
1511 return;
1512
1513 if (scaleFactor == d->devicePixelRatio)
1514 return;
1515
1516 detachMetadata();
1517 if (d)
1518 d->devicePixelRatio = scaleFactor;
1519}
1520
1521/*!
1522 Returns the size of the image in device independent pixels.
1523
1524 This value should be used when using the image size in user interface
1525 size calculations.
1526
1527 The return value is equivalent to image.size() / image.devicePixelRatio().
1528
1529 \since 6.2
1530*/
1531QSizeF QImage::deviceIndependentSize() const
1532{
1533 if (!d)
1534 return QSizeF(0, 0);
1535 return QSizeF(d->width, d->height) / d->devicePixelRatio;
1536}
1537
1538
1539/*!
1540 \since 5.10
1541 Returns the image data size in bytes.
1542
1543 \sa bytesPerLine(), bits(), {QImage#Image Information}{Image
1544 Information}
1545*/
1546qsizetype QImage::sizeInBytes() const
1547{
1548 return d ? d->nbytes : 0;
1549}
1550
1551/*!
1552 Returns the number of bytes per image scanline.
1553
1554 This is equivalent to sizeInBytes() / height() if height() is non-zero.
1555
1556 \sa scanLine()
1557*/
1558qsizetype QImage::bytesPerLine() const
1559{
1560 return d ? d->bytes_per_line : 0;
1561}
1562
1563
1564/*!
1565 Returns the color in the color table at index \a i. The first
1566 color is at index 0.
1567
1568 The colors in an image's color table are specified as ARGB
1569 quadruplets (QRgb). Use the qAlpha(), qRed(), qGreen(), and
1570 qBlue() functions to get the color value components.
1571
1572 \sa setColor(), pixelIndex(), {QImage#Pixel Manipulation}{Pixel
1573 Manipulation}
1574*/
1575QRgb QImage::color(int i) const
1576{
1577 Q_ASSERT(i < colorCount());
1578 return d ? d->colortable.at(i) : QRgb(uint(-1));
1579}
1580
1581/*!
1582 \fn void QImage::setColor(int index, QRgb colorValue)
1583
1584 Sets the color at the given \a index in the color table, to the
1585 given to \a colorValue. The color value is an ARGB quadruplet.
1586
1587 If \a index is outside the current size of the color table, it is
1588 expanded with setColorCount().
1589
1590 \sa color(), colorCount(), setColorTable(), {QImage#Pixel Manipulation}{Pixel
1591 Manipulation}
1592*/
1593void QImage::setColor(int i, QRgb c)
1594{
1595 if (!d)
1596 return;
1597 if (i < 0 || d->depth > 8 || i >= 1<<d->depth) {
1598 qWarning(msg: "QImage::setColor: Index out of bound %d", i);
1599 return;
1600 }
1601 detachMetadata(invalidateCache: true);
1602
1603 // In case detach() run out of memory
1604 if (!d)
1605 return;
1606
1607 if (i >= d->colortable.size())
1608 setColorCount(i+1);
1609 d->colortable[i] = c;
1610 d->has_alpha_clut |= (qAlpha(rgb: c) != 255);
1611}
1612
1613/*!
1614 Returns a pointer to the pixel data at the scanline with index \a
1615 i. The first scanline is at index 0.
1616
1617 The scanline data is as minimum 32-bit aligned. For 64-bit formats
1618 it follows the native alignment of 64-bit integers (64-bit for most
1619 platforms, but notably 32-bit on i386).
1620
1621 For example, to remove the green component of each pixel in an image:
1622
1623 \snippet code/src_gui_image_qimage.cpp scanLine
1624
1625 \warning If you are accessing 32-bpp image data, cast the returned
1626 pointer to \c{QRgb*} (QRgb has a 32-bit size) and use it to
1627 read/write the pixel value. You cannot use the \c{uchar*} pointer
1628 directly, because the pixel format depends on the byte order on
1629 the underlying platform. Use qRed(), qGreen(), qBlue(), and
1630 qAlpha() to access the pixels.
1631
1632 \sa bytesPerLine(), bits(), {QImage#Pixel Manipulation}{Pixel
1633 Manipulation}, constScanLine()
1634*/
1635uchar *QImage::scanLine(int i)
1636{
1637 if (!d)
1638 return nullptr;
1639
1640 detach();
1641
1642 // In case detach() ran out of memory
1643 if (!d)
1644 return nullptr;
1645
1646 return d->data + i * d->bytes_per_line;
1647}
1648
1649/*!
1650 \overload
1651*/
1652const uchar *QImage::scanLine(int i) const
1653{
1654 if (!d)
1655 return nullptr;
1656
1657 Q_ASSERT(i >= 0 && i < height());
1658 return d->data + i * d->bytes_per_line;
1659}
1660
1661
1662/*!
1663 Returns a pointer to the pixel data at the scanline with index \a
1664 i. The first scanline is at index 0.
1665
1666 The scanline data is as minimum 32-bit aligned. For 64-bit formats
1667 it follows the native alignment of 64-bit integers (64-bit for most
1668 platforms, but notably 32-bit on i386).
1669
1670 Note that QImage uses \l{Implicit Data Sharing} {implicit data
1671 sharing}, but this function does \e not perform a deep copy of the
1672 shared pixel data, because the returned data is const.
1673
1674 \sa scanLine(), constBits()
1675*/
1676const uchar *QImage::constScanLine(int i) const
1677{
1678 if (!d)
1679 return nullptr;
1680
1681 Q_ASSERT(i >= 0 && i < height());
1682 return d->data + i * d->bytes_per_line;
1683}
1684
1685/*!
1686 Returns a pointer to the first pixel data. This is equivalent to
1687 scanLine(0).
1688
1689 Note that QImage uses \l{Implicit Data Sharing} {implicit data
1690 sharing}. This function performs a deep copy of the shared pixel
1691 data, thus ensuring that this QImage is the only one using the
1692 current return value.
1693
1694 \sa scanLine(), sizeInBytes(), constBits()
1695*/
1696uchar *QImage::bits()
1697{
1698 if (!d)
1699 return nullptr;
1700 detach();
1701
1702 // In case detach ran out of memory...
1703 if (!d)
1704 return nullptr;
1705
1706 return d->data;
1707}
1708
1709/*!
1710 \overload
1711
1712 Note that QImage uses \l{Implicit Data Sharing} {implicit data
1713 sharing}, but this function does \e not perform a deep copy of the
1714 shared pixel data, because the returned data is const.
1715*/
1716const uchar *QImage::bits() const
1717{
1718 return d ? d->data : nullptr;
1719}
1720
1721
1722/*!
1723 Returns a pointer to the first pixel data.
1724
1725 Note that QImage uses \l{Implicit Data Sharing} {implicit data
1726 sharing}, but this function does \e not perform a deep copy of the
1727 shared pixel data, because the returned data is const.
1728
1729 \sa bits(), constScanLine()
1730*/
1731const uchar *QImage::constBits() const
1732{
1733 return d ? d->data : nullptr;
1734}
1735
1736/*!
1737 \fn void QImage::fill(uint pixelValue)
1738
1739 Fills the entire image with the given \a pixelValue.
1740
1741 If the depth of this image is 1, only the lowest bit is used. If
1742 you say fill(0), fill(2), etc., the image is filled with 0s. If
1743 you say fill(1), fill(3), etc., the image is filled with 1s. If
1744 the depth is 8, the lowest 8 bits are used and if the depth is 16
1745 the lowest 16 bits are used.
1746
1747 If the image depth is higher than 32bit the result is undefined.
1748
1749 \note There are no corresponding value getter, though QImage::pixelIndex()
1750 will return the same value for indexed formats, and QImage::pixel() for
1751 RGB32, ARGB32, and ARGB32PM formats.
1752
1753 \sa depth(), {QImage#Image Transformations}{Image Transformations}
1754*/
1755
1756void QImage::fill(uint pixel)
1757{
1758 if (!d)
1759 return;
1760
1761 detach();
1762
1763 // In case detach() ran out of memory
1764 if (!d)
1765 return;
1766
1767 if (d->depth == 1 || d->depth == 8) {
1768 int w = d->width;
1769 if (d->depth == 1) {
1770 if (pixel & 1)
1771 pixel = 0xffffffff;
1772 else
1773 pixel = 0;
1774 w = (w + 7) / 8;
1775 } else {
1776 pixel &= 0xff;
1777 }
1778 qt_rectfill<quint8>(dest: d->data, value: pixel, x: 0, y: 0,
1779 width: w, height: d->height, stride: d->bytes_per_line);
1780 return;
1781 } else if (d->depth == 16) {
1782 if (d->format == Format_RGB444)
1783 pixel |= 0xf000;
1784 qt_rectfill<quint16>(dest: reinterpret_cast<quint16*>(d->data), value: pixel,
1785 x: 0, y: 0, width: d->width, height: d->height, stride: d->bytes_per_line);
1786 return;
1787 } else if (d->depth == 24) {
1788 if (d->format == Format_RGB666)
1789 pixel |= 0xfc0000;
1790 qt_rectfill<quint24>(dest: reinterpret_cast<quint24*>(d->data), value: pixel,
1791 x: 0, y: 0, width: d->width, height: d->height, stride: d->bytes_per_line);
1792 return;
1793 } else if (d->format >= QImage::Format_RGBX64 && d->format <= QImage::Format_RGBA64_Premultiplied) {
1794 qt_rectfill<quint64>(dest: reinterpret_cast<quint64*>(d->data), value: QRgba64::fromArgb32(rgb: pixel),
1795 x: 0, y: 0, width: d->width, height: d->height, stride: d->bytes_per_line);
1796 return;
1797 } else if (d->format >= QImage::Format_RGBX16FPx4 && d->format <= QImage::Format_RGBA16FPx4_Premultiplied) {
1798 quint64 cu;
1799 QRgbaFloat16 cf = QRgbaFloat16::fromArgb32(rgb: pixel);
1800 ::memcpy(dest: &cu, src: &cf, n: sizeof(quint64));
1801 qt_rectfill<quint64>(dest: reinterpret_cast<quint64*>(d->data), value: cu,
1802 x: 0, y: 0, width: d->width, height: d->height, stride: d->bytes_per_line);
1803 return;
1804 } else if (d->format >= QImage::Format_RGBX32FPx4 && d->format <= QImage::Format_RGBA32FPx4_Premultiplied) {
1805 QRgbaFloat32 cf = QRgbaFloat32::fromArgb32(rgb: pixel);
1806 uchar *data = d->data;
1807 for (int y = 0; y < d->height; ++y) {
1808 QRgbaFloat32 *line = reinterpret_cast<QRgbaFloat32 *>(data);
1809 for (int x = 0; x < d->width; ++x)
1810 line[x] = cf;
1811 data += d->bytes_per_line;
1812 }
1813 return;
1814 }
1815 Q_ASSERT(d->depth == 32);
1816
1817 if (d->format == Format_RGB32)
1818 pixel |= 0xff000000;
1819 if (d->format == Format_RGBX8888)
1820#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1821 pixel |= 0xff000000;
1822#else
1823 pixel |= 0x000000ff;
1824#endif
1825 if (d->format == Format_BGR30 || d->format == Format_RGB30)
1826 pixel |= 0xc0000000;
1827
1828 qt_rectfill<uint>(dest: reinterpret_cast<uint*>(d->data), value: pixel,
1829 x: 0, y: 0, width: d->width, height: d->height, stride: d->bytes_per_line);
1830}
1831
1832
1833/*!
1834 \fn void QImage::fill(Qt::GlobalColor color)
1835 \overload
1836
1837 Fills the image with the given \a color, described as a standard global
1838 color.
1839 */
1840
1841void QImage::fill(Qt::GlobalColor color)
1842{
1843 fill(color: QColor(color));
1844}
1845
1846
1847
1848/*!
1849 \fn void QImage::fill(const QColor &color)
1850
1851 \overload
1852
1853 Fills the entire image with the given \a color.
1854
1855 If the depth of the image is 1, the image will be filled with 1 if
1856 \a color equals Qt::color1; it will otherwise be filled with 0.
1857
1858 If the depth of the image is 8, the image will be filled with the
1859 index corresponding the \a color in the color table if present; it
1860 will otherwise be filled with 0.
1861*/
1862
1863void QImage::fill(const QColor &color)
1864{
1865 if (!d)
1866 return;
1867 detach();
1868
1869 // In case we run out of memory
1870 if (!d)
1871 return;
1872
1873 QRgba64 opaque = color.rgba64();
1874 opaque.setAlpha(65535);
1875 switch (d->format) {
1876 case QImage::Format_RGB32:
1877 case QImage::Format_ARGB32:
1878 fill(pixel: color.rgba());
1879 break;
1880 case QImage::Format_ARGB32_Premultiplied:
1881 fill(pixel: qPremultiply(x: color.rgba()));
1882 break;
1883 case QImage::Format_RGBX8888:
1884 fill(pixel: ARGB2RGBA(x: color.rgba() | 0xff000000));
1885 break;
1886 case QImage::Format_RGBA8888:
1887 fill(pixel: ARGB2RGBA(x: color.rgba()));
1888 break;
1889 case QImage::Format_RGBA8888_Premultiplied:
1890 fill(pixel: ARGB2RGBA(x: qPremultiply(x: color.rgba())));
1891 break;
1892 case QImage::Format_BGR30:
1893 fill(pixel: qConvertRgb64ToRgb30<PixelOrderBGR>(c: opaque));
1894 break;
1895 case QImage::Format_RGB30:
1896 fill(pixel: qConvertRgb64ToRgb30<PixelOrderRGB>(c: opaque));
1897 break;
1898 case QImage::Format_RGB16:
1899 fill(pixel: (uint) qConvertRgb32To16(c: color.rgba()));
1900 break;
1901 case QImage::Format_Indexed8: {
1902 uint pixel = 0;
1903 for (int i=0; i<d->colortable.size(); ++i) {
1904 if (color.rgba() == d->colortable.at(i)) {
1905 pixel = i;
1906 break;
1907 }
1908 }
1909 fill(pixel);
1910 break;
1911 }
1912 case QImage::Format_Mono:
1913 case QImage::Format_MonoLSB:
1914 if (color == Qt::color1)
1915 fill(pixel: (uint) 1);
1916 else
1917 fill(pixel: (uint) 0);
1918 break;
1919 case QImage::Format_RGBX64:
1920 qt_rectfill<quint64>(dest: reinterpret_cast<quint64*>(d->data), value: opaque,
1921 x: 0, y: 0, width: d->width, height: d->height, stride: d->bytes_per_line);
1922 break;
1923 case QImage::Format_RGBA64:
1924 qt_rectfill<quint64>(dest: reinterpret_cast<quint64*>(d->data), value: color.rgba64(),
1925 x: 0, y: 0, width: d->width, height: d->height, stride: d->bytes_per_line);
1926 break;
1927 case QImage::Format_RGBA64_Premultiplied:
1928 qt_rectfill<quint64>(dest: reinterpret_cast<quint64 *>(d->data), value: color.rgba64().premultiplied(),
1929 x: 0, y: 0, width: d->width, height: d->height, stride: d->bytes_per_line);
1930 break;
1931 case QImage::Format_RGBX16FPx4:
1932 case QImage::Format_RGBA16FPx4:
1933 case QImage::Format_RGBA16FPx4_Premultiplied:
1934 case QImage::Format_RGBX32FPx4:
1935 case QImage::Format_RGBA32FPx4:
1936 case QImage::Format_RGBA32FPx4_Premultiplied:{
1937 float r, g, b, a;
1938 color.getRgbF(r: &r, g: &g, b: &b, a: &a);
1939 if (!hasAlphaChannel())
1940 a = 1.0f;
1941 if (depth() == 64) {
1942 QRgbaFloat16 c16{.r: qfloat16(r), .g: qfloat16(g), .b: qfloat16(b), .a: qfloat16(a)};
1943 if (d->format == Format_RGBA16FPx4_Premultiplied)
1944 c16 = c16.premultiplied();
1945 qt_rectfill<QRgbaFloat16>(dest: reinterpret_cast<QRgbaFloat16 *>(d->data), value: c16,
1946 x: 0, y: 0, width: d->width, height: d->height, stride: d->bytes_per_line);
1947 } else {
1948 QRgbaFloat32 c32{.r: r, .g: g, .b: b, .a: a};
1949 if (d->format == Format_RGBA32FPx4_Premultiplied)
1950 c32 = c32.premultiplied();
1951 qt_rectfill<QRgbaFloat32>(dest: reinterpret_cast<QRgbaFloat32 *>(d->data), value: c32,
1952 x: 0, y: 0, width: d->width, height: d->height, stride: d->bytes_per_line);
1953 }
1954 break;
1955 }
1956 default: {
1957 QPainter p(this);
1958 p.setCompositionMode(QPainter::CompositionMode_Source);
1959 p.fillRect(rect(), color);
1960 }}
1961}
1962
1963
1964
1965/*!
1966 Inverts all pixel values in the image.
1967
1968 The given invert \a mode only have a meaning when the image's
1969 depth is 32. The default \a mode is InvertRgb, which leaves the
1970 alpha channel unchanged. If the \a mode is InvertRgba, the alpha
1971 bits are also inverted.
1972
1973 Inverting an 8-bit image means to replace all pixels using color
1974 index \e i with a pixel using color index 255 minus \e i. The same
1975 is the case for a 1-bit image. Note that the color table is \e not
1976 changed.
1977
1978 If the image has a premultiplied alpha channel, the image is first
1979 converted to an unpremultiplied image format to be inverted and
1980 then converted back.
1981
1982 \sa {QImage#Image Transformations}{Image Transformations}
1983*/
1984
1985void QImage::invertPixels(InvertMode mode)
1986{
1987 if (!d)
1988 return;
1989
1990 detach();
1991
1992 // In case detach() ran out of memory
1993 if (!d)
1994 return;
1995
1996 QImage::Format originalFormat = d->format;
1997 // Inverting premultiplied pixels would produce invalid image data.
1998 if (hasAlphaChannel() && qPixelLayouts[d->format].premultiplied) {
1999 if (d->format == QImage::Format_RGBA16FPx4_Premultiplied) {
2000 if (!d->convertInPlace(newFormat: QImage::Format_RGBA16FPx4, { }))
2001 *this = convertToFormat(f: QImage::Format_RGBA16FPx4);
2002 } else if (d->format == QImage::Format_RGBA32FPx4_Premultiplied) {
2003 if (!d->convertInPlace(newFormat: QImage::Format_RGBA32FPx4, { }))
2004 *this = convertToFormat(f: QImage::Format_RGBA32FPx4);
2005 } else if (depth() > 32) {
2006 if (!d->convertInPlace(newFormat: QImage::Format_RGBA64, { }))
2007 *this = convertToFormat(f: QImage::Format_RGBA64);
2008 } else {
2009 if (!d->convertInPlace(newFormat: QImage::Format_ARGB32, { }))
2010 *this = convertToFormat(f: QImage::Format_ARGB32);
2011 }
2012 }
2013
2014 if (depth() < 32) {
2015 // This assumes no alpha-channel as the only formats with non-premultipled alpha are 32bit.
2016 qsizetype bpl = (qsizetype(d->width) * d->depth + 7) / 8;
2017 int pad = d->bytes_per_line - bpl;
2018 uchar *sl = d->data;
2019 for (int y=0; y<d->height; ++y) {
2020 for (qsizetype x=0; x<bpl; ++x)
2021 *sl++ ^= 0xff;
2022 sl += pad;
2023 }
2024 } else if (format() >= QImage::Format_RGBX16FPx4 && format() <= QImage::Format_RGBA16FPx4_Premultiplied) {
2025 qfloat16 *p = reinterpret_cast<qfloat16 *>(d->data);
2026 qfloat16 *end = reinterpret_cast<qfloat16 *>(d->data + d->nbytes);
2027 while (p < end) {
2028 p[0] = qfloat16(1) - p[0];
2029 p[1] = qfloat16(1) - p[1];
2030 p[2] = qfloat16(1) - p[2];
2031 if (mode == InvertRgba)
2032 p[3] = qfloat16(1) - p[3];
2033 p += 4;
2034 }
2035 } else if (format() >= QImage::Format_RGBX32FPx4 && format() <= QImage::Format_RGBA32FPx4_Premultiplied) {
2036 uchar *data = d->data;
2037 for (int y = 0; y < d->height; ++y) {
2038 float *p = reinterpret_cast<float *>(data);
2039 for (int x = 0; x < d->width; ++x) {
2040 p[0] = 1.0f - p[0];
2041 p[1] = 1.0f - p[1];
2042 p[2] = 1.0f - p[2];
2043 if (mode == InvertRgba)
2044 p[3] = 1.0f - p[3];
2045 p += 4;
2046 }
2047 data += d->bytes_per_line;
2048 }
2049 } else if (depth() == 64) {
2050 quint16 *p = (quint16*)d->data;
2051 quint16 *end = (quint16*)(d->data + d->nbytes);
2052 quint16 xorbits = 0xffff;
2053 while (p < end) {
2054 *p++ ^= xorbits;
2055 *p++ ^= xorbits;
2056 *p++ ^= xorbits;
2057 if (mode == InvertRgba)
2058 *p++ ^= xorbits;
2059 else
2060 p++;
2061 }
2062 } else {
2063 quint32 *p = (quint32*)d->data;
2064 quint32 *end = (quint32*)(d->data + d->nbytes);
2065 quint32 xorbits = 0xffffffff;
2066 switch (d->format) {
2067 case QImage::Format_RGBA8888:
2068 if (mode == InvertRgba)
2069 break;
2070 Q_FALLTHROUGH();
2071 case QImage::Format_RGBX8888:
2072#if Q_BYTE_ORDER == Q_BIG_ENDIAN
2073 xorbits = 0xffffff00;
2074 break;
2075#else
2076 xorbits = 0x00ffffff;
2077 break;
2078#endif
2079 case QImage::Format_ARGB32:
2080 if (mode == InvertRgba)
2081 break;
2082 Q_FALLTHROUGH();
2083 case QImage::Format_RGB32:
2084 xorbits = 0x00ffffff;
2085 break;
2086 case QImage::Format_BGR30:
2087 case QImage::Format_RGB30:
2088 xorbits = 0x3fffffff;
2089 break;
2090 default:
2091 Q_UNREACHABLE();
2092 xorbits = 0;
2093 break;
2094 }
2095 while (p < end)
2096 *p++ ^= xorbits;
2097 }
2098
2099 if (originalFormat != d->format) {
2100 if (!d->convertInPlace(newFormat: originalFormat, { }))
2101 *this = convertToFormat(f: originalFormat);
2102 }
2103}
2104
2105// Windows defines these
2106#if defined(write)
2107# undef write
2108#endif
2109#if defined(close)
2110# undef close
2111#endif
2112#if defined(read)
2113# undef read
2114#endif
2115
2116/*!
2117 Resizes the color table to contain \a colorCount entries.
2118
2119 If the color table is expanded, all the extra colors will be set to
2120 transparent (i.e qRgba(0, 0, 0, 0)).
2121
2122 When the image is used, the color table must be large enough to
2123 have entries for all the pixel/index values present in the image,
2124 otherwise the results are undefined.
2125
2126 \sa colorCount(), colorTable(), setColor(), {QImage#Image
2127 Transformations}{Image Transformations}
2128*/
2129
2130void QImage::setColorCount(int colorCount)
2131{
2132 if (!d) {
2133 qWarning(msg: "QImage::setColorCount: null image");
2134 return;
2135 }
2136
2137 detachMetadata(invalidateCache: true);
2138
2139 // In case detach() ran out of memory
2140 if (!d)
2141 return;
2142
2143 if (colorCount == d->colortable.size())
2144 return;
2145 if (colorCount <= 0) { // use no color table
2146 d->colortable.clear();
2147 return;
2148 }
2149 int nc = d->colortable.size();
2150 d->colortable.resize(size: colorCount);
2151 for (int i = nc; i < colorCount; ++i)
2152 d->colortable[i] = 0;
2153}
2154
2155/*!
2156 Returns the format of the image.
2157
2158 \sa {QImage#Image Formats}{Image Formats}
2159*/
2160QImage::Format QImage::format() const
2161{
2162 return d ? d->format : Format_Invalid;
2163}
2164
2165/*!
2166 \fn QImage QImage::convertToFormat(Format format, Qt::ImageConversionFlags flags) const &
2167 \fn QImage QImage::convertToFormat(Format format, Qt::ImageConversionFlags flags) &&
2168
2169 Returns a copy of the image in the given \a format.
2170
2171 The specified image conversion \a flags control how the image data
2172 is handled during the conversion process.
2173
2174 \sa convertTo(), {Image Formats}
2175*/
2176
2177/*!
2178 \fn QImage QImage::convertedTo(Format format, Qt::ImageConversionFlags flags) const &
2179 \fn QImage QImage::convertedTo(Format format, Qt::ImageConversionFlags flags) &&
2180 \since 6.0
2181
2182 Returns a copy of the image in the given \a format.
2183
2184 The specified image conversion \a flags control how the image data
2185 is handled during the conversion process.
2186
2187 \sa convertTo(), {Image Formats}
2188*/
2189
2190/*!
2191 \internal
2192*/
2193QImage QImage::convertToFormat_helper(Format format, Qt::ImageConversionFlags flags) const
2194{
2195 if (!d || d->format == format)
2196 return *this;
2197
2198 if (d->format == Format_Invalid || format <= Format_Invalid || format >= NImageFormats)
2199 return QImage();
2200
2201 const QPixelLayout *destLayout = &qPixelLayouts[format];
2202 Image_Converter converter = qimage_converter_map[d->format][format];
2203 if (!converter && format > QImage::Format_Indexed8 && d->format > QImage::Format_Indexed8) {
2204 if (qt_highColorPrecision(format: d->format, opaque: !destLayout->hasAlphaChannel)
2205 && qt_highColorPrecision(format, opaque: !hasAlphaChannel())) {
2206#if QT_CONFIG(raster_fp)
2207 if (qt_fpColorPrecision(format: d->format) && qt_fpColorPrecision(format))
2208 converter = convert_generic_over_rgba32f;
2209 else
2210#endif
2211 converter = convert_generic_over_rgb64;
2212 } else
2213 converter = convert_generic;
2214 }
2215 if (converter) {
2216 QImage image(d->width, d->height, format);
2217
2218 QIMAGE_SANITYCHECK_MEMORY(image);
2219
2220 copyMetadata(dst: image.d, src: d);
2221
2222 converter(image.d, d, flags);
2223 return image;
2224 }
2225
2226 // Convert indexed formats over ARGB32 or RGB32 to the final format.
2227 Q_ASSERT(format != QImage::Format_ARGB32 && format != QImage::Format_RGB32);
2228 Q_ASSERT(d->format != QImage::Format_ARGB32 && d->format != QImage::Format_RGB32);
2229
2230 if (!hasAlphaChannel())
2231 return convertToFormat(f: Format_RGB32, flags).convertToFormat(f: format, flags);
2232
2233 return convertToFormat(f: Format_ARGB32, flags).convertToFormat(f: format, flags);
2234}
2235
2236/*!
2237 \internal
2238*/
2239bool QImage::convertToFormat_inplace(Format format, Qt::ImageConversionFlags flags)
2240{
2241 return d && d->convertInPlace(newFormat: format, flags);
2242}
2243
2244static inline int pixel_distance(QRgb p1, QRgb p2) {
2245 int r1 = qRed(rgb: p1);
2246 int g1 = qGreen(rgb: p1);
2247 int b1 = qBlue(rgb: p1);
2248 int a1 = qAlpha(rgb: p1);
2249
2250 int r2 = qRed(rgb: p2);
2251 int g2 = qGreen(rgb: p2);
2252 int b2 = qBlue(rgb: p2);
2253 int a2 = qAlpha(rgb: p2);
2254
2255 return abs(x: r1 - r2) + abs(x: g1 - g2) + abs(x: b1 - b2) + abs(x: a1 - a2);
2256}
2257
2258static inline int closestMatch(QRgb pixel, const QList<QRgb> &clut) {
2259 int idx = 0;
2260 int current_distance = INT_MAX;
2261 for (int i=0; i<clut.size(); ++i) {
2262 int dist = pixel_distance(p1: pixel, p2: clut.at(i));
2263 if (dist < current_distance) {
2264 current_distance = dist;
2265 idx = i;
2266 }
2267 }
2268 return idx;
2269}
2270
2271static QImage convertWithPalette(const QImage &src, QImage::Format format,
2272 const QList<QRgb> &clut) {
2273 QImage dest(src.size(), format);
2274 dest.setColorTable(clut);
2275
2276 copyMetadata(dst: QImageData::get(img&: dest), src: QImageData::get(img: src));
2277
2278 int h = src.height();
2279 int w = src.width();
2280
2281 QHash<QRgb, int> cache;
2282
2283 if (format == QImage::Format_Indexed8) {
2284 for (int y=0; y<h; ++y) {
2285 const QRgb *src_pixels = (const QRgb *) src.scanLine(i: y);
2286 uchar *dest_pixels = (uchar *) dest.scanLine(i: y);
2287 for (int x=0; x<w; ++x) {
2288 int src_pixel = src_pixels[x];
2289 int value = cache.value(key: src_pixel, defaultValue: -1);
2290 if (value == -1) {
2291 value = closestMatch(pixel: src_pixel, clut);
2292 cache.insert(key: src_pixel, value);
2293 }
2294 dest_pixels[x] = (uchar) value;
2295 }
2296 }
2297 } else {
2298 QList<QRgb> table = clut;
2299 table.resize(size: 2);
2300 for (int y=0; y<h; ++y) {
2301 const QRgb *src_pixels = (const QRgb *) src.scanLine(i: y);
2302 for (int x=0; x<w; ++x) {
2303 int src_pixel = src_pixels[x];
2304 int value = cache.value(key: src_pixel, defaultValue: -1);
2305 if (value == -1) {
2306 value = closestMatch(pixel: src_pixel, clut: table);
2307 cache.insert(key: src_pixel, value);
2308 }
2309 dest.setPixel(x, y, index_or_rgb: value);
2310 }
2311 }
2312 }
2313
2314 return dest;
2315}
2316
2317/*!
2318 \overload
2319
2320 Returns a copy of the image converted to the given \a format,
2321 using the specified \a colorTable.
2322
2323 Conversion from RGB formats to indexed formats is a slow operation
2324 and will use a straightforward nearest color approach, with no
2325 dithering.
2326*/
2327QImage QImage::convertToFormat(Format format, const QList<QRgb> &colorTable, Qt::ImageConversionFlags flags) const
2328{
2329 if (!d || d->format == format)
2330 return *this;
2331
2332 if (format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
2333 return QImage();
2334 if (format <= QImage::Format_Indexed8)
2335 return convertWithPalette(src: convertToFormat(f: QImage::Format_ARGB32, flags), format, clut: colorTable);
2336
2337 return convertToFormat(f: format, flags);
2338}
2339
2340/*!
2341 \since 5.9
2342
2343 Changes the format of the image to \a format without changing the
2344 data. Only works between formats of the same depth.
2345
2346 Returns \c true if successful.
2347
2348 This function can be used to change images with alpha-channels to
2349 their corresponding opaque formats if the data is known to be opaque-only,
2350 or to change the format of a given image buffer before overwriting
2351 it with new data.
2352
2353 \warning The function does not check if the image data is valid in the
2354 new format and will still return \c true if the depths are compatible.
2355 Operations on an image with invalid data are undefined.
2356
2357 \warning If the image is not detached, this will cause the data to be
2358 copied.
2359
2360 \sa hasAlphaChannel(), convertToFormat()
2361*/
2362
2363bool QImage::reinterpretAsFormat(Format format)
2364{
2365 if (!d)
2366 return false;
2367 if (d->format == format)
2368 return true;
2369 if (qt_depthForFormat(format) != qt_depthForFormat(format: d->format))
2370 return false;
2371 if (!isDetached()) { // Detach only if shared, not for read-only data.
2372 QImageData *oldD = d;
2373 detach();
2374 // In case detach() ran out of memory
2375 if (!d) {
2376 d = oldD;
2377 d->ref.ref();
2378 return false;
2379 }
2380 }
2381
2382 d->format = format;
2383 return true;
2384}
2385
2386/*!
2387 \since 5.13
2388
2389 Converts the image to the given \a format in place, detaching if necessary.
2390
2391 The specified image conversion \a flags control how the image data
2392 is handled during the conversion process.
2393
2394 \sa convertedTo()
2395*/
2396
2397void QImage::convertTo(Format format, Qt::ImageConversionFlags flags)
2398{
2399 if (!d || format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
2400 return;
2401
2402 if (d->format == format)
2403 return;
2404
2405 detach();
2406 if (convertToFormat_inplace(format, flags))
2407 return;
2408
2409 *this = convertToFormat_helper(format, flags);
2410}
2411
2412/*!
2413 \fn bool QImage::valid(const QPoint &pos) const
2414
2415 Returns \c true if \a pos is a valid coordinate pair within the
2416 image; otherwise returns \c false.
2417
2418 \sa rect(), QRect::contains()
2419*/
2420
2421/*!
2422 \overload
2423
2424 Returns \c true if QPoint(\a x, \a y) is a valid coordinate pair
2425 within the image; otherwise returns \c false.
2426*/
2427bool QImage::valid(int x, int y) const
2428{
2429 return d
2430 && x >= 0 && x < d->width
2431 && y >= 0 && y < d->height;
2432}
2433
2434/*!
2435 \fn int QImage::pixelIndex(const QPoint &position) const
2436
2437 Returns the pixel index at the given \a position.
2438
2439 If \a position is not valid, or if the image is not a paletted
2440 image (depth() > 8), the results are undefined.
2441
2442 \sa valid(), depth(), {QImage#Pixel Manipulation}{Pixel Manipulation}
2443*/
2444
2445/*!
2446 \overload
2447
2448 Returns the pixel index at (\a x, \a y).
2449*/
2450int QImage::pixelIndex(int x, int y) const
2451{
2452 if (!d || x < 0 || x >= d->width || y < 0 || y >= height()) {
2453 qWarning(msg: "QImage::pixelIndex: coordinate (%d,%d) out of range", x, y);
2454 return -12345;
2455 }
2456 const uchar * s = scanLine(i: y);
2457 switch(d->format) {
2458 case Format_Mono:
2459 return (*(s + (x >> 3)) >> (7- (x & 7))) & 1;
2460 case Format_MonoLSB:
2461 return (*(s + (x >> 3)) >> (x & 7)) & 1;
2462 case Format_Indexed8:
2463 return (int)s[x];
2464 default:
2465 qWarning(msg: "QImage::pixelIndex: Not applicable for %d-bpp images (no palette)", d->depth);
2466 }
2467 return 0;
2468}
2469
2470
2471/*!
2472 \fn QRgb QImage::pixel(const QPoint &position) const
2473
2474 Returns the color of the pixel at the given \a position.
2475
2476 If the \a position is not valid, the results are undefined.
2477
2478 \warning This function is expensive when used for massive pixel
2479 manipulations. Use constBits() or constScanLine() when many
2480 pixels needs to be read.
2481
2482 \sa setPixel(), valid(), constBits(), constScanLine(), {QImage#Pixel Manipulation}{Pixel
2483 Manipulation}
2484*/
2485
2486/*!
2487 \overload
2488
2489 Returns the color of the pixel at coordinates (\a x, \a y).
2490*/
2491QRgb QImage::pixel(int x, int y) const
2492{
2493 if (!d || x < 0 || x >= d->width || y < 0 || y >= d->height) {
2494 qWarning(msg: "QImage::pixel: coordinate (%d,%d) out of range", x, y);
2495 return 12345;
2496 }
2497
2498 const uchar *s = d->data + y * d->bytes_per_line;
2499
2500 int index = -1;
2501 switch (d->format) {
2502 case Format_Mono:
2503 index = (*(s + (x >> 3)) >> (~x & 7)) & 1;
2504 break;
2505 case Format_MonoLSB:
2506 index = (*(s + (x >> 3)) >> (x & 7)) & 1;
2507 break;
2508 case Format_Indexed8:
2509 index = s[x];
2510 break;
2511 default:
2512 break;
2513 }
2514 if (index >= 0) { // Indexed format
2515 if (index >= d->colortable.size()) {
2516 qWarning(msg: "QImage::pixel: color table index %d out of range.", index);
2517 return 0;
2518 }
2519 return d->colortable.at(i: index);
2520 }
2521
2522 switch (d->format) {
2523 case Format_RGB32:
2524 return 0xff000000 | reinterpret_cast<const QRgb *>(s)[x];
2525 case Format_ARGB32: // Keep old behaviour.
2526 case Format_ARGB32_Premultiplied:
2527 return reinterpret_cast<const QRgb *>(s)[x];
2528 case Format_RGBX8888:
2529 case Format_RGBA8888: // Match ARGB32 behavior.
2530 case Format_RGBA8888_Premultiplied:
2531 return RGBA2ARGB(x: reinterpret_cast<const quint32 *>(s)[x]);
2532 case Format_BGR30:
2533 case Format_A2BGR30_Premultiplied:
2534 return qConvertA2rgb30ToArgb32<PixelOrderBGR>(c: reinterpret_cast<const quint32 *>(s)[x]);
2535 case Format_RGB30:
2536 case Format_A2RGB30_Premultiplied:
2537 return qConvertA2rgb30ToArgb32<PixelOrderRGB>(c: reinterpret_cast<const quint32 *>(s)[x]);
2538 case Format_RGB16:
2539 return qConvertRgb16To32(c: reinterpret_cast<const quint16 *>(s)[x]);
2540 case Format_RGBX64:
2541 case Format_RGBA64: // Match ARGB32 behavior.
2542 case Format_RGBA64_Premultiplied:
2543 return reinterpret_cast<const QRgba64 *>(s)[x].toArgb32();
2544 case Format_RGBX16FPx4:
2545 case Format_RGBA16FPx4: // Match ARGB32 behavior.
2546 case Format_RGBA16FPx4_Premultiplied:
2547 return reinterpret_cast<const QRgbaFloat16 *>(s)[x].toArgb32();
2548 case Format_RGBX32FPx4:
2549 case Format_RGBA32FPx4: // Match ARGB32 behavior.
2550 case Format_RGBA32FPx4_Premultiplied:
2551 return reinterpret_cast<const QRgbaFloat32 *>(s)[x].toArgb32();
2552 default:
2553 break;
2554 }
2555 const QPixelLayout *layout = &qPixelLayouts[d->format];
2556 uint result;
2557 return *layout->fetchToARGB32PM(&result, s, x, 1, nullptr, nullptr);
2558}
2559
2560/*!
2561 \fn void QImage::setPixel(const QPoint &position, uint index_or_rgb)
2562
2563 Sets the pixel index or color at the given \a position to \a
2564 index_or_rgb.
2565
2566 If the image's format is either monochrome or paletted, the given \a
2567 index_or_rgb value must be an index in the image's color table,
2568 otherwise the parameter must be a QRgb value.
2569
2570 If \a position is not a valid coordinate pair in the image, or if
2571 \a index_or_rgb >= colorCount() in the case of monochrome and
2572 paletted images, the result is undefined.
2573
2574 \warning This function is expensive due to the call of the internal
2575 \c{detach()} function called within; if performance is a concern, we
2576 recommend the use of scanLine() or bits() to access pixel data directly.
2577
2578 \sa pixel(), {QImage#Pixel Manipulation}{Pixel Manipulation}
2579*/
2580
2581/*!
2582 \overload
2583
2584 Sets the pixel index or color at (\a x, \a y) to \a index_or_rgb.
2585*/
2586void QImage::setPixel(int x, int y, uint index_or_rgb)
2587{
2588 if (!d || x < 0 || x >= width() || y < 0 || y >= height()) {
2589 qWarning(msg: "QImage::setPixel: coordinate (%d,%d) out of range", x, y);
2590 return;
2591 }
2592 // detach is called from within scanLine
2593 uchar * s = scanLine(i: y);
2594 switch(d->format) {
2595 case Format_Mono:
2596 case Format_MonoLSB:
2597 if (index_or_rgb > 1) {
2598 qWarning(msg: "QImage::setPixel: Index %d out of range", index_or_rgb);
2599 } else if (format() == Format_MonoLSB) {
2600 if (index_or_rgb==0)
2601 *(s + (x >> 3)) &= ~(1 << (x & 7));
2602 else
2603 *(s + (x >> 3)) |= (1 << (x & 7));
2604 } else {
2605 if (index_or_rgb==0)
2606 *(s + (x >> 3)) &= ~(1 << (7-(x & 7)));
2607 else
2608 *(s + (x >> 3)) |= (1 << (7-(x & 7)));
2609 }
2610 return;
2611 case Format_Indexed8:
2612 if (index_or_rgb >= (uint)d->colortable.size()) {
2613 qWarning(msg: "QImage::setPixel: Index %d out of range", index_or_rgb);
2614 return;
2615 }
2616 s[x] = index_or_rgb;
2617 return;
2618 case Format_RGB32:
2619 //make sure alpha is 255, we depend on it in qdrawhelper for cases
2620 // when image is set as a texture pattern on a qbrush
2621 ((uint *)s)[x] = 0xff000000 | index_or_rgb;
2622 return;
2623 case Format_ARGB32:
2624 case Format_ARGB32_Premultiplied:
2625 ((uint *)s)[x] = index_or_rgb;
2626 return;
2627 case Format_RGB16:
2628 ((quint16 *)s)[x] = qConvertRgb32To16(c: index_or_rgb);
2629 return;
2630 case Format_RGBX8888:
2631 ((uint *)s)[x] = ARGB2RGBA(x: 0xff000000 | index_or_rgb);
2632 return;
2633 case Format_RGBA8888:
2634 case Format_RGBA8888_Premultiplied:
2635 ((uint *)s)[x] = ARGB2RGBA(x: index_or_rgb);
2636 return;
2637 case Format_BGR30:
2638 ((uint *)s)[x] = qConvertRgb32ToRgb30<PixelOrderBGR>(c: index_or_rgb);
2639 return;
2640 case Format_A2BGR30_Premultiplied:
2641 ((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderBGR>(c: index_or_rgb);
2642 return;
2643 case Format_RGB30:
2644 ((uint *)s)[x] = qConvertRgb32ToRgb30<PixelOrderRGB>(c: index_or_rgb);
2645 return;
2646 case Format_A2RGB30_Premultiplied:
2647 ((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderRGB>(c: index_or_rgb);
2648 return;
2649 case Format_RGBX64:
2650 ((QRgba64 *)s)[x] = QRgba64::fromArgb32(rgb: index_or_rgb | 0xff000000);
2651 return;
2652 case Format_RGBA64:
2653 case Format_RGBA64_Premultiplied:
2654 ((QRgba64 *)s)[x] = QRgba64::fromArgb32(rgb: index_or_rgb);
2655 return;
2656 case Format_RGBX16FPx4:
2657 ((QRgbaFloat16 *)s)[x] = QRgbaFloat16::fromArgb32(rgb: index_or_rgb | 0xff000000);
2658 return;
2659 case Format_RGBA16FPx4:
2660 case Format_RGBA16FPx4_Premultiplied:
2661 ((QRgbaFloat16 *)s)[x] = QRgbaFloat16::fromArgb32(rgb: index_or_rgb);
2662 return;
2663 case Format_RGBX32FPx4:
2664 ((QRgbaFloat32 *)s)[x] = QRgbaFloat32::fromArgb32(rgb: index_or_rgb | 0xff000000);
2665 return;
2666 case Format_RGBA32FPx4:
2667 case Format_RGBA32FPx4_Premultiplied:
2668 ((QRgbaFloat32 *)s)[x] = QRgbaFloat32::fromArgb32(rgb: index_or_rgb);
2669 return;
2670 case Format_Invalid:
2671 case NImageFormats:
2672 Q_ASSERT(false);
2673 return;
2674 default:
2675 break;
2676 }
2677
2678 const QPixelLayout *layout = &qPixelLayouts[d->format];
2679 if (!hasAlphaChannel())
2680 layout->storeFromRGB32(s, &index_or_rgb, x, 1, nullptr, nullptr);
2681 else
2682 layout->storeFromARGB32PM(s, &index_or_rgb, x, 1, nullptr, nullptr);
2683}
2684
2685/*!
2686 \fn QColor QImage::pixelColor(const QPoint &position) const
2687 \since 5.6
2688
2689 Returns the color of the pixel at the given \a position as a QColor.
2690
2691 If the \a position is not valid, an invalid QColor is returned.
2692
2693 \warning This function is expensive when used for massive pixel
2694 manipulations. Use constBits() or constScanLine() when many
2695 pixels needs to be read.
2696
2697 \sa setPixel(), valid(), constBits(), constScanLine(), {QImage#Pixel Manipulation}{Pixel
2698 Manipulation}
2699*/
2700
2701/*!
2702 \overload
2703 \since 5.6
2704
2705 Returns the color of the pixel at coordinates (\a x, \a y) as a QColor.
2706*/
2707QColor QImage::pixelColor(int x, int y) const
2708{
2709 if (!d || x < 0 || x >= d->width || y < 0 || y >= height()) {
2710 qWarning(msg: "QImage::pixelColor: coordinate (%d,%d) out of range", x, y);
2711 return QColor();
2712 }
2713
2714 QRgba64 c;
2715 const uchar * s = constScanLine(i: y);
2716 switch (d->format) {
2717 case Format_BGR30:
2718 case Format_A2BGR30_Premultiplied:
2719 c = qConvertA2rgb30ToRgb64<PixelOrderBGR>(rgb: reinterpret_cast<const quint32 *>(s)[x]);
2720 break;
2721 case Format_RGB30:
2722 case Format_A2RGB30_Premultiplied:
2723 c = qConvertA2rgb30ToRgb64<PixelOrderRGB>(rgb: reinterpret_cast<const quint32 *>(s)[x]);
2724 break;
2725 case Format_RGBX64:
2726 case Format_RGBA64:
2727 case Format_RGBA64_Premultiplied:
2728 c = reinterpret_cast<const QRgba64 *>(s)[x];
2729 break;
2730 case Format_Grayscale16: {
2731 quint16 v = reinterpret_cast<const quint16 *>(s)[x];
2732 return QColor(qRgba64(r: v, g: v, b: v, a: 0xffff));
2733 }
2734 case Format_RGBX16FPx4:
2735 case Format_RGBA16FPx4:
2736 case Format_RGBA16FPx4_Premultiplied: {
2737 QRgbaFloat16 p = reinterpret_cast<const QRgbaFloat16 *>(s)[x];
2738 if (d->format == Format_RGBA16FPx4_Premultiplied)
2739 p = p.unpremultiplied();
2740 QColor color;
2741 color.setRgbF(r: p.red(), g: p.green(), b: p.blue(), a: p.alpha());
2742 return color;
2743 }
2744 case Format_RGBX32FPx4:
2745 case Format_RGBA32FPx4:
2746 case Format_RGBA32FPx4_Premultiplied: {
2747 QRgbaFloat32 p = reinterpret_cast<const QRgbaFloat32 *>(s)[x];
2748 if (d->format == Format_RGBA32FPx4_Premultiplied)
2749 p = p.unpremultiplied();
2750 QColor color;
2751 color.setRgbF(r: p.red(), g: p.green(), b: p.blue(), a: p.alpha());
2752 return color;
2753 }
2754 default:
2755 c = QRgba64::fromArgb32(rgb: pixel(x, y));
2756 break;
2757 }
2758 // QColor is always unpremultiplied
2759 if (hasAlphaChannel() && qPixelLayouts[d->format].premultiplied)
2760 c = c.unpremultiplied();
2761 return QColor(c);
2762}
2763
2764/*!
2765 \fn void QImage::setPixelColor(const QPoint &position, const QColor &color)
2766 \since 5.6
2767
2768 Sets the color at the given \a position to \a color.
2769
2770 If \a position is not a valid coordinate pair in the image, or
2771 the image's format is either monochrome or paletted, the result is undefined.
2772
2773 \warning This function is expensive due to the call of the internal
2774 \c{detach()} function called within; if performance is a concern, we
2775 recommend the use of scanLine() or bits() to access pixel data directly.
2776
2777 \sa pixel(), bits(), scanLine(), {QImage#Pixel Manipulation}{Pixel Manipulation}
2778*/
2779
2780/*!
2781 \overload
2782 \since 5.6
2783
2784 Sets the pixel color at (\a x, \a y) to \a color.
2785*/
2786void QImage::setPixelColor(int x, int y, const QColor &color)
2787{
2788 if (!d || x < 0 || x >= width() || y < 0 || y >= height()) {
2789 qWarning(msg: "QImage::setPixelColor: coordinate (%d,%d) out of range", x, y);
2790 return;
2791 }
2792
2793 if (!color.isValid()) {
2794 qWarning(msg: "QImage::setPixelColor: color is invalid");
2795 return;
2796 }
2797
2798 // QColor is always unpremultiplied
2799 QRgba64 c = color.rgba64();
2800 if (!hasAlphaChannel())
2801 c.setAlpha(65535);
2802 else if (qPixelLayouts[d->format].premultiplied)
2803 c = c.premultiplied();
2804 // detach is called from within scanLine
2805 uchar * s = scanLine(i: y);
2806 switch (d->format) {
2807 case Format_Mono:
2808 case Format_MonoLSB:
2809 case Format_Indexed8:
2810 qWarning(msg: "QImage::setPixelColor: called on monochrome or indexed format");
2811 return;
2812 case Format_BGR30:
2813 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderBGR>(c) | 0xc0000000;
2814 return;
2815 case Format_A2BGR30_Premultiplied:
2816 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderBGR>(c);
2817 return;
2818 case Format_RGB30:
2819 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderRGB>(c) | 0xc0000000;
2820 return;
2821 case Format_A2RGB30_Premultiplied:
2822 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderRGB>(c);
2823 return;
2824 case Format_RGBX64:
2825 case Format_RGBA64:
2826 case Format_RGBA64_Premultiplied:
2827 ((QRgba64 *)s)[x] = c;
2828 return;
2829 case Format_RGBX16FPx4:
2830 case Format_RGBA16FPx4:
2831 case Format_RGBA16FPx4_Premultiplied: {
2832 float r, g, b, a;
2833 color.getRgbF(r: &r, g: &g, b: &b, a: &a);
2834 if (d->format == Format_RGBX16FPx4)
2835 a = 1.0f;
2836 QRgbaFloat16 c16f{.r: qfloat16(r), .g: qfloat16(g), .b: qfloat16(b), .a: qfloat16(a)};
2837 if (d->format == Format_RGBA16FPx4_Premultiplied)
2838 c16f = c16f.premultiplied();
2839 ((QRgbaFloat16 *)s)[x] = c16f;
2840 return;
2841 }
2842 case Format_RGBX32FPx4:
2843 case Format_RGBA32FPx4:
2844 case Format_RGBA32FPx4_Premultiplied: {
2845 float r, g, b, a;
2846 color.getRgbF(r: &r, g: &g, b: &b, a: &a);
2847 if (d->format == Format_RGBX32FPx4)
2848 a = 1.0f;
2849 QRgbaFloat32 c32f{.r: r, .g: g, .b: b, .a: a};
2850 if (d->format == Format_RGBA32FPx4_Premultiplied)
2851 c32f = c32f.premultiplied();
2852 ((QRgbaFloat32 *)s)[x] = c32f;
2853 return;
2854 }
2855 default:
2856 setPixel(x, y, index_or_rgb: c.toArgb32());
2857 return;
2858 }
2859}
2860
2861/*!
2862 Returns \c true if all the colors in the image are shades of gray
2863 (i.e. their red, green and blue components are equal); otherwise
2864 false.
2865
2866 Note that this function is slow for images without color table.
2867
2868 \sa isGrayscale()
2869*/
2870bool QImage::allGray() const
2871{
2872 if (!d)
2873 return true;
2874
2875 switch (d->format) {
2876 case Format_Mono:
2877 case Format_MonoLSB:
2878 case Format_Indexed8:
2879 for (int i = 0; i < d->colortable.size(); ++i) {
2880 if (!qIsGray(rgb: d->colortable.at(i)))
2881 return false;
2882 }
2883 return true;
2884 case Format_Alpha8:
2885 return false;
2886 case Format_Grayscale8:
2887 case Format_Grayscale16:
2888 return true;
2889 case Format_RGB32:
2890 case Format_ARGB32:
2891 case Format_ARGB32_Premultiplied:
2892#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
2893 case Format_RGBX8888:
2894 case Format_RGBA8888:
2895 case Format_RGBA8888_Premultiplied:
2896#endif
2897 for (int j = 0; j < d->height; ++j) {
2898 const QRgb *b = (const QRgb *)constScanLine(i: j);
2899 for (int i = 0; i < d->width; ++i) {
2900 if (!qIsGray(rgb: b[i]))
2901 return false;
2902 }
2903 }
2904 return true;
2905 case Format_RGB16:
2906 for (int j = 0; j < d->height; ++j) {
2907 const quint16 *b = (const quint16 *)constScanLine(i: j);
2908 for (int i = 0; i < d->width; ++i) {
2909 if (!qIsGray(rgb: qConvertRgb16To32(c: b[i])))
2910 return false;
2911 }
2912 }
2913 return true;
2914 default:
2915 break;
2916 }
2917
2918 uint buffer[BufferSize];
2919 const QPixelLayout *layout = &qPixelLayouts[d->format];
2920 const auto fetch = layout->fetchToARGB32PM;
2921 for (int j = 0; j < d->height; ++j) {
2922 const uchar *b = constScanLine(i: j);
2923 int x = 0;
2924 while (x < d->width) {
2925 int l = qMin(a: d->width - x, b: BufferSize);
2926 const uint *ptr = fetch(buffer, b, x, l, nullptr, nullptr);
2927 for (int i = 0; i < l; ++i) {
2928 if (!qIsGray(rgb: ptr[i]))
2929 return false;
2930 }
2931 x += l;
2932 }
2933 }
2934 return true;
2935}
2936
2937/*!
2938 For 32-bit images, this function is equivalent to allGray().
2939
2940 For color indexed images, this function returns \c true if
2941 color(i) is QRgb(i, i, i) for all indexes of the color table;
2942 otherwise returns \c false.
2943
2944 \sa allGray(), {QImage#Image Formats}{Image Formats}
2945*/
2946bool QImage::isGrayscale() const
2947{
2948 if (!d)
2949 return false;
2950
2951 if (d->format == QImage::Format_Alpha8)
2952 return false;
2953
2954 if (d->format == QImage::Format_Grayscale8 || d->format == QImage::Format_Grayscale16)
2955 return true;
2956
2957 switch (depth()) {
2958 case 32:
2959 case 24:
2960 case 16:
2961 return allGray();
2962 case 8: {
2963 Q_ASSERT(d->format == QImage::Format_Indexed8);
2964 for (int i = 0; i < colorCount(); i++)
2965 if (d->colortable.at(i) != qRgb(r: i,g: i,b: i))
2966 return false;
2967 return true;
2968 }
2969 }
2970 return false;
2971}
2972
2973/*!
2974 \fn QImage QImage::scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode,
2975 Qt::TransformationMode transformMode) const
2976 \overload
2977
2978 Returns a copy of the image scaled to a rectangle with the given
2979 \a width and \a height according to the given \a aspectRatioMode
2980 and \a transformMode.
2981
2982 If either the \a width or the \a height is zero or negative, this
2983 function returns a null image.
2984*/
2985
2986/*!
2987 \fn QImage QImage::scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode,
2988 Qt::TransformationMode transformMode) const
2989
2990 Returns a copy of the image scaled to a rectangle defined by the
2991 given \a size according to the given \a aspectRatioMode and \a
2992 transformMode.
2993
2994 \image qimage-scaling.png
2995
2996 \list
2997 \li If \a aspectRatioMode is Qt::IgnoreAspectRatio, the image
2998 is scaled to \a size.
2999 \li If \a aspectRatioMode is Qt::KeepAspectRatio, the image is
3000 scaled to a rectangle as large as possible inside \a size, preserving the aspect ratio.
3001 \li If \a aspectRatioMode is Qt::KeepAspectRatioByExpanding,
3002 the image is scaled to a rectangle as small as possible
3003 outside \a size, preserving the aspect ratio.
3004 \endlist
3005
3006 If the given \a size is empty, this function returns a null image.
3007
3008 \sa isNull(), {QImage#Image Transformations}{Image
3009 Transformations}
3010*/
3011QImage Q_TRACE_INSTRUMENT(qtgui) QImage::scaled(const QSize& s, Qt::AspectRatioMode aspectMode, Qt::TransformationMode mode) const
3012{
3013 if (!d) {
3014 qWarning(msg: "QImage::scaled: Image is a null image");
3015 return QImage();
3016 }
3017 if (s.isEmpty())
3018 return QImage();
3019
3020 QSize newSize = size();
3021 newSize.scale(s, mode: aspectMode);
3022 newSize.rwidth() = qMax(a: newSize.width(), b: 1);
3023 newSize.rheight() = qMax(a: newSize.height(), b: 1);
3024 if (newSize == size())
3025 return *this;
3026
3027 Q_TRACE_SCOPE(QImage_scaled, s, aspectMode, mode);
3028
3029 QTransform wm = QTransform::fromScale(dx: (qreal)newSize.width() / width(), dy: (qreal)newSize.height() / height());
3030 QImage img = transformed(matrix: wm, mode);
3031 return img;
3032}
3033
3034/*!
3035 \fn QImage QImage::scaledToWidth(int width, Qt::TransformationMode mode) const
3036
3037 Returns a scaled copy of the image. The returned image is scaled
3038 to the given \a width using the specified transformation \a
3039 mode.
3040
3041 This function automatically calculates the height of the image so
3042 that its aspect ratio is preserved.
3043
3044 If the given \a width is 0 or negative, a null image is returned.
3045
3046 \sa {QImage#Image Transformations}{Image Transformations}
3047*/
3048QImage Q_TRACE_INSTRUMENT(qtgui) QImage::scaledToWidth(int w, Qt::TransformationMode mode) const
3049{
3050 if (!d) {
3051 qWarning(msg: "QImage::scaleWidth: Image is a null image");
3052 return QImage();
3053 }
3054 if (w <= 0)
3055 return QImage();
3056
3057 Q_TRACE_SCOPE(QImage_scaledToWidth, w, mode);
3058
3059 qreal factor = (qreal) w / width();
3060 QTransform wm = QTransform::fromScale(dx: factor, dy: factor);
3061 return transformed(matrix: wm, mode);
3062}
3063
3064/*!
3065 \fn QImage QImage::scaledToHeight(int height, Qt::TransformationMode mode) const
3066
3067 Returns a scaled copy of the image. The returned image is scaled
3068 to the given \a height using the specified transformation \a
3069 mode.
3070
3071 This function automatically calculates the width of the image so that
3072 the ratio of the image is preserved.
3073
3074 If the given \a height is 0 or negative, a null image is returned.
3075
3076 \sa {QImage#Image Transformations}{Image Transformations}
3077*/
3078QImage Q_TRACE_INSTRUMENT(qtgui) QImage::scaledToHeight(int h, Qt::TransformationMode mode) const
3079{
3080 if (!d) {
3081 qWarning(msg: "QImage::scaleHeight: Image is a null image");
3082 return QImage();
3083 }
3084 if (h <= 0)
3085 return QImage();
3086
3087 Q_TRACE_SCOPE(QImage_scaledToHeight, h, mode);
3088
3089 qreal factor = (qreal) h / height();
3090 QTransform wm = QTransform::fromScale(dx: factor, dy: factor);
3091 return transformed(matrix: wm, mode);
3092}
3093
3094/*!
3095 Builds and returns a 1-bpp mask from the alpha buffer in this
3096 image. Returns a null image if the image's format is
3097 QImage::Format_RGB32.
3098
3099 The \a flags argument is a bitwise-OR of the
3100 Qt::ImageConversionFlags, and controls the conversion
3101 process. Passing 0 for flags sets all the default options.
3102
3103 The returned image has little-endian bit order (i.e. the image's
3104 format is QImage::Format_MonoLSB), which you can convert to
3105 big-endian (QImage::Format_Mono) using the convertToFormat()
3106 function.
3107
3108 \sa createHeuristicMask(), {QImage#Image Transformations}{Image
3109 Transformations}
3110*/
3111QImage Q_TRACE_INSTRUMENT(qtgui) QImage::createAlphaMask(Qt::ImageConversionFlags flags) const
3112{
3113 if (!d || d->format == QImage::Format_RGB32)
3114 return QImage();
3115
3116 if (d->depth == 1) {
3117 // A monochrome pixmap, with alpha channels on those two colors.
3118 // Pretty unlikely, so use less efficient solution.
3119 return convertToFormat(f: Format_Indexed8, flags).createAlphaMask(flags);
3120 }
3121
3122 QImage mask(d->width, d->height, Format_MonoLSB);
3123 if (!mask.isNull()) {
3124 dither_to_Mono(dst: mask.d, src: d, flags, fromalpha: true);
3125 copyPhysicalMetadata(dst: mask.d, src: d);
3126 }
3127 return mask;
3128}
3129
3130#ifndef QT_NO_IMAGE_HEURISTIC_MASK
3131/*!
3132 Creates and returns a 1-bpp heuristic mask for this image.
3133
3134 The function works by selecting a color from one of the corners,
3135 then chipping away pixels of that color starting at all the edges.
3136 The four corners vote for which color is to be masked away. In
3137 case of a draw (this generally means that this function is not
3138 applicable to the image), the result is arbitrary.
3139
3140 The returned image has little-endian bit order (i.e. the image's
3141 format is QImage::Format_MonoLSB), which you can convert to
3142 big-endian (QImage::Format_Mono) using the convertToFormat()
3143 function.
3144
3145 If \a clipTight is true (the default) the mask is just large
3146 enough to cover the pixels; otherwise, the mask is larger than the
3147 data pixels.
3148
3149 Note that this function disregards the alpha buffer.
3150
3151 \sa createAlphaMask(), {QImage#Image Transformations}{Image
3152 Transformations}
3153*/
3154
3155QImage QImage::createHeuristicMask(bool clipTight) const
3156{
3157 if (!d)
3158 return QImage();
3159
3160 if (d->depth != 32) {
3161 QImage img32 = convertToFormat(f: Format_RGB32);
3162 return img32.createHeuristicMask(clipTight);
3163 }
3164
3165#define PIX(x,y) (*((const QRgb*)scanLine(y)+x) & 0x00ffffff)
3166
3167 int w = width();
3168 int h = height();
3169 QImage m(w, h, Format_MonoLSB);
3170 QIMAGE_SANITYCHECK_MEMORY(m);
3171 m.setColorCount(2);
3172 m.setColor(i: 0, c: QColor(Qt::color0).rgba());
3173 m.setColor(i: 1, c: QColor(Qt::color1).rgba());
3174 m.fill(pixel: 0xff);
3175
3176 QRgb background = PIX(0,0);
3177 if (background != PIX(w-1,0) &&
3178 background != PIX(0,h-1) &&
3179 background != PIX(w-1,h-1)) {
3180 background = PIX(w-1,0);
3181 if (background != PIX(w-1,h-1) &&
3182 background != PIX(0,h-1) &&
3183 PIX(0,h-1) == PIX(w-1,h-1)) {
3184 background = PIX(w-1,h-1);
3185 }
3186 }
3187
3188 int x,y;
3189 bool done = false;
3190 uchar *ypp, *ypc, *ypn;
3191 while(!done) {
3192 done = true;
3193 ypn = m.scanLine(i: 0);
3194 ypc = nullptr;
3195 for (y = 0; y < h; y++) {
3196 ypp = ypc;
3197 ypc = ypn;
3198 ypn = (y == h-1) ? nullptr : m.scanLine(i: y+1);
3199 const QRgb *p = (const QRgb *)scanLine(i: y);
3200 for (x = 0; x < w; x++) {
3201 // slowness here - it's possible to do six of these tests
3202 // together in one go. oh well.
3203 if ((x == 0 || y == 0 || x == w-1 || y == h-1 ||
3204 !(*(ypc + ((x-1) >> 3)) & (1 << ((x-1) & 7))) ||
3205 !(*(ypc + ((x+1) >> 3)) & (1 << ((x+1) & 7))) ||
3206 !(*(ypp + (x >> 3)) & (1 << (x & 7))) ||
3207 !(*(ypn + (x >> 3)) & (1 << (x & 7)))) &&
3208 ( (*(ypc + (x >> 3)) & (1 << (x & 7)))) &&
3209 ((*p & 0x00ffffff) == background)) {
3210 done = false;
3211 *(ypc + (x >> 3)) &= ~(1 << (x & 7));
3212 }
3213 p++;
3214 }
3215 }
3216 }
3217
3218 if (!clipTight) {
3219 ypn = m.scanLine(i: 0);
3220 ypc = nullptr;
3221 for (y = 0; y < h; y++) {
3222 ypp = ypc;
3223 ypc = ypn;
3224 ypn = (y == h-1) ? nullptr : m.scanLine(i: y+1);
3225 const QRgb *p = (const QRgb *)scanLine(i: y);
3226 for (x = 0; x < w; x++) {
3227 if ((*p & 0x00ffffff) != background) {
3228 if (x > 0)
3229 *(ypc + ((x-1) >> 3)) |= (1 << ((x-1) & 7));
3230 if (x < w-1)
3231 *(ypc + ((x+1) >> 3)) |= (1 << ((x+1) & 7));
3232 if (y > 0)
3233 *(ypp + (x >> 3)) |= (1 << (x & 7));
3234 if (y < h-1)
3235 *(ypn + (x >> 3)) |= (1 << (x & 7));
3236 }
3237 p++;
3238 }
3239 }
3240 }
3241
3242#undef PIX
3243
3244 copyPhysicalMetadata(dst: m.d, src: d);
3245 return m;
3246}
3247#endif //QT_NO_IMAGE_HEURISTIC_MASK
3248
3249/*!
3250 Creates and returns a mask for this image based on the given \a
3251 color value. If the \a mode is MaskInColor (the default value),
3252 all pixels matching \a color will be opaque pixels in the mask. If
3253 \a mode is MaskOutColor, all pixels matching the given color will
3254 be transparent.
3255
3256 \sa createAlphaMask(), createHeuristicMask()
3257*/
3258
3259QImage QImage::createMaskFromColor(QRgb color, Qt::MaskMode mode) const
3260{
3261 if (!d)
3262 return QImage();
3263 QImage maskImage(size(), QImage::Format_MonoLSB);
3264 QIMAGE_SANITYCHECK_MEMORY(maskImage);
3265 maskImage.fill(pixel: 0);
3266 uchar *s = maskImage.bits();
3267 if (!s)
3268 return QImage();
3269
3270 if (depth() == 32) {
3271 for (int h = 0; h < d->height; h++) {
3272 const uint *sl = (const uint *) scanLine(i: h);
3273 for (int w = 0; w < d->width; w++) {
3274 if (sl[w] == color)
3275 *(s + (w >> 3)) |= (1 << (w & 7));
3276 }
3277 s += maskImage.bytesPerLine();
3278 }
3279 } else {
3280 for (int h = 0; h < d->height; h++) {
3281 for (int w = 0; w < d->width; w++) {
3282 if ((uint) pixel(x: w, y: h) == color)
3283 *(s + (w >> 3)) |= (1 << (w & 7));
3284 }
3285 s += maskImage.bytesPerLine();
3286 }
3287 }
3288 if (mode == Qt::MaskOutColor)
3289 maskImage.invertPixels();
3290
3291 copyPhysicalMetadata(dst: maskImage.d, src: d);
3292 return maskImage;
3293}
3294
3295/*!
3296 \fn QImage QImage::mirrored(bool horizontal = false, bool vertical = true) const &
3297 \fn QImage QImage::mirrored(bool horizontal = false, bool vertical = true) &&
3298
3299 Returns a mirror of the image, mirrored in the horizontal and/or
3300 the vertical direction depending on whether \a horizontal and \a
3301 vertical are set to true or false.
3302
3303 Note that the original image is not changed.
3304
3305 \sa mirror(), {QImage#Image Transformations}{Image Transformations}
3306*/
3307
3308/*!
3309 \fn void QImage::mirror(bool horizontal = false, bool vertical = true)
3310 \since 6.0
3311
3312 Mirrors of the image in the horizontal and/or the vertical direction depending
3313 on whether \a horizontal and \a vertical are set to true or false.
3314
3315 \sa mirrored(), {QImage#Image Transformations}{Image Transformations}
3316*/
3317
3318template<class T> inline void do_mirror_data(QImageData *dst, QImageData *src,
3319 int dstX0, int dstY0,
3320 int dstXIncr, int dstYIncr,
3321 int w, int h)
3322{
3323 if (dst == src) {
3324 // When mirroring in-place, stop in the middle for one of the directions, since we
3325 // are swapping the bytes instead of merely copying.
3326 const int srcXEnd = (dstX0 && !dstY0) ? w / 2 : w;
3327 const int srcYEnd = dstY0 ? h / 2 : h;
3328 for (int srcY = 0, dstY = dstY0; srcY < srcYEnd; ++srcY, dstY += dstYIncr) {
3329 T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3330 T *dstPtr = (T *) (dst->data + dstY * dst->bytes_per_line);
3331 for (int srcX = 0, dstX = dstX0; srcX < srcXEnd; ++srcX, dstX += dstXIncr)
3332 std::swap(srcPtr[srcX], dstPtr[dstX]);
3333 }
3334 // If mirroring both ways, the middle line needs to be mirrored horizontally only.
3335 if (dstX0 && dstY0 && (h & 1)) {
3336 int srcY = h / 2;
3337 int srcXEnd2 = w / 2;
3338 T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3339 for (int srcX = 0, dstX = dstX0; srcX < srcXEnd2; ++srcX, dstX += dstXIncr)
3340 std::swap(srcPtr[srcX], srcPtr[dstX]);
3341 }
3342 } else {
3343 for (int srcY = 0, dstY = dstY0; srcY < h; ++srcY, dstY += dstYIncr) {
3344 T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3345 T *dstPtr = (T *) (dst->data + dstY * dst->bytes_per_line);
3346 for (int srcX = 0, dstX = dstX0; srcX < w; ++srcX, dstX += dstXIncr)
3347 dstPtr[dstX] = srcPtr[srcX];
3348 }
3349 }
3350}
3351
3352inline void do_flip(QImageData *dst, QImageData *src, int w, int h, int depth)
3353{
3354 const int data_bytes_per_line = w * (depth / 8);
3355 if (dst == src) {
3356 uint *srcPtr = reinterpret_cast<uint *>(src->data);
3357 uint *dstPtr = reinterpret_cast<uint *>(dst->data + (h - 1) * dst->bytes_per_line);
3358 h = h / 2;
3359 const int uint_per_line = (data_bytes_per_line + 3) >> 2; // bytes per line must be a multiple of 4
3360 for (int y = 0; y < h; ++y) {
3361 // This is auto-vectorized, no need for SSE2 or NEON versions:
3362 for (int x = 0; x < uint_per_line; x++) {
3363 const uint d = dstPtr[x];
3364 const uint s = srcPtr[x];
3365 dstPtr[x] = s;
3366 srcPtr[x] = d;
3367 }
3368 srcPtr += src->bytes_per_line >> 2;
3369 dstPtr -= dst->bytes_per_line >> 2;
3370 }
3371
3372 } else {
3373 const uchar *srcPtr = src->data;
3374 uchar *dstPtr = dst->data + (h - 1) * dst->bytes_per_line;
3375 for (int y = 0; y < h; ++y) {
3376 memcpy(dest: dstPtr, src: srcPtr, n: data_bytes_per_line);
3377 srcPtr += src->bytes_per_line;
3378 dstPtr -= dst->bytes_per_line;
3379 }
3380 }
3381}
3382
3383inline void do_mirror(QImageData *dst, QImageData *src, bool horizontal, bool vertical)
3384{
3385 Q_ASSERT(src->width == dst->width && src->height == dst->height && src->depth == dst->depth);
3386 int w = src->width;
3387 int h = src->height;
3388 int depth = src->depth;
3389
3390 if (src->depth == 1) {
3391 w = (w + 7) / 8; // byte aligned width
3392 depth = 8;
3393 }
3394
3395 if (vertical && !horizontal) {
3396 // This one is simple and common, so do it a little more optimized
3397 do_flip(dst, src, w, h, depth);
3398 return;
3399 }
3400
3401 int dstX0 = 0, dstXIncr = 1;
3402 int dstY0 = 0, dstYIncr = 1;
3403 if (horizontal) {
3404 // 0 -> w-1, 1 -> w-2, 2 -> w-3, ...
3405 dstX0 = w - 1;
3406 dstXIncr = -1;
3407 }
3408 if (vertical) {
3409 // 0 -> h-1, 1 -> h-2, 2 -> h-3, ...
3410 dstY0 = h - 1;
3411 dstYIncr = -1;
3412 }
3413
3414 switch (depth) {
3415 case 128:
3416 do_mirror_data<QRgbaFloat32>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3417 break;
3418 case 64:
3419 do_mirror_data<quint64>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3420 break;
3421 case 32:
3422 do_mirror_data<quint32>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3423 break;
3424 case 24:
3425 do_mirror_data<quint24>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3426 break;
3427 case 16:
3428 do_mirror_data<quint16>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3429 break;
3430 case 8:
3431 do_mirror_data<quint8>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3432 break;
3433 default:
3434 Q_ASSERT(false);
3435 break;
3436 }
3437
3438 // The bytes are now all in the correct place. In addition, the bits in the individual
3439 // bytes have to be flipped too when horizontally mirroring a 1 bit-per-pixel image.
3440 if (horizontal && dst->depth == 1) {
3441 Q_ASSERT(dst->format == QImage::Format_Mono || dst->format == QImage::Format_MonoLSB);
3442 const int shift = 8 - (dst->width % 8);
3443 const uchar *bitflip = qt_get_bitflip_array();
3444 for (int y = 0; y < h; ++y) {
3445 uchar *begin = dst->data + y * dst->bytes_per_line;
3446 uchar *end = begin + dst->bytes_per_line;
3447 for (uchar *p = begin; p < end; ++p) {
3448 *p = bitflip[*p];
3449 // When the data is non-byte aligned, an extra bit shift (of the number of
3450 // unused bits at the end) is needed for the entire scanline.
3451 if (shift != 8 && p != begin) {
3452 if (dst->format == QImage::Format_Mono) {
3453 for (int i = 0; i < shift; ++i) {
3454 p[-1] <<= 1;
3455 p[-1] |= (*p & (128 >> i)) >> (7 - i);
3456 }
3457 } else {
3458 for (int i = 0; i < shift; ++i) {
3459 p[-1] >>= 1;
3460 p[-1] |= (*p & (1 << i)) << (7 - i);
3461 }
3462 }
3463 }
3464 }
3465 if (shift != 8) {
3466 if (dst->format == QImage::Format_Mono)
3467 end[-1] <<= shift;
3468 else
3469 end[-1] >>= shift;
3470 }
3471 }
3472 }
3473}
3474
3475/*!
3476 \internal
3477*/
3478QImage QImage::mirrored_helper(bool horizontal, bool vertical) const
3479{
3480 if (!d)
3481 return QImage();
3482
3483 if ((d->width <= 1 && d->height <= 1) || (!horizontal && !vertical))
3484 return *this;
3485
3486 // Create result image, copy colormap
3487 QImage result(d->width, d->height, d->format);
3488 QIMAGE_SANITYCHECK_MEMORY(result);
3489
3490 // check if we ran out of of memory..
3491 if (!result.d)
3492 return QImage();
3493
3494 result.d->colortable = d->colortable;
3495 result.d->has_alpha_clut = d->has_alpha_clut;
3496 copyMetadata(dst: result.d, src: d);
3497
3498 do_mirror(dst: result.d, src: d, horizontal, vertical);
3499
3500 return result;
3501}
3502
3503/*!
3504 \internal
3505*/
3506void QImage::mirrored_inplace(bool horizontal, bool vertical)
3507{
3508 if (!d || (d->width <= 1 && d->height <= 1) || (!horizontal && !vertical))
3509 return;
3510
3511 detach();
3512 if (!d)
3513 return;
3514 if (!d->own_data)
3515 *this = copy();
3516
3517 do_mirror(dst: d, src: d, horizontal, vertical);
3518}
3519
3520/*!
3521 \fn QImage QImage::rgbSwapped() const &
3522 \fn QImage QImage::rgbSwapped() &&
3523
3524 Returns a QImage in which the values of the red and blue
3525 components of all pixels have been swapped, effectively converting
3526 an RGB image to an BGR image.
3527
3528 The original QImage is not changed.
3529
3530 \sa rgbSwap(), {QImage#Image Transformations}{Image Transformations}
3531*/
3532
3533/*!
3534 \fn void QImage::rgbSwap()
3535 \since 6.0
3536
3537 Swaps the values of the red and blue components of all pixels, effectively converting
3538 an RGB image to an BGR image.
3539
3540 \sa rgbSwapped(), {QImage#Image Transformations}{Image Transformations}
3541*/
3542
3543static inline void rgbSwapped_generic(int width, int height, const QImage *src, QImage *dst, const QPixelLayout* layout)
3544{
3545 const RbSwapFunc func = layout->rbSwap;
3546 if (!func) {
3547 qWarning(msg: "Trying to rb-swap an image format where it doesn't make sense");
3548 if (src != dst)
3549 *dst = *src;
3550 return;
3551 }
3552
3553 for (int i = 0; i < height; ++i) {
3554 uchar *q = dst->scanLine(i);
3555 const uchar *p = src->constScanLine(i);
3556 func(q, p, width);
3557 }
3558}
3559
3560/*!
3561 \internal
3562*/
3563QImage Q_TRACE_INSTRUMENT(qtgui) QImage::rgbSwapped_helper() const
3564{
3565 if (isNull())
3566 return *this;
3567
3568 Q_TRACE_SCOPE(QImage_rgbSwapped_helper);
3569
3570 QImage res;
3571
3572 switch (d->format) {
3573 case Format_Invalid:
3574 case NImageFormats:
3575 Q_ASSERT(false);
3576 break;
3577 case Format_Alpha8:
3578 case Format_Grayscale8:
3579 case Format_Grayscale16:
3580 return *this;
3581 case Format_Mono:
3582 case Format_MonoLSB:
3583 case Format_Indexed8:
3584 res = copy();
3585 for (int i = 0; i < res.d->colortable.size(); i++) {
3586 QRgb c = res.d->colortable.at(i);
3587 res.d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
3588 }
3589 break;
3590 case Format_RGBX8888:
3591 case Format_RGBA8888:
3592 case Format_RGBA8888_Premultiplied:
3593#if Q_BYTE_ORDER == Q_BIG_ENDIAN
3594 res = QImage(d->width, d->height, d->format);
3595 QIMAGE_SANITYCHECK_MEMORY(res);
3596 for (int i = 0; i < d->height; i++) {
3597 uint *q = (uint*)res.scanLine(i);
3598 const uint *p = (const uint*)constScanLine(i);
3599 const uint *end = p + d->width;
3600 while (p < end) {
3601 uint c = *p;
3602 *q = ((c << 16) & 0xff000000) | ((c >> 16) & 0xff00) | (c & 0x00ff00ff);
3603 p++;
3604 q++;
3605 }
3606 }
3607 break;
3608#else
3609 // On little-endian rgba8888 is abgr32 and can use same rgb-swap as argb32
3610 Q_FALLTHROUGH();
3611#endif
3612 case Format_RGB32:
3613 case Format_ARGB32:
3614 case Format_ARGB32_Premultiplied:
3615 res = QImage(d->width, d->height, d->format);
3616 QIMAGE_SANITYCHECK_MEMORY(res);
3617 for (int i = 0; i < d->height; i++) {
3618 uint *q = (uint*)res.scanLine(i);
3619 const uint *p = (const uint*)constScanLine(i);
3620 const uint *end = p + d->width;
3621 while (p < end) {
3622 uint c = *p;
3623 *q = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
3624 p++;
3625 q++;
3626 }
3627 }
3628 break;
3629 case Format_RGB16:
3630 res = QImage(d->width, d->height, d->format);
3631 QIMAGE_SANITYCHECK_MEMORY(res);
3632 for (int i = 0; i < d->height; i++) {
3633 ushort *q = (ushort*)res.scanLine(i);
3634 const ushort *p = (const ushort*)constScanLine(i);
3635 const ushort *end = p + d->width;
3636 while (p < end) {
3637 ushort c = *p;
3638 *q = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
3639 p++;
3640 q++;
3641 }
3642 }
3643 break;
3644 default:
3645 res = QImage(d->width, d->height, d->format);
3646 QIMAGE_SANITYCHECK_MEMORY(res);
3647 rgbSwapped_generic(width: d->width, height: d->height, src: this, dst: &res, layout: &qPixelLayouts[d->format]);
3648 break;
3649 }
3650 copyMetadata(dst: res.d, src: d);
3651 return res;
3652}
3653
3654/*!
3655 \internal
3656*/
3657void QImage::rgbSwapped_inplace()
3658{
3659 if (isNull())
3660 return;
3661
3662 detach();
3663 if (!d)
3664 return;
3665 if (!d->own_data)
3666 *this = copy();
3667
3668 switch (d->format) {
3669 case Format_Invalid:
3670 case NImageFormats:
3671 Q_ASSERT(false);
3672 break;
3673 case Format_Alpha8:
3674 case Format_Grayscale8:
3675 case Format_Grayscale16:
3676 return;
3677 case Format_Mono:
3678 case Format_MonoLSB:
3679 case Format_Indexed8:
3680 for (int i = 0; i < d->colortable.size(); i++) {
3681 QRgb c = d->colortable.at(i);
3682 d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
3683 }
3684 break;
3685 case Format_RGBX8888:
3686 case Format_RGBA8888:
3687 case Format_RGBA8888_Premultiplied:
3688#if Q_BYTE_ORDER == Q_BIG_ENDIAN
3689 for (int i = 0; i < d->height; i++) {
3690 uint *p = (uint*)scanLine(i);
3691 uint *end = p + d->width;
3692 while (p < end) {
3693 uint c = *p;
3694 *p = ((c << 16) & 0xff000000) | ((c >> 16) & 0xff00) | (c & 0x00ff00ff);
3695 p++;
3696 }
3697 }
3698 break;
3699#else
3700 // On little-endian rgba8888 is abgr32 and can use same rgb-swap as argb32
3701 Q_FALLTHROUGH();
3702#endif
3703 case Format_RGB32:
3704 case Format_ARGB32:
3705 case Format_ARGB32_Premultiplied:
3706 for (int i = 0; i < d->height; i++) {
3707 uint *p = (uint*)scanLine(i);
3708 uint *end = p + d->width;
3709 while (p < end) {
3710 uint c = *p;
3711 *p = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
3712 p++;
3713 }
3714 }
3715 break;
3716 case Format_RGB16:
3717 for (int i = 0; i < d->height; i++) {
3718 ushort *p = (ushort*)scanLine(i);
3719 ushort *end = p + d->width;
3720 while (p < end) {
3721 ushort c = *p;
3722 *p = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
3723 p++;
3724 }
3725 }
3726 break;
3727 case Format_BGR30:
3728 case Format_A2BGR30_Premultiplied:
3729 case Format_RGB30:
3730 case Format_A2RGB30_Premultiplied:
3731 for (int i = 0; i < d->height; i++) {
3732 uint *p = (uint*)scanLine(i);
3733 uint *end = p + d->width;
3734 while (p < end) {
3735 *p = qRgbSwapRgb30(c: *p);
3736 p++;
3737 }
3738 }
3739 break;
3740 default:
3741 rgbSwapped_generic(width: d->width, height: d->height, src: this, dst: this, layout: &qPixelLayouts[d->format]);
3742 break;
3743 }
3744}
3745
3746/*!
3747 Loads an image from the file with the given \a fileName. Returns \c true if
3748 the image was successfully loaded; otherwise invalidates the image
3749 and returns \c false.
3750
3751 The loader attempts to read the image using the specified \a format, e.g.,
3752 PNG or JPG. If \a format is not specified (which is the default), it is
3753 auto-detected based on the file's suffix and header. For details, see
3754 QImageReader::setAutoDetectImageFormat().
3755
3756 The file name can either refer to an actual file on disk or to one
3757 of the application's embedded resources. See the
3758 \l{resources.html}{Resource System} overview for details on how to
3759 embed images and other resource files in the application's
3760 executable.
3761
3762 \sa {QImage#Reading and Writing Image Files}{Reading and Writing Image Files}
3763*/
3764
3765bool QImage::load(const QString &fileName, const char* format)
3766{
3767 *this = QImageReader(fileName, format).read();
3768 return !isNull();
3769}
3770
3771/*!
3772 \overload
3773
3774 This function reads a QImage from the given \a device. This can,
3775 for example, be used to load an image directly into a QByteArray.
3776*/
3777
3778bool QImage::load(QIODevice* device, const char* format)
3779{
3780 *this = QImageReader(device, format).read();
3781 return !isNull();
3782}
3783
3784/*!
3785 \since 6.2
3786
3787 Loads an image from the given QByteArrayView \a data. Returns \c true if the image was
3788 successfully loaded; otherwise invalidates the image and returns \c false.
3789
3790 The loader attempts to read the image using the specified \a format, e.g.,
3791 PNG or JPG. If \a format is not specified (which is the default), the
3792 loader probes the file for a header to guess the file format.
3793
3794 \sa {QImage#Reading and Writing Image Files}{Reading and Writing Image Files}
3795*/
3796
3797bool QImage::loadFromData(QByteArrayView data, const char *format)
3798{
3799 *this = fromData(data, format);
3800 return !isNull();
3801}
3802
3803/*!
3804 \fn bool QImage::loadFromData(const uchar *data, int len, const char *format)
3805
3806 \overload
3807
3808 Loads an image from the first \a len bytes of the given binary \a data.
3809*/
3810
3811bool QImage::loadFromData(const uchar *buf, int len, const char *format)
3812{
3813 return loadFromData(data: QByteArrayView(buf, len), format);
3814}
3815
3816/*!
3817 \fn bool QImage::loadFromData(const QByteArray &data, const char *format)
3818
3819 \overload
3820
3821 Loads an image from the given QByteArray \a data.
3822*/
3823
3824/*!
3825 \since 6.2
3826
3827 Constructs an image from the given QByteArrayView \a data. The loader attempts to read the image
3828 using the specified \a format. If \a format is not specified (which is the default), the loader
3829 probes the data for a header to guess the file format.
3830
3831 If \a format is specified, it must be one of the values returned by
3832 QImageReader::supportedImageFormats().
3833
3834 If the loading of the image fails, the image returned will be a null image.
3835
3836 \sa load(), save(), {QImage#Reading and Writing Image Files}{Reading and Writing Image Files}
3837 */
3838
3839QImage QImage::fromData(QByteArrayView data, const char *format)
3840{
3841 QByteArray a = QByteArray::fromRawData(data: data.constData(), size: data.size());
3842 QBuffer b;
3843 b.setData(a);
3844 b.open(openMode: QIODevice::ReadOnly);
3845 return QImageReader(&b, format).read();
3846}
3847
3848/*!
3849 \fn QImage QImage::fromData(const uchar *data, int size, const char *format)
3850
3851 \overload
3852
3853 Constructs a QImage from the first \a size bytes of the given binary \a data.
3854*/
3855
3856QImage QImage::fromData(const uchar *data, int size, const char *format)
3857{
3858 return fromData(data: QByteArrayView(data, size), format);
3859}
3860
3861/*!
3862 \fn QImage QImage::fromData(const QByteArray &data, const char *format)
3863
3864 \overload
3865
3866 Constructs a QImage from the given QByteArray \a data.
3867
3868*/
3869
3870/*!
3871 Saves the image to the file with the given \a fileName, using the
3872 given image file \a format and \a quality factor. If \a format is
3873 \nullptr, QImage will attempt to guess the format by looking at
3874 \a fileName's suffix.
3875
3876 The \a quality factor must be in the range 0 to 100 or -1. Specify
3877 0 to obtain small compressed files, 100 for large uncompressed
3878 files, and -1 (the default) to use the default settings.
3879
3880 Returns \c true if the image was successfully saved; otherwise
3881 returns \c false.
3882
3883 \sa {QImage#Reading and Writing Image Files}{Reading and Writing
3884 Image Files}
3885*/
3886bool QImage::save(const QString &fileName, const char *format, int quality) const
3887{
3888 if (isNull())
3889 return false;
3890 QImageWriter writer(fileName, format);
3891 return d->doImageIO(image: this, io: &writer, quality);
3892}
3893
3894/*!
3895 \overload
3896
3897 This function writes a QImage to the given \a device.
3898
3899 This can, for example, be used to save an image directly into a
3900 QByteArray:
3901
3902 \snippet image/image.cpp 0
3903*/
3904
3905bool QImage::save(QIODevice* device, const char* format, int quality) const
3906{
3907 if (isNull())
3908 return false; // nothing to save
3909 QImageWriter writer(device, format);
3910 return d->doImageIO(image: this, io: &writer, quality);
3911}
3912
3913/* \internal
3914*/
3915
3916bool QImageData::doImageIO(const QImage *image, QImageWriter *writer, int quality) const
3917{
3918 if (quality > 100 || quality < -1)
3919 qWarning(msg: "QImage::save: Quality out of range [-1, 100]");
3920 if (quality >= 0)
3921 writer->setQuality(qMin(a: quality,b: 100));
3922 const bool result = writer->write(image: *image);
3923#ifdef QT_DEBUG
3924 if (!result)
3925 qWarning(msg: "QImage::save: failed to write image - %s", qPrintable(writer->errorString()));
3926#endif
3927 return result;
3928}
3929
3930/*****************************************************************************
3931 QImage stream functions
3932 *****************************************************************************/
3933#if !defined(QT_NO_DATASTREAM)
3934/*!
3935 \fn QDataStream &operator<<(QDataStream &stream, const QImage &image)
3936 \relates QImage
3937
3938 Writes the given \a image to the given \a stream as a PNG image,
3939 or as a BMP image if the stream's version is 1. Note that writing
3940 the stream to a file will not produce a valid image file.
3941
3942 \sa QImage::save(), {Serializing Qt Data Types}
3943*/
3944
3945QDataStream &operator<<(QDataStream &s, const QImage &image)
3946{
3947 if (s.version() >= 5) {
3948 if (image.isNull()) {
3949 s << (qint32) 0; // null image marker
3950 return s;
3951 } else {
3952 s << (qint32) 1;
3953 // continue ...
3954 }
3955 }
3956 QImageWriter writer(s.device(), s.version() == 1 ? "bmp" : "png");
3957 writer.write(image);
3958 return s;
3959}
3960
3961/*!
3962 \fn QDataStream &operator>>(QDataStream &stream, QImage &image)
3963 \relates QImage
3964
3965 Reads an image from the given \a stream and stores it in the given
3966 \a image.
3967
3968 \sa QImage::load(), {Serializing Qt Data Types}
3969*/
3970
3971QDataStream &operator>>(QDataStream &s, QImage &image)
3972{
3973 if (s.version() >= 5) {
3974 qint32 nullMarker;
3975 s >> nullMarker;
3976 if (!nullMarker) {
3977 image = QImage(); // null image
3978 return s;
3979 }
3980 }
3981 image = QImageReader(s.device(), s.version() == 1 ? "bmp" : "png").read();
3982 if (image.isNull() && s.version() >= 5)
3983 s.setStatus(QDataStream::ReadPastEnd);
3984 return s;
3985}
3986#endif // QT_NO_DATASTREAM
3987
3988
3989
3990/*!
3991 \fn bool QImage::operator==(const QImage & image) const
3992
3993 Returns \c true if this image and the given \a image have the same
3994 contents; otherwise returns \c false.
3995
3996 The comparison can be slow, unless there is some obvious
3997 difference (e.g. different size or format), in which case the
3998 function will return quickly.
3999
4000 \sa operator=()
4001*/
4002
4003bool QImage::operator==(const QImage & i) const
4004{
4005 // same object, or shared?
4006 if (i.d == d)
4007 return true;
4008 if (!i.d || !d)
4009 return false;
4010
4011 // obviously different stuff?
4012 if (i.d->height != d->height || i.d->width != d->width || i.d->format != d->format || i.d->colorSpace != d->colorSpace)
4013 return false;
4014
4015 if (d->format != Format_RGB32) {
4016 if (d->format >= Format_ARGB32) { // all bits defined
4017 const int n = d->width * d->depth / 8;
4018 if (n == d->bytes_per_line && n == i.d->bytes_per_line) {
4019 if (memcmp(s1: bits(), s2: i.bits(), n: d->nbytes))
4020 return false;
4021 } else {
4022 for (int y = 0; y < d->height; ++y) {
4023 if (memcmp(s1: scanLine(i: y), s2: i.scanLine(i: y), n: n))
4024 return false;
4025 }
4026 }
4027 } else {
4028 const int w = width();
4029 const int h = height();
4030 const QList<QRgb> &colortable = d->colortable;
4031 const QList<QRgb> &icolortable = i.d->colortable;
4032 for (int y=0; y<h; ++y) {
4033 for (int x=0; x<w; ++x) {
4034 if (colortable[pixelIndex(x, y)] != icolortable[i.pixelIndex(x, y)])
4035 return false;
4036 }
4037 }
4038 }
4039 } else {
4040 //alpha channel undefined, so we must mask it out
4041 for(int l = 0; l < d->height; l++) {
4042 int w = d->width;
4043 const uint *p1 = reinterpret_cast<const uint*>(scanLine(i: l));
4044 const uint *p2 = reinterpret_cast<const uint*>(i.scanLine(i: l));
4045 while (w--) {
4046 if ((*p1++ & 0x00ffffff) != (*p2++ & 0x00ffffff))
4047 return false;
4048 }
4049 }
4050 }
4051 return true;
4052}
4053
4054
4055/*!
4056 \fn bool QImage::operator!=(const QImage & image) const
4057
4058 Returns \c true if this image and the given \a image have different
4059 contents; otherwise returns \c false.
4060
4061 The comparison can be slow, unless there is some obvious
4062 difference, such as different widths, in which case the function
4063 will return quickly.
4064
4065 \sa operator=()
4066*/
4067
4068bool QImage::operator!=(const QImage & i) const
4069{
4070 return !(*this == i);
4071}
4072
4073
4074
4075
4076/*!
4077 Returns the number of pixels that fit horizontally in a physical
4078 meter. Together with dotsPerMeterY(), this number defines the
4079 intended scale and aspect ratio of the image.
4080
4081 \sa setDotsPerMeterX(), {QImage#Image Information}{Image
4082 Information}
4083*/
4084int QImage::dotsPerMeterX() const
4085{
4086 return d ? qRound(d: d->dpmx) : 0;
4087}
4088
4089/*!
4090 Returns the number of pixels that fit vertically in a physical
4091 meter. Together with dotsPerMeterX(), this number defines the
4092 intended scale and aspect ratio of the image.
4093
4094 \sa setDotsPerMeterY(), {QImage#Image Information}{Image
4095 Information}
4096*/
4097int QImage::dotsPerMeterY() const
4098{
4099 return d ? qRound(d: d->dpmy) : 0;
4100}
4101
4102/*!
4103 Sets the number of pixels that fit horizontally in a physical
4104 meter, to \a x.
4105
4106 Together with dotsPerMeterY(), this number defines the intended
4107 scale and aspect ratio of the image, and determines the scale
4108 at which QPainter will draw graphics on the image. It does not
4109 change the scale or aspect ratio of the image when it is rendered
4110 on other paint devices.
4111
4112 \sa dotsPerMeterX(), {QImage#Image Information}{Image Information}
4113*/
4114void QImage::setDotsPerMeterX(int x)
4115{
4116 if (!d || !x || d->dpmx == x)
4117 return;
4118 detachMetadata();
4119
4120 if (d)
4121 d->dpmx = x;
4122}
4123
4124/*!
4125 Sets the number of pixels that fit vertically in a physical meter,
4126 to \a y.
4127
4128 Together with dotsPerMeterX(), this number defines the intended
4129 scale and aspect ratio of the image, and determines the scale
4130 at which QPainter will draw graphics on the image. It does not
4131 change the scale or aspect ratio of the image when it is rendered
4132 on other paint devices.
4133
4134 \sa dotsPerMeterY(), {QImage#Image Information}{Image Information}
4135*/
4136void QImage::setDotsPerMeterY(int y)
4137{
4138 if (!d || !y || d->dpmy == y)
4139 return;
4140 detachMetadata();
4141
4142 if (d)
4143 d->dpmy = y;
4144}
4145
4146/*!
4147 \fn QPoint QImage::offset() const
4148
4149 Returns the number of pixels by which the image is intended to be
4150 offset by when positioning relative to other images.
4151
4152 \sa setOffset(), {QImage#Image Information}{Image Information}
4153*/
4154QPoint QImage::offset() const
4155{
4156 return d ? d->offset : QPoint();
4157}
4158
4159
4160/*!
4161 \fn void QImage::setOffset(const QPoint& offset)
4162
4163 Sets the number of pixels by which the image is intended to be
4164 offset by when positioning relative to other images, to \a offset.
4165
4166 \sa offset(), {QImage#Image Information}{Image Information}
4167*/
4168void QImage::setOffset(const QPoint& p)
4169{
4170 if (!d || d->offset == p)
4171 return;
4172 detachMetadata();
4173
4174 if (d)
4175 d->offset = p;
4176}
4177
4178/*!
4179 Returns the text keys for this image.
4180
4181 You can use these keys with text() to list the image text for a
4182 certain key.
4183
4184 \sa text()
4185*/
4186QStringList QImage::textKeys() const
4187{
4188 return d ? QStringList(d->text.keys()) : QStringList();
4189}
4190
4191/*!
4192 Returns the image text associated with the given \a key. If the
4193 specified \a key is an empty string, the whole image text is
4194 returned, with each key-text pair separated by a newline.
4195
4196 \sa setText(), textKeys()
4197*/
4198QString QImage::text(const QString &key) const
4199{
4200 if (!d)
4201 return QString();
4202
4203 if (!key.isEmpty())
4204 return d->text.value(key);
4205
4206 QString tmp;
4207 for (auto it = d->text.begin(), end = d->text.end(); it != end; ++it)
4208 tmp += it.key() + ": "_L1 + it.value().simplified() + "\n\n"_L1;
4209 if (!tmp.isEmpty())
4210 tmp.chop(n: 2); // remove final \n\n
4211 return tmp;
4212}
4213
4214/*!
4215 \fn void QImage::setText(const QString &key, const QString &text)
4216
4217 Sets the image text to the given \a text and associate it with the
4218 given \a key.
4219
4220 If you just want to store a single text block (i.e., a "comment"
4221 or just a description), you can either pass an empty key, or use a
4222 generic key like "Description".
4223
4224 The image text is embedded into the image data when you
4225 call save() or QImageWriter::write().
4226
4227 Not all image formats support embedded text. You can find out
4228 if a specific image or format supports embedding text
4229 by using QImageWriter::supportsOption(). We give an example:
4230
4231 \snippet image/supportedformat.cpp 0
4232
4233 You can use QImageWriter::supportedImageFormats() to find out
4234 which image formats are available to you.
4235
4236 \sa text(), textKeys()
4237*/
4238void QImage::setText(const QString &key, const QString &value)
4239{
4240 if (!d)
4241 return;
4242 detachMetadata();
4243
4244 if (d)
4245 d->text.insert(key, value);
4246}
4247
4248/*!
4249 \internal
4250
4251 Used by QPainter to retrieve a paint engine for the image.
4252*/
4253QPaintEngine *QImage::paintEngine() const
4254{
4255 if (!d)
4256 return nullptr;
4257
4258 if (!d->paintEngine) {
4259 QPaintDevice *paintDevice = const_cast<QImage *>(this);
4260 QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
4261 if (platformIntegration)
4262 d->paintEngine = platformIntegration->createImagePaintEngine(paintDevice);
4263 if (!d->paintEngine)
4264 d->paintEngine = new QRasterPaintEngine(paintDevice);
4265 }
4266
4267 return d->paintEngine;
4268}
4269
4270
4271/*!
4272 \internal
4273
4274 Returns the size for the specified \a metric on the device.
4275*/
4276int QImage::metric(PaintDeviceMetric metric) const
4277{
4278 if (!d)
4279 return 0;
4280
4281 switch (metric) {
4282 case PdmWidth:
4283 return d->width;
4284
4285 case PdmHeight:
4286 return d->height;
4287
4288 case PdmWidthMM:
4289 return qRound(d: d->width * 1000 / d->dpmx);
4290
4291 case PdmHeightMM:
4292 return qRound(d: d->height * 1000 / d->dpmy);
4293
4294 case PdmNumColors:
4295 return d->colortable.size();
4296
4297 case PdmDepth:
4298 return d->depth;
4299
4300 case PdmDpiX:
4301 return qRound(d: d->dpmx * 0.0254);
4302 break;
4303
4304 case PdmDpiY:
4305 return qRound(d: d->dpmy * 0.0254);
4306 break;
4307
4308 case PdmPhysicalDpiX:
4309 return qRound(d: d->dpmx * 0.0254);
4310 break;
4311
4312 case PdmPhysicalDpiY:
4313 return qRound(d: d->dpmy * 0.0254);
4314 break;
4315
4316 case PdmDevicePixelRatio:
4317 return d->devicePixelRatio;
4318 break;
4319
4320 case PdmDevicePixelRatioScaled:
4321 return d->devicePixelRatio * QPaintDevice::devicePixelRatioFScale();
4322 break;
4323
4324 case PdmDevicePixelRatioF_EncodedA:
4325 Q_FALLTHROUGH();
4326 case PdmDevicePixelRatioF_EncodedB:
4327 return QPaintDevice::encodeMetricF(metric, value: d->devicePixelRatio);
4328 break;
4329
4330 default:
4331 qWarning(msg: "QImage::metric(): Unhandled metric type %d", metric);
4332 break;
4333 }
4334 return 0;
4335}
4336
4337
4338
4339/*****************************************************************************
4340 QPixmap (and QImage) helper functions
4341 *****************************************************************************/
4342/*
4343 This internal function contains the common (i.e. platform independent) code
4344 to do a transformation of pixel data. It is used by QPixmap::transform() and by
4345 QImage::transform().
4346
4347 \a trueMat is the true transformation matrix (see QPixmap::trueMatrix()) and
4348 \a xoffset is an offset to the matrix.
4349
4350 \a msbfirst specifies for 1bpp images, if the MSB or LSB comes first and \a
4351 depth specifies the colordepth of the data.
4352
4353 \a dptr is a pointer to the destination data, \a dbpl specifies the bits per
4354 line for the destination data, \a p_inc is the offset that we advance for
4355 every scanline and \a dHeight is the height of the destination image.
4356
4357 \a sprt is the pointer to the source data, \a sbpl specifies the bits per
4358 line of the source data, \a sWidth and \a sHeight are the width and height of
4359 the source data.
4360*/
4361
4362#undef IWX_MSB
4363#define IWX_MSB(b) if (trigx < maxws && trigy < maxhs) { \
4364 if (*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
4365 (1 << (7-((trigx>>12)&7)))) \
4366 *dptr |= b; \
4367 } \
4368 trigx += m11; \
4369 trigy += m12;
4370 // END OF MACRO
4371#undef IWX_LSB
4372#define IWX_LSB(b) if (trigx < maxws && trigy < maxhs) { \
4373 if (*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
4374 (1 << ((trigx>>12)&7))) \
4375 *dptr |= b; \
4376 } \
4377 trigx += m11; \
4378 trigy += m12;
4379 // END OF MACRO
4380#undef IWX_PIX
4381#define IWX_PIX(b) if (trigx < maxws && trigy < maxhs) { \
4382 if ((*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
4383 (1 << (7-((trigx>>12)&7)))) == 0) \
4384 *dptr &= ~b; \
4385 } \
4386 trigx += m11; \
4387 trigy += m12;
4388 // END OF MACRO
4389bool qt_xForm_helper(const QTransform &trueMat, int xoffset, int type, int depth,
4390 uchar *dptr, qsizetype dbpl, int p_inc, int dHeight,
4391 const uchar *sptr, qsizetype sbpl, int sWidth, int sHeight)
4392{
4393 int m11 = int(trueMat.m11()*4096.0);
4394 int m12 = int(trueMat.m12()*4096.0);
4395 int m21 = int(trueMat.m21()*4096.0);
4396 int m22 = int(trueMat.m22()*4096.0);
4397 int dx = qRound(d: trueMat.dx()*4096.0);
4398 int dy = qRound(d: trueMat.dy()*4096.0);
4399
4400 int m21ydx = dx + (xoffset<<16) + (m11 + m21) / 2;
4401 int m22ydy = dy + (m12 + m22) / 2;
4402 uint trigx;
4403 uint trigy;
4404 uint maxws = sWidth<<12;
4405 uint maxhs = sHeight<<12;
4406
4407 for (int y=0; y<dHeight; y++) { // for each target scanline
4408 trigx = m21ydx;
4409 trigy = m22ydy;
4410 uchar *maxp = dptr + dbpl;
4411 if (depth != 1) {
4412 switch (depth) {
4413 case 8: // 8 bpp transform
4414 while (dptr < maxp) {
4415 if (trigx < maxws && trigy < maxhs)
4416 *dptr = *(sptr+sbpl*(trigy>>12)+(trigx>>12));
4417 trigx += m11;
4418 trigy += m12;
4419 dptr++;
4420 }
4421 break;
4422
4423 case 16: // 16 bpp transform
4424 while (dptr < maxp) {
4425 if (trigx < maxws && trigy < maxhs)
4426 *((ushort*)dptr) = *((const ushort *)(sptr+sbpl*(trigy>>12) +
4427 ((trigx>>12)<<1)));
4428 trigx += m11;
4429 trigy += m12;
4430 dptr++;
4431 dptr++;
4432 }
4433 break;
4434
4435 case 24: // 24 bpp transform
4436 while (dptr < maxp) {
4437 if (trigx < maxws && trigy < maxhs) {
4438 const uchar *p2 = sptr+sbpl*(trigy>>12) + ((trigx>>12)*3);
4439 dptr[0] = p2[0];
4440 dptr[1] = p2[1];
4441 dptr[2] = p2[2];
4442 }
4443 trigx += m11;
4444 trigy += m12;
4445 dptr += 3;
4446 }
4447 break;
4448
4449 case 32: // 32 bpp transform
4450 while (dptr < maxp) {
4451 if (trigx < maxws && trigy < maxhs)
4452 *((uint*)dptr) = *((const uint *)(sptr+sbpl*(trigy>>12) +
4453 ((trigx>>12)<<2)));
4454 trigx += m11;
4455 trigy += m12;
4456 dptr += 4;
4457 }
4458 break;
4459
4460 default: {
4461 return false;
4462 }
4463 }
4464 } else {
4465 switch (type) {
4466 case QT_XFORM_TYPE_MSBFIRST:
4467 while (dptr < maxp) {
4468 IWX_MSB(128);
4469 IWX_MSB(64);
4470 IWX_MSB(32);
4471 IWX_MSB(16);
4472 IWX_MSB(8);
4473 IWX_MSB(4);
4474 IWX_MSB(2);
4475 IWX_MSB(1);
4476 dptr++;
4477 }
4478 break;
4479 case QT_XFORM_TYPE_LSBFIRST:
4480 while (dptr < maxp) {
4481 IWX_LSB(1);
4482 IWX_LSB(2);
4483 IWX_LSB(4);
4484 IWX_LSB(8);
4485 IWX_LSB(16);
4486 IWX_LSB(32);
4487 IWX_LSB(64);
4488 IWX_LSB(128);
4489 dptr++;
4490 }
4491 break;
4492 }
4493 }
4494 m21ydx += m21;
4495 m22ydy += m22;
4496 dptr += p_inc;
4497 }
4498 return true;
4499}
4500#undef IWX_MSB
4501#undef IWX_LSB
4502#undef IWX_PIX
4503
4504/*!
4505 Returns a number that identifies the contents of this QImage
4506 object. Distinct QImage objects can only have the same key if they
4507 refer to the same contents.
4508
4509 The key will change when the image is altered.
4510*/
4511qint64 QImage::cacheKey() const
4512{
4513 if (!d)
4514 return 0;
4515 else
4516 return (((qint64) d->ser_no) << 32) | ((qint64) d->detach_no);
4517}
4518
4519/*!
4520 \internal
4521
4522 Returns \c true if the image is detached; otherwise returns \c false.
4523
4524 \sa detach(), {Implicit Data Sharing}
4525*/
4526
4527bool QImage::isDetached() const
4528{
4529 return d && d->ref.loadRelaxed() == 1;
4530}
4531
4532
4533/*!
4534 Sets the alpha channel of this image to the given \a alphaChannel.
4535
4536 If \a alphaChannel is an 8 bit alpha image, the alpha values are
4537 used directly. Otherwise, \a alphaChannel is converted to 8 bit
4538 grayscale and the intensity of the pixel values is used.
4539
4540 If the image already has an alpha channel, the existing alpha channel
4541 is multiplied with the new one. If the image doesn't have an alpha
4542 channel it will be converted to a format that does.
4543
4544 The operation is similar to painting \a alphaChannel as an alpha image
4545 over this image using \c QPainter::CompositionMode_DestinationIn.
4546
4547 \sa hasAlphaChannel(),
4548 {QImage#Image Transformations}{Image Transformations},
4549 {QImage#Image Formats}{Image Formats}
4550*/
4551
4552void QImage::setAlphaChannel(const QImage &alphaChannel)
4553{
4554 if (!d || alphaChannel.isNull())
4555 return;
4556
4557 if (d->paintEngine && d->paintEngine->isActive()) {
4558 qWarning(msg: "QImage::setAlphaChannel: "
4559 "Unable to set alpha channel while image is being painted on");
4560 return;
4561 }
4562
4563 const Format alphaFormat = qt_alphaVersionForPainting(format: d->format);
4564 if (d->format == alphaFormat)
4565 detach();
4566 else
4567 convertTo(format: alphaFormat);
4568
4569 if (isNull())
4570 return;
4571
4572 QImage sourceImage;
4573 if (alphaChannel.format() == QImage::Format_Alpha8 || (alphaChannel.d->depth == 8 && alphaChannel.isGrayscale()))
4574 sourceImage = alphaChannel;
4575 else
4576 sourceImage = alphaChannel.convertToFormat(f: QImage::Format_Grayscale8);
4577 if (!sourceImage.reinterpretAsFormat(format: QImage::Format_Alpha8))
4578 return;
4579
4580 QPainter painter(this);
4581 if (sourceImage.size() != size())
4582 painter.setRenderHint(hint: QPainter::SmoothPixmapTransform);
4583 painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
4584 painter.drawImage(r: rect(), image: sourceImage);
4585}
4586
4587/*!
4588 Returns \c true if the image has a format that respects the alpha
4589 channel, otherwise returns \c false.
4590
4591 \sa {QImage#Image Information}{Image Information}
4592*/
4593bool QImage::hasAlphaChannel() const
4594{
4595 if (!d)
4596 return false;
4597 const QPixelFormat format = pixelFormat();
4598 if (format.alphaUsage() == QPixelFormat::UsesAlpha)
4599 return true;
4600 if (format.colorModel() == QPixelFormat::Indexed)
4601 return d->has_alpha_clut;
4602 return false;
4603}
4604
4605/*!
4606 Returns the number of bit planes in the image.
4607
4608 The number of bit planes is the number of bits of color and
4609 transparency information for each pixel. This is different from
4610 (i.e. smaller than) the depth when the image format contains
4611 unused bits.
4612
4613 \sa depth(), format(), {QImage#Image Formats}{Image Formats}
4614*/
4615int QImage::bitPlaneCount() const
4616{
4617 if (!d)
4618 return 0;
4619 int bpc = 0;
4620 switch (d->format) {
4621 case QImage::Format_Invalid:
4622 break;
4623 case QImage::Format_BGR30:
4624 case QImage::Format_RGB30:
4625 bpc = 30;
4626 break;
4627 case QImage::Format_RGB32:
4628 case QImage::Format_RGBX8888:
4629 bpc = 24;
4630 break;
4631 case QImage::Format_RGB666:
4632 bpc = 18;
4633 break;
4634 case QImage::Format_RGB555:
4635 bpc = 15;
4636 break;
4637 case QImage::Format_ARGB8555_Premultiplied:
4638 bpc = 23;
4639 break;
4640 case QImage::Format_RGB444:
4641 bpc = 12;
4642 break;
4643 case QImage::Format_RGBX64:
4644 case QImage::Format_RGBX16FPx4:
4645 bpc = 48;
4646 break;
4647 case QImage::Format_RGBX32FPx4:
4648 bpc = 96;
4649 break;
4650 default:
4651 bpc = qt_depthForFormat(format: d->format);
4652 break;
4653 }
4654 return bpc;
4655}
4656
4657/*!
4658 \internal
4659 Returns a smoothly scaled copy of the image. The returned image has a size
4660 of width \a w by height \a h pixels.
4661
4662 The function operates internally on \c Format_RGB32, \c Format_ARGB32_Premultiplied,
4663 \c Format_RGBX8888, \c Format_RGBA8888_Premultiplied, \c Format_RGBX64,
4664 or \c Format_RGBA64_Premultiplied and will convert to those formats
4665 if necessary. To avoid unnecessary conversion the result is returned in the format
4666 internally used, and not in the original format.
4667*/
4668QImage QImage::smoothScaled(int w, int h) const
4669{
4670 QImage src = *this;
4671 switch (src.format()) {
4672 case QImage::Format_RGB32:
4673 case QImage::Format_ARGB32_Premultiplied:
4674#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4675 case QImage::Format_RGBX8888:
4676#endif
4677 case QImage::Format_RGBA8888_Premultiplied:
4678#if QT_CONFIG(raster_64bit)
4679 case QImage::Format_RGBX64:
4680 case QImage::Format_RGBA64_Premultiplied:
4681 break;
4682 case QImage::Format_RGBA64:
4683 case QImage::Format_Grayscale16:
4684 src.convertTo(format: QImage::Format_RGBA64_Premultiplied);
4685 break;
4686#endif
4687#if QT_CONFIG(raster_fp)
4688 case QImage::Format_RGBX32FPx4:
4689 case QImage::Format_RGBA32FPx4_Premultiplied:
4690 break;
4691 case QImage::Format_RGBX16FPx4:
4692 src.convertTo(format: QImage::Format_RGBX32FPx4);
4693 break;
4694 case QImage::Format_RGBA16FPx4:
4695 case QImage::Format_RGBA16FPx4_Premultiplied:
4696 case QImage::Format_RGBA32FPx4:
4697 src.convertTo(format: QImage::Format_RGBA32FPx4_Premultiplied);
4698 break;
4699#endif
4700 case QImage::Format_CMYK8888:
4701 break;
4702 default:
4703 if (src.hasAlphaChannel())
4704 src.convertTo(format: QImage::Format_ARGB32_Premultiplied);
4705 else
4706 src.convertTo(format: QImage::Format_RGB32);
4707 }
4708 src = qSmoothScaleImage(img: src, w, h);
4709 if (!src.isNull())
4710 copyMetadata(dst: src.d, src: d);
4711 return src;
4712}
4713
4714static QImage rotated90(const QImage &image)
4715{
4716 QImage out(image.height(), image.width(), image.format());
4717 if (out.isNull())
4718 return out;
4719 copyMetadata(dst: QImageData::get(img&: out), src: QImageData::get(img: image));
4720 if (image.colorCount() > 0)
4721 out.setColorTable(image.colorTable());
4722 int w = image.width();
4723 int h = image.height();
4724 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][2];
4725 if (memrotate) {
4726 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4727 } else {
4728 for (int y=0; y<h; ++y) {
4729 if (image.colorCount())
4730 for (int x=0; x<w; ++x)
4731 out.setPixel(x: h-y-1, y: x, index_or_rgb: image.pixelIndex(x, y));
4732 else
4733 for (int x=0; x<w; ++x)
4734 out.setPixel(x: h-y-1, y: x, index_or_rgb: image.pixel(x, y));
4735 }
4736 }
4737 return out;
4738}
4739
4740static QImage rotated180(const QImage &image)
4741{
4742 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][1];
4743 if (!memrotate)
4744 return image.mirrored(horizontally: true, vertically: true);
4745
4746 QImage out(image.width(), image.height(), image.format());
4747 if (out.isNull())
4748 return out;
4749 copyMetadata(dst: QImageData::get(img&: out), src: QImageData::get(img: image));
4750 if (image.colorCount() > 0)
4751 out.setColorTable(image.colorTable());
4752 int w = image.width();
4753 int h = image.height();
4754 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4755 return out;
4756}
4757
4758static QImage rotated270(const QImage &image)
4759{
4760 QImage out(image.height(), image.width(), image.format());
4761 if (out.isNull())
4762 return out;
4763 copyMetadata(dst: QImageData::get(img&: out), src: QImageData::get(img: image));
4764 if (image.colorCount() > 0)
4765 out.setColorTable(image.colorTable());
4766 int w = image.width();
4767 int h = image.height();
4768 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][0];
4769 if (memrotate) {
4770 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4771 } else {
4772 for (int y=0; y<h; ++y) {
4773 if (image.colorCount())
4774 for (int x=0; x<w; ++x)
4775 out.setPixel(x: y, y: w-x-1, index_or_rgb: image.pixelIndex(x, y));
4776 else
4777 for (int x=0; x<w; ++x)
4778 out.setPixel(x: y, y: w-x-1, index_or_rgb: image.pixel(x, y));
4779 }
4780 }
4781 return out;
4782}
4783
4784/*!
4785 Returns a copy of the image that is transformed using the given
4786 transformation \a matrix and transformation \a mode.
4787
4788 The returned image will normally have the same {Image Formats}{format} as
4789 the original image. However, a complex transformation may result in an
4790 image where not all pixels are covered by the transformed pixels of the
4791 original image. In such cases, those background pixels will be assigned a
4792 transparent color value, and the transformed image will be given a format
4793 with an alpha channel, even if the original image did not have that.
4794
4795 The transformation \a matrix is internally adjusted to compensate
4796 for unwanted translation; i.e. the image produced is the smallest
4797 image that contains all the transformed points of the original
4798 image. Use the trueMatrix() function to retrieve the actual matrix
4799 used for transforming an image.
4800
4801 Unlike the other overload, this function can be used to perform perspective
4802 transformations on images.
4803
4804 \sa trueMatrix(), {QImage#Image Transformations}{Image
4805 Transformations}
4806*/
4807
4808QImage Q_TRACE_INSTRUMENT(qtgui) QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode ) const
4809{
4810 if (!d)
4811 return QImage();
4812
4813 Q_TRACE_PARAM_REPLACE(const QTransform &, double[9]);
4814 Q_TRACE_SCOPE(QImage_transformed, QList<double>({matrix.m11(), matrix.m12(), matrix.m13(),
4815 matrix.m21(), matrix.m22(), matrix.m23(),
4816 matrix.m31(), matrix.m32(), matrix.m33()}).data(), mode);
4817
4818 // source image data
4819 const int ws = width();
4820 const int hs = height();
4821
4822 // target image data
4823 int wd;
4824 int hd;
4825
4826 // compute size of target image
4827 QTransform mat = trueMatrix(matrix, w: ws, h: hs);
4828 bool complex_xform = false;
4829 bool scale_xform = false;
4830 bool nonpaintable_scale_xform = false;
4831 if (mat.type() <= QTransform::TxScale) {
4832 if (mat.type() == QTransform::TxNone) // identity matrix
4833 return *this;
4834 else if (mat.m11() == -1. && mat.m22() == -1.)
4835 return rotated180(image: *this);
4836
4837 hd = qRound(d: qAbs(t: mat.m22()) * hs);
4838 wd = qRound(d: qAbs(t: mat.m11()) * ws);
4839 scale_xform = true;
4840 // The paint-based scaling is only bilinear, and has problems
4841 // with scaling smoothly more than 2x down.
4842 if (hd * 2 < hs || wd * 2 < ws)
4843 nonpaintable_scale_xform = true;
4844 // We cannot paint on a CMYK image, so don't try to do so
4845 if (format() == QImage::Format_CMYK8888)
4846 nonpaintable_scale_xform = true;
4847 } else {
4848 if (mat.type() <= QTransform::TxRotate && mat.m11() == 0 && mat.m22() == 0) {
4849 if (mat.m12() == 1. && mat.m21() == -1.)
4850 return rotated90(image: *this);
4851 else if (mat.m12() == -1. && mat.m21() == 1.)
4852 return rotated270(image: *this);
4853 }
4854
4855 QPolygonF a(QRectF(0, 0, ws, hs));
4856 a = mat.map(a);
4857 QRect r = a.boundingRect().toAlignedRect();
4858 wd = r.width();
4859 hd = r.height();
4860 complex_xform = true;
4861 }
4862
4863 if (wd == 0 || hd == 0)
4864 return QImage();
4865
4866 if (scale_xform && mode == Qt::SmoothTransformation) {
4867 switch (format()) {
4868 case QImage::Format_RGB32:
4869 case QImage::Format_ARGB32_Premultiplied:
4870#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4871 case QImage::Format_RGBX8888:
4872#endif
4873 case QImage::Format_RGBA8888_Premultiplied:
4874#if QT_CONFIG(raster_64bit)
4875 case QImage::Format_RGBX64:
4876 case QImage::Format_RGBA64_Premultiplied:
4877#endif
4878 case QImage::Format_CMYK8888:
4879 // Use smoothScaled for scaling when we can do so without conversion.
4880 if (mat.m11() > 0.0F && mat.m22() > 0.0F)
4881 return smoothScaled(w: wd, h: hd);
4882 break;
4883 default:
4884 break;
4885 }
4886 // Otherwise only use it when the scaling factor demands it, or the image is large enough to scale multi-threaded
4887 if (nonpaintable_scale_xform
4888#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
4889 || (ws * hs) >= (1<<20)
4890#endif
4891 ) {
4892 QImage scaledImage;
4893 if (mat.m11() < 0.0F && mat.m22() < 0.0F) { // horizontal/vertical flip
4894 scaledImage = smoothScaled(w: wd, h: hd).mirrored(horizontally: true, vertically: true);
4895 } else if (mat.m11() < 0.0F) { // horizontal flip
4896 scaledImage = smoothScaled(w: wd, h: hd).mirrored(horizontally: true, vertically: false);
4897 } else if (mat.m22() < 0.0F) { // vertical flip
4898 scaledImage = smoothScaled(w: wd, h: hd).mirrored(horizontally: false, vertically: true);
4899 } else { // no flipping
4900 scaledImage = smoothScaled(w: wd, h: hd);
4901 }
4902
4903 switch (format()) {
4904 case QImage::Format_Mono:
4905 case QImage::Format_MonoLSB:
4906 case QImage::Format_Indexed8:
4907 return scaledImage;
4908 default:
4909 return scaledImage.convertToFormat(f: format());
4910 }
4911 }
4912 }
4913
4914 int bpp = depth();
4915
4916 qsizetype sbpl = bytesPerLine();
4917 const uchar *sptr = bits();
4918
4919 QImage::Format target_format = d->format;
4920
4921 if (complex_xform || mode == Qt::SmoothTransformation) {
4922 if (d->format < QImage::Format_RGB32 || (!hasAlphaChannel() && complex_xform)) {
4923 target_format = qt_alphaVersion(format: d->format);
4924 }
4925 }
4926
4927 QImage dImage(wd, hd, target_format);
4928 QIMAGE_SANITYCHECK_MEMORY(dImage);
4929
4930 if (target_format == QImage::Format_MonoLSB
4931 || target_format == QImage::Format_Mono
4932 || target_format == QImage::Format_Indexed8) {
4933 dImage.d->colortable = d->colortable;
4934 dImage.d->has_alpha_clut = d->has_alpha_clut | complex_xform;
4935 }
4936
4937 // initizialize the data
4938 if (target_format == QImage::Format_Indexed8) {
4939 if (dImage.d->colortable.size() < 256) {
4940 // colors are left in the color table, so pick that one as transparent
4941 dImage.d->colortable.append(t: 0x0);
4942 memset(s: dImage.bits(), c: dImage.d->colortable.size() - 1, n: dImage.d->nbytes);
4943 } else {
4944 memset(s: dImage.bits(), c: 0, n: dImage.d->nbytes);
4945 }
4946 } else
4947 memset(s: dImage.bits(), c: 0x00, n: dImage.d->nbytes);
4948
4949 if (target_format >= QImage::Format_RGB32 && target_format != QImage::Format_CMYK8888) {
4950 // Prevent QPainter from applying devicePixelRatio corrections
4951 QImage sImage = (devicePixelRatio() != 1) ? QImage(constBits(), width(), height(), format()) : *this;
4952 if (sImage.d != d
4953 && (d->format == QImage::Format_MonoLSB
4954 || d->format == QImage::Format_Mono
4955 || d->format == QImage::Format_Indexed8)) {
4956 sImage.d->colortable = d->colortable;
4957 sImage.d->has_alpha_clut = d->has_alpha_clut;
4958 }
4959
4960 Q_ASSERT(sImage.devicePixelRatio() == 1);
4961 Q_ASSERT(sImage.devicePixelRatio() == dImage.devicePixelRatio());
4962
4963 QPainter p(&dImage);
4964 if (mode == Qt::SmoothTransformation) {
4965 p.setRenderHint(hint: QPainter::Antialiasing);
4966 p.setRenderHint(hint: QPainter::SmoothPixmapTransform);
4967 }
4968 p.setTransform(transform: mat);
4969 p.drawImage(p: QPoint(0, 0), image: sImage);
4970 } else {
4971 bool invertible;
4972 mat = mat.inverted(invertible: &invertible); // invert matrix
4973 if (!invertible) // error, return null image
4974 return QImage();
4975
4976 // create target image (some of the code is from QImage::copy())
4977 int type = format() == Format_Mono ? QT_XFORM_TYPE_MSBFIRST : QT_XFORM_TYPE_LSBFIRST;
4978 qsizetype dbpl = dImage.bytesPerLine();
4979 qt_xForm_helper(trueMat: mat, xoffset: 0, type, depth: bpp, dptr: dImage.bits(), dbpl, p_inc: 0, dHeight: hd, sptr, sbpl, sWidth: ws, sHeight: hs);
4980 }
4981 copyMetadata(dst: dImage.d, src: d);
4982
4983 return dImage;
4984}
4985
4986/*!
4987 \fn QTransform QImage::trueMatrix(const QTransform &matrix, int width, int height)
4988
4989 Returns the actual matrix used for transforming an image with the
4990 given \a width, \a height and \a matrix.
4991
4992 When transforming an image using the transformed() function, the
4993 transformation matrix is internally adjusted to compensate for
4994 unwanted translation, i.e. transformed() returns the smallest
4995 image containing all transformed points of the original image.
4996 This function returns the modified matrix, which maps points
4997 correctly from the original image into the new image.
4998
4999 Unlike the other overload, this function creates transformation
5000 matrices that can be used to perform perspective
5001 transformations on images.
5002
5003 \sa transformed(), {QImage#Image Transformations}{Image
5004 Transformations}
5005*/
5006
5007QTransform QImage::trueMatrix(const QTransform &matrix, int w, int h)
5008{
5009 const QRectF rect(0, 0, w, h);
5010 const QRect mapped = matrix.mapRect(rect).toAlignedRect();
5011 const QPoint delta = mapped.topLeft();
5012 return matrix * QTransform().translate(dx: -delta.x(), dy: -delta.y());
5013}
5014
5015/*!
5016 \since 5.14
5017
5018 Sets the image color space to \a colorSpace without performing any conversions on image data.
5019
5020 \sa colorSpace()
5021*/
5022void QImage::setColorSpace(const QColorSpace &colorSpace)
5023{
5024 if (!d)
5025 return;
5026 if (d->colorSpace == colorSpace)
5027 return;
5028 if (colorSpace.isValid() && !qt_compatibleColorModelSource(data: pixelFormat().colorModel(), cs: colorSpace.colorModel()))
5029 return;
5030
5031 detachMetadata(invalidateCache: false);
5032 if (d)
5033 d->colorSpace = colorSpace;
5034}
5035
5036/*!
5037 \since 5.14
5038
5039 Converts the image to \a colorSpace.
5040
5041 If the image has no valid color space, the method does nothing.
5042
5043 \note If \a colorSpace is not compatible with the current format, the image
5044 will be converted to one that is.
5045
5046 \sa convertedToColorSpace(), setColorSpace()
5047*/
5048void QImage::convertToColorSpace(const QColorSpace &colorSpace)
5049{
5050 if (!d || !d->colorSpace.isValid())
5051 return;
5052 if (!colorSpace.isValidTarget()) {
5053 qWarning() << "QImage::convertToColorSpace: Output colorspace is not valid";
5054 return;
5055 }
5056 if (d->colorSpace == colorSpace)
5057 return;
5058 if (!qt_compatibleColorModelTarget(data: pixelFormat().colorModel(),
5059 cs: colorSpace.colorModel(), tm: colorSpace.transformModel())) {
5060 *this = convertedToColorSpace(colorSpace);
5061 return;
5062 }
5063 applyColorTransform(transform: d->colorSpace.transformationToColorSpace(colorspace: colorSpace));
5064 if (d->ref.loadRelaxed() != 1)
5065 detachMetadata(invalidateCache: false);
5066 d->colorSpace = colorSpace;
5067}
5068
5069/*!
5070 \since 6.8
5071
5072 Converts the image to \a colorSpace and \a format.
5073
5074 If the image has no valid color space, the method does nothing,
5075 nor if the color space is not compatible with with the format.
5076
5077 The specified image conversion \a flags control how the image data
5078 is handled during the format conversion process.
5079
5080 \sa convertedToColorSpace(), setColorSpace()
5081*/
5082void QImage::convertToColorSpace(const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags)
5083{
5084 if (!d || !d->colorSpace.isValid())
5085 return;
5086 if (!colorSpace.isValidTarget()) {
5087 qWarning() << "QImage::convertToColorSpace: Output colorspace is not valid";
5088 return;
5089 }
5090 if (!qt_compatibleColorModelTarget(data: toPixelFormat(format).colorModel(),
5091 cs: colorSpace.colorModel(), tm: colorSpace.transformModel())) {
5092 qWarning() << "QImage::convertToColorSpace: Color space is not compatible with format";
5093 return;
5094 }
5095
5096 if (d->colorSpace == colorSpace)
5097 return convertTo(format, flags);
5098 applyColorTransform(transform: d->colorSpace.transformationToColorSpace(colorspace: colorSpace), format, flags);
5099 d->colorSpace = colorSpace;
5100}
5101
5102/*!
5103 \since 5.14
5104
5105 Returns the image converted to \a colorSpace.
5106
5107 If the image has no valid color space, a null QImage is returned.
5108
5109 \note If \a colorSpace is not compatible with the current format,
5110 the returned image will also be converted to a format this is.
5111 For more control over returned image format, see the three argument
5112 overload of this method.
5113
5114 \sa convertToColorSpace(), colorTransformed()
5115*/
5116QImage QImage::convertedToColorSpace(const QColorSpace &colorSpace) const
5117{
5118 if (!d || !d->colorSpace.isValid())
5119 return QImage();
5120 if (!colorSpace.isValidTarget()) {
5121 qWarning() << "QImage::convertedToColorSpace: Output colorspace is not valid";
5122 return QImage();
5123 }
5124 if (d->colorSpace == colorSpace)
5125 return *this;
5126 QImage image = colorTransformed(transform: d->colorSpace.transformationToColorSpace(colorspace: colorSpace));
5127 image.setColorSpace(colorSpace);
5128 return image;
5129}
5130
5131/*!
5132 \fn QImage QImage::convertedToColorSpace(const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags) const &
5133 \fn QImage QImage::convertedToColorSpace(const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags) &&
5134 \since 6.8
5135
5136 Returns the image converted to \a colorSpace and \a format.
5137
5138 If the image has no valid color space, a null QImage is returned.
5139
5140 The specified image conversion \a flags control how the image data
5141 is handled during the format conversion process.
5142
5143 \sa colorTransformed()
5144*/
5145QImage QImage::convertedToColorSpace(const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags) const &
5146{
5147 if (!d || !d->colorSpace.isValid())
5148 return QImage();
5149 if (!colorSpace.isValidTarget()) {
5150 qWarning() << "QImage::convertedToColorSpace: Output colorspace is not valid";
5151 return QImage();
5152 }
5153 if (!qt_compatibleColorModelTarget(data: toPixelFormat(format).colorModel(),
5154 cs: colorSpace.colorModel(), tm: colorSpace.transformModel())) {
5155 qWarning() << "QImage::convertedToColorSpace: Color space is not compatible with format";
5156 return QImage();
5157 }
5158 if (d->colorSpace == colorSpace)
5159 return convertedTo(f: format, flags);
5160 QImage image = colorTransformed(transform: d->colorSpace.transformationToColorSpace(colorspace: colorSpace), format, flags);
5161 image.setColorSpace(colorSpace);
5162 return image;
5163}
5164
5165QImage QImage::convertedToColorSpace(const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags) &&
5166{
5167 if (!d || !d->colorSpace.isValid())
5168 return QImage();
5169 if (!colorSpace.isValidTarget()) {
5170 qWarning() << "QImage::convertedToColorSpace: Output colorspace is not valid";
5171 return QImage();
5172 }
5173 if (!qt_compatibleColorModelTarget(data: toPixelFormat(format).colorModel(),
5174 cs: colorSpace.colorModel(), tm: colorSpace.transformModel())) {
5175 qWarning() << "QImage::convertedToColorSpace: Color space is not compatible with format";
5176 return QImage();
5177 }
5178 if (d->colorSpace == colorSpace)
5179 return convertedTo(f: format, flags);
5180 applyColorTransform(transform: d->colorSpace.transformationToColorSpace(colorspace: colorSpace), format, flags);
5181 return std::move(*this);
5182}
5183
5184/*!
5185 \since 5.14
5186
5187 Returns the color space of the image if a color space is defined.
5188*/
5189QColorSpace QImage::colorSpace() const
5190{
5191 if (!d)
5192 return QColorSpace();
5193 return d->colorSpace;
5194}
5195
5196/*!
5197 \since 5.14
5198
5199 Applies the color transformation \a transform to all pixels in the image.
5200*/
5201void QImage::applyColorTransform(const QColorTransform &transform)
5202{
5203 if (transform.isIdentity())
5204 return;
5205
5206 if (!qt_compatibleColorModelSource(data: pixelFormat().colorModel(), cs: QColorTransformPrivate::get(q: transform)->colorSpaceIn->colorModel) ||
5207 !qt_compatibleColorModelTarget(data: pixelFormat().colorModel(), cs: QColorTransformPrivate::get(q: transform)->colorSpaceOut->colorModel,
5208 tm: QColorTransformPrivate::get(q: transform)->colorSpaceOut->transformModel)) {
5209 qWarning() << "QImage::applyColorTransform can not apply format switching transform without switching format";
5210 return;
5211 }
5212
5213 detach();
5214 if (!d)
5215 return;
5216 if (pixelFormat().colorModel() == QPixelFormat::Indexed) {
5217 for (int i = 0; i < d->colortable.size(); ++i)
5218 d->colortable[i] = transform.map(argb: d->colortable[i]);
5219 return;
5220 }
5221 QImage::Format oldFormat = format();
5222 if (qt_fpColorPrecision(format: oldFormat)) {
5223 if (oldFormat != QImage::Format_RGBX32FPx4 && oldFormat != QImage::Format_RGBA32FPx4
5224 && oldFormat != QImage::Format_RGBA32FPx4_Premultiplied)
5225 convertTo(format: QImage::Format_RGBA32FPx4);
5226 } else if (depth() > 32) {
5227 if (oldFormat != QImage::Format_RGBX64 && oldFormat != QImage::Format_RGBA64
5228 && oldFormat != QImage::Format_RGBA64_Premultiplied)
5229 convertTo(format: QImage::Format_RGBA64);
5230 } else if (oldFormat != QImage::Format_ARGB32 && oldFormat != QImage::Format_RGB32
5231 && oldFormat != QImage::Format_ARGB32_Premultiplied && oldFormat != QImage::Format_CMYK8888
5232 && oldFormat != QImage::Format_Grayscale8 && oldFormat != QImage::Format_Grayscale16) {
5233 if (hasAlphaChannel())
5234 convertTo(format: QImage::Format_ARGB32);
5235 else
5236 convertTo(format: QImage::Format_RGB32);
5237 }
5238
5239 QColorTransformPrivate::TransformFlags flags = QColorTransformPrivate::Unpremultiplied;
5240 switch (format()) {
5241 case Format_ARGB32_Premultiplied:
5242 case Format_RGBA64_Premultiplied:
5243 case Format_RGBA32FPx4_Premultiplied:
5244 flags = QColorTransformPrivate::Premultiplied;
5245 break;
5246 case Format_Grayscale8:
5247 case Format_Grayscale16:
5248 case Format_RGB32:
5249 case Format_CMYK8888:
5250 case Format_RGBX64:
5251 case Format_RGBX32FPx4:
5252 flags = QColorTransformPrivate::InputOpaque;
5253 break;
5254 case Format_ARGB32:
5255 case Format_RGBA64:
5256 case Format_RGBA32FPx4:
5257 break;
5258 default:
5259 Q_UNREACHABLE();
5260 }
5261
5262 std::function<void(int,int)> transformSegment;
5263
5264 if (format() == Format_Grayscale8) {
5265 transformSegment = [&](int yStart, int yEnd) {
5266 for (int y = yStart; y < yEnd; ++y) {
5267 uint8_t *scanline = reinterpret_cast<uint8_t *>(d->data + y * d->bytes_per_line);
5268 QColorTransformPrivate::get(q: transform)->apply(dst: scanline, src: scanline, count: width(), flags);
5269 }
5270 };
5271 } else if (format() == Format_Grayscale16) {
5272 transformSegment = [&](int yStart, int yEnd) {
5273 for (int y = yStart; y < yEnd; ++y) {
5274 uint16_t *scanline = reinterpret_cast<uint16_t *>(d->data + y * d->bytes_per_line);
5275 QColorTransformPrivate::get(q: transform)->apply(dst: scanline, src: scanline, count: width(), flags);
5276 }
5277 };
5278 } else if (qt_fpColorPrecision(format: format())) {
5279 transformSegment = [&](int yStart, int yEnd) {
5280 for (int y = yStart; y < yEnd; ++y) {
5281 QRgbaFloat32 *scanline = reinterpret_cast<QRgbaFloat32 *>(d->data + y * d->bytes_per_line);
5282 QColorTransformPrivate::get(q: transform)->apply(dst: scanline, src: scanline, count: width(), flags);
5283 }
5284 };
5285 } else if (depth() > 32) {
5286 transformSegment = [&](int yStart, int yEnd) {
5287 for (int y = yStart; y < yEnd; ++y) {
5288 QRgba64 *scanline = reinterpret_cast<QRgba64 *>(d->data + y * d->bytes_per_line);
5289 QColorTransformPrivate::get(q: transform)->apply(dst: scanline, src: scanline, count: width(), flags);
5290 }
5291 };
5292 } else if (oldFormat == QImage::Format_CMYK8888) {
5293 transformSegment = [&](int yStart, int yEnd) {
5294 for (int y = yStart; y < yEnd; ++y) {
5295 QCmyk32 *scanline = reinterpret_cast<QCmyk32 *>(d->data + y * d->bytes_per_line);
5296 QColorTransformPrivate::get(q: transform)->apply(dst: scanline, src: scanline, count: width(), flags);
5297 }
5298 };
5299 } else {
5300 transformSegment = [&](int yStart, int yEnd) {
5301 for (int y = yStart; y < yEnd; ++y) {
5302 QRgb *scanline = reinterpret_cast<QRgb *>(d->data + y * d->bytes_per_line);
5303 QColorTransformPrivate::get(q: transform)->apply(dst: scanline, src: scanline, count: width(), flags);
5304 }
5305 };
5306 }
5307
5308#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
5309 int segments = (qsizetype(width()) * height()) >> 16;
5310 segments = std::min(a: segments, b: height());
5311 QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
5312 if (segments > 1 && threadPool && !threadPool->contains(thread: QThread::currentThread())) {
5313 QSemaphore semaphore;
5314 int y = 0;
5315 for (int i = 0; i < segments; ++i) {
5316 int yn = (height() - y) / (segments - i);
5317 threadPool->start(functionToRun: [&, y, yn]() {
5318 transformSegment(y, y + yn);
5319 semaphore.release(n: 1);
5320 });
5321 y += yn;
5322 }
5323 semaphore.acquire(n: segments);
5324 } else
5325#endif
5326 transformSegment(0, height());
5327
5328 if (oldFormat != format())
5329 *this = std::move(*this).convertToFormat(f: oldFormat);
5330}
5331
5332/*!
5333 \since 6.8
5334
5335 Applies the color transformation \a transform to all pixels in the image, and converts the format of the image to \a toFormat.
5336
5337 The specified image conversion \a flags control how the image data
5338 is handled during the format conversion process.
5339*/
5340void QImage::applyColorTransform(const QColorTransform &transform, QImage::Format toFormat, Qt::ImageConversionFlags flags)
5341{
5342 if (!d)
5343 return;
5344 if (transform.isIdentity())
5345 return convertTo(format: toFormat, flags);
5346
5347 *this = colorTransformed(transform, format: toFormat, flags);
5348}
5349
5350/*!
5351 \since 6.4
5352
5353 Returns the image color transformed using \a transform on all pixels in the image.
5354
5355 \note If \a transform has a source color space which is incompatible with the format of this image,
5356 returns a null QImage. If \a transform has a target color space which is incompatible with the format
5357 of this image, the image will also be converted to a compatible format. For more control about the
5358 choice of the target pixel format, see the three argument overload of this method.
5359
5360 \sa applyColorTransform()
5361*/
5362QImage QImage::colorTransformed(const QColorTransform &transform) const &
5363{
5364 if (!d)
5365 return QImage();
5366 if (transform.isIdentity())
5367 return *this;
5368
5369 const QColorSpacePrivate *inColorSpace = QColorTransformPrivate::get(q: transform)->colorSpaceIn.constData();
5370 const QColorSpacePrivate *outColorSpace = QColorTransformPrivate::get(q: transform)->colorSpaceOut.constData();
5371 if (!qt_compatibleColorModelSource(data: pixelFormat().colorModel(), cs: inColorSpace->colorModel)) {
5372 qWarning() << "QImage::colorTransformed: Invalid input color space for transform";
5373 return QImage();
5374 }
5375 if (!qt_compatibleColorModelTarget(data: pixelFormat().colorModel(), cs: outColorSpace->colorModel, tm: outColorSpace->transformModel)) {
5376 // All model switching transforms are opaque in at least one end.
5377 switch (outColorSpace->colorModel) {
5378 case QColorSpace::ColorModel::Rgb:
5379 return colorTransformed(transform, format: qt_highColorPrecision(format: format(), opaque: true) ? QImage::Format_RGBX64 : QImage::Format_RGB32);
5380 case QColorSpace::ColorModel::Gray:
5381 return colorTransformed(transform, format: qt_highColorPrecision(format: format(), opaque: true) ? QImage::Format_Grayscale16 : QImage::Format_Grayscale8);
5382 case QColorSpace::ColorModel::Cmyk:
5383 return colorTransformed(transform, format: QImage::Format_CMYK8888);
5384 case QColorSpace::ColorModel::Undefined:
5385 break;
5386 }
5387 return QImage();
5388 }
5389
5390 QImage image = copy();
5391 image.applyColorTransform(transform);
5392 return image;
5393}
5394
5395static bool isRgb32Data(QImage::Format f)
5396{
5397 switch (f) {
5398 case QImage::Format_RGB32:
5399 case QImage::Format_ARGB32:
5400 case QImage::Format_ARGB32_Premultiplied:
5401 return true;
5402 default:
5403 break;
5404 }
5405 return false;
5406}
5407
5408static bool isRgb64Data(QImage::Format f)
5409{
5410 switch (f) {
5411 case QImage::Format_RGBX64:
5412 case QImage::Format_RGBA64:
5413 case QImage::Format_RGBA64_Premultiplied:
5414 return true;
5415 default:
5416 break;
5417 }
5418 return false;
5419}
5420
5421static bool isRgb32fpx4Data(QImage::Format f)
5422{
5423 switch (f) {
5424 case QImage::Format_RGBX32FPx4:
5425 case QImage::Format_RGBA32FPx4:
5426 case QImage::Format_RGBA32FPx4_Premultiplied:
5427 return true;
5428 default:
5429 break;
5430 }
5431 return false;
5432}
5433
5434/*!
5435 \since 6.8
5436
5437 Returns the image color transformed using \a transform on all pixels in the image, returning an image of format \a toFormat.
5438
5439 The specified image conversion \a flags control how the image data
5440 is handled during the format conversion process.
5441
5442 \note If \a transform has a source color space which is incompatible with the format of this image,
5443 or a target color space that is incompatible with \a toFormat, returns a null QImage.
5444
5445 \sa applyColorTransform()
5446*/
5447QImage QImage::colorTransformed(const QColorTransform &transform, QImage::Format toFormat, Qt::ImageConversionFlags flags) const &
5448{
5449 if (!d)
5450 return QImage();
5451 if (toFormat == QImage::Format_Invalid)
5452 toFormat = format();
5453 if (transform.isIdentity())
5454 return convertedTo(f: toFormat, flags);
5455
5456 const QColorSpacePrivate *inColorSpace = QColorTransformPrivate::get(q: transform)->colorSpaceIn.constData();
5457 const QColorSpacePrivate *outColorSpace = QColorTransformPrivate::get(q: transform)->colorSpaceOut.constData();
5458 if (!qt_compatibleColorModelSource(data: pixelFormat().colorModel(), cs: inColorSpace->colorModel)) {
5459 qWarning() << "QImage::colorTransformed: Invalid input color space for transform";
5460 return QImage();
5461 }
5462 if (!qt_compatibleColorModelTarget(data: toPixelFormat(format: toFormat).colorModel(), cs: outColorSpace->colorModel, tm: outColorSpace->transformModel)) {
5463 qWarning() << "QImage::colorTransformed: Invalid output color space for transform";
5464 return QImage();
5465 }
5466
5467 QImage fromImage = *this;
5468
5469 QImage::Format tmpFormat = toFormat;
5470 switch (toFormat) {
5471 case QImage::Format_RGB32:
5472 case QImage::Format_ARGB32:
5473 case QImage::Format_ARGB32_Premultiplied:
5474 case QImage::Format_RGBX32FPx4:
5475 case QImage::Format_RGBA32FPx4:
5476 case QImage::Format_RGBA32FPx4_Premultiplied:
5477 case QImage::Format_RGBX64:
5478 case QImage::Format_RGBA64:
5479 case QImage::Format_RGBA64_Premultiplied:
5480 case QImage::Format_Grayscale8:
5481 case QImage::Format_Grayscale16:
5482 case QImage::Format_CMYK8888:
5483 // can be output natively
5484 break;
5485 case QImage::Format_RGB16:
5486 case QImage::Format_RGB444:
5487 case QImage::Format_RGB555:
5488 case QImage::Format_RGB666:
5489 case QImage::Format_RGB888:
5490 case QImage::Format_BGR888:
5491 case QImage::Format_RGBX8888:
5492 tmpFormat = QImage::Format_RGB32;
5493 break;
5494 case QImage::Format_Mono:
5495 case QImage::Format_MonoLSB:
5496 case QImage::Format_Indexed8:
5497 case QImage::Format_ARGB8565_Premultiplied:
5498 case QImage::Format_ARGB6666_Premultiplied:
5499 case QImage::Format_ARGB8555_Premultiplied:
5500 case QImage::Format_ARGB4444_Premultiplied:
5501 case QImage::Format_RGBA8888:
5502 case QImage::Format_RGBA8888_Premultiplied:
5503 tmpFormat = QImage::Format_ARGB32;
5504 break;
5505 case QImage::Format_BGR30:
5506 case QImage::Format_RGB30:
5507 tmpFormat = QImage::Format_RGBX64;
5508 break;
5509 case QImage::Format_A2BGR30_Premultiplied:
5510 case QImage::Format_A2RGB30_Premultiplied:
5511 tmpFormat = QImage::Format_RGBA64;
5512 break;
5513 case QImage::Format_RGBX16FPx4:
5514 case QImage::Format_RGBA16FPx4:
5515 case QImage::Format_RGBA16FPx4_Premultiplied:
5516 tmpFormat = QImage::Format_RGBA32FPx4;
5517 break;
5518 case QImage::Format_Alpha8:
5519 return convertedTo(f: QImage::Format_Alpha8);
5520 case QImage::Format_Invalid:
5521 case QImage::NImageFormats:
5522 Q_UNREACHABLE();
5523 break;
5524 }
5525 QColorSpace::ColorModel inColorData = qt_csColorData(format: pixelFormat().colorModel());
5526 QColorSpace::ColorModel outColorData = qt_csColorData(format: toPixelFormat(format: toFormat).colorModel());
5527 // Ensure only precision increasing transforms
5528 if (inColorData != outColorData) {
5529 if (fromImage.format() == QImage::Format_Grayscale8 && outColorData == QColorSpace::ColorModel::Rgb)
5530 tmpFormat = QImage::Format_RGB32;
5531 else if (tmpFormat == QImage::Format_Grayscale8 && qt_highColorPrecision(format: fromImage.format()))
5532 tmpFormat = QImage::Format_Grayscale16;
5533 else if (fromImage.format() == QImage::Format_Grayscale16 && outColorData == QColorSpace::ColorModel::Rgb)
5534 tmpFormat = QImage::Format_RGBX64;
5535 } else {
5536 if (tmpFormat == QImage::Format_Grayscale8 && fromImage.format() == QImage::Format_Grayscale16)
5537 tmpFormat = QImage::Format_Grayscale16;
5538 else if (qt_fpColorPrecision(format: fromImage.format()) && !qt_fpColorPrecision(format: tmpFormat))
5539 tmpFormat = QImage::Format_RGBA32FPx4;
5540 else if (isRgb32Data(f: tmpFormat) && qt_highColorPrecision(format: fromImage.format(), opaque: true))
5541 tmpFormat = QImage::Format_RGBA64;
5542 }
5543
5544 QImage toImage(size(), tmpFormat);
5545 copyMetadata(dst: &toImage, src: *this);
5546
5547 std::function<void(int, int)> transformSegment;
5548 QColorTransformPrivate::TransformFlags transFlags = QColorTransformPrivate::Unpremultiplied;
5549
5550 if (inColorData != outColorData) {
5551 // Needs color model switching transform
5552 if (inColorData == QColorSpace::ColorModel::Gray && outColorData == QColorSpace::ColorModel::Rgb) {
5553 // Gray -> RGB
5554 if (format() == QImage::Format_Grayscale8) {
5555 transformSegment = [&](int yStart, int yEnd) {
5556 for (int y = yStart; y < yEnd; ++y) {
5557 const quint8 *in_scanline = reinterpret_cast<const quint8 *>(d->data + y * d->bytes_per_line);
5558 QRgb *out_scanline = reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
5559 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: QColorTransformPrivate::InputOpaque);
5560 }
5561 };
5562 } else {
5563 transformSegment = [&](int yStart, int yEnd) {
5564 for (int y = yStart; y < yEnd; ++y) {
5565 const quint16 *in_scanline = reinterpret_cast<const quint16 *>(d->data + y * d->bytes_per_line);
5566 QRgba64 *out_scanline = reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5567 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: QColorTransformPrivate::InputOpaque);
5568 }
5569 };
5570 }
5571 } else if (inColorData == QColorSpace::ColorModel::Gray && outColorData == QColorSpace::ColorModel::Cmyk) {
5572 // Gray -> CMYK
5573 if (format() == QImage::Format_Grayscale8) {
5574 transformSegment = [&](int yStart, int yEnd) {
5575 for (int y = yStart; y < yEnd; ++y) {
5576 const quint8 *in_scanline = reinterpret_cast<const quint8 *>(d->data + y * d->bytes_per_line);
5577 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5578 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: QColorTransformPrivate::InputOpaque);
5579 }
5580 };
5581 } else {
5582 transformSegment = [&](int yStart, int yEnd) {
5583 for (int y = yStart; y < yEnd; ++y) {
5584 const quint16 *in_scanline = reinterpret_cast<const quint16 *>(d->data + y * d->bytes_per_line);
5585 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5586 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: QColorTransformPrivate::InputOpaque);
5587 }
5588 };
5589 }
5590 } else if (inColorData == QColorSpace::ColorModel::Rgb && outColorData == QColorSpace::ColorModel::Gray) {
5591 // RGB -> Gray
5592 if (tmpFormat == QImage::Format_Grayscale8) {
5593 fromImage.convertTo(format: QImage::Format_RGB32);
5594 transformSegment = [&](int yStart, int yEnd) {
5595 for (int y = yStart; y < yEnd; ++y) {
5596 const QRgb *in_scanline = reinterpret_cast<const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5597 quint8 *out_scanline = reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
5598 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: QColorTransformPrivate::InputOpaque);
5599 }
5600 };
5601 } else {
5602 fromImage.convertTo(format: QImage::Format_RGBX64);
5603 transformSegment = [&](int yStart, int yEnd) {
5604 for (int y = yStart; y < yEnd; ++y) {
5605 const QRgba64 *in_scanline = reinterpret_cast<const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5606 quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5607 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: QColorTransformPrivate::InputOpaque);
5608 }
5609 };
5610 }
5611 } else if (inColorData == QColorSpace::ColorModel::Cmyk && outColorData == QColorSpace::ColorModel::Gray) {
5612 // CMYK -> Gray
5613 if (tmpFormat == QImage::Format_Grayscale8) {
5614 transformSegment = [&](int yStart, int yEnd) {
5615 for (int y = yStart; y < yEnd; ++y) {
5616 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5617 quint8 *out_scanline = reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
5618 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: QColorTransformPrivate::InputOpaque);
5619 }
5620 };
5621 } else {
5622 transformSegment = [&](int yStart, int yEnd) {
5623 for (int y = yStart; y < yEnd; ++y) {
5624 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5625 quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5626 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: QColorTransformPrivate::InputOpaque);
5627 }
5628 };
5629 }
5630 } else if (inColorData == QColorSpace::ColorModel::Cmyk && outColorData == QColorSpace::ColorModel::Rgb) {
5631 // CMYK -> RGB
5632 if (isRgb32Data(f: tmpFormat) ) {
5633 transformSegment = [&](int yStart, int yEnd) {
5634 for (int y = yStart; y < yEnd; ++y) {
5635 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5636 QRgb *out_scanline = reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
5637 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: QColorTransformPrivate::InputOpaque);
5638 }
5639 };
5640 } else if (isRgb64Data(f: tmpFormat)) {
5641 transformSegment = [&](int yStart, int yEnd) {
5642 for (int y = yStart; y < yEnd; ++y) {
5643 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5644 QRgba64 *out_scanline = reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5645 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: QColorTransformPrivate::InputOpaque);
5646 }
5647 };
5648 } else {
5649 Q_ASSERT(isRgb32fpx4Data(tmpFormat));
5650 transformSegment = [&](int yStart, int yEnd) {
5651 for (int y = yStart; y < yEnd; ++y) {
5652 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5653 QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5654 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: QColorTransformPrivate::InputOpaque);
5655 }
5656 };
5657 }
5658 } else if (inColorData == QColorSpace::ColorModel::Rgb && outColorData == QColorSpace::ColorModel::Cmyk) {
5659 // RGB -> CMYK
5660 if (!fromImage.hasAlphaChannel())
5661 transFlags = QColorTransformPrivate::InputOpaque;
5662 else if (qPixelLayouts[fromImage.format()].premultiplied)
5663 transFlags = QColorTransformPrivate::Premultiplied;
5664 if (isRgb32Data(f: fromImage.format()) ) {
5665 transformSegment = [&](int yStart, int yEnd) {
5666 for (int y = yStart; y < yEnd; ++y) {
5667 const QRgb *in_scanline = reinterpret_cast<const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5668 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5669 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: transFlags);
5670 }
5671 };
5672 } else if (isRgb64Data(f: fromImage.format())) {
5673 transformSegment = [&](int yStart, int yEnd) {
5674 for (int y = yStart; y < yEnd; ++y) {
5675 const QRgba64 *in_scanline = reinterpret_cast<const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5676 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5677 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: transFlags);
5678 }
5679 };
5680 } else {
5681 Q_ASSERT(isRgb32fpx4Data(fromImage.format()));
5682 transformSegment = [&](int yStart, int yEnd) {
5683 for (int y = yStart; y < yEnd; ++y) {
5684 const QRgbaFloat32 *in_scanline = reinterpret_cast<const QRgbaFloat32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5685 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5686 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: transFlags);
5687 }
5688 };
5689 }
5690 } else {
5691 Q_UNREACHABLE();
5692 }
5693 } else {
5694 // Conversion on same color model
5695 if (pixelFormat().colorModel() == QPixelFormat::Indexed) {
5696 for (int i = 0; i < d->colortable.size(); ++i)
5697 fromImage.d->colortable[i] = transform.map(argb: d->colortable[i]);
5698 return fromImage.convertedTo(f: toFormat, flags);
5699 }
5700
5701 QImage::Format oldFormat = format();
5702 if (qt_fpColorPrecision(format: oldFormat)) {
5703 if (oldFormat != QImage::Format_RGBX32FPx4 && oldFormat != QImage::Format_RGBA32FPx4
5704 && oldFormat != QImage::Format_RGBA32FPx4_Premultiplied)
5705 fromImage.convertTo(format: QImage::Format_RGBA32FPx4);
5706 } else if (qt_highColorPrecision(format: oldFormat, opaque: true)) {
5707 if (oldFormat != QImage::Format_RGBX64 && oldFormat != QImage::Format_RGBA64
5708 && oldFormat != QImage::Format_RGBA64_Premultiplied && oldFormat != QImage::Format_Grayscale16)
5709 fromImage.convertTo(format: QImage::Format_RGBA64);
5710 } else if (oldFormat != QImage::Format_ARGB32 && oldFormat != QImage::Format_RGB32
5711 && oldFormat != QImage::Format_ARGB32_Premultiplied && oldFormat != QImage::Format_CMYK8888
5712 && oldFormat != QImage::Format_Grayscale8 && oldFormat != QImage::Format_Grayscale16) {
5713 if (hasAlphaChannel())
5714 fromImage.convertTo(format: QImage::Format_ARGB32);
5715 else
5716 fromImage.convertTo(format: QImage::Format_RGB32);
5717 }
5718
5719 if (!fromImage.hasAlphaChannel())
5720 transFlags = QColorTransformPrivate::InputOpaque;
5721 else if (qPixelLayouts[fromImage.format()].premultiplied)
5722 transFlags = QColorTransformPrivate::Premultiplied;
5723
5724 if (fromImage.format() == Format_Grayscale8) {
5725 transformSegment = [&](int yStart, int yEnd) {
5726 for (int y = yStart; y < yEnd; ++y) {
5727 const quint8 *in_scanline = reinterpret_cast<const quint8 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5728 if (tmpFormat == Format_Grayscale8) {
5729 quint8 *out_scanline = reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
5730 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: transFlags);
5731 } else {
5732 Q_ASSERT(tmpFormat == Format_Grayscale16);
5733 quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5734 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: transFlags);
5735 }
5736 }
5737 };
5738 } else if (fromImage.format() == Format_Grayscale16) {
5739 transformSegment = [&](int yStart, int yEnd) {
5740 for (int y = yStart; y < yEnd; ++y) {
5741 const quint16 *in_scanline = reinterpret_cast<const quint16 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5742 quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5743 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: transFlags);
5744 }
5745 };
5746 } else if (fromImage.format() == Format_CMYK8888) {
5747 Q_ASSERT(tmpFormat == Format_CMYK8888);
5748 transformSegment = [&](int yStart, int yEnd) {
5749 for (int y = yStart; y < yEnd; ++y) {
5750 const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5751 QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5752 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: transFlags);
5753 }
5754 };
5755 } else if (isRgb32fpx4Data(f: fromImage.format())) {
5756 Q_ASSERT(isRgb32fpx4Data(tmpFormat));
5757 transformSegment = [&](int yStart, int yEnd) {
5758 for (int y = yStart; y < yEnd; ++y) {
5759 const QRgbaFloat32 *in_scanline = reinterpret_cast<const QRgbaFloat32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5760 QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5761 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: transFlags);
5762 }
5763 };
5764 } else if (isRgb64Data(f: fromImage.format())) {
5765 transformSegment = [&](int yStart, int yEnd) {
5766 for (int y = yStart; y < yEnd; ++y) {
5767 const QRgba64 *in_scanline = reinterpret_cast<const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5768 if (isRgb32fpx4Data(f: tmpFormat)) {
5769 QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5770 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: transFlags);
5771 } else {
5772 Q_ASSERT(isRgb64Data(tmpFormat));
5773 QRgba64 *out_scanline = reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5774 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: transFlags);
5775 }
5776 }
5777 };
5778 } else {
5779 transformSegment = [&](int yStart, int yEnd) {
5780 for (int y = yStart; y < yEnd; ++y) {
5781 const QRgb *in_scanline = reinterpret_cast<const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5782 if (isRgb32fpx4Data(f: tmpFormat)) {
5783 QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5784 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: transFlags);
5785 } else if (isRgb64Data(f: tmpFormat)) {
5786 QRgba64 *out_scanline = reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5787 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: transFlags);
5788 } else {
5789 Q_ASSERT(isRgb32Data(tmpFormat));
5790 QRgb *out_scanline = reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
5791 QColorTransformPrivate::get(q: transform)->apply(dst: out_scanline, src: in_scanline, count: width(), flags: transFlags);
5792 }
5793 }
5794 };
5795 }
5796 }
5797
5798#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
5799 int segments = (qsizetype(width()) * height()) >> 16;
5800 segments = std::min(a: segments, b: height());
5801 QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
5802 if (segments > 1 && threadPool && !threadPool->contains(thread: QThread::currentThread())) {
5803 QSemaphore semaphore;
5804 int y = 0;
5805 for (int i = 0; i < segments; ++i) {
5806 int yn = (height() - y) / (segments - i);
5807 threadPool->start(functionToRun: [&, y, yn]() {
5808 transformSegment(y, y + yn);
5809 semaphore.release(n: 1);
5810 });
5811 y += yn;
5812 }
5813 semaphore.acquire(n: segments);
5814 } else
5815#endif
5816 transformSegment(0, height());
5817
5818 if (tmpFormat != toFormat)
5819 toImage.convertTo(format: toFormat);
5820
5821 return toImage;
5822}
5823
5824/*!
5825 \since 6.4
5826 \overload
5827
5828 Returns the image color transformed using \a transform on all pixels in the image.
5829
5830 \sa applyColorTransform()
5831*/
5832QImage QImage::colorTransformed(const QColorTransform &transform) &&
5833{
5834 if (!d)
5835 return QImage();
5836
5837 const QColorSpacePrivate *inColorSpace = QColorTransformPrivate::get(q: transform)->colorSpaceIn.constData();
5838 const QColorSpacePrivate *outColorSpace = QColorTransformPrivate::get(q: transform)->colorSpaceOut.constData();
5839 if (!qt_compatibleColorModelSource(data: pixelFormat().colorModel(), cs: inColorSpace->colorModel)) {
5840 qWarning() << "QImage::colorTransformed: Invalid input color space for transform";
5841 return QImage();
5842 }
5843 if (!qt_compatibleColorModelTarget(data: pixelFormat().colorModel(), cs: outColorSpace->colorModel, tm: outColorSpace->transformModel)) {
5844 // There is currently no inplace conversion of both colorspace and format, so just use the normal version.
5845 switch (outColorSpace->colorModel) {
5846 case QColorSpace::ColorModel::Rgb:
5847 return colorTransformed(transform, toFormat: qt_highColorPrecision(format: format(), opaque: true) ? QImage::Format_RGBX64 : QImage::Format_RGB32);
5848 case QColorSpace::ColorModel::Gray:
5849 return colorTransformed(transform, toFormat: qt_highColorPrecision(format: format(), opaque: true) ? QImage::Format_Grayscale16 : QImage::Format_Grayscale8);
5850 case QColorSpace::ColorModel::Cmyk:
5851 return colorTransformed(transform, toFormat: QImage::Format_CMYK8888);
5852 case QColorSpace::ColorModel::Undefined:
5853 break;
5854 }
5855 return QImage();
5856 }
5857
5858 applyColorTransform(transform);
5859 return std::move(*this);
5860}
5861
5862/*!
5863 \since 6.8
5864 \overload
5865
5866 Returns the image color transformed using \a transform on all pixels in the image.
5867
5868 \sa applyColorTransform()
5869*/
5870QImage QImage::colorTransformed(const QColorTransform &transform, QImage::Format format, Qt::ImageConversionFlags flags) &&
5871{
5872 // There is currently no inplace conversion of both colorspace and format, so just use the normal version.
5873 return colorTransformed(transform, toFormat: format, flags);
5874}
5875
5876bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags flags)
5877{
5878 if (format == newFormat)
5879 return true;
5880
5881 // No in-place conversion if we have to detach
5882 if (ref.loadRelaxed() > 1 || !own_data)
5883 return false;
5884
5885 InPlace_Image_Converter converter = qimage_inplace_converter_map[format][newFormat];
5886 if (converter)
5887 return converter(this, flags);
5888 if (format > QImage::Format_Indexed8 && newFormat > QImage::Format_Indexed8 && !qimage_converter_map[format][newFormat]) {
5889 // Convert inplace generic, but only if there are no direct converters,
5890 // any direct ones are probably better even if not inplace.
5891 if (qt_highColorPrecision(format: newFormat, opaque: !qPixelLayouts[newFormat].hasAlphaChannel)
5892 && qt_highColorPrecision(format, opaque: !qPixelLayouts[format].hasAlphaChannel)) {
5893#if QT_CONFIG(raster_fp)
5894 if (qt_fpColorPrecision(format) && qt_fpColorPrecision(format: newFormat))
5895 return convert_generic_inplace_over_rgba32f(data: this, dst_format: newFormat, flags);
5896#endif
5897 return convert_generic_inplace_over_rgb64(data: this, dst_format: newFormat, flags);
5898 }
5899 return convert_generic_inplace(data: this, dst_format: newFormat, flags);
5900 }
5901 return false;
5902}
5903
5904/*!
5905 \typedef QImage::DataPtr
5906 \internal
5907*/
5908
5909/*!
5910 \fn DataPtr & QImage::data_ptr()
5911 \internal
5912*/
5913
5914#ifndef QT_NO_DEBUG_STREAM
5915QDebug operator<<(QDebug dbg, const QImage &i)
5916{
5917 QDebugStateSaver saver(dbg);
5918 dbg.nospace();
5919 dbg.noquote();
5920 dbg << "QImage(";
5921 if (i.isNull()) {
5922 dbg << "null";
5923 } else {
5924 dbg << i.size() << ",format=" << i.format() << ",depth=" << i.depth();
5925 if (i.colorCount())
5926 dbg << ",colorCount=" << i.colorCount();
5927 const int bytesPerLine = i.bytesPerLine();
5928 dbg << ",devicePixelRatio=" << i.devicePixelRatio()
5929 << ",bytesPerLine=" << bytesPerLine << ",sizeInBytes=" << i.sizeInBytes();
5930 if (dbg.verbosity() > 2 && i.height() > 0) {
5931 const int outputLength = qMin(a: bytesPerLine, b: 24);
5932 dbg << ",line0="
5933 << QByteArray(reinterpret_cast<const char *>(i.scanLine(i: 0)), outputLength).toHex()
5934 << "...";
5935 }
5936 }
5937 dbg << ')';
5938 return dbg;
5939}
5940#endif
5941
5942static constexpr QPixelFormat pixelformats[] = {
5943 //QImage::Format_Invalid:
5944 QPixelFormat(),
5945 //QImage::Format_Mono:
5946 QPixelFormat(QPixelFormat::Indexed,
5947 /*RED*/ 1,
5948 /*GREEN*/ 0,
5949 /*BLUE*/ 0,
5950 /*FOURTH*/ 0,
5951 /*FIFTH*/ 0,
5952 /*ALPHA*/ 0,
5953 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5954 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5955 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5956 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5957 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5958 //QImage::Format_MonoLSB:
5959 QPixelFormat(QPixelFormat::Indexed,
5960 /*RED*/ 1,
5961 /*GREEN*/ 0,
5962 /*BLUE*/ 0,
5963 /*FOURTH*/ 0,
5964 /*FIFTH*/ 0,
5965 /*ALPHA*/ 0,
5966 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5967 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5968 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5969 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5970 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5971 //QImage::Format_Indexed8:
5972 QPixelFormat(QPixelFormat::Indexed,
5973 /*RED*/ 8,
5974 /*GREEN*/ 0,
5975 /*BLUE*/ 0,
5976 /*FOURTH*/ 0,
5977 /*FIFTH*/ 0,
5978 /*ALPHA*/ 0,
5979 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5980 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5981 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5982 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
5983 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5984 //QImage::Format_RGB32:
5985 QPixelFormat(QPixelFormat::RGB,
5986 /*RED*/ 8,
5987 /*GREEN*/ 8,
5988 /*BLUE*/ 8,
5989 /*FOURTH*/ 0,
5990 /*FIFTH*/ 0,
5991 /*ALPHA*/ 8,
5992 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
5993 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
5994 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
5995 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
5996 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
5997 //QImage::Format_ARGB32:
5998 QPixelFormat(QPixelFormat::RGB,
5999 /*RED*/ 8,
6000 /*GREEN*/ 8,
6001 /*BLUE*/ 8,
6002 /*FOURTH*/ 0,
6003 /*FIFTH*/ 0,
6004 /*ALPHA*/ 8,
6005 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6006 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6007 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6008 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6009 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6010 //QImage::Format_ARGB32_Premultiplied:
6011 QPixelFormat(QPixelFormat::RGB,
6012 /*RED*/ 8,
6013 /*GREEN*/ 8,
6014 /*BLUE*/ 8,
6015 /*FOURTH*/ 0,
6016 /*FIFTH*/ 0,
6017 /*ALPHA*/ 8,
6018 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6019 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6020 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6021 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6022 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6023 //QImage::Format_RGB16:
6024 QPixelFormat(QPixelFormat::RGB,
6025 /*RED*/ 5,
6026 /*GREEN*/ 6,
6027 /*BLUE*/ 5,
6028 /*FOURTH*/ 0,
6029 /*FIFTH*/ 0,
6030 /*ALPHA*/ 0,
6031 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6032 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6033 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6034 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6035 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6036 //QImage::Format_ARGB8565_Premultiplied:
6037 QPixelFormat(QPixelFormat::RGB,
6038 /*RED*/ 5,
6039 /*GREEN*/ 6,
6040 /*BLUE*/ 5,
6041 /*FOURTH*/ 0,
6042 /*FIFTH*/ 0,
6043 /*ALPHA*/ 8,
6044 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6045 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6046 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6047 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6048 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6049 //QImage::Format_RGB666:
6050 QPixelFormat(QPixelFormat::RGB,
6051 /*RED*/ 6,
6052 /*GREEN*/ 6,
6053 /*BLUE*/ 6,
6054 /*FOURTH*/ 0,
6055 /*FIFTH*/ 0,
6056 /*ALPHA*/ 0,
6057 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6058 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6059 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6060 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6061 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6062 //QImage::Format_ARGB6666_Premultiplied:
6063 QPixelFormat(QPixelFormat::RGB,
6064 /*RED*/ 6,
6065 /*GREEN*/ 6,
6066 /*BLUE*/ 6,
6067 /*FOURTH*/ 0,
6068 /*FIFTH*/ 0,
6069 /*ALPHA*/ 6,
6070 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6071 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6072 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6073 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6074 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6075 //QImage::Format_RGB555:
6076 QPixelFormat(QPixelFormat::RGB,
6077 /*RED*/ 5,
6078 /*GREEN*/ 5,
6079 /*BLUE*/ 5,
6080 /*FOURTH*/ 0,
6081 /*FIFTH*/ 0,
6082 /*ALPHA*/ 0,
6083 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6084 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6085 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6086 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6087 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6088 //QImage::Format_ARGB8555_Premultiplied:
6089 QPixelFormat(QPixelFormat::RGB,
6090 /*RED*/ 5,
6091 /*GREEN*/ 5,
6092 /*BLUE*/ 5,
6093 /*FOURTH*/ 0,
6094 /*FIFTH*/ 0,
6095 /*ALPHA*/ 8,
6096 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6097 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6098 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6099 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6100 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6101 //QImage::Format_RGB888:
6102 QPixelFormat(QPixelFormat::RGB,
6103 /*RED*/ 8,
6104 /*GREEN*/ 8,
6105 /*BLUE*/ 8,
6106 /*FOURTH*/ 0,
6107 /*FIFTH*/ 0,
6108 /*ALPHA*/ 0,
6109 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6110 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6111 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6112 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6113 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6114 //QImage::Format_RGB444:
6115 QPixelFormat(QPixelFormat::RGB,
6116 /*RED*/ 4,
6117 /*GREEN*/ 4,
6118 /*BLUE*/ 4,
6119 /*FOURTH*/ 0,
6120 /*FIFTH*/ 0,
6121 /*ALPHA*/ 0,
6122 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6123 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6124 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6125 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6126 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6127 //QImage::Format_ARGB4444_Premultiplied:
6128 QPixelFormat(QPixelFormat::RGB,
6129 /*RED*/ 4,
6130 /*GREEN*/ 4,
6131 /*BLUE*/ 4,
6132 /*FOURTH*/ 0,
6133 /*FIFTH*/ 0,
6134 /*ALPHA*/ 4,
6135 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6136 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6137 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6138 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6139 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6140 //QImage::Format_RGBX8888:
6141 QPixelFormat(QPixelFormat::RGB,
6142 /*RED*/ 8,
6143 /*GREEN*/ 8,
6144 /*BLUE*/ 8,
6145 /*FOURTH*/ 0,
6146 /*FIFTH*/ 0,
6147 /*ALPHA*/ 8,
6148 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6149 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6150 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6151 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6152 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6153 //QImage::Format_RGBA8888:
6154 QPixelFormat(QPixelFormat::RGB,
6155 /*RED*/ 8,
6156 /*GREEN*/ 8,
6157 /*BLUE*/ 8,
6158 /*FOURTH*/ 0,
6159 /*FIFTH*/ 0,
6160 /*ALPHA*/ 8,
6161 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6162 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6163 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6164 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6165 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6166 //QImage::Format_RGBA8888_Premultiplied:
6167 QPixelFormat(QPixelFormat::RGB,
6168 /*RED*/ 8,
6169 /*GREEN*/ 8,
6170 /*BLUE*/ 8,
6171 /*FOURTH*/ 0,
6172 /*FIFTH*/ 0,
6173 /*ALPHA*/ 8,
6174 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6175 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6176 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6177 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6178 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6179 //QImage::Format_BGR30:
6180 QPixelFormat(QPixelFormat::BGR,
6181 /*RED*/ 10,
6182 /*GREEN*/ 10,
6183 /*BLUE*/ 10,
6184 /*FOURTH*/ 0,
6185 /*FIFTH*/ 0,
6186 /*ALPHA*/ 2,
6187 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6188 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6189 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6190 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6191 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6192 //QImage::Format_A2BGR30_Premultiplied:
6193 QPixelFormat(QPixelFormat::BGR,
6194 /*RED*/ 10,
6195 /*GREEN*/ 10,
6196 /*BLUE*/ 10,
6197 /*FOURTH*/ 0,
6198 /*FIFTH*/ 0,
6199 /*ALPHA*/ 2,
6200 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6201 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6202 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6203 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6204 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6205 //QImage::Format_RGB30:
6206 QPixelFormat(QPixelFormat::RGB,
6207 /*RED*/ 10,
6208 /*GREEN*/ 10,
6209 /*BLUE*/ 10,
6210 /*FOURTH*/ 0,
6211 /*FIFTH*/ 0,
6212 /*ALPHA*/ 2,
6213 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6214 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6215 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6216 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6217 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6218 //QImage::Format_A2RGB30_Premultiplied:
6219 QPixelFormat(QPixelFormat::RGB,
6220 /*RED*/ 10,
6221 /*GREEN*/ 10,
6222 /*BLUE*/ 10,
6223 /*FOURTH*/ 0,
6224 /*FIFTH*/ 0,
6225 /*ALPHA*/ 2,
6226 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6227 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6228 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6229 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6230 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6231 //QImage::Format_Alpha8:
6232 QPixelFormat(QPixelFormat::Alpha,
6233 /*First*/ 0,
6234 /*SECOND*/ 0,
6235 /*THIRD*/ 0,
6236 /*FOURTH*/ 0,
6237 /*FIFTH*/ 0,
6238 /*ALPHA*/ 8,
6239 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6240 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6241 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6242 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6243 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6244 //QImage::Format_Grayscale8:
6245 QPixelFormat(QPixelFormat::Grayscale,
6246 /*GRAY*/ 8,
6247 /*SECOND*/ 0,
6248 /*THIRD*/ 0,
6249 /*FOURTH*/ 0,
6250 /*FIFTH*/ 0,
6251 /*ALPHA*/ 0,
6252 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6253 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6254 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6255 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6256 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6257 //QImage::Format_RGBX64:
6258 QPixelFormat(QPixelFormat::RGB,
6259 /*RED*/ 16,
6260 /*GREEN*/ 16,
6261 /*BLUE*/ 16,
6262 /*FOURTH*/ 0,
6263 /*FIFTH*/ 0,
6264 /*ALPHA*/ 16,
6265 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6266 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6267 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6268 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6269 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6270 //QImage::Format_RGBA64:
6271 QPixelFormat(QPixelFormat::RGB,
6272 /*RED*/ 16,
6273 /*GREEN*/ 16,
6274 /*BLUE*/ 16,
6275 /*FOURTH*/ 0,
6276 /*FIFTH*/ 0,
6277 /*ALPHA*/ 16,
6278 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6279 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6280 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6281 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6282 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6283 //QImage::Format_RGBA64_Premultiplied:
6284 QPixelFormat(QPixelFormat::RGB,
6285 /*RED*/ 16,
6286 /*GREEN*/ 16,
6287 /*BLUE*/ 16,
6288 /*FOURTH*/ 0,
6289 /*FIFTH*/ 0,
6290 /*ALPHA*/ 16,
6291 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6292 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6293 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6294 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6295 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6296 //QImage::Format_Grayscale16:
6297 QPixelFormat(QPixelFormat::Grayscale,
6298 /*GRAY*/ 16,
6299 /*SECOND*/ 0,
6300 /*THIRD*/ 0,
6301 /*FOURTH*/ 0,
6302 /*FIFTH*/ 0,
6303 /*ALPHA*/ 0,
6304 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6305 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6306 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6307 /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
6308 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6309 //QImage::Format_BGR888:
6310 QPixelFormat(QPixelFormat::BGR,
6311 /*RED*/ 8,
6312 /*GREEN*/ 8,
6313 /*BLUE*/ 8,
6314 /*FOURTH*/ 0,
6315 /*FIFTH*/ 0,
6316 /*ALPHA*/ 0,
6317 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6318 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6319 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6320 /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
6321 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6322 //QImage::Format_RGBX16FPx4:
6323 QPixelFormat(QPixelFormat::RGB,
6324 /*RED*/ 16,
6325 /*GREEN*/ 16,
6326 /*BLUE*/ 16,
6327 /*FOURTH*/ 0,
6328 /*FIFTH*/ 0,
6329 /*ALPHA*/ 16,
6330 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6331 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6332 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6333 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6334 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6335 //QImage::Format_RGBA16FPx4:
6336 QPixelFormat(QPixelFormat::RGB,
6337 /*RED*/ 16,
6338 /*GREEN*/ 16,
6339 /*BLUE*/ 16,
6340 /*FOURTH*/ 0,
6341 /*FIFTH*/ 0,
6342 /*ALPHA*/ 16,
6343 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6344 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6345 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6346 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6347 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6348 //QImage::Format_RGBA16FPx4_Premultiplied:
6349 QPixelFormat(QPixelFormat::RGB,
6350 /*RED*/ 16,
6351 /*GREEN*/ 16,
6352 /*BLUE*/ 16,
6353 /*FOURTH*/ 0,
6354 /*FIFTH*/ 0,
6355 /*ALPHA*/ 16,
6356 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6357 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6358 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6359 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6360 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6361 //QImage::Format_RGBX32FPx4:
6362 QPixelFormat(QPixelFormat::RGB,
6363 /*RED*/ 32,
6364 /*GREEN*/ 32,
6365 /*BLUE*/ 32,
6366 /*FOURTH*/ 0,
6367 /*FIFTH*/ 0,
6368 /*ALPHA*/ 32,
6369 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6370 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6371 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6372 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6373 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6374 //QImage::Format_RGBA32FPx4:
6375 QPixelFormat(QPixelFormat::RGB,
6376 /*RED*/ 32,
6377 /*GREEN*/ 32,
6378 /*BLUE*/ 32,
6379 /*FOURTH*/ 0,
6380 /*FIFTH*/ 0,
6381 /*ALPHA*/ 32,
6382 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6383 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6384 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6385 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6386 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6387 //QImage::Format_RGBA32FPx4_Premultiplied:
6388 QPixelFormat(QPixelFormat::RGB,
6389 /*RED*/ 32,
6390 /*GREEN*/ 32,
6391 /*BLUE*/ 32,
6392 /*FOURTH*/ 0,
6393 /*FIFTH*/ 0,
6394 /*ALPHA*/ 32,
6395 /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
6396 /*ALPHA POSITION*/ QPixelFormat::AtEnd,
6397 /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
6398 /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
6399 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6400 //QImage::Format_CMYK8888:
6401 QPixelFormat(QPixelFormat::CMYK,
6402 /*RED*/ 8,
6403 /*GREEN*/ 8,
6404 /*BLUE*/ 8,
6405 /*FOURTH*/ 8,
6406 /*FIFTH*/ 0,
6407 /*ALPHA*/ 0,
6408 /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
6409 /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
6410 /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
6411 /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
6412 /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
6413};
6414static_assert(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats);
6415
6416/*!
6417 Returns the QImage::Format as a QPixelFormat
6418*/
6419QPixelFormat QImage::pixelFormat() const noexcept
6420{
6421 return toPixelFormat(format: format());
6422}
6423
6424/*!
6425 Converts \a format into a QPixelFormat
6426*/
6427QPixelFormat QImage::toPixelFormat(QImage::Format format) noexcept
6428{
6429 Q_ASSERT(static_cast<int>(format) < NImageFormats && static_cast<int>(format) >= 0);
6430 return pixelformats[format];
6431}
6432
6433/*!
6434 Converts \a format into a QImage::Format
6435*/
6436QImage::Format QImage::toImageFormat(QPixelFormat format) noexcept
6437{
6438 for (int i = 0; i < NImageFormats; i++) {
6439 if (format == pixelformats[i])
6440 return Format(i);
6441 }
6442 return Format_Invalid;
6443}
6444
6445Q_GUI_EXPORT void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient)
6446{
6447 if (orient == QImageIOHandler::TransformationNone)
6448 return;
6449 if (orient == QImageIOHandler::TransformationRotate270) {
6450 src = rotated270(image: src);
6451 } else {
6452 src = std::move(src).mirrored(horizontally: orient & QImageIOHandler::TransformationMirror,
6453 vertically: orient & QImageIOHandler::TransformationFlip);
6454 if (orient & QImageIOHandler::TransformationRotate90)
6455 src = rotated90(image: src);
6456 }
6457}
6458
6459QMap<QString, QString> qt_getImageText(const QImage &image, const QString &description)
6460{
6461 QMap<QString, QString> text = qt_getImageTextFromDescription(description);
6462 const auto textKeys = image.textKeys();
6463 for (const QString &key : textKeys) {
6464 if (!key.isEmpty() && !text.contains(key))
6465 text.insert(key, value: image.text(key));
6466 }
6467 return text;
6468}
6469
6470QMap<QString, QString> qt_getImageTextFromDescription(const QString &description)
6471{
6472 QMap<QString, QString> text;
6473 for (const auto &pair : QStringView{description}.tokenize(needle: u"\n\n")) {
6474 int index = pair.indexOf(c: u':');
6475 if (index >= 0 && pair.indexOf(c: u' ') < index) {
6476 if (!pair.trimmed().isEmpty())
6477 text.insert(key: "Description"_L1, value: pair.toString().simplified());
6478 } else {
6479 const auto key = pair.left(n: index);
6480 if (!key.trimmed().isEmpty())
6481 text.insert(key: key.toString(), value: pair.mid(pos: index + 2).toString().simplified());
6482 }
6483 }
6484 return text;
6485}
6486
6487QT_END_NAMESPACE
6488
6489#include "moc_qimage.cpp"
6490

source code of qtbase/src/gui/image/qimage.cpp