Coverage Report

Created: 2026-08-17 07:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/image/qimage_conversions.cpp
Line
Count
Source
1
// Copyright (C) 2021 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:significant reason:default
4
5
#include <private/qguiapplication_p.h>
6
#include <private/qcolortransform_p.h>
7
#include <private/qcolortrclut_p.h>
8
#include <private/qcmyk_p.h>
9
#include <private/qdrawhelper_p.h>
10
#include <private/qendian_p.h>
11
#include <private/qpixellayout_p.h>
12
#include <private/qsimd_p.h>
13
#include <private/qimage_p.h>
14
15
#include <qendian.h>
16
#include <qrgbafloat.h>
17
#if QT_CONFIG(thread)
18
#include <private/qlatch_p.h>
19
#include <qthreadpool.h>
20
#include <private/qthreadpool_p.h>
21
#endif
22
23
#include <QtCore/q20iterator.h>
24
#include <QtCore/q20utility.h>
25
26
QT_BEGIN_NAMESPACE
27
28
struct QDefaultColorTables
29
{
30
    QDefaultColorTables()
31
0
        : gray(256), alpha(256)
32
0
    {
33
0
        for (int i = 0; i < 256; ++i) {
34
0
            gray[i] = qRgb(i, i, i);
35
0
            alpha[i] = qRgba(0, 0, 0, i);
36
0
        }
37
0
    }
38
39
    QList<QRgb> gray, alpha;
40
};
41
42
Q_GLOBAL_STATIC(QDefaultColorTables, defaultColorTables);
43
44
// table to flip bits
45
static const uchar bitflip[256] = {
46
    /*
47
        open OUT, "| fmt";
48
        for $i (0..255) {
49
            print OUT (($i >> 7) & 0x01) | (($i >> 5) & 0x02) |
50
                      (($i >> 3) & 0x04) | (($i >> 1) & 0x08) |
51
                      (($i << 7) & 0x80) | (($i << 5) & 0x40) |
52
                      (($i << 3) & 0x20) | (($i << 1) & 0x10), ", ";
53
        }
54
        close OUT;
55
    */
56
    0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
57
    8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
58
    4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
59
    12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
60
    2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
61
    10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
62
    6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
63
    14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
64
    1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
65
    9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
66
    5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
67
    13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
68
    3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
69
    11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
70
    7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
71
    15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
72
};
73
74
const uchar *qt_get_bitflip_array()
75
0
{
76
0
    return bitflip;
77
0
}
78
79
void qGamma_correct_back_to_linear_cs(QImage *image)
80
0
{
81
0
    const QColorTrcLut *cp = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
82
0
    if (!cp)
83
0
        return;
84
    // gamma correct the pixels back to linear color space...
85
0
    int h = image->height();
86
0
    int w = image->width();
87
88
0
    for (int y=0; y<h; ++y) {
89
0
        QRgb *pixels = reinterpret_cast<QRgb *>(image->scanLine(y));
90
0
        for (int x=0; x<w; ++x)
91
0
            pixels[x] = cp->toLinear(pixels[x]);
92
0
    }
93
0
}
94
95
/*****************************************************************************
96
  Internal routines for converting image depth.
97
 *****************************************************************************/
98
99
// The drawhelper conversions from/to RGB32 are passthroughs which is not always correct for general image conversion
100
#if !defined(__ARM_NEON__) || !(Q_BYTE_ORDER == Q_LITTLE_ENDIAN)
101
static void QT_FASTCALL storeRGB32FromARGB32PM(uchar *dest, const uint *src, int index, int count,
102
                                               const QList<QRgb> *, QDitherInfo *)
103
0
{
104
0
    uint *d = reinterpret_cast<uint *>(dest) + index;
105
0
    for (int i = 0; i < count; ++i)
106
0
        d[i] = 0xff000000 | qUnpremultiply(src[i]);
107
0
}
108
#endif
109
110
static void QT_FASTCALL storeRGB32FromARGB32(uchar *dest, const uint *src, int index, int count,
111
                                             const QList<QRgb> *, QDitherInfo *)
112
0
{
113
0
    uint *d = reinterpret_cast<uint *>(dest) + index;
114
0
    for (int i = 0; i < count; ++i)
115
0
        d[i] = 0xff000000 | src[i];
116
0
}
117
118
static const uint *QT_FASTCALL fetchRGB32ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
119
                                                    const QList<QRgb> *, QDitherInfo *)
120
0
{
121
0
    const uint *s = reinterpret_cast<const uint *>(src) + index;
122
0
    for (int i = 0; i < count; ++i)
123
0
        buffer[i] = 0xff000000 | s[i];
124
0
    return buffer;
125
0
}
126
127
#ifdef QT_COMPILER_SUPPORTS_SSE4_1
128
extern void QT_FASTCALL storeRGB32FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
129
                                                    const QList<QRgb> *, QDitherInfo *);
130
#elif defined(__ARM_NEON__) && (Q_BYTE_ORDER == Q_LITTLE_ENDIAN)
131
extern void QT_FASTCALL storeRGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count,
132
                                                    const QList<QRgb> *, QDitherInfo *);
133
#elif defined QT_COMPILER_SUPPORTS_LSX
134
// from painting/qdrawhelper_lsx.cpp
135
extern void QT_FASTCALL storeRGB32FromARGB32PM_lsx(uchar *dest, const uint *src, int index, int count,
136
                                                   const QList<QRgb> *, QDitherInfo *);
137
#endif
138
139
void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags flags)
140
1.26k
{
141
    // Cannot be used with indexed formats.
142
1.26k
    Q_ASSERT(dest->format > QImage::Format_Indexed8);
143
1.26k
    Q_ASSERT(src->format > QImage::Format_Indexed8);
144
1.26k
    const QPixelLayout *srcLayout = &qPixelLayouts[src->format];
145
1.26k
    const QPixelLayout *destLayout = &qPixelLayouts[dest->format];
146
147
1.26k
    FetchAndConvertPixelsFunc fetch = srcLayout->fetchToARGB32PM;
148
1.26k
    ConvertAndStorePixelsFunc store = destLayout->storeFromARGB32PM;
149
1.26k
    if (!srcLayout->hasAlphaChannel && destLayout->storeFromRGB32) {
150
        // If the source doesn't have an alpha channel, we can use the faster storeFromRGB32 method.
151
941
        store = destLayout->storeFromRGB32;
152
941
    } else {
153
        // The drawhelpers do not mask the alpha value in RGB32, we want to here.
154
324
        if (src->format == QImage::Format_RGB32)
155
0
            fetch = fetchRGB32ToARGB32PM;
156
324
        if (dest->format == QImage::Format_RGB32) {
157
0
#ifdef QT_COMPILER_SUPPORTS_SSE4_1
158
0
            if (qCpuHasFeature(SSE4_1))
159
0
                store = storeRGB32FromARGB32PM_sse4;
160
0
            else
161
0
                store = storeRGB32FromARGB32PM;
162
#elif defined QT_COMPILER_SUPPORTS_LSX
163
            if (qCpuHasFeature(LSX))
164
                store = storeRGB32FromARGB32PM_lsx;
165
            else
166
                store = storeRGB32FromARGB32PM;
167
#elif defined(__ARM_NEON__) && (Q_BYTE_ORDER == Q_LITTLE_ENDIAN)
168
            store = storeRGB32FromARGB32PM_neon;
169
#else
170
            store = storeRGB32FromARGB32PM;
171
#endif
172
0
        }
173
324
    }
174
1.26k
    if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied &&
175
324
            !destLayout->hasAlphaChannel && destLayout->storeFromRGB32) {
176
        // Avoid unnecessary premultiply and unpremultiply when converting from unpremultiplied src format.
177
0
        fetch = qPixelLayouts[qt_toPremultipliedFormat(src->format)].fetchToARGB32PM;
178
0
        if (dest->format == QImage::Format_RGB32)
179
0
            store = storeRGB32FromARGB32;
180
0
        else
181
0
            store = destLayout->storeFromRGB32;
182
0
    }
183
184
49.3k
    auto convertSegment = [=](int yStart, int yEnd) {
185
49.3k
        Q_DECL_UNINITIALIZED uint buf[BufferSize];
186
49.3k
        uint *buffer = buf;
187
49.3k
        const uchar *srcData = src->data + src->bytes_per_line * yStart;
188
49.3k
        uchar *destData = dest->data + dest->bytes_per_line * yStart;
189
49.3k
        QDitherInfo dither;
190
49.3k
        QDitherInfo *ditherPtr = nullptr;
191
49.3k
        if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither)
192
0
            ditherPtr = &dither;
193
14.4M
        for (int y = yStart; y < yEnd; ++y) {
194
14.4M
            dither.y = y;
195
14.4M
            int x = 0;
196
28.9M
            while (x < src->width) {
197
14.4M
                dither.x = x;
198
14.4M
                int l = src->width - x;
199
14.4M
                if (destLayout->bpp == QPixelLayout::BPP32)
200
14.5M
                    buffer = reinterpret_cast<uint *>(destData) + x;
201
18.4E
                else
202
18.4E
                    l = qMin(l, BufferSize);
203
14.4M
                const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr);
204
14.4M
                store(destData, ptr, x, l, nullptr, ditherPtr);
205
14.4M
                x += l;
206
14.4M
            }
207
14.4M
            srcData += src->bytes_per_line;
208
14.4M
            destData += dest->bytes_per_line;
209
14.4M
        }
210
49.3k
    };
211
212
1.26k
#if QT_CONFIG(qtgui_threadpool)
213
1.26k
    int segments = (qsizetype(src->width) * src->height) >> 16;
214
1.26k
    segments = std::min(segments, src->height);
215
216
1.26k
    QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
217
1.26k
    if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
218
374
        return convertSegment(0, src->height);
219
220
891
    QLatch latch(segments);
221
891
    int y = 0;
222
49.8k
    for (int i = 0; i < segments; ++i) {
223
48.9k
        int yn = (src->height - y) / (segments - i);
224
48.9k
        threadPool->start([&, y, yn]() {
225
48.9k
            convertSegment(y, y + yn);
226
48.9k
            latch.countDown();
227
48.9k
        });
228
48.9k
        y += yn;
229
48.9k
    }
230
891
    latch.wait();
231
#else
232
    convertSegment(0, src->height);
233
#endif
234
891
}
235
236
void convert_generic_over_rgb64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
237
0
{
238
0
    Q_ASSERT(dest->format > QImage::Format_Indexed8);
239
0
    Q_ASSERT(src->format > QImage::Format_Indexed8);
240
0
    const QPixelLayout *srcLayout = &qPixelLayouts[src->format];
241
0
    const QPixelLayout *destLayout = &qPixelLayouts[dest->format];
242
243
0
    const FetchAndConvertPixelsFunc64 fetch = srcLayout->fetchToRGBA64PM;
244
0
    const ConvertAndStorePixelsFunc64 store = qStoreFromRGBA64PM[dest->format];
245
246
0
    auto convertSegment = [=](int yStart, int yEnd) {
247
0
        Q_DECL_UNINITIALIZED QRgba64 buf[BufferSize];
248
0
        QRgba64 *buffer = buf;
249
0
        const uchar *srcData = src->data + yStart * src->bytes_per_line;
250
0
        uchar *destData = dest->data + yStart * dest->bytes_per_line;
251
0
        for (int y = yStart; y < yEnd; ++y) {
252
0
            int x = 0;
253
0
            while (x < src->width) {
254
0
                int l = src->width - x;
255
0
                if (destLayout->bpp == QPixelLayout::BPP64)
256
0
                    buffer = reinterpret_cast<QRgba64 *>(destData) + x;
257
0
                else
258
0
                    l = qMin(l, BufferSize);
259
0
                const QRgba64 *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr);
260
0
                store(destData, ptr, x, l, nullptr, nullptr);
261
0
                x += l;
262
0
            }
263
0
            srcData += src->bytes_per_line;
264
0
            destData += dest->bytes_per_line;
265
0
        }
266
0
    };
267
0
#if QT_CONFIG(qtgui_threadpool)
268
0
    int segments = (qsizetype(src->width) * src->height) >> 16;
269
0
    segments = std::min(segments, src->height);
270
271
0
    QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
272
0
    if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
273
0
        return convertSegment(0, src->height);
274
275
0
    QLatch latch(segments);
276
0
    int y = 0;
277
0
    for (int i = 0; i < segments; ++i) {
278
0
        int yn = (src->height - y) / (segments - i);
279
0
        threadPool->start([&, y, yn]() {
280
0
            convertSegment(y, y + yn);
281
0
            latch.countDown();
282
0
        });
283
0
        y += yn;
284
0
    }
285
0
    latch.wait();
286
#else
287
    convertSegment(0, src->height);
288
#endif
289
0
}
290
291
#if QT_CONFIG(raster_fp)
292
void convert_generic_over_rgba32f(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
293
0
{
294
0
    Q_ASSERT(dest->format >= QImage::Format_RGBX16FPx4);
295
0
    Q_ASSERT(src->format >= QImage::Format_RGBX16FPx4);
296
297
0
    const FetchAndConvertPixelsFuncFP fetch = qFetchToRGBA32F[src->format];
298
0
    const ConvertAndStorePixelsFuncFP store = qStoreFromRGBA32F[dest->format];
299
300
0
    auto convertSegment = [=](int yStart, int yEnd) {
301
0
        Q_DECL_UNINITIALIZED QRgbaFloat32 buf[BufferSize / 2];
302
0
        QRgbaFloat32 *buffer = buf;
303
0
        const uchar *srcData = src->data + yStart * src->bytes_per_line;
304
0
        uchar *destData = dest->data + yStart * dest->bytes_per_line;
305
0
        for (int y = yStart; y < yEnd; ++y) {
306
0
            int x = 0;
307
0
            while (x < src->width) {
308
0
                int l = src->width - x;
309
0
                if (dest->depth == 128)
310
0
                    buffer = reinterpret_cast<QRgbaFloat32 *>(destData) + x;
311
0
                else
312
0
                    l = (std::min)(l, int{q20::ssize(buf)});
313
0
                const QRgbaFloat32 *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr);
314
0
                store(destData, ptr, x, l, nullptr, nullptr);
315
0
                x += l;
316
0
            }
317
0
            srcData += src->bytes_per_line;
318
0
            destData += dest->bytes_per_line;
319
0
        }
320
0
    };
321
0
#if QT_CONFIG(qtgui_threadpool)
322
0
    int segments = (qsizetype(src->width) * src->height) >> 16;
323
0
    segments = std::min(segments, src->height);
324
325
0
    QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
326
0
    if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
327
0
        return convertSegment(0, src->height);
328
329
0
    QLatch latch(segments);
330
0
    int y = 0;
331
0
    for (int i = 0; i < segments; ++i) {
332
0
        int yn = (src->height - y) / (segments - i);
333
0
        threadPool->start([&, y, yn]() {
334
0
            convertSegment(y, y + yn);
335
0
            latch.countDown();
336
0
        });
337
0
        y += yn;
338
0
    }
339
0
    latch.wait();
340
#else
341
    convertSegment(0, src->height);
342
#endif
343
0
}
344
#endif
345
346
bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags flags)
347
81.7k
{
348
    // Cannot be used with indexed formats or between formats with different pixel depths.
349
81.7k
    Q_ASSERT(dst_format > QImage::Format_Indexed8);
350
81.7k
    Q_ASSERT(dst_format < QImage::NImageFormats);
351
81.7k
    Q_ASSERT(data->format > QImage::Format_Indexed8);
352
81.7k
    const int destDepth = qt_depthForFormat(dst_format);
353
81.7k
    if (data->depth < destDepth)
354
941
        return false;
355
356
80.7k
    const QPixelLayout *srcLayout = &qPixelLayouts[data->format];
357
80.7k
    const QPixelLayout *destLayout = &qPixelLayouts[dst_format];
358
359
    // The precision here is only ARGB32PM so don't convert between higher accuracy
360
    // formats.
361
80.7k
    Q_ASSERT(!qt_highColorPrecision(data->format, !destLayout->hasAlphaChannel)
362
80.7k
             || !qt_highColorPrecision(dst_format, !srcLayout->hasAlphaChannel));
363
364
80.7k
    QImageData::ImageSizeParameters params = { data->bytes_per_line, data->nbytes };
365
80.7k
    if (data->depth != destDepth) {
366
0
        params = QImageData::calculateImageParameters(data->width, data->height, destDepth);
367
0
        if (!params.isValid())
368
0
            return false;
369
0
    }
370
371
80.7k
    Q_ASSERT(destLayout->bpp < QPixelLayout::BPP64);
372
80.7k
    FetchAndConvertPixelsFunc fetch = srcLayout->fetchToARGB32PM;
373
80.7k
    ConvertAndStorePixelsFunc store = destLayout->storeFromARGB32PM;
374
80.7k
    if (!srcLayout->hasAlphaChannel && destLayout->storeFromRGB32) {
375
        // If the source doesn't have an alpha channel, we can use the faster storeFromRGB32 method.
376
0
        store = destLayout->storeFromRGB32;
377
80.7k
    } else {
378
80.7k
        if (data->format == QImage::Format_RGB32)
379
0
            fetch = fetchRGB32ToARGB32PM;
380
80.7k
        if (dst_format == QImage::Format_RGB32) {
381
0
#ifdef QT_COMPILER_SUPPORTS_SSE4_1
382
0
            if (qCpuHasFeature(SSE4_1))
383
0
                store = storeRGB32FromARGB32PM_sse4;
384
0
            else
385
0
                store = storeRGB32FromARGB32PM;
386
#elif defined QT_COMPILER_SUPPORTS_LSX
387
            if (qCpuHasFeature(LSX))
388
                store = storeRGB32FromARGB32PM_lsx;
389
            else
390
                store = storeRGB32FromARGB32PM;
391
#elif defined(__ARM_NEON__) && (Q_BYTE_ORDER == Q_LITTLE_ENDIAN)
392
            store = storeRGB32FromARGB32PM_neon;
393
#else
394
            store = storeRGB32FromARGB32PM;
395
#endif
396
0
        }
397
80.7k
    }
398
80.7k
    if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied &&
399
80.7k
            !destLayout->hasAlphaChannel && destLayout->storeFromRGB32) {
400
        // Avoid unnecessary premultiply and unpremultiply when converting from unpremultiplied src format.
401
0
        fetch = qPixelLayouts[qt_toPremultipliedFormat(data->format)].fetchToARGB32PM;
402
0
        if (dst_format == QImage::Format_RGB32)
403
0
            store = storeRGB32FromARGB32;
404
0
        else
405
0
            store = destLayout->storeFromRGB32;
406
0
    }
407
408
80.7k
    auto convertSegment = [=](int yStart, int yEnd) {
409
80.7k
        Q_DECL_UNINITIALIZED uint buf[BufferSize];
410
80.7k
        uint *buffer = buf;
411
80.7k
        uchar *srcData = data->data + data->bytes_per_line * yStart;
412
80.7k
        uchar *destData = srcData; // This can be temporarily wrong if we doing a shrinking conversion
413
80.7k
        QDitherInfo dither;
414
80.7k
        QDitherInfo *ditherPtr = nullptr;
415
80.7k
        if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither)
416
0
            ditherPtr = &dither;
417
12.0M
        for (int y = yStart; y < yEnd; ++y) {
418
11.9M
            dither.y = y;
419
11.9M
            int x = 0;
420
23.9M
            while (x < data->width) {
421
11.9M
                dither.x = x;
422
11.9M
                int l = data->width - x;
423
11.9M
                if (srcLayout->bpp == QPixelLayout::BPP32)
424
11.9M
                    buffer = reinterpret_cast<uint *>(srcData) + x;
425
0
                else
426
0
                    l = qMin(l, BufferSize);
427
11.9M
                const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr);
428
11.9M
                store(destData, ptr, x, l, nullptr, ditherPtr);
429
11.9M
                x += l;
430
11.9M
            }
431
11.9M
            srcData += data->bytes_per_line;
432
11.9M
            destData += params.bytesPerLine;
433
11.9M
        }
434
80.7k
    };
435
80.7k
#if QT_CONFIG(qtgui_threadpool)
436
80.7k
    int segments = (qsizetype(data->width) * data->height) >> 16;
437
80.7k
    segments = std::min(segments, data->height);
438
80.7k
    QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
439
80.7k
    if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
440
0
        QLatch latch(segments);
441
0
        int y = 0;
442
0
        for (int i = 0; i < segments; ++i) {
443
0
            int yn = (data->height - y) / (segments - i);
444
0
            threadPool->start([&, y, yn]() {
445
0
                convertSegment(y, y + yn);
446
0
                latch.countDown();
447
0
            });
448
0
            y += yn;
449
0
        }
450
0
        latch.wait();
451
0
        if (data->bytes_per_line != params.bytesPerLine) {
452
            // Compress segments to a continuous block
453
0
            y = 0;
454
0
            for (int i = 0; i < segments; ++i) {
455
0
                int yn = (data->height - y) / (segments - i);
456
0
                uchar *srcData = data->data + data->bytes_per_line * y;
457
0
                uchar *destData = data->data + params.bytesPerLine * y;
458
0
                if (srcData != destData)
459
0
                    memmove(destData, srcData, params.bytesPerLine * yn);
460
0
                y += yn;
461
0
            }
462
0
        }
463
0
    } else
464
80.7k
#endif
465
80.7k
        convertSegment(0, data->height);
466
80.7k
    if (params.totalSize != data->nbytes) {
467
0
        Q_ASSERT(params.totalSize < data->nbytes);
468
0
        void *newData = realloc(data->data, params.totalSize);
469
0
        if (newData) {
470
0
            data->data = (uchar *)newData;
471
0
            data->nbytes = params.totalSize;
472
0
        }
473
0
        data->bytes_per_line = params.bytesPerLine;
474
0
    }
475
80.7k
    data->depth = destDepth;
476
80.7k
    data->format = dst_format;
477
80.7k
    return true;
478
80.7k
}
479
480
bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags)
481
0
{
482
0
    Q_ASSERT(data->format > QImage::Format_Indexed8);
483
0
    Q_ASSERT(dst_format > QImage::Format_Indexed8);
484
0
    Q_ASSERT(dst_format < QImage::NImageFormats);
485
0
    const int destDepth = qt_depthForFormat(dst_format);
486
0
    if (data->depth < destDepth)
487
0
        return false;
488
489
0
    const QPixelLayout *srcLayout = &qPixelLayouts[data->format];
490
0
    const QPixelLayout *destLayout = &qPixelLayouts[dst_format];
491
492
0
    QImageData::ImageSizeParameters params = { data->bytes_per_line, data->nbytes };
493
0
    if (data->depth != destDepth) {
494
0
        params = QImageData::calculateImageParameters(data->width, data->height, destDepth);
495
0
        if (!params.isValid())
496
0
            return false;
497
0
    }
498
499
0
    FetchAndConvertPixelsFunc64 fetch = srcLayout->fetchToRGBA64PM;
500
0
    ConvertAndStorePixelsFunc64 store = qStoreFromRGBA64PM[dst_format];
501
0
    if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied &&
502
0
        destLayout->hasAlphaChannel && !destLayout->premultiplied) {
503
        // Avoid unnecessary premultiply and unpremultiply when converting between two unpremultiplied formats.
504
0
        fetch = qPixelLayouts[qt_toPremultipliedFormat(data->format)].fetchToRGBA64PM;
505
0
        store = qStoreFromRGBA64PM[qt_toPremultipliedFormat(dst_format)];
506
0
    }
507
508
0
    auto convertSegment = [=](int yStart, int yEnd) {
509
0
        Q_DECL_UNINITIALIZED QRgba64 buf[BufferSize];
510
0
        QRgba64 *buffer = buf;
511
0
        uchar *srcData = data->data + yStart * data->bytes_per_line;
512
0
        uchar *destData = srcData;
513
0
        for (int y = yStart; y < yEnd; ++y) {
514
0
            int x = 0;
515
0
            while (x < data->width) {
516
0
                int l = data->width - x;
517
0
                if (srcLayout->bpp == QPixelLayout::BPP64)
518
0
                    buffer = reinterpret_cast<QRgba64 *>(srcData) + x;
519
0
                else
520
0
                    l = qMin(l, BufferSize);
521
0
                const QRgba64 *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr);
522
0
                store(destData, ptr, x, l, nullptr, nullptr);
523
0
                x += l;
524
0
            }
525
0
            srcData += data->bytes_per_line;
526
0
            destData += params.bytesPerLine;
527
0
        }
528
0
    };
529
0
#if QT_CONFIG(qtgui_threadpool)
530
0
    int segments = (qsizetype(data->width) * data->height) >> 16;
531
0
    segments = std::min(segments, data->height);
532
0
    QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
533
0
    if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
534
0
        QLatch latch(segments);
535
0
        int y = 0;
536
0
        for (int i = 0; i < segments; ++i) {
537
0
            int yn = (data->height - y) / (segments - i);
538
0
            threadPool->start([&, y, yn]() {
539
0
                convertSegment(y, y + yn);
540
0
                latch.countDown();
541
0
            });
542
0
            y += yn;
543
0
        }
544
0
        latch.wait();
545
0
        if (data->bytes_per_line != params.bytesPerLine) {
546
            // Compress segments to a continuous block
547
0
            y = 0;
548
0
            for (int i = 0; i < segments; ++i) {
549
0
                int yn = (data->height - y) / (segments - i);
550
0
                uchar *srcData = data->data + data->bytes_per_line * y;
551
0
                uchar *destData = data->data + params.bytesPerLine * y;
552
0
                if (srcData != destData)
553
0
                    memmove(destData, srcData, params.bytesPerLine * yn);
554
0
                y += yn;
555
0
            }
556
0
        }
557
0
    } else
558
0
#endif
559
0
        convertSegment(0, data->height);
560
0
    if (params.totalSize != data->nbytes) {
561
0
        Q_ASSERT(params.totalSize < data->nbytes);
562
0
        void *newData = realloc(data->data, params.totalSize);
563
0
        if (newData) {
564
0
            data->data = (uchar *)newData;
565
0
            data->nbytes = params.totalSize;
566
0
        }
567
0
        data->bytes_per_line = params.bytesPerLine;
568
0
    }
569
0
    data->depth = destDepth;
570
0
    data->format = dst_format;
571
0
    return true;
572
0
}
573
574
#if QT_CONFIG(raster_fp)
575
bool convert_generic_inplace_over_rgba32f(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags)
576
0
{
577
0
    Q_ASSERT(data->format >= QImage::Format_RGBX16FPx4);
578
0
    Q_ASSERT(dst_format >= QImage::Format_RGBX16FPx4);
579
0
    Q_ASSERT(dst_format < QImage::NImageFormats);
580
0
    const int destDepth = qt_depthForFormat(dst_format);
581
0
    if (data->depth < destDepth)
582
0
        return false;
583
584
0
    const QPixelLayout *srcLayout = &qPixelLayouts[data->format];
585
0
    const QPixelLayout *destLayout = &qPixelLayouts[dst_format];
586
587
0
    QImageData::ImageSizeParameters params = { data->bytes_per_line, data->nbytes };
588
0
    if (data->depth != destDepth) {
589
0
        params = QImageData::calculateImageParameters(data->width, data->height, destDepth);
590
0
        if (!params.isValid())
591
0
            return false;
592
0
    }
593
594
0
    FetchAndConvertPixelsFuncFP fetch = qFetchToRGBA32F[data->format];
595
0
    ConvertAndStorePixelsFuncFP store = qStoreFromRGBA32F[dst_format];
596
0
    if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied &&
597
0
        destLayout->hasAlphaChannel && !destLayout->premultiplied) {
598
        // Avoid unnecessary premultiply and unpremultiply when converting between two unpremultiplied formats.
599
0
        fetch = qFetchToRGBA32F[qt_toPremultipliedFormat(data->format)];
600
0
        store = qStoreFromRGBA32F[qt_toPremultipliedFormat(dst_format)];
601
0
    }
602
603
0
    auto convertSegment = [=](int yStart, int yEnd) {
604
0
        Q_DECL_UNINITIALIZED QRgbaFloat32 buf[BufferSize / 2];
605
0
        QRgbaFloat32 *buffer = buf;
606
0
        uchar *srcData = data->data + yStart * data->bytes_per_line;
607
0
        uchar *destData = srcData;
608
0
        for (int y = yStart; y < yEnd; ++y) {
609
0
            int x = 0;
610
0
            while (x < data->width) {
611
0
                int l = data->width - x;
612
0
                if (srcLayout->bpp == QPixelLayout::BPP32FPx4)
613
0
                    buffer = reinterpret_cast<QRgbaFloat32 *>(srcData) + x;
614
0
                else
615
0
                    l = (std::min)(l, int{q20::ssize(buf)});
616
0
                const QRgbaFloat32 *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr);
617
0
                store(destData, ptr, x, l, nullptr, nullptr);
618
0
                x += l;
619
0
            }
620
0
            srcData += data->bytes_per_line;
621
0
            destData += params.bytesPerLine;
622
0
        }
623
0
    };
624
0
#if QT_CONFIG(qtgui_threadpool)
625
0
    int segments = (qsizetype(data->width) * data->height) >> 16;
626
0
    segments = std::min(segments, data->height);
627
0
    QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
628
0
    if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
629
0
        QLatch latch(segments);
630
0
        int y = 0;
631
0
        for (int i = 0; i < segments; ++i) {
632
0
            int yn = (data->height - y) / (segments - i);
633
0
            threadPool->start([&, y, yn]() {
634
0
                convertSegment(y, y + yn);
635
0
                latch.countDown();
636
0
            });
637
0
            y += yn;
638
0
        }
639
0
        latch.wait();
640
0
        if (data->bytes_per_line != params.bytesPerLine) {
641
            // Compress segments to a continuous block
642
0
            y = 0;
643
0
            for (int i = 0; i < segments; ++i) {
644
0
                int yn = (data->height - y) / (segments - i);
645
0
                uchar *srcData = data->data + data->bytes_per_line * y;
646
0
                uchar *destData = data->data + params.bytesPerLine * y;
647
0
                if (srcData != destData)
648
0
                    memmove(destData, srcData, params.bytesPerLine * yn);
649
0
                y += yn;
650
0
            }
651
0
        }
652
0
    } else
653
0
#endif
654
0
        convertSegment(0, data->height);
655
0
    if (params.totalSize != data->nbytes) {
656
0
        Q_ASSERT(params.totalSize < data->nbytes);
657
0
        void *newData = realloc(data->data, params.totalSize);
658
0
        if (newData) {
659
0
            data->data = (uchar *)newData;
660
0
            data->nbytes = params.totalSize;
661
0
        }
662
0
        data->bytes_per_line = params.bytesPerLine;
663
0
    }
664
0
    data->depth = destDepth;
665
0
    data->format = dst_format;
666
0
    return true;
667
0
}
668
#endif
669
670
static void convert_passthrough(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
671
0
{
672
0
    Q_ASSERT(src->width == dest->width);
673
0
    Q_ASSERT(src->height == dest->height);
674
675
0
    const int src_bpl = src->bytes_per_line;
676
0
    const int dest_bpl = dest->bytes_per_line;
677
0
    const uchar *src_data = src->data;
678
0
    uchar *dest_data = dest->data;
679
680
0
    for (int i = 0; i < src->height; ++i) {
681
0
        memcpy(dest_data, src_data, src_bpl);
682
0
        src_data += src_bpl;
683
0
        dest_data += dest_bpl;
684
0
    }
685
0
}
686
687
template<QImage::Format Format>
688
static bool convert_passthrough_inplace(QImageData *data, Qt::ImageConversionFlags)
689
0
{
690
0
    static_assert(Format > QImage::Format_Invalid);
691
0
    static_assert(Format < QImage::NImageFormats);
692
0
    data->format = Format;
693
0
    return true;
694
0
}
Unexecuted instantiation: qimage_conversions.cpp:bool convert_passthrough_inplace<(QImage::Format)17>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_passthrough_inplace<(QImage::Format)18>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_passthrough_inplace<(QImage::Format)20>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_passthrough_inplace<(QImage::Format)22>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_passthrough_inplace<(QImage::Format)26>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_passthrough_inplace<(QImage::Format)27>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_passthrough_inplace<(QImage::Format)31>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_passthrough_inplace<(QImage::Format)32>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_passthrough_inplace<(QImage::Format)34>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_passthrough_inplace<(QImage::Format)35>(QImageData*, QFlags<Qt::ImageConversionFlag>)
695
696
Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32(quint32 *dest_data, const uchar *src_data, int len)
697
0
{
698
0
    int pixel = 0;
699
    // prolog: align input to 32bit
700
0
    while ((quintptr(src_data) & 0x3) && pixel < len) {
701
0
        *dest_data = 0xff000000 | (src_data[0] << 16) | (src_data[1] << 8) | (src_data[2]);
702
0
        src_data += 3;
703
0
        ++dest_data;
704
0
        ++pixel;
705
0
    }
706
707
    // Handle 4 pixels at a time 12 bytes input to 16 bytes output.
708
0
    for (; pixel + 3 < len; pixel += 4) {
709
0
        const quint32_be *src_packed = reinterpret_cast<const quint32_be *>(src_data);
710
0
        const quint32 src1 = src_packed[0];
711
0
        const quint32 src2 = src_packed[1];
712
0
        const quint32 src3 = src_packed[2];
713
714
0
        dest_data[0] = 0xff000000 | (src1 >> 8);
715
0
        dest_data[1] = 0xff000000 | (src1 << 16) | (src2 >> 16);
716
0
        dest_data[2] = 0xff000000 | (src2 << 8) | (src3 >> 24);
717
0
        dest_data[3] = 0xff000000 | src3;
718
719
0
        src_data += 12;
720
0
        dest_data += 4;
721
0
    }
722
723
    // epilog: handle left over pixels
724
0
    for (; pixel < len; ++pixel) {
725
0
        *dest_data = 0xff000000 | (src_data[0] << 16) | (src_data[1] << 8) | (src_data[2]);
726
0
        src_data += 3;
727
0
        ++dest_data;
728
0
    }
729
0
}
730
731
Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgbx8888(quint32 *dest_data, const uchar *src_data, int len)
732
0
{
733
0
    int pixel = 0;
734
    // prolog: align input to 32bit
735
0
    while ((quintptr(src_data) & 0x3) && pixel < len) {
736
0
        *dest_data = ARGB2RGBA(0xff000000 | (src_data[0] << 16) | (src_data[1] << 8) | (src_data[2]));
737
0
        src_data += 3;
738
0
        ++dest_data;
739
0
        ++pixel;
740
0
    }
741
742
    // Handle 4 pixels at a time 12 bytes input to 16 bytes output.
743
0
    for (; pixel + 3 < len; pixel += 4) {
744
0
        const quint32 *src_packed = (const quint32 *) src_data;
745
0
        const quint32 src1 = src_packed[0];
746
0
        const quint32 src2 = src_packed[1];
747
0
        const quint32 src3 = src_packed[2];
748
749
0
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
750
0
        dest_data[0] = 0xff000000 | src1;
751
0
        dest_data[1] = 0xff000000 | (src1 >> 24) | (src2 << 8);
752
0
        dest_data[2] = 0xff000000 | (src2 >> 16) | (src3 << 16);
753
0
        dest_data[3] = 0xff000000 | (src3 >> 8);
754
#else
755
        dest_data[0] = 0xff | src1;
756
        dest_data[1] = 0xff | (src1 << 24) | (src2 >> 8);
757
        dest_data[2] = 0xff | (src2 << 16) | (src3 >> 16);
758
        dest_data[3] = 0xff | (src3 << 8);
759
#endif
760
761
0
        src_data += 12;
762
0
        dest_data += 4;
763
0
    }
764
765
    // epilog: handle left over pixels
766
0
    for (; pixel < len; ++pixel) {
767
0
        *dest_data = ARGB2RGBA(0xff000000 | (src_data[0] << 16) | (src_data[1] << 8) | (src_data[2]));
768
0
        src_data += 3;
769
0
        ++dest_data;
770
0
    }
771
0
}
772
773
typedef void (QT_FASTCALL *Rgb888ToRgbConverter)(quint32 *dst, const uchar *src, int len);
774
775
template <bool rgbx>
776
static void convert_RGB888_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
777
0
{
778
0
    Q_ASSERT(src->format == QImage::Format_RGB888 || src->format == QImage::Format_BGR888);
779
0
    if (rgbx ^ (src->format == QImage::Format_BGR888))
780
0
        Q_ASSERT(dest->format == QImage::Format_RGBX8888 || dest->format == QImage::Format_RGBA8888 || dest->format == QImage::Format_RGBA8888_Premultiplied);
781
0
    else
782
0
        Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied);
783
0
    Q_ASSERT(src->width == dest->width);
784
0
    Q_ASSERT(src->height == dest->height);
785
786
0
    const uchar *src_data = (uchar *) src->data;
787
0
    quint32 *dest_data = (quint32 *) dest->data;
788
789
0
    Rgb888ToRgbConverter line_converter= rgbx ? qt_convert_rgb888_to_rgbx8888 : qt_convert_rgb888_to_rgb32;
790
791
0
    for (int i = 0; i < src->height; ++i) {
792
0
        line_converter(dest_data, src_data, src->width);
793
0
        src_data += src->bytes_per_line;
794
0
        dest_data = (quint32 *)((uchar*)dest_data + dest->bytes_per_line);
795
0
    }
796
0
}
Unexecuted instantiation: qimage_conversions.cpp:void convert_RGB888_to_RGB<false>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:void convert_RGB888_to_RGB<true>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
797
798
static void convert_ARGB_to_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
799
0
{
800
0
    Q_ASSERT(src->format == QImage::Format_ARGB32);
801
0
    Q_ASSERT(dest->format == QImage::Format_RGBX8888);
802
0
    Q_ASSERT(src->width == dest->width);
803
0
    Q_ASSERT(src->height == dest->height);
804
805
0
    const int src_pad = (src->bytes_per_line >> 2) - src->width;
806
0
    const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
807
0
    const quint32 *src_data = (quint32 *) src->data;
808
0
    quint32 *dest_data = (quint32 *) dest->data;
809
810
0
    for (int i = 0; i < src->height; ++i) {
811
0
        const quint32 *end = src_data + src->width;
812
0
        while (src_data < end) {
813
0
            *dest_data = ARGB2RGBA(0xff000000 | *src_data);
814
0
            ++src_data;
815
0
            ++dest_data;
816
0
        }
817
0
        src_data += src_pad;
818
0
        dest_data += dest_pad;
819
0
    }
820
0
}
821
822
static void convert_ARGB_to_RGBA(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
823
0
{
824
0
    Q_ASSERT(src->format == QImage::Format_ARGB32 || src->format == QImage::Format_ARGB32_Premultiplied);
825
0
    Q_ASSERT(dest->format == QImage::Format_RGBA8888 || dest->format == QImage::Format_RGBA8888_Premultiplied);
826
0
    Q_ASSERT(src->width == dest->width);
827
0
    Q_ASSERT(src->height == dest->height);
828
829
0
    const int src_pad = (src->bytes_per_line >> 2) - src->width;
830
0
    const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
831
0
    const quint32 *src_data = (quint32 *) src->data;
832
0
    quint32 *dest_data = (quint32 *) dest->data;
833
834
0
    for (int i = 0; i < src->height; ++i) {
835
0
        const quint32 *end = src_data + src->width;
836
0
        while (src_data < end) {
837
0
            *dest_data = ARGB2RGBA(*src_data);
838
0
            ++src_data;
839
0
            ++dest_data;
840
0
        }
841
0
        src_data += src_pad;
842
0
        dest_data += dest_pad;
843
0
    }
844
0
}
845
846
template<QImage::Format DestFormat>
847
static bool convert_ARGB_to_RGBA_inplace(QImageData *data, Qt::ImageConversionFlags)
848
0
{
849
0
    static_assert(DestFormat > QImage::Format_Invalid);
850
0
    static_assert(DestFormat < QImage::NImageFormats);
851
0
    Q_ASSERT(data->format == QImage::Format_ARGB32 || data->format == QImage::Format_ARGB32_Premultiplied);
852
853
0
    const int pad = (data->bytes_per_line >> 2) - data->width;
854
0
    quint32 *rgb_data = (quint32 *) data->data;
855
0
    constexpr uint mask = (DestFormat == QImage::Format_RGBX8888) ? 0xff000000 : 0;
856
857
0
    for (int i = 0; i < data->height; ++i) {
858
0
        const quint32 *end = rgb_data + data->width;
859
0
        while (rgb_data < end) {
860
0
            *rgb_data = ARGB2RGBA(*rgb_data | mask);
861
0
            ++rgb_data;
862
0
        }
863
0
        rgb_data += pad;
864
0
    }
865
866
0
    data->format = DestFormat;
867
0
    return true;
868
0
}
Unexecuted instantiation: qimage_conversions.cpp:bool convert_ARGB_to_RGBA_inplace<(QImage::Format)16>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_ARGB_to_RGBA_inplace<(QImage::Format)17>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_ARGB_to_RGBA_inplace<(QImage::Format)18>(QImageData*, QFlags<Qt::ImageConversionFlag>)
869
870
static void convert_RGBA_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
871
0
{
872
0
    Q_ASSERT(src->format == QImage::Format_RGBX8888 || src->format == QImage::Format_RGBA8888 || src->format == QImage::Format_RGBA8888_Premultiplied);
873
0
    Q_ASSERT(dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied);
874
0
    Q_ASSERT(src->width == dest->width);
875
0
    Q_ASSERT(src->height == dest->height);
876
877
0
    const int src_pad = (src->bytes_per_line >> 2) - src->width;
878
0
    const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
879
0
    const quint32 *src_data = (quint32 *) src->data;
880
0
    quint32 *dest_data = (quint32 *) dest->data;
881
882
0
    for (int i = 0; i < src->height; ++i) {
883
0
        const quint32 *end = src_data + src->width;
884
0
        while (src_data < end) {
885
0
            *dest_data = RGBA2ARGB(*src_data);
886
0
            ++src_data;
887
0
            ++dest_data;
888
0
        }
889
0
        src_data += src_pad;
890
0
        dest_data += dest_pad;
891
0
    }
892
0
}
893
894
template<QImage::Format DestFormat>
895
static bool convert_RGBA_to_ARGB_inplace(QImageData *data, Qt::ImageConversionFlags)
896
0
{
897
0
    static_assert(DestFormat > QImage::Format_Invalid);
898
0
    static_assert(DestFormat < QImage::NImageFormats);
899
0
    Q_ASSERT(data->format == QImage::Format_RGBX8888 || data->format == QImage::Format_RGBA8888 || data->format == QImage::Format_RGBA8888_Premultiplied);
900
901
0
    const int pad = (data->bytes_per_line >> 2) - data->width;
902
0
    QRgb *rgb_data = (QRgb *) data->data;
903
0
    constexpr uint mask = (DestFormat == QImage::Format_RGB32) ? 0xff000000 : 0;
904
905
0
    for (int i = 0; i < data->height; ++i) {
906
0
        const QRgb *end = rgb_data + data->width;
907
0
        while (rgb_data < end) {
908
0
            *rgb_data = mask | RGBA2ARGB(*rgb_data);
909
0
            ++rgb_data;
910
0
        }
911
0
        rgb_data += pad;
912
0
    }
913
0
    data->format = DestFormat;
914
0
    return true;
915
0
}
Unexecuted instantiation: qimage_conversions.cpp:bool convert_RGBA_to_ARGB_inplace<(QImage::Format)4>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_RGBA_to_ARGB_inplace<(QImage::Format)5>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_RGBA_to_ARGB_inplace<(QImage::Format)6>(QImageData*, QFlags<Qt::ImageConversionFlag>)
916
917
static void convert_rgbswap_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
918
0
{
919
0
    Q_ASSERT(src->width == dest->width);
920
0
    Q_ASSERT(src->height == dest->height);
921
922
0
    const RbSwapFunc func = qPixelLayouts[src->format].rbSwap;
923
0
    Q_ASSERT(func);
924
925
0
    const qsizetype sbpl = src->bytes_per_line;
926
0
    const qsizetype dbpl = dest->bytes_per_line;
927
0
    const uchar *src_data = src->data;
928
0
    uchar *dest_data = dest->data;
929
930
0
    for (int i = 0; i < src->height; ++i) {
931
0
        func(dest_data, src_data, src->width);
932
933
0
        src_data += sbpl;
934
0
        dest_data += dbpl;
935
0
    }
936
0
}
937
938
static bool convert_rgbswap_generic_inplace(QImageData *data, Qt::ImageConversionFlags)
939
0
{
940
0
    const RbSwapFunc func = qPixelLayouts[data->format].rbSwap;
941
0
    Q_ASSERT(func);
942
943
0
    const qsizetype bpl = data->bytes_per_line;
944
0
    uchar *line_data = data->data;
945
946
0
    for (int i = 0; i < data->height; ++i) {
947
0
        func(line_data, line_data, data->width);
948
0
        line_data += bpl;
949
0
    }
950
951
0
    switch (data->format) {
952
0
    case QImage::Format_RGB888:
953
0
        data->format = QImage::Format_BGR888;
954
0
        break;
955
0
    case QImage::Format_BGR888:
956
0
        data->format = QImage::Format_RGB888;
957
0
        break;
958
0
    case QImage::Format_BGR30:
959
0
        data->format = QImage::Format_RGB30;
960
0
        break;
961
0
    case QImage::Format_A2BGR30_Premultiplied:
962
0
        data->format = QImage::Format_A2RGB30_Premultiplied;
963
0
        break;
964
0
    case QImage::Format_RGB30:
965
0
        data->format = QImage::Format_BGR30;
966
0
        break;
967
0
    case QImage::Format_A2RGB30_Premultiplied:
968
0
        data->format = QImage::Format_A2BGR30_Premultiplied;
969
0
        break;
970
0
    default:
971
0
        Q_UNREACHABLE();
972
0
        data->format = QImage::Format_Invalid;
973
0
        return false;
974
0
    }
975
0
    return true;
976
0
}
977
978
template<QtPixelOrder PixelOrder, bool RGBA>
979
static void convert_ARGB_to_A2RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
980
0
{
981
982
0
    Q_ASSERT(RGBA || src->format == QImage::Format_ARGB32);
983
0
    Q_ASSERT(!RGBA || src->format == QImage::Format_RGBA8888);
984
0
    Q_ASSERT(dest->format == QImage::Format_A2BGR30_Premultiplied
985
0
             || dest->format == QImage::Format_A2RGB30_Premultiplied);
986
0
    Q_ASSERT(src->width == dest->width);
987
0
    Q_ASSERT(src->height == dest->height);
988
989
0
    const int src_pad = (src->bytes_per_line >> 2) - src->width;
990
0
    const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
991
0
    const quint32 *src_data = (quint32 *) src->data;
992
0
    quint32 *dest_data = (quint32 *) dest->data;
993
994
0
    for (int i = 0; i < src->height; ++i) {
995
0
        const quint32 *end = src_data + src->width;
996
0
        while (src_data < end) {
997
0
            QRgb c = *src_data;
998
0
            if (RGBA)
999
0
                c = RGBA2ARGB(c);
1000
0
            const uint alpha = (qAlpha(c) >> 6) * 85;
1001
0
            c = BYTE_MUL(c, alpha);
1002
0
            *dest_data = (qConvertRgb32ToRgb30<PixelOrder>(c) & 0x3fffffff) | (alpha << 30);
1003
0
            ++src_data;
1004
0
            ++dest_data;
1005
0
        }
1006
0
        src_data += src_pad;
1007
0
        dest_data += dest_pad;
1008
0
    }
1009
0
}
Unexecuted instantiation: qimage_conversions.cpp:void convert_ARGB_to_A2RGB30<(QtPixelOrder)1, false>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:void convert_ARGB_to_A2RGB30<(QtPixelOrder)0, false>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:void convert_ARGB_to_A2RGB30<(QtPixelOrder)1, true>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:void convert_ARGB_to_A2RGB30<(QtPixelOrder)0, true>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
1010
1011
template<QtPixelOrder PixelOrder, bool RGBA>
1012
static bool convert_ARGB_to_A2RGB30_inplace(QImageData *data, Qt::ImageConversionFlags)
1013
0
{
1014
0
    Q_ASSERT(RGBA || data->format == QImage::Format_ARGB32);
1015
0
    Q_ASSERT(!RGBA || data->format == QImage::Format_RGBA8888);
1016
1017
0
    const int pad = (data->bytes_per_line >> 2) - data->width;
1018
0
    QRgb *rgb_data = (QRgb *) data->data;
1019
1020
0
    for (int i = 0; i < data->height; ++i) {
1021
0
        const QRgb *end = rgb_data + data->width;
1022
0
        while (rgb_data < end) {
1023
0
            QRgb c = *rgb_data;
1024
0
            if (RGBA)
1025
0
                c = RGBA2ARGB(c);
1026
0
            const uint alpha = (qAlpha(c) >> 6) * 85;
1027
0
            c = BYTE_MUL(c, alpha);
1028
0
            *rgb_data = (qConvertRgb32ToRgb30<PixelOrder>(c) & 0x3fffffff) | (alpha << 30);
1029
0
            ++rgb_data;
1030
0
        }
1031
0
        rgb_data += pad;
1032
0
    }
1033
1034
0
    data->format = (PixelOrder == PixelOrderRGB) ? QImage::Format_A2RGB30_Premultiplied
1035
0
                                                 : QImage::Format_A2BGR30_Premultiplied;
1036
0
    return true;
1037
0
}
Unexecuted instantiation: qimage_conversions.cpp:bool convert_ARGB_to_A2RGB30_inplace<(QtPixelOrder)1, false>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_ARGB_to_A2RGB30_inplace<(QtPixelOrder)0, false>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_ARGB_to_A2RGB30_inplace<(QtPixelOrder)1, true>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_ARGB_to_A2RGB30_inplace<(QtPixelOrder)0, true>(QImageData*, QFlags<Qt::ImageConversionFlag>)
1038
1039
static inline uint qUnpremultiplyRgb30(uint rgb30)
1040
0
{
1041
0
    const uint a = rgb30 >> 30;
1042
0
    switch (a) {
1043
0
    case 0:
1044
0
        return 0;
1045
0
    case 1: {
1046
0
        uint rgb = rgb30 & 0x3fffffff;
1047
0
        rgb *= 3;
1048
0
        return (a << 30) | rgb;
1049
0
    }
1050
0
    case 2: {
1051
0
        uint rgb = rgb30 & 0x3fffffff;
1052
0
        rgb += (rgb >> 1) & 0x5ff7fdff;
1053
0
        return (a << 30) | rgb;
1054
0
    }
1055
0
    case 3:
1056
0
        return rgb30;
1057
0
    }
1058
0
    Q_UNREACHABLE_RETURN(0);
1059
0
}
1060
1061
template<bool rgbswap>
1062
static void convert_A2RGB30_PM_to_RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
1063
0
{
1064
0
    Q_ASSERT(src->format == QImage::Format_A2RGB30_Premultiplied || src->format == QImage::Format_A2BGR30_Premultiplied);
1065
0
    Q_ASSERT(dest->format == QImage::Format_RGB30 || dest->format == QImage::Format_BGR30);
1066
0
    Q_ASSERT(src->width == dest->width);
1067
0
    Q_ASSERT(src->height == dest->height);
1068
1069
0
    const int src_pad = (src->bytes_per_line >> 2) - src->width;
1070
0
    const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
1071
0
    const quint32 *src_data = (quint32 *) src->data;
1072
0
    quint32 *dest_data = (quint32 *) dest->data;
1073
1074
0
    for (int i = 0; i < src->height; ++i) {
1075
0
        const quint32 *end = src_data + src->width;
1076
0
        while (src_data < end) {
1077
0
            const uint p = 0xc0000000 | qUnpremultiplyRgb30(*src_data);
1078
0
            *dest_data = (rgbswap) ? qRgbSwapRgb30(p) : p;
1079
0
            ++src_data;
1080
0
            ++dest_data;
1081
0
        }
1082
0
        src_data += src_pad;
1083
0
        dest_data += dest_pad;
1084
0
    }
1085
0
}
Unexecuted instantiation: qimage_conversions.cpp:void convert_A2RGB30_PM_to_RGB30<false>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:void convert_A2RGB30_PM_to_RGB30<true>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
1086
1087
template<bool rgbswap>
1088
static bool convert_A2RGB30_PM_to_RGB30_inplace(QImageData *data, Qt::ImageConversionFlags)
1089
0
{
1090
0
    Q_ASSERT(data->format == QImage::Format_A2RGB30_Premultiplied || data->format == QImage::Format_A2BGR30_Premultiplied);
1091
1092
0
    const int pad = (data->bytes_per_line >> 2) - data->width;
1093
0
    uint *rgb_data = (uint *) data->data;
1094
1095
0
    for (int i = 0; i < data->height; ++i) {
1096
0
        const uint *end = rgb_data + data->width;
1097
0
        while (rgb_data < end) {
1098
0
            const uint p = 0xc0000000 | qUnpremultiplyRgb30(*rgb_data);
1099
0
            *rgb_data = (rgbswap) ? qRgbSwapRgb30(p) : p;
1100
0
            ++rgb_data;
1101
0
        }
1102
0
        rgb_data += pad;
1103
0
    }
1104
1105
0
    if (data->format == QImage::Format_A2RGB30_Premultiplied)
1106
0
        data->format = (rgbswap) ? QImage::Format_BGR30 : QImage::Format_RGB30;
1107
0
    else
1108
0
        data->format = (rgbswap) ? QImage::Format_RGB30 : QImage::Format_BGR30;
1109
0
    return true;
1110
0
}
Unexecuted instantiation: qimage_conversions.cpp:bool convert_A2RGB30_PM_to_RGB30_inplace<false>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_A2RGB30_PM_to_RGB30_inplace<true>(QImageData*, QFlags<Qt::ImageConversionFlag>)
1111
1112
static bool convert_BGR30_to_A2RGB30_inplace(QImageData *data, Qt::ImageConversionFlags flags)
1113
0
{
1114
0
    Q_ASSERT(data->format == QImage::Format_RGB30 || data->format == QImage::Format_BGR30);
1115
0
    if (!convert_rgbswap_generic_inplace(data, flags))
1116
0
        return false;
1117
1118
0
    if (data->format == QImage::Format_RGB30)
1119
0
        data->format = QImage::Format_A2RGB30_Premultiplied;
1120
0
    else
1121
0
        data->format = QImage::Format_A2BGR30_Premultiplied;
1122
0
    return true;
1123
0
}
1124
1125
template<QtPixelOrder PixelOrder, bool RGBA>
1126
static void convert_A2RGB30_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
1127
0
{
1128
0
    Q_ASSERT(src->format == QImage::Format_A2RGB30_Premultiplied || src->format == QImage::Format_A2BGR30_Premultiplied);
1129
0
    Q_ASSERT(RGBA ? dest->format == QImage::Format_RGBA8888 : dest->format == QImage::Format_ARGB32);
1130
0
    Q_ASSERT(src->width == dest->width);
1131
0
    Q_ASSERT(src->height == dest->height);
1132
1133
0
    const int src_pad = (src->bytes_per_line >> 2) - src->width;
1134
0
    const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
1135
0
    const quint32 *src_data = (quint32 *) src->data;
1136
0
    quint32 *dest_data = (quint32 *) dest->data;
1137
1138
0
    for (int i = 0; i < src->height; ++i) {
1139
0
        const quint32 *end = src_data + src->width;
1140
0
        while (src_data < end) {
1141
0
            *dest_data = qConvertA2rgb30ToArgb32<PixelOrder>(qUnpremultiplyRgb30(*src_data));
1142
0
            if (RGBA)
1143
0
                *dest_data = ARGB2RGBA(*dest_data);
1144
0
            ++src_data;
1145
0
            ++dest_data;
1146
0
        }
1147
0
        src_data += src_pad;
1148
0
        dest_data += dest_pad;
1149
0
    }
1150
0
}
Unexecuted instantiation: qimage_conversions.cpp:void convert_A2RGB30_PM_to_ARGB<(QtPixelOrder)1, false>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:void convert_A2RGB30_PM_to_ARGB<(QtPixelOrder)1, true>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:void convert_A2RGB30_PM_to_ARGB<(QtPixelOrder)0, false>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:void convert_A2RGB30_PM_to_ARGB<(QtPixelOrder)0, true>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
1151
1152
template<QtPixelOrder PixelOrder, bool RGBA>
1153
static bool convert_A2RGB30_PM_to_ARGB_inplace(QImageData *data, Qt::ImageConversionFlags)
1154
0
{
1155
0
    Q_ASSERT(data->format == QImage::Format_A2RGB30_Premultiplied || data->format == QImage::Format_A2BGR30_Premultiplied);
1156
1157
0
    const int pad = (data->bytes_per_line >> 2) - data->width;
1158
0
    uint *rgb_data = (uint *) data->data;
1159
1160
0
    for (int i = 0; i < data->height; ++i) {
1161
0
        const uint *end = rgb_data + data->width;
1162
0
        while (rgb_data < end) {
1163
0
            *rgb_data = qConvertA2rgb30ToArgb32<PixelOrder>(qUnpremultiplyRgb30(*rgb_data));
1164
0
            if (RGBA)
1165
0
                *rgb_data = ARGB2RGBA(*rgb_data);
1166
0
            ++rgb_data;
1167
0
        }
1168
0
        rgb_data += pad;
1169
0
    }
1170
0
    if (RGBA)
1171
0
        data->format = QImage::Format_RGBA8888;
1172
0
    else
1173
0
        data->format = QImage::Format_ARGB32;
1174
0
    return true;
1175
0
}
Unexecuted instantiation: qimage_conversions.cpp:bool convert_A2RGB30_PM_to_ARGB_inplace<(QtPixelOrder)1, false>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_A2RGB30_PM_to_ARGB_inplace<(QtPixelOrder)1, true>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_A2RGB30_PM_to_ARGB_inplace<(QtPixelOrder)0, false>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool convert_A2RGB30_PM_to_ARGB_inplace<(QtPixelOrder)0, true>(QImageData*, QFlags<Qt::ImageConversionFlag>)
1176
1177
static void convert_RGBA_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
1178
0
{
1179
0
    Q_ASSERT(src->format == QImage::Format_RGBA8888 || src->format == QImage::Format_RGBX8888);
1180
0
    Q_ASSERT(dest->format == QImage::Format_RGB32);
1181
0
    Q_ASSERT(src->width == dest->width);
1182
0
    Q_ASSERT(src->height == dest->height);
1183
1184
0
    const int src_pad = (src->bytes_per_line >> 2) - src->width;
1185
0
    const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
1186
0
    const uint *src_data = (const uint *)src->data;
1187
0
    uint *dest_data = (uint *)dest->data;
1188
1189
0
    for (int i = 0; i < src->height; ++i) {
1190
0
        const uint *end = src_data + src->width;
1191
0
        while (src_data < end) {
1192
0
            *dest_data = RGBA2ARGB(*src_data) | 0xff000000;
1193
0
            ++src_data;
1194
0
            ++dest_data;
1195
0
        }
1196
0
        src_data += src_pad;
1197
0
        dest_data += dest_pad;
1198
0
    }
1199
0
}
1200
1201
static void swap_bit_order(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
1202
0
{
1203
0
    Q_ASSERT(src->format == QImage::Format_Mono || src->format == QImage::Format_MonoLSB);
1204
0
    Q_ASSERT(dest->format == QImage::Format_Mono || dest->format == QImage::Format_MonoLSB);
1205
0
    Q_ASSERT(src->width == dest->width);
1206
0
    Q_ASSERT(src->height == dest->height);
1207
0
    Q_ASSERT(src->nbytes == dest->nbytes);
1208
0
    Q_ASSERT(src->bytes_per_line == dest->bytes_per_line);
1209
1210
0
    dest->colortable = src->colortable;
1211
1212
0
    const uchar *src_data = src->data;
1213
0
    const uchar *end = src->data + src->nbytes;
1214
0
    uchar *dest_data = dest->data;
1215
0
    while (src_data < end) {
1216
0
        *dest_data = bitflip[*src_data];
1217
0
        ++src_data;
1218
0
        ++dest_data;
1219
0
    }
1220
0
}
1221
1222
static void mask_alpha_converter(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
1223
0
{
1224
0
    Q_ASSERT(src->width == dest->width);
1225
0
    Q_ASSERT(src->height == dest->height);
1226
1227
0
    const int src_pad = (src->bytes_per_line >> 2) - src->width;
1228
0
    const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
1229
0
    const uint *src_data = (const uint *)src->data;
1230
0
    uint *dest_data = (uint *)dest->data;
1231
1232
0
    for (int i = 0; i < src->height; ++i) {
1233
0
        const uint *end = src_data + src->width;
1234
0
        while (src_data < end) {
1235
0
            *dest_data = *src_data | 0xff000000;
1236
0
            ++src_data;
1237
0
            ++dest_data;
1238
0
        }
1239
0
        src_data += src_pad;
1240
0
        dest_data += dest_pad;
1241
0
    }
1242
0
}
1243
1244
template<QImage::Format DestFormat>
1245
static bool mask_alpha_converter_inplace(QImageData *data, Qt::ImageConversionFlags)
1246
6.07k
{
1247
6.07k
    static_assert(DestFormat > QImage::Format_Invalid);
1248
6.07k
    static_assert(DestFormat < QImage::NImageFormats);
1249
6.07k
    Q_ASSERT(data->format == QImage::Format_RGB32
1250
6.07k
            || DestFormat == QImage::Format_RGB32
1251
6.07k
            || DestFormat == QImage::Format_RGBX8888);
1252
6.07k
    const int pad = (data->bytes_per_line >> 2) - data->width;
1253
6.07k
    QRgb *rgb_data = (QRgb *) data->data;
1254
1255
503k
    for (int i = 0; i < data->height; ++i) {
1256
497k
        const QRgb *end = rgb_data + data->width;
1257
51.8M
        while (rgb_data < end) {
1258
51.3M
            *rgb_data = *rgb_data | 0xff000000;
1259
51.3M
            ++rgb_data;
1260
51.3M
        }
1261
497k
        rgb_data += pad;
1262
497k
    }
1263
6.07k
    data->format = DestFormat;
1264
6.07k
    return true;
1265
6.07k
}
Unexecuted instantiation: qimage_conversions.cpp:bool mask_alpha_converter_inplace<(QImage::Format)5>(QImageData*, QFlags<Qt::ImageConversionFlag>)
qimage_conversions.cpp:bool mask_alpha_converter_inplace<(QImage::Format)6>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Line
Count
Source
1246
6.07k
{
1247
6.07k
    static_assert(DestFormat > QImage::Format_Invalid);
1248
6.07k
    static_assert(DestFormat < QImage::NImageFormats);
1249
6.07k
    Q_ASSERT(data->format == QImage::Format_RGB32
1250
6.07k
            || DestFormat == QImage::Format_RGB32
1251
6.07k
            || DestFormat == QImage::Format_RGBX8888);
1252
6.07k
    const int pad = (data->bytes_per_line >> 2) - data->width;
1253
6.07k
    QRgb *rgb_data = (QRgb *) data->data;
1254
1255
503k
    for (int i = 0; i < data->height; ++i) {
1256
497k
        const QRgb *end = rgb_data + data->width;
1257
51.8M
        while (rgb_data < end) {
1258
51.3M
            *rgb_data = *rgb_data | 0xff000000;
1259
51.3M
            ++rgb_data;
1260
51.3M
        }
1261
497k
        rgb_data += pad;
1262
497k
    }
1263
6.07k
    data->format = DestFormat;
1264
6.07k
    return true;
1265
6.07k
}
Unexecuted instantiation: qimage_conversions.cpp:bool mask_alpha_converter_inplace<(QImage::Format)4>(QImageData*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:bool mask_alpha_converter_inplace<(QImage::Format)16>(QImageData*, QFlags<Qt::ImageConversionFlag>)
1266
1267
static void mask_alpha_converter_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags flags)
1268
0
{
1269
0
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1270
0
    return mask_alpha_converter(dest, src, flags);
1271
#else
1272
    Q_UNUSED(flags);
1273
    Q_ASSERT(src->width == dest->width);
1274
    Q_ASSERT(src->height == dest->height);
1275
1276
    const int src_pad = (src->bytes_per_line >> 2) - src->width;
1277
    const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
1278
    const uint *src_data = (const uint *)src->data;
1279
    uint *dest_data = (uint *)dest->data;
1280
1281
    for (int i = 0; i < src->height; ++i) {
1282
        const uint *end = src_data + src->width;
1283
        while (src_data < end) {
1284
            *dest_data = *src_data | 0x000000ff;
1285
            ++src_data;
1286
            ++dest_data;
1287
        }
1288
        src_data += src_pad;
1289
        dest_data += dest_pad;
1290
    }
1291
#endif
1292
0
}
1293
1294
static bool mask_alpha_converter_rgbx_inplace(QImageData *data, Qt::ImageConversionFlags flags)
1295
0
{
1296
0
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1297
0
    return mask_alpha_converter_inplace<QImage::Format_RGBX8888>(data, flags);
1298
#else
1299
    Q_UNUSED(flags);
1300
1301
    const int pad = (data->bytes_per_line >> 2) - data->width;
1302
    QRgb *rgb_data = (QRgb *) data->data;
1303
1304
    for (int i = 0; i < data->height; ++i) {
1305
        const QRgb *end = rgb_data + data->width;
1306
        while (rgb_data < end) {
1307
            *rgb_data = *rgb_data | 0x000000fff;
1308
            ++rgb_data;
1309
        }
1310
        rgb_data += pad;
1311
    }
1312
    data->format = QImage::Format_RGBX8888;
1313
    return true;
1314
#endif
1315
0
}
1316
1317
template<bool RGBA>
1318
static void convert_RGBA64_to_ARGB32(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
1319
0
{
1320
0
    Q_ASSERT(src->format == QImage::Format_RGBA64);
1321
0
    Q_ASSERT(RGBA || dest->format == QImage::Format_ARGB32);
1322
0
    Q_ASSERT(!RGBA || dest->format == QImage::Format_RGBA8888);
1323
0
    Q_ASSERT(src->width == dest->width);
1324
0
    Q_ASSERT(src->height == dest->height);
1325
1326
0
    const uchar *srcData = src->data;
1327
0
    uchar *destData = dest->data;
1328
1329
0
    for (int i = 0; i < src->height; ++i) {
1330
0
        uint *d = reinterpret_cast<uint *>(destData);
1331
0
        const QRgba64 *s = reinterpret_cast<const QRgba64 *>(srcData);
1332
0
        qt_convertRGBA64ToARGB32<RGBA>(d, s, src->width);
1333
0
        srcData += src->bytes_per_line;
1334
0
        destData += dest->bytes_per_line;
1335
0
    }
1336
0
}
Unexecuted instantiation: qimage_conversions.cpp:void convert_RGBA64_to_ARGB32<false>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:void convert_RGBA64_to_ARGB32<true>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
1337
1338
template<bool RGBA>
1339
static void convert_ARGB32_to_RGBA64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
1340
0
{
1341
0
    Q_ASSERT(RGBA || src->format == QImage::Format_ARGB32);
1342
0
    Q_ASSERT(!RGBA || src->format == QImage::Format_RGBA8888);
1343
0
    Q_ASSERT(dest->format == QImage::Format_RGBA64);
1344
0
    Q_ASSERT(src->width == dest->width);
1345
0
    Q_ASSERT(src->height == dest->height);
1346
1347
0
    const uchar *src_data = src->data;
1348
0
    uchar *dest_data = dest->data;
1349
0
    const FetchAndConvertPixelsFunc64 fetch = qPixelLayouts[qt_toPremultipliedFormat(src->format)].fetchToRGBA64PM;
1350
1351
0
    for (int i = 0; i < src->height; ++i) {
1352
0
        fetch(reinterpret_cast<QRgba64 *>(dest_data), src_data, 0, src->width, nullptr, nullptr);
1353
0
        src_data += src->bytes_per_line;
1354
0
        dest_data += dest->bytes_per_line;
1355
0
    }
1356
0
}
Unexecuted instantiation: qimage_conversions.cpp:void convert_ARGB32_to_RGBA64<false>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:void convert_ARGB32_to_RGBA64<true>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
1357
1358
static void convert_RGBA64_to_RGBx64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
1359
0
{
1360
0
    Q_ASSERT(src->format == QImage::Format_RGBA64);
1361
0
    Q_ASSERT(dest->format == QImage::Format_RGBX64);
1362
0
    Q_ASSERT(src->width == dest->width);
1363
0
    Q_ASSERT(src->height == dest->height);
1364
1365
0
    const int src_pad = (src->bytes_per_line >> 3) - src->width;
1366
0
    const int dest_pad = (dest->bytes_per_line >> 3) - dest->width;
1367
0
    const QRgba64 *src_data = reinterpret_cast<const QRgba64 *>(src->data);
1368
0
    QRgba64 *dest_data = reinterpret_cast<QRgba64 *>(dest->data);
1369
1370
0
    for (int i = 0; i < src->height; ++i) {
1371
0
        const QRgba64 *end = src_data + src->width;
1372
0
        while (src_data < end) {
1373
0
            *dest_data = *src_data;
1374
0
            dest_data->setAlpha(65535);
1375
0
            ++src_data;
1376
0
            ++dest_data;
1377
0
        }
1378
0
        src_data += src_pad;
1379
0
        dest_data += dest_pad;
1380
0
    }
1381
0
}
1382
1383
static bool convert_RGBA64_to_RGBx64_inplace(QImageData *data, Qt::ImageConversionFlags)
1384
0
{
1385
0
    Q_ASSERT(data->format == QImage::Format_RGBA64);
1386
1387
0
    const int pad = (data->bytes_per_line >> 3) - data->width;
1388
0
    QRgba64 *rgb_data = reinterpret_cast<QRgba64 *>(data->data);
1389
1390
0
    for (int i = 0; i < data->height; ++i) {
1391
0
        const QRgba64 *end = rgb_data + data->width;
1392
0
        while (rgb_data < end) {
1393
0
            rgb_data->setAlpha(65535);
1394
0
            ++rgb_data;
1395
0
        }
1396
0
        rgb_data += pad;
1397
0
    }
1398
0
    data->format = QImage::Format_RGBX64;
1399
0
    return true;
1400
0
}
1401
1402
static void convert_gray16_to_RGBA64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
1403
0
{
1404
0
    Q_ASSERT(src->format == QImage::Format_Grayscale16);
1405
0
    Q_ASSERT(dest->format == QImage::Format_RGBA64 || dest->format == QImage::Format_RGBX64 ||
1406
0
             dest->format == QImage::Format_RGBA64_Premultiplied);
1407
0
    Q_ASSERT(src->width == dest->width);
1408
0
    Q_ASSERT(src->height == dest->height);
1409
1410
0
    const qsizetype sbpl = src->bytes_per_line;
1411
0
    const qsizetype dbpl = dest->bytes_per_line;
1412
0
    const uchar *src_data = src->data;
1413
0
    uchar *dest_data = dest->data;
1414
1415
0
    for (int i = 0; i < src->height; ++i) {
1416
0
        const quint16 *src_line = reinterpret_cast<const quint16 *>(src_data);
1417
0
        QRgba64 *dest_line = reinterpret_cast<QRgba64 *>(dest_data);
1418
0
        for (int j = 0; j < src->width; ++j) {
1419
0
            quint16 s = src_line[j];
1420
0
            dest_line[j] = qRgba64(s, s, s, 0xFFFF);
1421
0
        }
1422
0
        src_data += sbpl;
1423
0
        dest_data += dbpl;
1424
0
    }
1425
0
}
1426
1427
template<bool Premultiplied>
1428
static void convert_ARGB_to_gray8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
1429
119k
{
1430
119k
    Q_ASSERT(dest->format == QImage::Format_Grayscale8);
1431
119k
    Q_ASSERT(src->format == QImage::Format_RGB32 ||
1432
119k
             src->format == QImage::Format_ARGB32 ||
1433
119k
             src->format == QImage::Format_ARGB32_Premultiplied);
1434
119k
    Q_ASSERT(src->width == dest->width);
1435
119k
    Q_ASSERT(src->height == dest->height);
1436
1437
119k
    const qsizetype sbpl = src->bytes_per_line;
1438
119k
    const qsizetype dbpl = dest->bytes_per_line;
1439
119k
    const uchar *src_data = src->data;
1440
119k
    uchar *dest_data = dest->data;
1441
1442
119k
    QColorSpace fromCS = src->colorSpace.isValid() ? src->colorSpace : QColorSpace::SRgb;
1443
119k
    QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ();
1444
119k
    const QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf);
1445
119k
    QColorTransformPrivate::TransformFlags flags = Premultiplied
1446
119k
            ? QColorTransformPrivate::InputPremultiplied
1447
119k
            : QColorTransformPrivate::Unpremultiplied;
1448
1449
15.1M
    for (int i = 0; i < src->height; ++i) {
1450
15.0M
        const QRgb *src_line = reinterpret_cast<const QRgb *>(src_data);
1451
15.0M
        tfd->apply(dest_data, src_line, src->width, flags);
1452
15.0M
        src_data += sbpl;
1453
15.0M
        dest_data += dbpl;
1454
15.0M
    }
1455
119k
}
qimage_conversions.cpp:void convert_ARGB_to_gray8<false>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
Line
Count
Source
1429
119k
{
1430
119k
    Q_ASSERT(dest->format == QImage::Format_Grayscale8);
1431
119k
    Q_ASSERT(src->format == QImage::Format_RGB32 ||
1432
119k
             src->format == QImage::Format_ARGB32 ||
1433
119k
             src->format == QImage::Format_ARGB32_Premultiplied);
1434
119k
    Q_ASSERT(src->width == dest->width);
1435
119k
    Q_ASSERT(src->height == dest->height);
1436
1437
119k
    const qsizetype sbpl = src->bytes_per_line;
1438
119k
    const qsizetype dbpl = dest->bytes_per_line;
1439
119k
    const uchar *src_data = src->data;
1440
119k
    uchar *dest_data = dest->data;
1441
1442
119k
    QColorSpace fromCS = src->colorSpace.isValid() ? src->colorSpace : QColorSpace::SRgb;
1443
119k
    QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ();
1444
119k
    const QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf);
1445
119k
    QColorTransformPrivate::TransformFlags flags = Premultiplied
1446
119k
            ? QColorTransformPrivate::InputPremultiplied
1447
119k
            : QColorTransformPrivate::Unpremultiplied;
1448
1449
15.1M
    for (int i = 0; i < src->height; ++i) {
1450
15.0M
        const QRgb *src_line = reinterpret_cast<const QRgb *>(src_data);
1451
15.0M
        tfd->apply(dest_data, src_line, src->width, flags);
1452
15.0M
        src_data += sbpl;
1453
15.0M
        dest_data += dbpl;
1454
15.0M
    }
1455
119k
}
Unexecuted instantiation: qimage_conversions.cpp:void convert_ARGB_to_gray8<true>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
1456
1457
template<bool Premultiplied>
1458
static void convert_ARGB_to_gray16(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
1459
0
{
1460
0
    Q_ASSERT(dest->format == QImage::Format_Grayscale16);
1461
0
    Q_ASSERT(src->format == QImage::Format_RGB32 ||
1462
0
             src->format == QImage::Format_ARGB32 ||
1463
0
             src->format == QImage::Format_ARGB32_Premultiplied);
1464
0
    Q_ASSERT(src->width == dest->width);
1465
0
    Q_ASSERT(src->height == dest->height);
1466
1467
0
    const qsizetype sbpl = src->bytes_per_line;
1468
0
    const qsizetype dbpl = dest->bytes_per_line;
1469
0
    const uchar *src_data = src->data;
1470
0
    uchar *dest_data = dest->data;
1471
1472
0
    QColorSpace fromCS = src->colorSpace.isValid() ? src->colorSpace : QColorSpace::SRgb;
1473
0
    QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ();
1474
0
    const QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf);
1475
0
    QColorTransformPrivate::TransformFlags flags = Premultiplied
1476
0
            ? QColorTransformPrivate::InputPremultiplied
1477
0
            : QColorTransformPrivate::Unpremultiplied;
1478
1479
0
    Q_DECL_UNINITIALIZED QRgba64 tmp_line[BufferSize];
1480
0
    for (int i = 0; i < src->height; ++i) {
1481
0
        const QRgb *src_line = reinterpret_cast<const QRgb *>(src_data);
1482
0
        quint16 *dest_line = reinterpret_cast<quint16 *>(dest_data);
1483
0
        int j = 0;
1484
0
        while (j < src->width) {
1485
0
            const int len = std::min(src->width - j, BufferSize);
1486
0
            for (int k = 0; k < len; ++k)
1487
0
                tmp_line[k] = QRgba64::fromArgb32(src_line[j + k]);
1488
0
            tfd->apply(dest_line + j, tmp_line, len, flags);
1489
0
            j += len;
1490
0
        }
1491
0
        src_data += sbpl;
1492
0
        dest_data += dbpl;
1493
0
    }
1494
0
}
Unexecuted instantiation: qimage_conversions.cpp:void convert_ARGB_to_gray16<false>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:void convert_ARGB_to_gray16<true>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
1495
1496
template<bool Premultiplied>
1497
static void convert_RGBA64_to_gray8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
1498
0
{
1499
0
    Q_ASSERT(dest->format == QImage::Format_Grayscale8);
1500
0
    Q_ASSERT(src->format == QImage::Format_RGBX64 ||
1501
0
             src->format == QImage::Format_RGBA64 ||
1502
0
             src->format == QImage::Format_RGBA64_Premultiplied);
1503
0
    Q_ASSERT(src->width == dest->width);
1504
0
    Q_ASSERT(src->height == dest->height);
1505
1506
0
    const qsizetype sbpl = src->bytes_per_line;
1507
0
    const qsizetype dbpl = dest->bytes_per_line;
1508
0
    const uchar *src_data = src->data;
1509
0
    uchar *dest_data = dest->data;
1510
1511
0
    QColorSpace fromCS = src->colorSpace.isValid() ? src->colorSpace : QColorSpace::SRgb;
1512
0
    QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ();
1513
0
    const QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf);
1514
0
    QColorTransformPrivate::TransformFlags flags = Premultiplied
1515
0
            ? QColorTransformPrivate::InputPremultiplied
1516
0
            : QColorTransformPrivate::Unpremultiplied;
1517
1518
0
    Q_DECL_UNINITIALIZED quint16 gray_line[BufferSize];
1519
0
    for (int i = 0; i < src->height; ++i) {
1520
0
        const QRgba64 *src_line = reinterpret_cast<const QRgba64 *>(src_data);
1521
0
        uchar *dest_line = dest_data;
1522
0
        int j = 0;
1523
0
        while (j < src->width) {
1524
0
            const int len = std::min(src->width - j, BufferSize);
1525
0
            tfd->apply(gray_line, src_line + j, len, flags);
1526
0
            for (int k = 0; k < len; ++k)
1527
0
                dest_line[j + k] = qt_div_257(gray_line[k]);
1528
0
            j += len;
1529
0
        }
1530
0
        src_data += sbpl;
1531
0
        dest_data += dbpl;
1532
0
    }
1533
0
}
Unexecuted instantiation: qimage_conversions.cpp:void convert_RGBA64_to_gray8<false>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:void convert_RGBA64_to_gray8<true>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
1534
1535
template<bool Premultiplied>
1536
static void convert_RGBA64_to_gray16(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
1537
0
{
1538
0
    Q_ASSERT(dest->format == QImage::Format_Grayscale16);
1539
0
    Q_ASSERT(src->format == QImage::Format_RGBX64 ||
1540
0
             src->format == QImage::Format_RGBA64 ||
1541
0
             src->format == QImage::Format_RGBA64_Premultiplied);
1542
0
    Q_ASSERT(src->width == dest->width);
1543
0
    Q_ASSERT(src->height == dest->height);
1544
1545
0
    const qsizetype sbpl = src->bytes_per_line;
1546
0
    const qsizetype dbpl = dest->bytes_per_line;
1547
0
    const uchar *src_data = src->data;
1548
0
    uchar *dest_data = dest->data;
1549
1550
0
    QColorSpace fromCS = src->colorSpace.isValid() ? src->colorSpace : QColorSpace::SRgb;
1551
0
    QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ();
1552
0
    const QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf);
1553
0
    QColorTransformPrivate::TransformFlags flags = Premultiplied
1554
0
            ? QColorTransformPrivate::InputPremultiplied
1555
0
            : QColorTransformPrivate::Unpremultiplied;
1556
1557
0
    for (int i = 0; i < src->height; ++i) {
1558
0
        const QRgba64 *src_line = reinterpret_cast<const QRgba64 *>(src_data);
1559
0
        quint16 *dest_line = reinterpret_cast<quint16 *>(dest_data);
1560
0
        tfd->apply(dest_line, src_line, src->width, flags);
1561
0
        src_data += sbpl;
1562
0
        dest_data += dbpl;
1563
0
    }
1564
0
}
Unexecuted instantiation: qimage_conversions.cpp:void convert_RGBA64_to_gray16<false>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:void convert_RGBA64_to_gray16<true>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
1565
1566
template<bool MaskAlpha>
1567
static void convert_RGBA16FPM_to_RGBA16F(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
1568
{
1569
    Q_ASSERT(src->format == QImage::Format_RGBA16FPx4_Premultiplied);
1570
    Q_ASSERT(dest->format == QImage::Format_RGBA16FPx4 || dest->format == QImage::Format_RGBX16FPx4);
1571
    Q_ASSERT(src->width == dest->width);
1572
    Q_ASSERT(src->height == dest->height);
1573
1574
    const int src_pad = (src->bytes_per_line >> 3) - src->width;
1575
    const int dest_pad = (dest->bytes_per_line >> 3) - dest->width;
1576
    const QRgbaFloat16 *src_data = reinterpret_cast<const QRgbaFloat16 *>(src->data);
1577
    QRgbaFloat16 *dest_data = reinterpret_cast<QRgbaFloat16 *>(dest->data);
1578
1579
    for (int i = 0; i < src->height; ++i) {
1580
        const QRgbaFloat16 *end = src_data + src->width;
1581
        while (src_data < end) {
1582
            *dest_data = src_data->unpremultiplied();
1583
            if (MaskAlpha)
1584
                dest_data->setAlpha(1.0f);
1585
            ++src_data;
1586
            ++dest_data;
1587
        }
1588
        src_data += src_pad;
1589
        dest_data += dest_pad;
1590
    }
1591
}
1592
1593
template<bool MaskAlpha>
1594
static bool convert_RGBA16FPM_to_RGBA16F_inplace(QImageData *data, Qt::ImageConversionFlags)
1595
{
1596
    Q_ASSERT(data->format == QImage::Format_RGBA16FPx4_Premultiplied);
1597
1598
    const int pad = (data->bytes_per_line >> 3) - data->width;
1599
    QRgbaFloat16 *rgb_data = reinterpret_cast<QRgbaFloat16 *>(data->data);
1600
1601
    for (int i = 0; i < data->height; ++i) {
1602
        const QRgbaFloat16 *end = rgb_data + data->width;
1603
        while (rgb_data < end) {
1604
            *rgb_data = rgb_data->unpremultiplied();
1605
            if (MaskAlpha)
1606
                rgb_data->setAlpha(1.0f);
1607
            ++rgb_data;
1608
        }
1609
        rgb_data += pad;
1610
    }
1611
    data->format = MaskAlpha ? QImage::Format_RGBX16FPx4 : QImage::Format_RGBA16FPx4;
1612
    return true;
1613
}
1614
1615
static QList<QRgb> fix_color_table(const QList<QRgb> &ctbl, QImage::Format format)
1616
149k
{
1617
149k
    QList<QRgb> colorTable = ctbl;
1618
149k
    if (format == QImage::Format_RGB32) {
1619
        // check if the color table has alpha
1620
357k
        for (int i = 0; i < colorTable.size(); ++i)
1621
238k
            if (qAlpha(colorTable.at(i)) != 0xff)
1622
0
                colorTable[i] = colorTable.at(i) | 0xff000000;
1623
119k
    } else if (format == QImage::Format_ARGB32_Premultiplied) {
1624
        // check if the color table has alpha
1625
90.5k
        for (int i = 0; i < colorTable.size(); ++i)
1626
60.3k
            colorTable[i] = qPremultiply(colorTable.at(i));
1627
30.1k
    }
1628
149k
    return colorTable;
1629
149k
}
1630
1631
//
1632
// dither_to_1:  Uses selected dithering algorithm.
1633
//
1634
1635
void dither_to_Mono(QImageData *dst, const QImageData *src,
1636
                           Qt::ImageConversionFlags flags, bool fromalpha)
1637
0
{
1638
0
    Q_ASSERT(src->width == dst->width);
1639
0
    Q_ASSERT(src->height == dst->height);
1640
0
    Q_ASSERT(dst->format == QImage::Format_Mono || dst->format == QImage::Format_MonoLSB);
1641
1642
0
    dst->colortable.clear();
1643
0
    dst->colortable.append(0xffffffff);
1644
0
    dst->colortable.append(0xff000000);
1645
1646
0
    enum { Threshold, Ordered, Diffuse } dithermode;
1647
1648
0
    if (fromalpha) {
1649
0
        if ((flags & Qt::AlphaDither_Mask) == Qt::DiffuseAlphaDither)
1650
0
            dithermode = Diffuse;
1651
0
        else if ((flags & Qt::AlphaDither_Mask) == Qt::OrderedAlphaDither)
1652
0
            dithermode = Ordered;
1653
0
        else
1654
0
            dithermode = Threshold;
1655
0
    } else {
1656
0
        if ((flags & Qt::Dither_Mask) == Qt::ThresholdDither)
1657
0
            dithermode = Threshold;
1658
0
        else if ((flags & Qt::Dither_Mask) == Qt::OrderedDither)
1659
0
            dithermode = Ordered;
1660
0
        else
1661
0
            dithermode = Diffuse;
1662
0
    }
1663
1664
0
    int          w = src->width;
1665
0
    int          h = src->height;
1666
0
    int          d = src->depth;
1667
0
    uchar gray[256];                                // gray map for 8 bit images
1668
0
    bool  use_gray = (d == 8);
1669
0
    if (use_gray) {                                // make gray map
1670
0
        if (fromalpha) {
1671
            // Alpha 0x00 -> 0 pixels (white)
1672
            // Alpha 0xFF -> 1 pixels (black)
1673
0
            for (int i = 0; i < src->colortable.size(); i++)
1674
0
                gray[i] = (255 - (src->colortable.at(i) >> 24));
1675
0
        } else {
1676
            // Pixel 0x00 -> 1 pixels (black)
1677
            // Pixel 0xFF -> 0 pixels (white)
1678
0
            for (int i = 0; i < src->colortable.size(); i++)
1679
0
                gray[i] = qGray(src->colortable.at(i));
1680
0
        }
1681
0
    }
1682
1683
0
    uchar *dst_data = dst->data;
1684
0
    qsizetype dst_bpl = dst->bytes_per_line;
1685
0
    const uchar *src_data = src->data;
1686
0
    qsizetype src_bpl = src->bytes_per_line;
1687
1688
0
    switch (dithermode) {
1689
0
    case Diffuse: {
1690
0
        QScopedArrayPointer<int> lineBuffer(new int[w * 2]);
1691
0
        int *line1 = lineBuffer.data();
1692
0
        int *line2 = lineBuffer.data() + w;
1693
0
        int bmwidth = (w+7)/8;
1694
1695
0
        int *b1, *b2;
1696
0
        int wbytes = w * (d/8);
1697
0
        const uchar *p = src->data;
1698
0
        const uchar *end = p + wbytes;
1699
0
        b2 = line2;
1700
0
        if (use_gray) {                        // 8 bit image
1701
0
            while (p < end)
1702
0
                *b2++ = gray[*p++];
1703
0
        } else {                                // 32 bit image
1704
0
            if (fromalpha) {
1705
0
                while (p < end) {
1706
0
                    *b2++ = 255 - (*(const uint*)p >> 24);
1707
0
                    p += 4;
1708
0
                }
1709
0
            } else {
1710
0
                while (p < end) {
1711
0
                    *b2++ = qGray(*(const uint*)p);
1712
0
                    p += 4;
1713
0
                }
1714
0
            }
1715
0
        }
1716
0
        for (int y=0; y<h; y++) {                        // for each scan line...
1717
0
            int *tmp = line1; line1 = line2; line2 = tmp;
1718
0
            bool not_last_line = y < h - 1;
1719
0
            if (not_last_line) {                // calc. grayvals for next line
1720
0
                p = src->data + (y+1)*src->bytes_per_line;
1721
0
                end = p + wbytes;
1722
0
                b2 = line2;
1723
0
                if (use_gray) {                // 8 bit image
1724
0
                    while (p < end)
1725
0
                        *b2++ = gray[*p++];
1726
0
                } else {                        // 24 bit image
1727
0
                    if (fromalpha) {
1728
0
                        while (p < end) {
1729
0
                            *b2++ = 255 - (*(const uint*)p >> 24);
1730
0
                            p += 4;
1731
0
                        }
1732
0
                    } else {
1733
0
                        while (p < end) {
1734
0
                            *b2++ = qGray(*(const uint*)p);
1735
0
                            p += 4;
1736
0
                        }
1737
0
                    }
1738
0
                }
1739
0
            }
1740
1741
0
            int err;
1742
0
            uchar *p = dst->data + y*dst->bytes_per_line;
1743
0
            memset(p, 0, bmwidth);
1744
0
            b1 = line1;
1745
0
            b2 = line2;
1746
0
            int bit = 7;
1747
0
            for (int x=1; x<=w; x++) {
1748
0
                if (*b1 < 128) {                // black pixel
1749
0
                    err = *b1++;
1750
0
                    *p |= 1 << bit;
1751
0
                } else {                        // white pixel
1752
0
                    err = *b1++ - 255;
1753
0
                }
1754
0
                if (bit == 0) {
1755
0
                    p++;
1756
0
                    bit = 7;
1757
0
                } else {
1758
0
                    bit--;
1759
0
                }
1760
0
                const int e7 = ((err * 7) + 8) >> 4;
1761
0
                const int e5 = ((err * 5) + 8) >> 4;
1762
0
                const int e3 = ((err * 3) + 8) >> 4;
1763
0
                const int e1 = err - (e7 + e5 + e3);
1764
0
                if (x < w)
1765
0
                    *b1 += e7;                  // spread error to right pixel
1766
0
                if (not_last_line) {
1767
0
                    b2[0] += e5;                // pixel below
1768
0
                    if (x > 1)
1769
0
                        b2[-1] += e3;           // pixel below left
1770
0
                    if (x < w)
1771
0
                        b2[1] += e1;            // pixel below right
1772
0
                }
1773
0
                b2++;
1774
0
            }
1775
0
        }
1776
0
    } break;
1777
0
    case Ordered: {
1778
1779
0
        memset(dst->data, 0, dst->nbytes);
1780
0
        if (d == 32) {
1781
0
            for (int i=0; i<h; i++) {
1782
0
                const uint *p = (const uint *)src_data;
1783
0
                const uint *end = p + w;
1784
0
                uchar *m = dst_data;
1785
0
                int bit = 7;
1786
0
                int j = 0;
1787
0
                if (fromalpha) {
1788
0
                    while (p < end) {
1789
0
                        if ((*p++ >> 24) >= qt_bayer_matrix[j++&15][i&15])
1790
0
                            *m |= 1 << bit;
1791
0
                        if (bit == 0) {
1792
0
                            m++;
1793
0
                            bit = 7;
1794
0
                        } else {
1795
0
                            bit--;
1796
0
                        }
1797
0
                    }
1798
0
                } else {
1799
0
                    while (p < end) {
1800
0
                        if (q20::cmp_less(qGray(*p++), qt_bayer_matrix[j++&15][i&15]))
1801
0
                            *m |= 1 << bit;
1802
0
                        if (bit == 0) {
1803
0
                            m++;
1804
0
                            bit = 7;
1805
0
                        } else {
1806
0
                            bit--;
1807
0
                        }
1808
0
                    }
1809
0
                }
1810
0
                dst_data += dst_bpl;
1811
0
                src_data += src_bpl;
1812
0
            }
1813
0
        } else if (d == 8) {
1814
0
            for (int i=0; i<h; i++) {
1815
0
                const uchar *p = src_data;
1816
0
                const uchar *end = p + w;
1817
0
                uchar *m = dst_data;
1818
0
                int bit = 7;
1819
0
                int j = 0;
1820
0
                while (p < end) {
1821
0
                    if ((uint)gray[*p++] < qt_bayer_matrix[j++&15][i&15])
1822
0
                        *m |= 1 << bit;
1823
0
                    if (bit == 0) {
1824
0
                        m++;
1825
0
                        bit = 7;
1826
0
                    } else {
1827
0
                        bit--;
1828
0
                    }
1829
0
                }
1830
0
                dst_data += dst_bpl;
1831
0
                src_data += src_bpl;
1832
0
            }
1833
0
        }
1834
0
    } break;
1835
0
    default: { // Threshold:
1836
0
        memset(dst->data, 0, dst->nbytes);
1837
0
        if (d == 32) {
1838
0
            for (int i=0; i<h; i++) {
1839
0
                const uint *p = (const uint *)src_data;
1840
0
                const uint *end = p + w;
1841
0
                uchar *m = dst_data;
1842
0
                int bit = 7;
1843
0
                if (fromalpha) {
1844
0
                    while (p < end) {
1845
0
                        if ((*p++ >> 24) >= 128)
1846
0
                            *m |= 1 << bit;        // Set mask "on"
1847
0
                        if (bit == 0) {
1848
0
                            m++;
1849
0
                            bit = 7;
1850
0
                        } else {
1851
0
                            bit--;
1852
0
                        }
1853
0
                    }
1854
0
                } else {
1855
0
                    while (p < end) {
1856
0
                        if (qGray(*p++) < 128)
1857
0
                            *m |= 1 << bit;        // Set pixel "black"
1858
0
                        if (bit == 0) {
1859
0
                            m++;
1860
0
                            bit = 7;
1861
0
                        } else {
1862
0
                            bit--;
1863
0
                        }
1864
0
                    }
1865
0
                }
1866
0
                dst_data += dst_bpl;
1867
0
                src_data += src_bpl;
1868
0
            }
1869
0
        } else
1870
0
            if (d == 8) {
1871
0
                for (int i=0; i<h; i++) {
1872
0
                    const uchar *p = src_data;
1873
0
                    const uchar *end = p + w;
1874
0
                    uchar *m = dst_data;
1875
0
                    int bit = 7;
1876
0
                    while (p < end) {
1877
0
                        if (gray[*p++] < 128)
1878
0
                            *m |= 1 << bit;                // Set mask "on"/ pixel "black"
1879
0
                        if (bit == 0) {
1880
0
                            m++;
1881
0
                            bit = 7;
1882
0
                        } else {
1883
0
                            bit--;
1884
0
                        }
1885
0
                    }
1886
0
                    dst_data += dst_bpl;
1887
0
                    src_data += src_bpl;
1888
0
                }
1889
0
            }
1890
0
        }
1891
0
    }
1892
1893
0
    if (dst->format == QImage::Format_MonoLSB) {
1894
        // need to swap bit order
1895
0
        uchar *sl = dst->data;
1896
0
        int bpl = (dst->width + 7) * dst->depth / 8;
1897
0
        int pad = dst->bytes_per_line - bpl;
1898
0
        for (int y=0; y<dst->height; ++y) {
1899
0
            for (int x=0; x<bpl; ++x) {
1900
0
                *sl = bitflip[*sl];
1901
0
                ++sl;
1902
0
            }
1903
0
            sl += pad;
1904
0
        }
1905
0
    }
1906
0
}
1907
1908
static void convert_X_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags)
1909
0
{
1910
0
    dither_to_Mono(dst, src, flags, false);
1911
0
}
1912
1913
static void convert_ARGB_PM_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags)
1914
0
{
1915
0
    QScopedPointer<QImageData> tmp(QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32));
1916
0
    convert_generic(tmp.data(), src, Qt::AutoColor);
1917
0
    dither_to_Mono(dst, tmp.data(), flags, false);
1918
0
}
1919
1920
//
1921
// convert_32_to_8:  Converts a 32 bits depth (true color) to an 8 bit
1922
// image with a colormap. If the 32 bit image has more than 256 colors,
1923
// we convert the red,green and blue bytes into a single byte encoded
1924
// as 6 shades of each of red, green and blue.
1925
//
1926
// if dithering is needed, only 1 color at most is available for alpha.
1927
//
1928
struct QRgbMap {
1929
0
    inline QRgbMap() : used(0) { }
1930
    uchar  pix;
1931
    uchar used;
1932
    QRgb  rgb;
1933
};
1934
1935
static void convert_RGB_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags)
1936
0
{
1937
0
    Q_ASSERT(src->format == QImage::Format_RGB32 || src->format == QImage::Format_ARGB32);
1938
0
    Q_ASSERT(dst->format == QImage::Format_Indexed8);
1939
0
    Q_ASSERT(src->width == dst->width);
1940
0
    Q_ASSERT(src->height == dst->height);
1941
1942
0
    bool    do_quant = (flags & Qt::DitherMode_Mask) == Qt::PreferDither
1943
0
                       || src->format == QImage::Format_ARGB32;
1944
0
    uint alpha_mask = src->format == QImage::Format_RGB32 ? 0xff000000 : 0;
1945
1946
0
    const int tablesize = 997; // prime
1947
0
    QRgbMap table[tablesize];
1948
0
    int   pix=0;
1949
1950
0
    if (!dst->colortable.isEmpty()) {
1951
0
        QList<QRgb> ctbl = dst->colortable;
1952
0
        dst->colortable.resize(256);
1953
        // Preload palette into table.
1954
        // Almost same code as pixel insertion below
1955
0
        for (int i = 0; i < dst->colortable.size(); ++i) {
1956
            // Find in table...
1957
0
            QRgb p = ctbl.at(i) | alpha_mask;
1958
0
            int hash = p % tablesize;
1959
0
            for (;;) {
1960
0
                if (table[hash].used) {
1961
0
                    if (table[hash].rgb == p) {
1962
                        // Found previous insertion - use it
1963
0
                        break;
1964
0
                    } else {
1965
                        // Keep searching...
1966
0
                        if (++hash == tablesize) hash = 0;
1967
0
                    }
1968
0
                } else {
1969
                    // Cannot be in table
1970
0
                    Q_ASSERT (pix != 256);        // too many colors
1971
                    // Insert into table at this unused position
1972
0
                    dst->colortable[pix] = p;
1973
0
                    table[hash].pix = pix++;
1974
0
                    table[hash].rgb = p;
1975
0
                    table[hash].used = 1;
1976
0
                    break;
1977
0
                }
1978
0
            }
1979
0
        }
1980
0
    }
1981
1982
0
    if ((flags & Qt::DitherMode_Mask) != Qt::PreferDither) {
1983
0
        dst->colortable.resize(256);
1984
0
        const uchar *src_data = src->data;
1985
0
        uchar *dest_data = dst->data;
1986
0
        for (int y = 0; y < src->height; y++) {        // check if <= 256 colors
1987
0
            const QRgb *s = (const QRgb *)src_data;
1988
0
            uchar *b = dest_data;
1989
0
            for (int x = 0; x < src->width; ++x) {
1990
0
                QRgb p = s[x] | alpha_mask;
1991
0
                int hash = p % tablesize;
1992
0
                for (;;) {
1993
0
                    if (table[hash].used) {
1994
0
                        if (table[hash].rgb == (p)) {
1995
                            // Found previous insertion - use it
1996
0
                            break;
1997
0
                        } else {
1998
                            // Keep searching...
1999
0
                            if (++hash == tablesize) hash = 0;
2000
0
                        }
2001
0
                    } else {
2002
                        // Cannot be in table
2003
0
                        if (pix == 256) {        // too many colors
2004
0
                            do_quant = true;
2005
                            // Break right out
2006
0
                            x = src->width;
2007
0
                            y = src->height;
2008
0
                        } else {
2009
                            // Insert into table at this unused position
2010
0
                            dst->colortable[pix] = p;
2011
0
                            table[hash].pix = pix++;
2012
0
                            table[hash].rgb = p;
2013
0
                            table[hash].used = 1;
2014
0
                        }
2015
0
                        break;
2016
0
                    }
2017
0
                }
2018
0
                *b++ = table[hash].pix;                // May occur once incorrectly
2019
0
            }
2020
0
            src_data += src->bytes_per_line;
2021
0
            dest_data += dst->bytes_per_line;
2022
0
        }
2023
0
    }
2024
0
    int numColors = do_quant ? 256 : pix;
2025
2026
0
    dst->colortable.resize(numColors);
2027
2028
0
    if (do_quant) {                                // quantization needed
2029
2030
0
#define MAX_R 5
2031
0
#define MAX_G 5
2032
0
#define MAX_B 5
2033
0
#define INDEXOF(r,g,b) (((r)*(MAX_G+1)+(g))*(MAX_B+1)+(b))
2034
2035
0
        for (int rc=0; rc<=MAX_R; rc++)                // build 6x6x6 color cube
2036
0
            for (int gc=0; gc<=MAX_G; gc++)
2037
0
                for (int bc=0; bc<=MAX_B; bc++)
2038
0
                    dst->colortable[INDEXOF(rc,gc,bc)] = 0xff000000 | qRgb(rc*255/MAX_R, gc*255/MAX_G, bc*255/MAX_B);
2039
2040
0
        const uchar *src_data = src->data;
2041
0
        uchar *dest_data = dst->data;
2042
0
        if ((flags & Qt::Dither_Mask) == Qt::ThresholdDither) {
2043
0
            for (int y = 0; y < src->height; y++) {
2044
0
                const QRgb *p = (const QRgb *)src_data;
2045
0
                const QRgb *end = p + src->width;
2046
0
                uchar *b = dest_data;
2047
2048
0
                while (p < end) {
2049
0
#define DITHER(p,m) ((uchar) ((p * (m) + 127) / 255))
2050
0
                    *b++ =
2051
0
                        INDEXOF(
2052
0
                            DITHER(qRed(*p), MAX_R),
2053
0
                            DITHER(qGreen(*p), MAX_G),
2054
0
                            DITHER(qBlue(*p), MAX_B)
2055
0
                            );
2056
0
#undef DITHER
2057
0
                    p++;
2058
0
                }
2059
0
                src_data += src->bytes_per_line;
2060
0
                dest_data += dst->bytes_per_line;
2061
0
            }
2062
0
        } else if ((flags & Qt::Dither_Mask) == Qt::DiffuseDither) {
2063
0
            int* line1[3];
2064
0
            int* line2[3];
2065
0
            int* pv[3];
2066
0
            QScopedArrayPointer<int> lineBuffer(new int[src->width * 9]);
2067
0
            line1[0] = lineBuffer.data();
2068
0
            line2[0] = lineBuffer.data() + src->width;
2069
0
            line1[1] = lineBuffer.data() + src->width * 2;
2070
0
            line2[1] = lineBuffer.data() + src->width * 3;
2071
0
            line1[2] = lineBuffer.data() + src->width * 4;
2072
0
            line2[2] = lineBuffer.data() + src->width * 5;
2073
0
            pv[0] = lineBuffer.data() + src->width * 6;
2074
0
            pv[1] = lineBuffer.data() + src->width * 7;
2075
0
            pv[2] = lineBuffer.data() + src->width * 8;
2076
2077
0
            int endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian);
2078
0
            for (int y = 0; y < src->height; y++) {
2079
0
                const uchar* q = src_data;
2080
0
                const uchar* q2 = y < src->height - 1 ? q + src->bytes_per_line : src->data;
2081
0
                uchar *b = dest_data;
2082
0
                for (int chan = 0; chan < 3; chan++) {
2083
0
                    int *l1 = (y&1) ? line2[chan] : line1[chan];
2084
0
                    int *l2 = (y&1) ? line1[chan] : line2[chan];
2085
0
                    if (y == 0) {
2086
0
                        for (int i = 0; i < src->width; i++)
2087
0
                            l1[i] = q[i*4+chan+endian];
2088
0
                    }
2089
0
                    if (y+1 < src->height) {
2090
0
                        for (int i = 0; i < src->width; i++)
2091
0
                            l2[i] = q2[i*4+chan+endian];
2092
0
                    }
2093
                    // Bi-directional error diffusion
2094
0
                    if (y&1) {
2095
0
                        for (int x = 0; x < src->width; x++) {
2096
0
                            int pix = qMax(qMin(5, (l1[x] * 5 + 128)/ 255), 0);
2097
0
                            int err = l1[x] - pix * 255 / 5;
2098
0
                            pv[chan][x] = pix;
2099
2100
                            // Spread the error around...
2101
0
                            if (x + 1< src->width) {
2102
0
                                l1[x+1] += (err*7)>>4;
2103
0
                                l2[x+1] += err>>4;
2104
0
                            }
2105
0
                            l2[x]+=(err*5)>>4;
2106
0
                            if (x>1)
2107
0
                                l2[x-1]+=(err*3)>>4;
2108
0
                        }
2109
0
                    } else {
2110
0
                        for (int x = src->width; x-- > 0;) {
2111
0
                            int pix = qMax(qMin(5, (l1[x] * 5 + 128)/ 255), 0);
2112
0
                            int err = l1[x] - pix * 255 / 5;
2113
0
                            pv[chan][x] = pix;
2114
2115
                            // Spread the error around...
2116
0
                            if (x > 0) {
2117
0
                                l1[x-1] += (err*7)>>4;
2118
0
                                l2[x-1] += err>>4;
2119
0
                            }
2120
0
                            l2[x]+=(err*5)>>4;
2121
0
                            if (x + 1 < src->width)
2122
0
                                l2[x+1]+=(err*3)>>4;
2123
0
                        }
2124
0
                    }
2125
0
                }
2126
0
                if (endian) {
2127
0
                    for (int x = 0; x < src->width; x++) {
2128
0
                        *b++ = INDEXOF(pv[0][x],pv[1][x],pv[2][x]);
2129
0
                    }
2130
0
                } else {
2131
0
                    for (int x = 0; x < src->width; x++) {
2132
0
                        *b++ = INDEXOF(pv[2][x],pv[1][x],pv[0][x]);
2133
0
                    }
2134
0
                }
2135
0
                src_data += src->bytes_per_line;
2136
0
                dest_data += dst->bytes_per_line;
2137
0
            }
2138
0
        } else { // OrderedDither
2139
0
            for (int y = 0; y < src->height; y++) {
2140
0
                const QRgb *p = (const QRgb *)src_data;
2141
0
                const QRgb *end = p + src->width;
2142
0
                uchar *b = dest_data;
2143
2144
0
                int x = 0;
2145
0
                while (p < end) {
2146
0
                    uint d = qt_bayer_matrix[y & 15][x & 15] << 8;
2147
2148
0
#define DITHER(p, d, m) ((uchar) ((((256 * (m) + (m) + 1)) * (p) + (d)) >> 16))
2149
0
                    *b++ =
2150
0
                        INDEXOF(
2151
0
                            DITHER(qRed(*p), d, MAX_R),
2152
0
                            DITHER(qGreen(*p), d, MAX_G),
2153
0
                            DITHER(qBlue(*p), d, MAX_B)
2154
0
                            );
2155
0
#undef DITHER
2156
2157
0
                    p++;
2158
0
                    x++;
2159
0
                }
2160
0
                src_data += src->bytes_per_line;
2161
0
                dest_data += dst->bytes_per_line;
2162
0
            }
2163
0
        }
2164
2165
0
        if (src->format != QImage::Format_RGB32
2166
0
            && src->format != QImage::Format_RGB16) {
2167
0
            const int trans = 216;
2168
0
            Q_ASSERT(dst->colortable.size() > trans);
2169
0
            dst->colortable[trans] = 0;
2170
0
            QScopedPointer<QImageData> mask(QImageData::create(QSize(src->width, src->height), QImage::Format_Mono));
2171
0
            dither_to_Mono(mask.data(), src, flags, true);
2172
0
            uchar *dst_data = dst->data;
2173
0
            const uchar *mask_data = mask->data;
2174
0
            for (int y = 0; y < src->height; y++) {
2175
0
                for (int x = 0; x < src->width ; x++) {
2176
0
                    if (!(mask_data[x>>3] & (0x80 >> (x & 7))))
2177
0
                        dst_data[x] = trans;
2178
0
                }
2179
0
                mask_data += mask->bytes_per_line;
2180
0
                dst_data += dst->bytes_per_line;
2181
0
            }
2182
0
            dst->has_alpha_clut = true;
2183
0
        }
2184
2185
0
#undef MAX_R
2186
0
#undef MAX_G
2187
0
#undef MAX_B
2188
0
#undef INDEXOF
2189
2190
0
    }
2191
0
}
2192
2193
static void convert_ARGB_PM_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags)
2194
0
{
2195
0
    QScopedPointer<QImageData> tmp(QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32));
2196
0
    convert_generic(tmp.data(), src, Qt::AutoColor);
2197
0
    convert_RGB_to_Indexed8(dst, tmp.data(), flags);
2198
0
}
2199
2200
static void convert_ARGB_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags)
2201
0
{
2202
0
    convert_RGB_to_Indexed8(dst, src, flags);
2203
0
}
2204
2205
static void convert_Indexed8_to_X32(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
2206
4.07k
{
2207
4.07k
    Q_ASSERT(src->format == QImage::Format_Indexed8);
2208
4.07k
    Q_ASSERT(dest->format == QImage::Format_RGB32
2209
4.07k
             || dest->format == QImage::Format_ARGB32
2210
4.07k
             || dest->format == QImage::Format_ARGB32_Premultiplied);
2211
4.07k
    Q_ASSERT(src->width == dest->width);
2212
4.07k
    Q_ASSERT(src->height == dest->height);
2213
2214
4.07k
    QList<QRgb> colorTable = src->has_alpha_clut ? fix_color_table(src->colortable, dest->format) : src->colortable;
2215
4.07k
    if (colorTable.size() == 0) {
2216
0
        colorTable.resize(256);
2217
0
        for (int i=0; i<256; ++i)
2218
0
            colorTable[i] = qRgb(i, i, i);
2219
0
    }
2220
4.07k
    if (colorTable.size() < 256) {
2221
3.51k
        int tableSize = colorTable.size();
2222
3.51k
        colorTable.resize(256);
2223
3.51k
        QRgb fallbackColor = (dest->format == QImage::Format_RGB32) ? 0xff000000 : 0;
2224
627k
        for (int i=tableSize; i<256; ++i)
2225
623k
            colorTable[i] = fallbackColor;
2226
3.51k
    }
2227
2228
4.07k
    int w = src->width;
2229
4.07k
    const uchar *src_data = src->data;
2230
4.07k
    uchar *dest_data = dest->data;
2231
4.07k
    const QRgb *colorTablePtr = colorTable.constData();
2232
318k
    for (int y = 0; y < src->height; y++) {
2233
314k
        uint *p = reinterpret_cast<uint *>(dest_data);
2234
314k
        const uchar *b = src_data;
2235
314k
        uint *end = p + w;
2236
2237
37.6M
        while (p < end)
2238
37.3M
            *p++ = colorTablePtr[*b++];
2239
2240
314k
        src_data += src->bytes_per_line;
2241
314k
        dest_data += dest->bytes_per_line;
2242
314k
    }
2243
4.07k
}
2244
2245
static void convert_Mono_to_X32(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
2246
149k
{
2247
149k
    Q_ASSERT(src->format == QImage::Format_Mono || src->format == QImage::Format_MonoLSB);
2248
149k
    Q_ASSERT(dest->format == QImage::Format_RGB32
2249
149k
             || dest->format == QImage::Format_ARGB32
2250
149k
             || dest->format == QImage::Format_ARGB32_Premultiplied);
2251
149k
    Q_ASSERT(src->width == dest->width);
2252
149k
    Q_ASSERT(src->height == dest->height);
2253
2254
149k
    QList<QRgb> colorTable = fix_color_table(src->colortable, dest->format);
2255
2256
    // Default to black / white colors
2257
149k
    if (colorTable.size() < 2) {
2258
0
        if (colorTable.size() == 0)
2259
0
            colorTable << 0xff000000;
2260
0
        colorTable << 0xffffffff;
2261
0
    }
2262
2263
149k
    const uchar *src_data = src->data;
2264
149k
    uchar *dest_data = dest->data;
2265
149k
    if (src->format == QImage::Format_Mono) {
2266
17.3M
        for (int y = 0; y < dest->height; y++) {
2267
17.2M
            uint *p = (uint *)dest_data;
2268
2.60G
            for (int x = 0; x < dest->width; x++)
2269
2.58G
                *p++ = colorTable.at((src_data[x>>3] >> (7 - (x & 7))) & 1);
2270
2271
17.2M
            src_data += src->bytes_per_line;
2272
17.2M
            dest_data += dest->bytes_per_line;
2273
17.2M
        }
2274
149k
    } else {
2275
0
        for (int y = 0; y < dest->height; y++) {
2276
0
            uint *p = (uint *)dest_data;
2277
0
            for (int x = 0; x < dest->width; x++)
2278
0
                *p++ = colorTable.at((src_data[x>>3] >> (x & 7)) & 1);
2279
2280
0
            src_data += src->bytes_per_line;
2281
0
            dest_data += dest->bytes_per_line;
2282
0
        }
2283
0
    }
2284
149k
}
2285
2286
2287
static void convert_Mono_to_Indexed8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
2288
0
{
2289
0
    Q_ASSERT(src->format == QImage::Format_Mono || src->format == QImage::Format_MonoLSB);
2290
0
    Q_ASSERT(dest->format == QImage::Format_Indexed8);
2291
0
    Q_ASSERT(src->width == dest->width);
2292
0
    Q_ASSERT(src->height == dest->height);
2293
2294
0
    QList<QRgb> ctbl = src->colortable;
2295
0
    if (ctbl.size() > 2) {
2296
0
        ctbl.resize(2);
2297
0
    } else if (ctbl.size() < 2) {
2298
0
        if (ctbl.size() == 0)
2299
0
            ctbl << 0xff000000;
2300
0
        ctbl << 0xffffffff;
2301
0
    }
2302
0
    dest->colortable = ctbl;
2303
0
    dest->has_alpha_clut = src->has_alpha_clut;
2304
2305
2306
0
    const uchar *src_data = src->data;
2307
0
    uchar *dest_data = dest->data;
2308
0
    if (src->format == QImage::Format_Mono) {
2309
0
        for (int y = 0; y < dest->height; y++) {
2310
0
            uchar *p = dest_data;
2311
0
            for (int x = 0; x < dest->width; x++)
2312
0
                *p++ = (src_data[x>>3] >> (7 - (x & 7))) & 1;
2313
0
            src_data += src->bytes_per_line;
2314
0
            dest_data += dest->bytes_per_line;
2315
0
        }
2316
0
    } else {
2317
0
        for (int y = 0; y < dest->height; y++) {
2318
0
            uchar *p = dest_data;
2319
0
            for (int x = 0; x < dest->width; x++)
2320
0
                *p++ = (src_data[x>>3] >> (x & 7)) & 1;
2321
0
            src_data += src->bytes_per_line;
2322
0
            dest_data += dest->bytes_per_line;
2323
0
        }
2324
0
    }
2325
0
}
2326
2327
static void copy_8bit_pixels(QImageData *dest, const QImageData *src)
2328
0
{
2329
0
    if (src->bytes_per_line == dest->bytes_per_line) {
2330
0
        memcpy(dest->data, src->data, src->bytes_per_line * src->height);
2331
0
    } else {
2332
0
        const uchar *sdata = src->data;
2333
0
        uchar *ddata = dest->data;
2334
0
        for (int y = 0; y < src->height; ++y) {
2335
0
            memcpy(ddata, sdata, src->width);
2336
0
            sdata += src->bytes_per_line;
2337
0
            ddata += dest->bytes_per_line;
2338
0
        }
2339
0
    }
2340
0
}
2341
2342
static void convert_Indexed8_to_Alpha8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
2343
0
{
2344
0
    Q_ASSERT(src->format == QImage::Format_Indexed8);
2345
0
    Q_ASSERT(dest->format == QImage::Format_Alpha8);
2346
2347
0
    uchar translate[256];
2348
0
    const QList<QRgb> &colors = src->colortable;
2349
0
    bool simpleCase = (colors.size() == 256);
2350
0
    for (int i = 0; i < colors.size(); ++i) {
2351
0
        uchar alpha = qAlpha(colors[i]);
2352
0
        translate[i] = alpha;
2353
0
        simpleCase = simpleCase && (alpha == i);
2354
0
    }
2355
2356
0
    if (simpleCase)
2357
0
        copy_8bit_pixels(dest, src);
2358
0
    else {
2359
0
        const uchar *sdata = src->data;
2360
0
        uchar *ddata = dest->data;
2361
0
        for (int y = 0; y < src->height; ++y) {
2362
0
            for (int x = 0; x < src->width; ++x)
2363
0
                ddata[x] = translate[sdata[x]];
2364
0
            sdata += src->bytes_per_line;
2365
0
            ddata += dest->bytes_per_line;
2366
0
        }
2367
0
    }
2368
0
}
2369
2370
static void convert_Indexed8_to_Grayscale8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
2371
0
{
2372
0
    Q_ASSERT(src->format == QImage::Format_Indexed8);
2373
0
    Q_ASSERT(dest->format == QImage::Format_Grayscale8);
2374
2375
0
    uchar translate[256];
2376
0
    const QList<QRgb> &colors = src->colortable;
2377
0
    bool simpleCase = (colors.size() == 256);
2378
0
    for (int i = 0; i < colors.size() && simpleCase; ++i) {
2379
0
        if (colors[i] != qRgb(i, i, i))
2380
0
            simpleCase = false;
2381
0
    }
2382
0
    if (simpleCase) {
2383
0
        copy_8bit_pixels(dest, src);
2384
0
        return;
2385
0
    }
2386
2387
0
    QColorSpace fromCS = src->colorSpace.isValid() ? src->colorSpace : QColorSpace::SRgb;
2388
0
    QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ();
2389
0
    for (int i = 0; i < colors.size(); ++i) {
2390
0
        QRgba64 c16 = tf.map(QRgba64::fromArgb32(colors[i]));
2391
0
        translate[i] = c16.green8(); // Y from XYZ ends up in the G channel
2392
0
    }
2393
2394
0
    const uchar *sdata = src->data;
2395
0
    uchar *ddata = dest->data;
2396
0
    for (int y = 0; y < src->height; ++y) {
2397
0
        for (int x = 0; x < src->width; ++x)
2398
0
            ddata[x] = translate[sdata[x]];
2399
0
        sdata += src->bytes_per_line;
2400
0
        ddata += dest->bytes_per_line;
2401
0
    }
2402
0
}
2403
2404
static bool convert_Indexed8_to_Alpha8_inplace(QImageData *data, Qt::ImageConversionFlags)
2405
0
{
2406
0
    Q_ASSERT(data->format == QImage::Format_Indexed8);
2407
2408
    // Just check if this is an Alpha8 in Indexed8 disguise.
2409
0
    const QList<QRgb> &colors = data->colortable;
2410
0
    if (colors.size() != 256)
2411
0
        return false;
2412
0
    for (int i = 0; i < colors.size(); ++i) {
2413
0
        if (i != qAlpha(colors[i]))
2414
0
            return false;
2415
0
    }
2416
2417
0
    data->colortable.clear();
2418
0
    data->format = QImage::Format_Alpha8;
2419
2420
0
    return true;
2421
0
}
2422
2423
static bool convert_Indexed8_to_Grayscale8_inplace(QImageData *data, Qt::ImageConversionFlags)
2424
0
{
2425
0
    Q_ASSERT(data->format == QImage::Format_Indexed8);
2426
2427
    // Just check if this is a Grayscale8 in Indexed8 disguise.
2428
0
    const QList<QRgb> &colors = data->colortable;
2429
0
    if (colors.size() != 256)
2430
0
        return false;
2431
0
    for (int i = 0; i < colors.size(); ++i) {
2432
0
        if (colors[i] != qRgb(i, i, i))
2433
0
            return false;
2434
0
    }
2435
2436
0
    data->colortable.clear();
2437
0
    data->format = QImage::Format_Grayscale8;
2438
2439
0
    return true;
2440
0
}
2441
2442
static void convert_Alpha8_to_Indexed8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
2443
0
{
2444
0
    Q_ASSERT(src->format == QImage::Format_Alpha8);
2445
0
    Q_ASSERT(dest->format == QImage::Format_Indexed8);
2446
2447
0
    copy_8bit_pixels(dest, src);
2448
2449
0
    dest->colortable = defaultColorTables->alpha;
2450
0
}
2451
2452
static void convert_Grayscale8_to_Indexed8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
2453
0
{
2454
0
    Q_ASSERT(src->format == QImage::Format_Grayscale8);
2455
0
    Q_ASSERT(dest->format == QImage::Format_Indexed8);
2456
2457
0
    copy_8bit_pixels(dest, src);
2458
2459
0
    dest->colortable = defaultColorTables->gray;
2460
0
}
2461
2462
static bool convert_Alpha8_to_Indexed8_inplace(QImageData *data, Qt::ImageConversionFlags)
2463
0
{
2464
0
    Q_ASSERT(data->format == QImage::Format_Alpha8);
2465
2466
0
    data->colortable = defaultColorTables->alpha;
2467
0
    data->format = QImage::Format_Indexed8;
2468
2469
0
    return true;
2470
0
}
2471
2472
static bool convert_Grayscale8_to_Indexed8_inplace(QImageData *data, Qt::ImageConversionFlags)
2473
0
{
2474
0
    Q_ASSERT(data->format == QImage::Format_Grayscale8);
2475
2476
0
    data->colortable = defaultColorTables->gray;
2477
0
    data->format = QImage::Format_Indexed8;
2478
2479
0
    return true;
2480
0
}
2481
2482
template <bool SourceIsPremultiplied>
2483
static void convert_ARGB32_to_CMYK8888(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
2484
0
{
2485
0
    Q_ASSERT(src->format == QImage::Format_RGB32 ||
2486
0
             src->format == QImage::Format_ARGB32 ||
2487
0
             src->format == QImage::Format_ARGB32_Premultiplied);
2488
0
    Q_ASSERT(dest->format == QImage::Format_CMYK8888);
2489
0
    Q_ASSERT(src->width == dest->width);
2490
0
    Q_ASSERT(src->height == dest->height);
2491
2492
0
    const uchar *src_data = src->data;
2493
0
    uchar *dest_data = dest->data;
2494
0
    for (int y = 0; y < src->height; ++y) {
2495
0
        const QRgb *srcRgba = reinterpret_cast<const QRgb *>(src_data);
2496
0
        uint *destCmyk = reinterpret_cast<uint *>(dest_data);
2497
2498
0
        for (int x = 0; x < src->width; ++x) {
2499
0
            QRgb sourcePixel = srcRgba[x];
2500
            if constexpr (SourceIsPremultiplied)
2501
0
                sourcePixel = qUnpremultiply(sourcePixel);
2502
2503
0
            destCmyk[x] = QCmyk32::fromRgba(sourcePixel).toUint();
2504
0
        }
2505
2506
0
        src_data += src->bytes_per_line;;
2507
0
        dest_data += dest->bytes_per_line;
2508
0
    }
2509
0
}
Unexecuted instantiation: qimage_conversions.cpp:void convert_ARGB32_to_CMYK8888<false>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
Unexecuted instantiation: qimage_conversions.cpp:void convert_ARGB32_to_CMYK8888<true>(QImageData*, QImageData const*, QFlags<Qt::ImageConversionFlag>)
2510
2511
// first index source, second dest
2512
Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats] = {};
2513
InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats] = {};
2514
2515
static void qInitImageConversions()
2516
40
{
2517
    // Some conversions can not be generic, other are just hard to make as fast in the generic converter.
2518
2519
    // All conversions to and from indexed formats can not be generic and needs to go over RGB32 or ARGB32
2520
40
    qimage_converter_map[QImage::Format_Mono][QImage::Format_MonoLSB] = swap_bit_order;
2521
40
    qimage_converter_map[QImage::Format_Mono][QImage::Format_Indexed8] = convert_Mono_to_Indexed8;
2522
40
    qimage_converter_map[QImage::Format_Mono][QImage::Format_RGB32] = convert_Mono_to_X32;
2523
40
    qimage_converter_map[QImage::Format_Mono][QImage::Format_ARGB32] = convert_Mono_to_X32;
2524
40
    qimage_converter_map[QImage::Format_Mono][QImage::Format_ARGB32_Premultiplied] = convert_Mono_to_X32;
2525
2526
40
    qimage_converter_map[QImage::Format_MonoLSB][QImage::Format_Mono] = swap_bit_order;
2527
40
    qimage_converter_map[QImage::Format_MonoLSB][QImage::Format_Indexed8] = convert_Mono_to_Indexed8;
2528
40
    qimage_converter_map[QImage::Format_MonoLSB][QImage::Format_RGB32] = convert_Mono_to_X32;
2529
40
    qimage_converter_map[QImage::Format_MonoLSB][QImage::Format_ARGB32] = convert_Mono_to_X32;
2530
40
    qimage_converter_map[QImage::Format_MonoLSB][QImage::Format_ARGB32_Premultiplied] = convert_Mono_to_X32;
2531
2532
40
    qimage_converter_map[QImage::Format_Indexed8][QImage::Format_Mono] = convert_X_to_Mono;
2533
40
    qimage_converter_map[QImage::Format_Indexed8][QImage::Format_MonoLSB] = convert_X_to_Mono;
2534
40
    qimage_converter_map[QImage::Format_Indexed8][QImage::Format_RGB32] = convert_Indexed8_to_X32;
2535
40
    qimage_converter_map[QImage::Format_Indexed8][QImage::Format_ARGB32] = convert_Indexed8_to_X32;
2536
40
    qimage_converter_map[QImage::Format_Indexed8][QImage::Format_ARGB32_Premultiplied] = convert_Indexed8_to_X32;
2537
    // Indexed8, Alpha8 and Grayscale8 have a special relationship that can be short-cut.
2538
40
    qimage_converter_map[QImage::Format_Indexed8][QImage::Format_Grayscale8] = convert_Indexed8_to_Grayscale8;
2539
40
    qimage_converter_map[QImage::Format_Indexed8][QImage::Format_Alpha8] = convert_Indexed8_to_Alpha8;
2540
2541
40
    qimage_converter_map[QImage::Format_RGB32][QImage::Format_Mono] = convert_X_to_Mono;
2542
40
    qimage_converter_map[QImage::Format_RGB32][QImage::Format_MonoLSB] = convert_X_to_Mono;
2543
40
    qimage_converter_map[QImage::Format_RGB32][QImage::Format_Indexed8] = convert_RGB_to_Indexed8;
2544
40
    qimage_converter_map[QImage::Format_RGB32][QImage::Format_ARGB32] = mask_alpha_converter;
2545
40
    qimage_converter_map[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = mask_alpha_converter;
2546
40
    qimage_converter_map[QImage::Format_RGB32][QImage::Format_Grayscale8] = convert_ARGB_to_gray8<false>;
2547
40
    qimage_converter_map[QImage::Format_RGB32][QImage::Format_Grayscale16] = convert_ARGB_to_gray16<false>;
2548
2549
40
    qimage_converter_map[QImage::Format_ARGB32][QImage::Format_Mono] = convert_X_to_Mono;
2550
40
    qimage_converter_map[QImage::Format_ARGB32][QImage::Format_MonoLSB] = convert_X_to_Mono;
2551
40
    qimage_converter_map[QImage::Format_ARGB32][QImage::Format_Indexed8] = convert_ARGB_to_Indexed8;
2552
40
    qimage_converter_map[QImage::Format_ARGB32][QImage::Format_RGB32] = mask_alpha_converter;
2553
40
    qimage_converter_map[QImage::Format_ARGB32][QImage::Format_RGBX8888] = convert_ARGB_to_RGBx;
2554
40
    qimage_converter_map[QImage::Format_ARGB32][QImage::Format_RGBA8888] = convert_ARGB_to_RGBA;
2555
    // ARGB32 has higher precision than ARGB32PM and needs explicit conversions to other higher color-precision formats with alpha
2556
40
    qimage_converter_map[QImage::Format_ARGB32][QImage::Format_A2BGR30_Premultiplied] = convert_ARGB_to_A2RGB30<PixelOrderBGR, false>;
2557
40
    qimage_converter_map[QImage::Format_ARGB32][QImage::Format_A2RGB30_Premultiplied] = convert_ARGB_to_A2RGB30<PixelOrderRGB, false>;
2558
40
    qimage_converter_map[QImage::Format_ARGB32][QImage::Format_RGBA64] = convert_ARGB32_to_RGBA64<false>;
2559
40
    qimage_converter_map[QImage::Format_ARGB32][QImage::Format_Grayscale8] = convert_ARGB_to_gray8<false>;
2560
40
    qimage_converter_map[QImage::Format_ARGB32][QImage::Format_Grayscale16] = convert_ARGB_to_gray16<false>;
2561
2562
40
    qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_Mono] = convert_ARGB_PM_to_Mono;
2563
40
    qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_MonoLSB] = convert_ARGB_PM_to_Mono;
2564
40
    qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_Indexed8] = convert_ARGB_PM_to_Indexed8;
2565
40
    qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = convert_ARGB_to_RGBA;
2566
40
    qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_Grayscale8] = convert_ARGB_to_gray8<true>;
2567
40
    qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_Grayscale16] = convert_ARGB_to_gray16<true>;
2568
2569
40
    qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB<false>;
2570
40
    qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB<false>;
2571
40
    qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB<false>;
2572
40
    qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGBX8888] = convert_RGB888_to_RGB<true>;
2573
40
    qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGBA8888] = convert_RGB888_to_RGB<true>;
2574
40
    qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGBA8888_Premultiplied] = convert_RGB888_to_RGB<true>;
2575
40
    qimage_converter_map[QImage::Format_RGB888][QImage::Format_BGR888] = convert_rgbswap_generic;
2576
2577
40
    qimage_converter_map[QImage::Format_RGBX8888][QImage::Format_RGB32] = convert_RGBA_to_RGB;
2578
40
    qimage_converter_map[QImage::Format_RGBX8888][QImage::Format_ARGB32] = convert_RGBA_to_ARGB;
2579
40
    qimage_converter_map[QImage::Format_RGBX8888][QImage::Format_ARGB32_Premultiplied] = convert_RGBA_to_ARGB;
2580
40
    qimage_converter_map[QImage::Format_RGBX8888][QImage::Format_RGBA8888] = convert_passthrough;
2581
40
    qimage_converter_map[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = convert_passthrough;
2582
2583
40
    qimage_converter_map[QImage::Format_RGBA8888][QImage::Format_RGB32] = convert_RGBA_to_RGB;
2584
40
    qimage_converter_map[QImage::Format_RGBA8888][QImage::Format_ARGB32] = convert_RGBA_to_ARGB;
2585
40
    qimage_converter_map[QImage::Format_RGBA8888][QImage::Format_RGBX8888] = mask_alpha_converter_RGBx;
2586
40
    qimage_converter_map[QImage::Format_RGBA8888][QImage::Format_A2BGR30_Premultiplied] = convert_ARGB_to_A2RGB30<PixelOrderBGR, true>;
2587
40
    qimage_converter_map[QImage::Format_RGBA8888][QImage::Format_A2RGB30_Premultiplied] = convert_ARGB_to_A2RGB30<PixelOrderRGB, true>;
2588
40
    qimage_converter_map[QImage::Format_RGBA8888][QImage::Format_RGBA64] = convert_ARGB32_to_RGBA64<true>;
2589
2590
40
    qimage_converter_map[QImage::Format_RGBA8888_Premultiplied][QImage::Format_ARGB32_Premultiplied] = convert_RGBA_to_ARGB;
2591
2592
40
    qimage_converter_map[QImage::Format_BGR30][QImage::Format_A2BGR30_Premultiplied] = convert_passthrough;
2593
40
    qimage_converter_map[QImage::Format_BGR30][QImage::Format_RGB30] = convert_rgbswap_generic;
2594
40
    qimage_converter_map[QImage::Format_BGR30][QImage::Format_A2RGB30_Premultiplied] = convert_rgbswap_generic;
2595
2596
40
    qimage_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_ARGB32] = convert_A2RGB30_PM_to_ARGB<PixelOrderBGR, false>;
2597
40
    qimage_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGBA8888] = convert_A2RGB30_PM_to_ARGB<PixelOrderBGR, true>;
2598
40
    qimage_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_BGR30] = convert_A2RGB30_PM_to_RGB30<false>;
2599
40
    qimage_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGB30] = convert_A2RGB30_PM_to_RGB30<true>;
2600
40
    qimage_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_A2RGB30_Premultiplied] = convert_rgbswap_generic;
2601
2602
40
    qimage_converter_map[QImage::Format_RGB30][QImage::Format_BGR30] = convert_rgbswap_generic;
2603
40
    qimage_converter_map[QImage::Format_RGB30][QImage::Format_A2BGR30_Premultiplied] = convert_rgbswap_generic;
2604
40
    qimage_converter_map[QImage::Format_RGB30][QImage::Format_A2RGB30_Premultiplied] = convert_passthrough;
2605
2606
40
    qimage_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_ARGB32] = convert_A2RGB30_PM_to_ARGB<PixelOrderRGB, false>;
2607
40
    qimage_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGBA8888] = convert_A2RGB30_PM_to_ARGB<PixelOrderRGB, true>;
2608
40
    qimage_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_BGR30] = convert_A2RGB30_PM_to_RGB30<true>;
2609
40
    qimage_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_A2BGR30_Premultiplied] = convert_rgbswap_generic;
2610
40
    qimage_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGB30] = convert_A2RGB30_PM_to_RGB30<false>;
2611
2612
40
    qimage_converter_map[QImage::Format_Grayscale8][QImage::Format_Indexed8] = convert_Grayscale8_to_Indexed8;
2613
40
    qimage_converter_map[QImage::Format_Alpha8][QImage::Format_Indexed8] = convert_Alpha8_to_Indexed8;
2614
2615
40
    qimage_converter_map[QImage::Format_RGBX64][QImage::Format_RGBA64] = convert_passthrough;
2616
40
    qimage_converter_map[QImage::Format_RGBX64][QImage::Format_RGBA64_Premultiplied] = convert_passthrough;
2617
40
    qimage_converter_map[QImage::Format_RGBX64][QImage::Format_Grayscale8] = convert_RGBA64_to_gray8<false>;
2618
40
    qimage_converter_map[QImage::Format_RGBX64][QImage::Format_Grayscale16] = convert_RGBA64_to_gray16<false>;
2619
2620
40
    qimage_converter_map[QImage::Format_RGBA64][QImage::Format_ARGB32] = convert_RGBA64_to_ARGB32<false>;
2621
40
    qimage_converter_map[QImage::Format_RGBA64][QImage::Format_RGBA8888] = convert_RGBA64_to_ARGB32<true>;
2622
40
    qimage_converter_map[QImage::Format_RGBA64][QImage::Format_RGBX64] = convert_RGBA64_to_RGBx64;
2623
40
    qimage_converter_map[QImage::Format_RGBA64][QImage::Format_Grayscale8] = convert_RGBA64_to_gray8<false>;
2624
40
    qimage_converter_map[QImage::Format_RGBA64][QImage::Format_Grayscale16] = convert_RGBA64_to_gray16<false>;
2625
2626
40
    qimage_converter_map[QImage::Format_RGBA64_Premultiplied][QImage::Format_Grayscale8] = convert_RGBA64_to_gray8<true>;
2627
40
    qimage_converter_map[QImage::Format_RGBA64_Premultiplied][QImage::Format_Grayscale16] = convert_RGBA64_to_gray16<true>;
2628
2629
40
    qimage_converter_map[QImage::Format_Grayscale16][QImage::Format_RGBX64] = convert_gray16_to_RGBA64;
2630
40
    qimage_converter_map[QImage::Format_Grayscale16][QImage::Format_RGBA64] = convert_gray16_to_RGBA64;
2631
40
    qimage_converter_map[QImage::Format_Grayscale16][QImage::Format_RGBA64_Premultiplied] = convert_gray16_to_RGBA64;
2632
2633
40
    qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGB888] = convert_rgbswap_generic;
2634
40
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
2635
40
    qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBX8888] = convert_RGB888_to_RGB<false>;
2636
40
    qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBA8888] = convert_RGB888_to_RGB<false>;
2637
40
    qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBA8888_Premultiplied] = convert_RGB888_to_RGB<false>;
2638
40
#endif
2639
2640
40
    qimage_converter_map[QImage::Format_RGBX16FPx4][QImage::Format_RGBA16FPx4] = convert_passthrough;
2641
40
    qimage_converter_map[QImage::Format_RGBX16FPx4][QImage::Format_RGBA16FPx4_Premultiplied] = convert_passthrough;
2642
2643
40
    qimage_converter_map[QImage::Format_RGBX32FPx4][QImage::Format_RGBA32FPx4] = convert_passthrough;
2644
40
    qimage_converter_map[QImage::Format_RGBX32FPx4][QImage::Format_RGBA32FPx4_Premultiplied] = convert_passthrough;
2645
2646
40
    qimage_converter_map[QImage::Format_CMYK8888][QImage::Format_CMYK8888] = convert_passthrough;
2647
40
    qimage_converter_map[QImage::Format_RGB32][QImage::Format_CMYK8888] = convert_ARGB32_to_CMYK8888<false>;
2648
40
    qimage_converter_map[QImage::Format_ARGB32][QImage::Format_CMYK8888] = convert_ARGB32_to_CMYK8888<false>;
2649
40
    qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_CMYK8888] = convert_ARGB32_to_CMYK8888<true>;
2650
2651
    // Inline converters:
2652
40
    qimage_inplace_converter_map[QImage::Format_Indexed8][QImage::Format_Grayscale8] =
2653
40
            convert_Indexed8_to_Grayscale8_inplace;
2654
40
    qimage_inplace_converter_map[QImage::Format_Indexed8][QImage::Format_Alpha8] =
2655
40
            convert_Indexed8_to_Alpha8_inplace;
2656
2657
40
    qimage_inplace_converter_map[QImage::Format_RGB32][QImage::Format_ARGB32] =
2658
40
            mask_alpha_converter_inplace<QImage::Format_ARGB32>;
2659
40
    qimage_inplace_converter_map[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] =
2660
40
            mask_alpha_converter_inplace<QImage::Format_ARGB32_Premultiplied>;
2661
2662
40
    qimage_inplace_converter_map[QImage::Format_ARGB32][QImage::Format_RGB32] =
2663
40
            mask_alpha_converter_inplace<QImage::Format_RGB32>;
2664
40
    qimage_inplace_converter_map[QImage::Format_ARGB32][QImage::Format_RGBX8888] =
2665
40
            convert_ARGB_to_RGBA_inplace<QImage::Format_RGBX8888>;
2666
40
    qimage_inplace_converter_map[QImage::Format_ARGB32][QImage::Format_RGBA8888] =
2667
40
            convert_ARGB_to_RGBA_inplace<QImage::Format_RGBA8888>;
2668
40
    qimage_inplace_converter_map[QImage::Format_ARGB32][QImage::Format_A2BGR30_Premultiplied] =
2669
40
            convert_ARGB_to_A2RGB30_inplace<PixelOrderBGR, false>;
2670
40
    qimage_inplace_converter_map[QImage::Format_ARGB32][QImage::Format_A2RGB30_Premultiplied] =
2671
40
            convert_ARGB_to_A2RGB30_inplace<PixelOrderRGB, false>;
2672
2673
40
    qimage_inplace_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGBA8888_Premultiplied] =
2674
40
            convert_ARGB_to_RGBA_inplace<QImage::Format_RGBA8888_Premultiplied>;
2675
2676
40
    qimage_inplace_converter_map[QImage::Format_RGB888][QImage::Format_BGR888] =
2677
40
            convert_rgbswap_generic_inplace;
2678
2679
40
    qimage_inplace_converter_map[QImage::Format_RGBX8888][QImage::Format_RGB32] =
2680
40
            convert_RGBA_to_ARGB_inplace<QImage::Format_RGB32>;
2681
40
    qimage_inplace_converter_map[QImage::Format_RGBX8888][QImage::Format_ARGB32] =
2682
40
            convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32>;
2683
40
    qimage_inplace_converter_map[QImage::Format_RGBX8888][QImage::Format_ARGB32_Premultiplied] =
2684
40
            convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32_Premultiplied>;
2685
40
    qimage_inplace_converter_map[QImage::Format_RGBX8888][QImage::Format_RGBA8888] =
2686
40
            convert_passthrough_inplace<QImage::Format_RGBA8888>;
2687
40
    qimage_inplace_converter_map[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] =
2688
40
            convert_passthrough_inplace<QImage::Format_RGBA8888_Premultiplied>;
2689
2690
40
    qimage_inplace_converter_map[QImage::Format_RGBA8888][QImage::Format_RGB32] =
2691
40
            convert_RGBA_to_ARGB_inplace<QImage::Format_RGB32>;
2692
40
    qimage_inplace_converter_map[QImage::Format_RGBA8888][QImage::Format_ARGB32] =
2693
40
            convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32>;
2694
40
    qimage_inplace_converter_map[QImage::Format_RGBA8888][QImage::Format_RGBX8888] =
2695
40
            mask_alpha_converter_rgbx_inplace;
2696
40
    qimage_inplace_converter_map[QImage::Format_RGBA8888][QImage::Format_A2BGR30_Premultiplied] =
2697
40
            convert_ARGB_to_A2RGB30_inplace<PixelOrderBGR, true>;
2698
40
    qimage_inplace_converter_map[QImage::Format_RGBA8888][QImage::Format_A2RGB30_Premultiplied] =
2699
40
            convert_ARGB_to_A2RGB30_inplace<PixelOrderRGB, true>;
2700
2701
40
    qimage_inplace_converter_map[QImage::Format_RGBA8888_Premultiplied][QImage::Format_ARGB32_Premultiplied] =
2702
40
            convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32_Premultiplied>;
2703
2704
40
    qimage_inplace_converter_map[QImage::Format_BGR30][QImage::Format_A2BGR30_Premultiplied] =
2705
40
            convert_passthrough_inplace<QImage::Format_A2BGR30_Premultiplied>;
2706
40
    qimage_inplace_converter_map[QImage::Format_BGR30][QImage::Format_RGB30] =
2707
40
            convert_rgbswap_generic_inplace;
2708
40
    qimage_inplace_converter_map[QImage::Format_BGR30][QImage::Format_A2RGB30_Premultiplied] =
2709
40
            convert_BGR30_to_A2RGB30_inplace;
2710
2711
40
    qimage_inplace_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_ARGB32] =
2712
40
            convert_A2RGB30_PM_to_ARGB_inplace<PixelOrderBGR, false>;
2713
40
    qimage_inplace_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGBA8888] =
2714
40
            convert_A2RGB30_PM_to_ARGB_inplace<PixelOrderBGR, true>;
2715
40
    qimage_inplace_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_BGR30] =
2716
40
            convert_A2RGB30_PM_to_RGB30_inplace<false>;
2717
40
    qimage_inplace_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGB30] =
2718
40
            convert_A2RGB30_PM_to_RGB30_inplace<true>;
2719
40
    qimage_inplace_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_A2RGB30_Premultiplied] =
2720
40
            convert_rgbswap_generic_inplace;
2721
2722
40
    qimage_inplace_converter_map[QImage::Format_RGB30][QImage::Format_BGR30] =
2723
40
            convert_rgbswap_generic_inplace;
2724
40
    qimage_inplace_converter_map[QImage::Format_RGB30][QImage::Format_A2BGR30_Premultiplied] =
2725
40
            convert_BGR30_to_A2RGB30_inplace;
2726
40
    qimage_inplace_converter_map[QImage::Format_RGB30][QImage::Format_A2RGB30_Premultiplied] =
2727
40
            convert_passthrough_inplace<QImage::Format_A2RGB30_Premultiplied>;
2728
2729
40
    qimage_inplace_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_ARGB32] =
2730
40
            convert_A2RGB30_PM_to_ARGB_inplace<PixelOrderRGB, false>;
2731
40
    qimage_inplace_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGBA8888] =
2732
40
            convert_A2RGB30_PM_to_ARGB_inplace<PixelOrderRGB, true>;
2733
40
    qimage_inplace_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_BGR30] =
2734
40
            convert_A2RGB30_PM_to_RGB30_inplace<true>;
2735
40
    qimage_inplace_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_A2BGR30_Premultiplied] =
2736
40
            convert_rgbswap_generic_inplace;
2737
40
    qimage_inplace_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGB30] =
2738
40
            convert_A2RGB30_PM_to_RGB30_inplace<false>;
2739
2740
40
    qimage_inplace_converter_map[QImage::Format_Grayscale8][QImage::Format_Indexed8] =
2741
40
            convert_Grayscale8_to_Indexed8_inplace;
2742
40
    qimage_inplace_converter_map[QImage::Format_Alpha8][QImage::Format_Indexed8] =
2743
40
            convert_Alpha8_to_Indexed8_inplace;
2744
2745
40
    qimage_inplace_converter_map[QImage::Format_RGBX64][QImage::Format_RGBA64] =
2746
40
            convert_passthrough_inplace<QImage::Format_RGBA64>;
2747
40
    qimage_inplace_converter_map[QImage::Format_RGBX64][QImage::Format_RGBA64_Premultiplied] =
2748
40
            convert_passthrough_inplace<QImage::Format_RGBA64_Premultiplied>;
2749
2750
40
    qimage_inplace_converter_map[QImage::Format_RGBA64][QImage::Format_RGBX64] =
2751
40
            convert_RGBA64_to_RGBx64_inplace;
2752
2753
40
    qimage_inplace_converter_map[QImage::Format_BGR888][QImage::Format_RGB888] =
2754
40
            convert_rgbswap_generic_inplace;
2755
2756
40
    qimage_inplace_converter_map[QImage::Format_RGBX16FPx4][QImage::Format_RGBA16FPx4] =
2757
40
            convert_passthrough_inplace<QImage::Format_RGBA16FPx4>;
2758
40
    qimage_inplace_converter_map[QImage::Format_RGBX16FPx4][QImage::Format_RGBA16FPx4_Premultiplied] =
2759
40
            convert_passthrough_inplace<QImage::Format_RGBA16FPx4_Premultiplied>;
2760
2761
40
    qimage_inplace_converter_map[QImage::Format_RGBX32FPx4][QImage::Format_RGBA32FPx4] =
2762
40
            convert_passthrough_inplace<QImage::Format_RGBA32FPx4>;
2763
40
    qimage_inplace_converter_map[QImage::Format_RGBX32FPx4][QImage::Format_RGBA32FPx4_Premultiplied] =
2764
40
            convert_passthrough_inplace<QImage::Format_RGBA32FPx4_Premultiplied>;
2765
2766
    // Now architecture specific conversions:
2767
40
#if defined(__SSE2__) && defined(QT_COMPILER_SUPPORTS_SSSE3)
2768
40
    if (qCpuHasFeature(SSSE3)) {
2769
40
        extern void convert_RGB888_to_RGB32_ssse3(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
2770
40
        qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_ssse3;
2771
40
        qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_ssse3;
2772
40
        qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_ssse3;
2773
40
        qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBX8888] = convert_RGB888_to_RGB32_ssse3;
2774
40
        qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBA8888] = convert_RGB888_to_RGB32_ssse3;
2775
40
        qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBA8888_Premultiplied] = convert_RGB888_to_RGB32_ssse3;
2776
40
    }
2777
40
#endif
2778
2779
#if defined(QT_COMPILER_SUPPORTS_LSX)
2780
    if (qCpuHasFeature(LSX)) {
2781
        extern void convert_RGB888_to_RGB32_lsx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
2782
        qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_lsx;
2783
        qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_lsx;
2784
        qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_lsx;
2785
        qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBX8888] = convert_RGB888_to_RGB32_lsx;
2786
        qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBA8888] = convert_RGB888_to_RGB32_lsx;
2787
        qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBA8888_Premultiplied] = convert_RGB888_to_RGB32_lsx;
2788
    }
2789
#endif
2790
2791
#if defined(QT_COMPILER_SUPPORTS_LASX)
2792
    if (qCpuHasFeature(LASX)) {
2793
        extern void convert_RGB888_to_RGB32_lasx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
2794
        qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_lasx;
2795
        qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_lasx;
2796
        qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_lasx;
2797
        qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBX8888] = convert_RGB888_to_RGB32_lasx;
2798
        qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBA8888] = convert_RGB888_to_RGB32_lasx;
2799
        qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBA8888_Premultiplied] = convert_RGB888_to_RGB32_lasx;
2800
    }
2801
#endif
2802
2803
#if defined(__ARM_NEON__)
2804
    extern void convert_RGB888_to_RGB32_neon(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
2805
    qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_neon;
2806
    qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_neon;
2807
    qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_neon;
2808
#endif
2809
2810
#if defined(__MIPS_DSPR2__)
2811
    extern bool convert_ARGB_to_ARGB_PM_inplace_mips_dspr2(QImageData *data, Qt::ImageConversionFlags);
2812
    qimage_inplace_converter_map[QImage::Format_ARGB32][QImage::Format_ARGB32_Premultiplied] = convert_ARGB_to_ARGB_PM_inplace_mips_dspr2;
2813
2814
    extern void convert_RGB888_to_RGB32_mips_dspr2(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
2815
    qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_mips_dspr2;
2816
    qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_mips_dspr2;
2817
    qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_mips_dspr2;
2818
#endif
2819
40
}
2820
2821
Q_CONSTRUCTOR_FUNCTION(qInitImageConversions);
2822
2823
QT_END_NAMESPACE