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