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