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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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