Coverage Report

Created: 2026-02-10 07:39

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