Coverage Report

Created: 2025-07-12 07:23

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