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