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

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