Coverage Report

Created: 2026-05-31 06:50

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