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