diff options
Diffstat (limited to 'src/gui/image/qimage_conversions.cpp')
-rw-r--r-- | src/gui/image/qimage_conversions.cpp | 2252 |
1 files changed, 913 insertions, 1339 deletions
diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 27088698ec..a806954df2 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -1,49 +1,28 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -#include <private/qdrawhelper_p.h> #include <private/qguiapplication_p.h> +#include <private/qcolortransform_p.h> #include <private/qcolortrclut_p.h> +#include <private/qcmyk_p.h> +#include <private/qdrawhelper_p.h> #include <private/qendian_p.h> +#include <private/qpixellayout_p.h> #include <private/qsimd_p.h> #include <private/qimage_p.h> + #include <qendian.h> +#include <qrgbafloat.h> +#if QT_CONFIG(thread) +#include <qsemaphore.h> +#include <qthreadpool.h> +#include <private/qthreadpool_p.h> +#ifdef Q_OS_WASM +// WebAssembly has threads; however we can't block the main thread. +#else +#define QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS +#endif +#endif QT_BEGIN_NAMESPACE @@ -58,7 +37,7 @@ struct QDefaultColorTables } } - QVector<QRgb> gray, alpha; + QList<QRgb> gray, alpha; }; Q_GLOBAL_STATIC(QDefaultColorTables, defaultColorTables); @@ -119,9 +98,9 @@ void qGamma_correct_back_to_linear_cs(QImage *image) *****************************************************************************/ // The drawhelper conversions from/to RGB32 are passthroughs which is not always correct for general image conversion -#if !defined(__ARM_NEON__) +#if !defined(__ARM_NEON__) || !(Q_BYTE_ORDER == Q_LITTLE_ENDIAN) static void QT_FASTCALL storeRGB32FromARGB32PM(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) + const QList<QRgb> *, QDitherInfo *) { uint *d = reinterpret_cast<uint *>(dest) + index; for (int i = 0; i < count; ++i) @@ -130,7 +109,7 @@ static void QT_FASTCALL storeRGB32FromARGB32PM(uchar *dest, const uint *src, int #endif static void QT_FASTCALL storeRGB32FromARGB32(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) + const QList<QRgb> *, QDitherInfo *) { uint *d = reinterpret_cast<uint *>(dest) + index; for (int i = 0; i < count; ++i) @@ -138,7 +117,7 @@ static void QT_FASTCALL storeRGB32FromARGB32(uchar *dest, const uint *src, int i } static const uint *QT_FASTCALL fetchRGB32ToARGB32PM(uint *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) + const QList<QRgb> *, QDitherInfo *) { const uint *s = reinterpret_cast<const uint *>(src) + index; for (int i = 0; i < count; ++i) @@ -148,10 +127,10 @@ static const uint *QT_FASTCALL fetchRGB32ToARGB32PM(uint *buffer, const uchar *s #ifdef QT_COMPILER_SUPPORTS_SSE4_1 extern void QT_FASTCALL storeRGB32FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *); -#elif defined(__ARM_NEON__) + const QList<QRgb> *, QDitherInfo *); +#elif defined(__ARM_NEON__) && (Q_BYTE_ORDER == Q_LITTLE_ENDIAN) extern void QT_FASTCALL storeRGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *); + const QList<QRgb> *, QDitherInfo *); #endif void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags flags) @@ -159,12 +138,8 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio // Cannot be used with indexed formats. Q_ASSERT(dest->format > QImage::Format_Indexed8); Q_ASSERT(src->format > QImage::Format_Indexed8); - uint buf[BufferSize]; - uint *buffer = buf; const QPixelLayout *srcLayout = &qPixelLayouts[src->format]; const QPixelLayout *destLayout = &qPixelLayouts[dest->format]; - const uchar *srcData = src->data; - uchar *destData = dest->data; FetchAndConvertPixelsFunc fetch = srcLayout->fetchToARGB32PM; ConvertAndStorePixelsFunc store = destLayout->storeFromARGB32PM; @@ -181,7 +156,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio store = storeRGB32FromARGB32PM_sse4; else store = storeRGB32FromARGB32PM; -#elif defined(__ARM_NEON__) +#elif defined(__ARM_NEON__) && (Q_BYTE_ORDER == Q_LITTLE_ENDIAN) store = storeRGB32FromARGB32PM_neon; #else store = storeRGB32FromARGB32PM; @@ -191,66 +166,174 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied && !destLayout->hasAlphaChannel && destLayout->storeFromRGB32) { // Avoid unnecessary premultiply and unpremultiply when converting from unpremultiplied src format. - fetch = qPixelLayouts[src->format + 1].fetchToARGB32PM; + fetch = qPixelLayouts[qt_toPremultipliedFormat(src->format)].fetchToARGB32PM; if (dest->format == QImage::Format_RGB32) store = storeRGB32FromARGB32; else store = destLayout->storeFromRGB32; } - QDitherInfo dither; - QDitherInfo *ditherPtr = nullptr; - if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither) - ditherPtr = &dither; - for (int y = 0; y < src->height; ++y) { - dither.y = y; - int x = 0; - while (x < src->width) { - dither.x = x; - int l = src->width - x; - if (destLayout->bpp == QPixelLayout::BPP32) - buffer = reinterpret_cast<uint *>(destData) + x; - else - l = qMin(l, BufferSize); - const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr); - store(destData, ptr, x, l, nullptr, ditherPtr); - x += l; + auto convertSegment = [=](int yStart, int yEnd) { + uint buf[BufferSize]; + uint *buffer = buf; + const uchar *srcData = src->data + src->bytes_per_line * yStart; + uchar *destData = dest->data + dest->bytes_per_line * yStart; + QDitherInfo dither; + QDitherInfo *ditherPtr = nullptr; + if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither) + ditherPtr = &dither; + for (int y = yStart; y < yEnd; ++y) { + dither.y = y; + int x = 0; + while (x < src->width) { + dither.x = x; + int l = src->width - x; + if (destLayout->bpp == QPixelLayout::BPP32) + buffer = reinterpret_cast<uint *>(destData) + x; + else + l = qMin(l, BufferSize); + const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr); + store(destData, ptr, x, l, nullptr, ditherPtr); + x += l; + } + srcData += src->bytes_per_line; + destData += dest->bytes_per_line; } - srcData += src->bytes_per_line; - destData += dest->bytes_per_line; - } + }; + +#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS + int segments = (qsizetype(src->width) * src->height) >> 16; + segments = std::min(segments, src->height); + + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); + if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread())) + return convertSegment(0, src->height); + + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (src->height - y) / (segments - i); + threadPool->start([&, y, yn]() { + convertSegment(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); +#else + convertSegment(0, src->height); +#endif } -void convert_generic_to_rgb64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +void convert_generic_over_rgb64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(dest->format > QImage::Format_Indexed8); Q_ASSERT(src->format > QImage::Format_Indexed8); - QRgba64 buf[BufferSize]; - QRgba64 *buffer = buf; const QPixelLayout *srcLayout = &qPixelLayouts[src->format]; const QPixelLayout *destLayout = &qPixelLayouts[dest->format]; - const uchar *srcData = src->data; - uchar *destData = dest->data; const FetchAndConvertPixelsFunc64 fetch = srcLayout->fetchToRGBA64PM; const ConvertAndStorePixelsFunc64 store = qStoreFromRGBA64PM[dest->format]; - for (int y = 0; y < src->height; ++y) { - int x = 0; - while (x < src->width) { - int l = src->width - x; - if (destLayout->bpp == QPixelLayout::BPP64) - buffer = reinterpret_cast<QRgba64 *>(destData) + x; - else - l = qMin(l, BufferSize); - const QRgba64 *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr); - store(destData, ptr, x, l, nullptr, nullptr); - x += l; + auto convertSegment = [=](int yStart, int yEnd) { + QRgba64 buf[BufferSize]; + QRgba64 *buffer = buf; + const uchar *srcData = src->data + yStart * src->bytes_per_line; + uchar *destData = dest->data + yStart * dest->bytes_per_line; + for (int y = yStart; y < yEnd; ++y) { + int x = 0; + while (x < src->width) { + int l = src->width - x; + if (destLayout->bpp == QPixelLayout::BPP64) + buffer = reinterpret_cast<QRgba64 *>(destData) + x; + else + l = qMin(l, BufferSize); + const QRgba64 *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr); + store(destData, ptr, x, l, nullptr, nullptr); + x += l; + } + srcData += src->bytes_per_line; + destData += dest->bytes_per_line; } - srcData += src->bytes_per_line; - destData += dest->bytes_per_line; - } + }; +#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS + int segments = (qsizetype(src->width) * src->height) >> 16; + segments = std::min(segments, src->height); + + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); + if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread())) + return convertSegment(0, src->height); + + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (src->height - y) / (segments - i); + threadPool->start([&, y, yn]() { + convertSegment(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); +#else + convertSegment(0, src->height); +#endif +} + +#if QT_CONFIG(raster_fp) +void convert_generic_over_rgba32f(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(dest->format >= QImage::Format_RGBX16FPx4); + Q_ASSERT(src->format >= QImage::Format_RGBX16FPx4); + + const FetchAndConvertPixelsFuncFP fetch = qFetchToRGBA32F[src->format]; + const ConvertAndStorePixelsFuncFP store = qStoreFromRGBA32F[dest->format]; + + auto convertSegment = [=](int yStart, int yEnd) { + QRgbaFloat32 buf[BufferSize]; + QRgbaFloat32 *buffer = buf; + const uchar *srcData = src->data + yStart * src->bytes_per_line; + uchar *destData = dest->data + yStart * dest->bytes_per_line; + for (int y = yStart; y < yEnd; ++y) { + int x = 0; + while (x < src->width) { + int l = src->width - x; + if (dest->depth == 128) + buffer = reinterpret_cast<QRgbaFloat32 *>(destData) + x; + else + l = qMin(l, BufferSize); + const QRgbaFloat32 *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr); + store(destData, ptr, x, l, nullptr, nullptr); + x += l; + } + srcData += src->bytes_per_line; + destData += dest->bytes_per_line; + } + }; +#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS + int segments = (qsizetype(src->width) * src->height) >> 16; + segments = std::min(segments, src->height); + + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); + if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread())) + return convertSegment(0, src->height); + + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (src->height - y) / (segments - i); + threadPool->start([&, y, yn]() { + convertSegment(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); +#else + convertSegment(0, src->height); +#endif } +#endif bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags flags) { @@ -265,15 +348,9 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im const QPixelLayout *destLayout = &qPixelLayouts[dst_format]; // The precision here is only ARGB32PM so don't convert between higher accuracy - // formats (assert instead when we have a convert_generic_over_rgb64_inplace). - if (qt_highColorPrecision(data->format, !destLayout->hasAlphaChannel) - && qt_highColorPrecision(dst_format, !srcLayout->hasAlphaChannel)) - return false; - - uint buf[BufferSize]; - uint *buffer = buf; - uchar *srcData = data->data; - uchar *destData = data->data; + // formats. + Q_ASSERT(!qt_highColorPrecision(data->format, !destLayout->hasAlphaChannel) + || !qt_highColorPrecision(dst_format, !srcLayout->hasAlphaChannel)); QImageData::ImageSizeParameters params = { data->bytes_per_line, data->nbytes }; if (data->depth != destDepth) { @@ -282,7 +359,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im return false; } - Q_ASSERT(destLayout->bpp != QPixelLayout::BPP64); + Q_ASSERT(destLayout->bpp < QPixelLayout::BPP64); FetchAndConvertPixelsFunc fetch = srcLayout->fetchToARGB32PM; ConvertAndStorePixelsFunc store = destLayout->storeFromARGB32PM; if (!srcLayout->hasAlphaChannel && destLayout->storeFromRGB32) { @@ -297,7 +374,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im store = storeRGB32FromARGB32PM_sse4; else store = storeRGB32FromARGB32PM; -#elif defined(__ARM_NEON__) +#elif defined(__ARM_NEON__) && (Q_BYTE_ORDER == Q_LITTLE_ENDIAN) store = storeRGB32FromARGB32PM_neon; #else store = storeRGB32FromARGB32PM; @@ -307,34 +384,164 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied && !destLayout->hasAlphaChannel && destLayout->storeFromRGB32) { // Avoid unnecessary premultiply and unpremultiply when converting from unpremultiplied src format. - fetch = qPixelLayouts[data->format + 1].fetchToARGB32PM; + fetch = qPixelLayouts[qt_toPremultipliedFormat(data->format)].fetchToARGB32PM; if (data->format == QImage::Format_RGB32) store = storeRGB32FromARGB32; else store = destLayout->storeFromRGB32; } - QDitherInfo dither; - QDitherInfo *ditherPtr = nullptr; - if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither) - ditherPtr = &dither; - - for (int y = 0; y < data->height; ++y) { - dither.y = y; - int x = 0; - while (x < data->width) { - dither.x = x; - int l = data->width - x; - if (srcLayout->bpp == QPixelLayout::BPP32) - buffer = reinterpret_cast<uint *>(srcData) + x; - else - l = qMin(l, BufferSize); - const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr); - store(destData, ptr, x, l, nullptr, ditherPtr); - x += l; + + auto convertSegment = [=](int yStart, int yEnd) { + uint buf[BufferSize]; + uint *buffer = buf; + uchar *srcData = data->data + data->bytes_per_line * yStart; + uchar *destData = srcData; // This can be temporarily wrong if we doing a shrinking conversion + QDitherInfo dither; + QDitherInfo *ditherPtr = nullptr; + if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither) + ditherPtr = &dither; + for (int y = yStart; y < yEnd; ++y) { + dither.y = y; + int x = 0; + while (x < data->width) { + dither.x = x; + int l = data->width - x; + if (srcLayout->bpp == QPixelLayout::BPP32) + buffer = reinterpret_cast<uint *>(srcData) + x; + else + l = qMin(l, BufferSize); + const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr); + store(destData, ptr, x, l, nullptr, ditherPtr); + x += l; + } + srcData += data->bytes_per_line; + destData += params.bytesPerLine; + } + }; +#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS + int segments = (qsizetype(data->width) * data->height) >> 16; + segments = std::min(segments, data->height); + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); + if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (data->height - y) / (segments - i); + threadPool->start([&, y, yn]() { + convertSegment(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + if (data->bytes_per_line != params.bytesPerLine) { + // Compress segments to a continuous block + y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (data->height - y) / (segments - i); + uchar *srcData = data->data + data->bytes_per_line * y; + uchar *destData = data->data + params.bytesPerLine * y; + if (srcData != destData) + memmove(destData, srcData, params.bytesPerLine * yn); + y += yn; + } + } + } else +#endif + convertSegment(0, data->height); + if (params.totalSize != data->nbytes) { + Q_ASSERT(params.totalSize < data->nbytes); + void *newData = realloc(data->data, params.totalSize); + if (newData) { + data->data = (uchar *)newData; + data->nbytes = params.totalSize; } - srcData += data->bytes_per_line; - destData += params.bytesPerLine; + data->bytes_per_line = params.bytesPerLine; + } + data->depth = destDepth; + data->format = dst_format; + return true; +} + +bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format > QImage::Format_Indexed8); + Q_ASSERT(dst_format > QImage::Format_Indexed8); + const int destDepth = qt_depthForFormat(dst_format); + if (data->depth < destDepth) + return false; + + const QPixelLayout *srcLayout = &qPixelLayouts[data->format]; + const QPixelLayout *destLayout = &qPixelLayouts[dst_format]; + + QImageData::ImageSizeParameters params = { data->bytes_per_line, data->nbytes }; + if (data->depth != destDepth) { + params = QImageData::calculateImageParameters(data->width, data->height, destDepth); + if (!params.isValid()) + return false; } + + FetchAndConvertPixelsFunc64 fetch = srcLayout->fetchToRGBA64PM; + ConvertAndStorePixelsFunc64 store = qStoreFromRGBA64PM[dst_format]; + if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied && + destLayout->hasAlphaChannel && !destLayout->premultiplied) { + // Avoid unnecessary premultiply and unpremultiply when converting between two unpremultiplied formats. + fetch = qPixelLayouts[qt_toPremultipliedFormat(data->format)].fetchToRGBA64PM; + store = qStoreFromRGBA64PM[qt_toPremultipliedFormat(dst_format)]; + } + + auto convertSegment = [=](int yStart, int yEnd) { + QRgba64 buf[BufferSize]; + QRgba64 *buffer = buf; + uchar *srcData = data->data + yStart * data->bytes_per_line; + uchar *destData = srcData; + for (int y = yStart; y < yEnd; ++y) { + int x = 0; + while (x < data->width) { + int l = data->width - x; + if (srcLayout->bpp == QPixelLayout::BPP64) + buffer = reinterpret_cast<QRgba64 *>(srcData) + x; + else + l = qMin(l, BufferSize); + const QRgba64 *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr); + store(destData, ptr, x, l, nullptr, nullptr); + x += l; + } + srcData += data->bytes_per_line; + destData += params.bytesPerLine; + } + }; +#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS + int segments = (qsizetype(data->width) * data->height) >> 16; + segments = std::min(segments, data->height); + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); + if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (data->height - y) / (segments - i); + threadPool->start([&, y, yn]() { + convertSegment(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + if (data->bytes_per_line != params.bytesPerLine) { + // Compress segments to a continuous block + y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (data->height - y) / (segments - i); + uchar *srcData = data->data + data->bytes_per_line * y; + uchar *destData = data->data + params.bytesPerLine * y; + if (srcData != destData) + memmove(destData, srcData, params.bytesPerLine * yn); + y += yn; + } + } + } else +#endif + convertSegment(0, data->height); if (params.totalSize != data->nbytes) { Q_ASSERT(params.totalSize < data->nbytes); void *newData = realloc(data->data, params.totalSize); @@ -343,12 +550,107 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im data->nbytes = params.totalSize; } data->bytes_per_line = params.bytesPerLine; - data->depth = destDepth; } + data->depth = destDepth; data->format = dst_format; return true; } +#if QT_CONFIG(raster_fp) +bool convert_generic_inplace_over_rgba32f(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format >= QImage::Format_RGBX16FPx4); + Q_ASSERT(dst_format >= QImage::Format_RGBX16FPx4); + const int destDepth = qt_depthForFormat(dst_format); + if (data->depth < destDepth) + return false; + + const QPixelLayout *srcLayout = &qPixelLayouts[data->format]; + const QPixelLayout *destLayout = &qPixelLayouts[dst_format]; + + QImageData::ImageSizeParameters params = { data->bytes_per_line, data->nbytes }; + if (data->depth != destDepth) { + params = QImageData::calculateImageParameters(data->width, data->height, destDepth); + if (!params.isValid()) + return false; + } + + FetchAndConvertPixelsFuncFP fetch = qFetchToRGBA32F[data->format]; + ConvertAndStorePixelsFuncFP store = qStoreFromRGBA32F[dst_format]; + if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied && + destLayout->hasAlphaChannel && !destLayout->premultiplied) { + // Avoid unnecessary premultiply and unpremultiply when converting between two unpremultiplied formats. + fetch = qFetchToRGBA32F[qt_toPremultipliedFormat(data->format)]; + store = qStoreFromRGBA32F[qt_toPremultipliedFormat(dst_format)]; + } + + auto convertSegment = [=](int yStart, int yEnd) { + QRgbaFloat32 buf[BufferSize]; + QRgbaFloat32 *buffer = buf; + uchar *srcData = data->data + yStart * data->bytes_per_line; + uchar *destData = srcData; + for (int y = yStart; y < yEnd; ++y) { + int x = 0; + while (x < data->width) { + int l = data->width - x; + if (srcLayout->bpp == QPixelLayout::BPP32FPx4) + buffer = reinterpret_cast<QRgbaFloat32 *>(srcData) + x; + else + l = qMin(l, BufferSize); + const QRgbaFloat32 *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr); + store(destData, ptr, x, l, nullptr, nullptr); + x += l; + } + srcData += data->bytes_per_line; + destData += params.bytesPerLine; + } + }; +#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS + int segments = (qsizetype(data->width) * data->height) >> 16; + segments = std::min(segments, data->height); + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); + if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (data->height - y) / (segments - i); + threadPool->start([&, y, yn]() { + convertSegment(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + if (data->bytes_per_line != params.bytesPerLine) { + // Compress segments to a continuous block + y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (data->height - y) / (segments - i); + uchar *srcData = data->data + data->bytes_per_line * y; + uchar *destData = data->data + params.bytesPerLine * y; + if (srcData != destData) + memmove(destData, srcData, params.bytesPerLine * yn); + y += yn; + } + } + } else +#endif + convertSegment(0, data->height); + if (params.totalSize != data->nbytes) { + Q_ASSERT(params.totalSize < data->nbytes); + void *newData = realloc(data->data, params.totalSize); + if (newData) { + data->data = (uchar *)newData; + data->nbytes = params.totalSize; + } + data->bytes_per_line = params.bytesPerLine; + } + data->depth = destDepth; + data->format = dst_format; + return true; +} +#endif + static void convert_passthrough(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(src->width == dest->width); @@ -530,7 +832,7 @@ static bool convert_ARGB_to_RGBA_inplace(QImageData *data, Qt::ImageConversionFl const int pad = (data->bytes_per_line >> 2) - data->width; quint32 *rgb_data = (quint32 *) data->data; - Q_CONSTEXPR uint mask = (DestFormat == QImage::Format_RGBX8888) ? 0xff000000 : 0; + constexpr uint mask = (DestFormat == QImage::Format_RGBX8888) ? 0xff000000 : 0; for (int i = 0; i < data->height; ++i) { const quint32 *end = rgb_data + data->width; @@ -576,7 +878,7 @@ static bool convert_RGBA_to_ARGB_inplace(QImageData *data, Qt::ImageConversionFl const int pad = (data->bytes_per_line >> 2) - data->width; QRgb *rgb_data = (QRgb *) data->data; - Q_CONSTEXPR uint mask = (DestFormat == QImage::Format_RGB32) ? 0xff000000 : 0; + constexpr uint mask = (DestFormat == QImage::Format_RGB32) ? 0xff000000 : 0; for (int i = 0; i < data->height; ++i) { const QRgb *end = rgb_data + data->width; @@ -731,8 +1033,7 @@ static inline uint qUnpremultiplyRgb30(uint rgb30) case 3: return rgb30; } - Q_UNREACHABLE(); - return 0; + Q_UNREACHABLE_RETURN(0); } template<bool rgbswap> @@ -1021,11 +1322,11 @@ static void convert_ARGB32_to_RGBA64(QImageData *dest, const QImageData *src, Qt const uchar *src_data = src->data; uchar *dest_data = dest->data; - const FetchAndConvertPixelsFunc64 fetch = qPixelLayouts[src->format + 1].fetchToRGBA64PM; + const FetchAndConvertPixelsFunc64 fetch = qPixelLayouts[qt_toPremultipliedFormat(src->format)].fetchToRGBA64PM; for (int i = 0; i < src->height; ++i) { fetch(reinterpret_cast<QRgba64 *>(dest_data), src_data, 0, src->width, nullptr, nullptr); - src_data += src->bytes_per_line;; + src_data += src->bytes_per_line; dest_data += dest->bytes_per_line; } } @@ -1074,103 +1375,107 @@ static bool convert_RGBA64_to_RGBx64_inplace(QImageData *data, Qt::ImageConversi return true; } -static void convert_RGBA64_to_RGBA64PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +static void convert_gray16_to_RGBA64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { - Q_ASSERT(src->format == QImage::Format_RGBA64); - Q_ASSERT(dest->format == QImage::Format_RGBA64_Premultiplied); + Q_ASSERT(src->format == QImage::Format_Grayscale16); + Q_ASSERT(dest->format == QImage::Format_RGBA64 || dest->format == QImage::Format_RGBX64 || + dest->format == QImage::Format_RGBA64_Premultiplied); Q_ASSERT(src->width == dest->width); Q_ASSERT(src->height == dest->height); - const int src_pad = (src->bytes_per_line >> 3) - src->width; - const int dest_pad = (dest->bytes_per_line >> 3) - dest->width; - const QRgba64 *src_data = reinterpret_cast<const QRgba64 *>(src->data); - QRgba64 *dest_data = reinterpret_cast<QRgba64 *>(dest->data); + const qsizetype sbpl = src->bytes_per_line; + const qsizetype dbpl = dest->bytes_per_line; + const uchar *src_data = src->data; + uchar *dest_data = dest->data; for (int i = 0; i < src->height; ++i) { - const QRgba64 *end = src_data + src->width; - while (src_data < end) { - *dest_data = src_data->premultiplied(); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static bool convert_RGBA64_to_RGBA64PM_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_RGBA64); - - const int pad = (data->bytes_per_line >> 3) - data->width; - QRgba64 *rgb_data = reinterpret_cast<QRgba64 *>(data->data); - - for (int i = 0; i < data->height; ++i) { - const QRgba64 *end = rgb_data + data->width; - while (rgb_data < end) { - *rgb_data = rgb_data->premultiplied(); - ++rgb_data; + const quint16 *src_line = reinterpret_cast<const quint16 *>(src_data); + QRgba64 *dest_line = reinterpret_cast<QRgba64 *>(dest_data); + for (int j = 0; j < src->width; ++j) { + quint16 s = src_line[j]; + dest_line[j] = qRgba64(s, s, s, 0xFFFF); } - rgb_data += pad; + src_data += sbpl; + dest_data += dbpl; } - data->format = QImage::Format_RGBA64_Premultiplied; - return true; } -template<bool MaskAlpha> -static void convert_RGBA64PM_to_RGBA64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +template<bool Premultiplied> +static void convert_ARGB_to_gray8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { - Q_ASSERT(src->format == QImage::Format_RGBA64_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_RGBA64 || dest->format == QImage::Format_RGBX64); + Q_ASSERT(dest->format == QImage::Format_Grayscale8); + Q_ASSERT(src->format == QImage::Format_RGB32 || + src->format == QImage::Format_ARGB32 || + src->format == QImage::Format_ARGB32_Premultiplied); Q_ASSERT(src->width == dest->width); Q_ASSERT(src->height == dest->height); - const int src_pad = (src->bytes_per_line >> 3) - src->width; - const int dest_pad = (dest->bytes_per_line >> 3) - dest->width; - const QRgba64 *src_data = reinterpret_cast<const QRgba64 *>(src->data); - QRgba64 *dest_data = reinterpret_cast<QRgba64 *>(dest->data); + const qsizetype sbpl = src->bytes_per_line; + const qsizetype dbpl = dest->bytes_per_line; + const uchar *src_data = src->data; + uchar *dest_data = dest->data; + + QColorSpace fromCS = src->colorSpace.isValid() ? src->colorSpace : QColorSpace::SRgb; + QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ(); + const QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf); + QColorTransformPrivate::TransformFlags flags = Premultiplied + ? QColorTransformPrivate::InputPremultiplied + : QColorTransformPrivate::Unpremultiplied; for (int i = 0; i < src->height; ++i) { - const QRgba64 *end = src_data + src->width; - while (src_data < end) { - *dest_data = src_data->unpremultiplied(); - if (MaskAlpha) - dest_data->setAlpha(65535); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; + const QRgb *src_line = reinterpret_cast<const QRgb *>(src_data); + tfd->applyReturnGray(dest_data, src_line, src->width, flags); + src_data += sbpl; + dest_data += dbpl; } } -template<bool MaskAlpha> -static bool convert_RGBA64PM_to_RGBA64_inplace(QImageData *data, Qt::ImageConversionFlags) +template<bool Premultiplied> +static void convert_ARGB_to_gray16(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { - Q_ASSERT(data->format == QImage::Format_RGBA64_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_Grayscale16); + Q_ASSERT(src->format == QImage::Format_RGB32 || + src->format == QImage::Format_ARGB32 || + src->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); - const int pad = (data->bytes_per_line >> 3) - data->width; - QRgba64 *rgb_data = reinterpret_cast<QRgba64 *>(data->data); + const qsizetype sbpl = src->bytes_per_line; + const qsizetype dbpl = dest->bytes_per_line; + const uchar *src_data = src->data; + uchar *dest_data = dest->data; - for (int i = 0; i < data->height; ++i) { - const QRgba64 *end = rgb_data + data->width; - while (rgb_data < end) { - *rgb_data = rgb_data->unpremultiplied(); - if (MaskAlpha) - rgb_data->setAlpha(65535); - ++rgb_data; + QColorSpace fromCS = src->colorSpace.isValid() ? src->colorSpace : QColorSpace::SRgb; + QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ(); + const QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf); + QColorTransformPrivate::TransformFlags flags = Premultiplied + ? QColorTransformPrivate::InputPremultiplied + : QColorTransformPrivate::Unpremultiplied; + + QRgba64 tmp_line[BufferSize]; + for (int i = 0; i < src->height; ++i) { + const QRgb *src_line = reinterpret_cast<const QRgb *>(src_data); + quint16 *dest_line = reinterpret_cast<quint16 *>(dest_data); + int j = 0; + while (j < src->width) { + const int len = std::min(src->width - j, BufferSize); + for (int k = 0; k < len; ++k) + tmp_line[k] = QRgba64::fromArgb32(src_line[j + k]); + tfd->applyReturnGray(dest_line + j, tmp_line, len, flags); + j += len; } - rgb_data += pad; + src_data += sbpl; + dest_data += dbpl; } - data->format = MaskAlpha ? QImage::Format_RGBX64 : QImage::Format_RGBA64; - return true; } -static void convert_gray16_to_RGBA64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +template<bool Premultiplied> +static void convert_RGBA64_to_gray8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { - Q_ASSERT(src->format == QImage::Format_Grayscale16); - Q_ASSERT(dest->format == QImage::Format_RGBA64 || dest->format == QImage::Format_RGBX64 || - dest->format == QImage::Format_RGBA64_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_Grayscale8); + Q_ASSERT(src->format == QImage::Format_RGBX64 || + src->format == QImage::Format_RGBA64 || + src->format == QImage::Format_RGBA64_Premultiplied); Q_ASSERT(src->width == dest->width); Q_ASSERT(src->height == dest->height); @@ -1179,22 +1484,36 @@ static void convert_gray16_to_RGBA64(QImageData *dest, const QImageData *src, Qt const uchar *src_data = src->data; uchar *dest_data = dest->data; + QColorSpace fromCS = src->colorSpace.isValid() ? src->colorSpace : QColorSpace::SRgb; + QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ(); + const QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf); + QColorTransformPrivate::TransformFlags flags = Premultiplied + ? QColorTransformPrivate::InputPremultiplied + : QColorTransformPrivate::Unpremultiplied; + + quint16 gray_line[BufferSize]; for (int i = 0; i < src->height; ++i) { - const quint16 *src_line = reinterpret_cast<const quint16 *>(src_data); - QRgba64 *dest_line = reinterpret_cast<QRgba64 *>(dest_data); - for (int j = 0; j < src->width; ++j) { - quint16 s = src_line[j]; - dest_line[j] = qRgba64(s, s, s, 0xFFFF); + const QRgba64 *src_line = reinterpret_cast<const QRgba64 *>(src_data); + uchar *dest_line = dest_data; + int j = 0; + while (j < src->width) { + const int len = std::min(src->width - j, BufferSize); + tfd->applyReturnGray(gray_line, src_line + j, len, flags); + for (int k = 0; k < len; ++k) + dest_line[j + k] = qt_div_257(gray_line[k]); + j += len; } src_data += sbpl; dest_data += dbpl; } } +template<bool Premultiplied> static void convert_RGBA64_to_gray16(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(dest->format == QImage::Format_Grayscale16); Q_ASSERT(src->format == QImage::Format_RGBX64 || + src->format == QImage::Format_RGBA64 || src->format == QImage::Format_RGBA64_Premultiplied); Q_ASSERT(src->width == dest->width); Q_ASSERT(src->height == dest->height); @@ -1204,21 +1523,74 @@ static void convert_RGBA64_to_gray16(QImageData *dest, const QImageData *src, Qt const uchar *src_data = src->data; uchar *dest_data = dest->data; + QColorSpace fromCS = src->colorSpace.isValid() ? src->colorSpace : QColorSpace::SRgb; + QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ(); + const QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf); + QColorTransformPrivate::TransformFlags flags = Premultiplied + ? QColorTransformPrivate::InputPremultiplied + : QColorTransformPrivate::Unpremultiplied; + for (int i = 0; i < src->height; ++i) { const QRgba64 *src_line = reinterpret_cast<const QRgba64 *>(src_data); quint16 *dest_line = reinterpret_cast<quint16 *>(dest_data); - for (int j = 0; j < src->width; ++j) { - QRgba64 s = src_line[j].unpremultiplied(); - dest_line[j] = qGray(s.red(), s.green(), s.blue()); - } + tfd->applyReturnGray(dest_line, src_line, src->width, flags); src_data += sbpl; dest_data += dbpl; } } -static QVector<QRgb> fix_color_table(const QVector<QRgb> &ctbl, QImage::Format format) +template<bool MaskAlpha> +static void convert_RGBA16FPM_to_RGBA16F(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_RGBA16FPx4_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_RGBA16FPx4 || dest->format == QImage::Format_RGBX16FPx4); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 3) - src->width; + const int dest_pad = (dest->bytes_per_line >> 3) - dest->width; + const QRgbaFloat16 *src_data = reinterpret_cast<const QRgbaFloat16 *>(src->data); + QRgbaFloat16 *dest_data = reinterpret_cast<QRgbaFloat16 *>(dest->data); + + for (int i = 0; i < src->height; ++i) { + const QRgbaFloat16 *end = src_data + src->width; + while (src_data < end) { + *dest_data = src_data->unpremultiplied(); + if (MaskAlpha) + dest_data->setAlpha(1.0f); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +template<bool MaskAlpha> +static bool convert_RGBA16FPM_to_RGBA16F_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_RGBA16FPx4_Premultiplied); + + const int pad = (data->bytes_per_line >> 3) - data->width; + QRgbaFloat16 *rgb_data = reinterpret_cast<QRgbaFloat16 *>(data->data); + + for (int i = 0; i < data->height; ++i) { + const QRgbaFloat16 *end = rgb_data + data->width; + while (rgb_data < end) { + *rgb_data = rgb_data->unpremultiplied(); + if (MaskAlpha) + rgb_data->setAlpha(1.0f); + ++rgb_data; + } + rgb_data += pad; + } + data->format = MaskAlpha ? QImage::Format_RGBX16FPx4 : QImage::Format_RGBA16FPx4; + return true; +} + +static QList<QRgb> fix_color_table(const QList<QRgb> &ctbl, QImage::Format format) { - QVector<QRgb> colorTable = ctbl; + QList<QRgb> colorTable = ctbl; if (format == QImage::Format_RGB32) { // check if the color table has alpha for (int i = 0; i < colorTable.size(); ++i) @@ -1552,7 +1924,7 @@ static void convert_RGB_to_Indexed8(QImageData *dst, const QImageData *src, Qt:: int pix=0; if (!dst->colortable.isEmpty()) { - QVector<QRgb> ctbl = dst->colortable; + QList<QRgb> ctbl = dst->colortable; dst->colortable.resize(256); // Preload palette into table. // Almost same code as pixel insertion below @@ -1815,7 +2187,7 @@ static void convert_Indexed8_to_X32(QImageData *dest, const QImageData *src, Qt: Q_ASSERT(src->width == dest->width); Q_ASSERT(src->height == dest->height); - QVector<QRgb> colorTable = src->has_alpha_clut ? fix_color_table(src->colortable, dest->format) : src->colortable; + QList<QRgb> colorTable = src->has_alpha_clut ? fix_color_table(src->colortable, dest->format) : src->colortable; if (colorTable.size() == 0) { colorTable.resize(256); for (int i=0; i<256; ++i) @@ -1855,7 +2227,7 @@ static void convert_Mono_to_X32(QImageData *dest, const QImageData *src, Qt::Ima Q_ASSERT(src->width == dest->width); Q_ASSERT(src->height == dest->height); - QVector<QRgb> colorTable = fix_color_table(src->colortable, dest->format); + QList<QRgb> colorTable = fix_color_table(src->colortable, dest->format); // Default to black / white colors if (colorTable.size() < 2) { @@ -1895,7 +2267,7 @@ static void convert_Mono_to_Indexed8(QImageData *dest, const QImageData *src, Qt Q_ASSERT(src->width == dest->width); Q_ASSERT(src->height == dest->height); - QVector<QRgb> ctbl = src->colortable; + QList<QRgb> ctbl = src->colortable; if (ctbl.size() > 2) { ctbl.resize(2); } else if (ctbl.size() < 2) { @@ -1928,13 +2300,28 @@ static void convert_Mono_to_Indexed8(QImageData *dest, const QImageData *src, Qt } } +static void copy_8bit_pixels(QImageData *dest, const QImageData *src) +{ + if (src->bytes_per_line == dest->bytes_per_line) { + memcpy(dest->data, src->data, src->bytes_per_line * src->height); + } else { + const uchar *sdata = src->data; + uchar *ddata = dest->data; + for (int y = 0; y < src->height; ++y) { + memcpy(ddata, sdata, src->width); + sdata += src->bytes_per_line; + ddata += dest->bytes_per_line; + } + } +} + static void convert_Indexed8_to_Alpha8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(src->format == QImage::Format_Indexed8); Q_ASSERT(dest->format == QImage::Format_Alpha8); uchar translate[256]; - const QVector<QRgb> &colors = src->colortable; + const QList<QRgb> &colors = src->colortable; bool simpleCase = (colors.size() == 256); for (int i = 0; i < colors.size(); ++i) { uchar alpha = qAlpha(colors[i]); @@ -1943,11 +2330,15 @@ static void convert_Indexed8_to_Alpha8(QImageData *dest, const QImageData *src, } if (simpleCase) - memcpy(dest->data, src->data, src->bytes_per_line * src->height); + copy_8bit_pixels(dest, src); else { - qsizetype size = src->bytes_per_line * src->height; - for (qsizetype i = 0; i < size; ++i) { - dest->data[i] = translate[src->data[i]]; + const uchar *sdata = src->data; + uchar *ddata = dest->data; + for (int y = 0; y < src->height; ++y) { + for (int x = 0; x < src->width; ++x) + ddata[x] = translate[sdata[x]]; + sdata += src->bytes_per_line; + ddata += dest->bytes_per_line; } } } @@ -1958,21 +2349,31 @@ static void convert_Indexed8_to_Grayscale8(QImageData *dest, const QImageData *s Q_ASSERT(dest->format == QImage::Format_Grayscale8); uchar translate[256]; - const QVector<QRgb> &colors = src->colortable; + const QList<QRgb> &colors = src->colortable; bool simpleCase = (colors.size() == 256); + for (int i = 0; i < colors.size() && simpleCase; ++i) { + if (colors[i] != qRgb(i, i, i)) + simpleCase = false; + } + if (simpleCase) { + copy_8bit_pixels(dest, src); + return; + } + + QColorSpace fromCS = src->colorSpace.isValid() ? src->colorSpace : QColorSpace::SRgb; + QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ(); for (int i = 0; i < colors.size(); ++i) { - uchar gray = qGray(colors[i]); - translate[i] = gray; - simpleCase = simpleCase && (gray == i); + QRgba64 c16 = tf.map(QRgba64::fromArgb32(colors[i])); + translate[i] = c16.green8(); // Y from XYZ ends up in the G channel } - if (simpleCase) - memcpy(dest->data, src->data, src->bytes_per_line * src->height); - else { - qsizetype size = src->bytes_per_line * src->height; - for (qsizetype i = 0; i < size; ++i) { - dest->data[i] = translate[src->data[i]]; - } + const uchar *sdata = src->data; + uchar *ddata = dest->data; + for (int y = 0; y < src->height; ++y) { + for (int x = 0; x < src->width; ++x) + ddata[x] = translate[sdata[x]]; + sdata += src->bytes_per_line; + ddata += dest->bytes_per_line; } } @@ -1981,7 +2382,7 @@ static bool convert_Indexed8_to_Alpha8_inplace(QImageData *data, Qt::ImageConver Q_ASSERT(data->format == QImage::Format_Indexed8); // Just check if this is an Alpha8 in Indexed8 disguise. - const QVector<QRgb> &colors = data->colortable; + const QList<QRgb> &colors = data->colortable; if (colors.size() != 256) return false; for (int i = 0; i < colors.size(); ++i) { @@ -2000,11 +2401,11 @@ static bool convert_Indexed8_to_Grayscale8_inplace(QImageData *data, Qt::ImageCo Q_ASSERT(data->format == QImage::Format_Indexed8); // Just check if this is a Grayscale8 in Indexed8 disguise. - const QVector<QRgb> &colors = data->colortable; + const QList<QRgb> &colors = data->colortable; if (colors.size() != 256) return false; for (int i = 0; i < colors.size(); ++i) { - if (i != qGray(colors[i])) + if (colors[i] != qRgb(i, i, i)) return false; } @@ -2019,7 +2420,7 @@ static void convert_Alpha8_to_Indexed8(QImageData *dest, const QImageData *src, Q_ASSERT(src->format == QImage::Format_Alpha8); Q_ASSERT(dest->format == QImage::Format_Indexed8); - memcpy(dest->data, src->data, src->bytes_per_line * src->height); + copy_8bit_pixels(dest, src); dest->colortable = defaultColorTables->alpha; } @@ -2029,8 +2430,7 @@ static void convert_Grayscale8_to_Indexed8(QImageData *dest, const QImageData *s Q_ASSERT(src->format == QImage::Format_Grayscale8); Q_ASSERT(dest->format == QImage::Format_Indexed8); - memcpy(dest->data, src->data, src->bytes_per_line * src->height); - + copy_8bit_pixels(dest, src); dest->colortable = defaultColorTables->gray; } @@ -2055,1117 +2455,291 @@ static bool convert_Grayscale8_to_Indexed8_inplace(QImageData *data, Qt::ImageCo return true; } - -// first index source, second dest -Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats] = +template <bool SourceIsPremultiplied> +static void convert_ARGB32_to_CMYK8888(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, - { - 0, - 0, - swap_bit_order, - convert_Mono_to_Indexed8, - convert_Mono_to_X32, - convert_Mono_to_X32, - convert_Mono_to_X32, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_Mono - - { - 0, - swap_bit_order, - 0, - convert_Mono_to_Indexed8, - convert_Mono_to_X32, - convert_Mono_to_X32, - convert_Mono_to_X32, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_MonoLSB - - { - 0, - convert_X_to_Mono, - convert_X_to_Mono, - 0, - convert_Indexed8_to_X32, - convert_Indexed8_to_X32, - convert_Indexed8_to_X32, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, - convert_Indexed8_to_Alpha8, - convert_Indexed8_to_Grayscale8, - 0, 0, 0, 0, 0 - }, // Format_Indexed8 - - { - 0, - convert_X_to_Mono, - convert_X_to_Mono, - convert_RGB_to_Indexed8, - 0, - mask_alpha_converter, - mask_alpha_converter, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, - 0, 0, 0, 0, 0 - }, // Format_RGB32 - - { - 0, - convert_X_to_Mono, - convert_X_to_Mono, - convert_ARGB_to_Indexed8, - mask_alpha_converter, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_ARGB_to_RGBx, - convert_ARGB_to_RGBA, - 0, - 0, - convert_ARGB_to_A2RGB30<PixelOrderBGR, false>, - 0, - convert_ARGB_to_A2RGB30<PixelOrderRGB, false>, - 0, 0, - 0, - convert_ARGB32_to_RGBA64<false>, - 0, 0, 0 - }, // Format_ARGB32 - - { - 0, - convert_ARGB_PM_to_Mono, - convert_ARGB_PM_to_Mono, - convert_ARGB_PM_to_Indexed8, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_ARGB_to_RGBA, - 0, 0, 0, 0, - 0, 0, - 0, 0, 0, 0, 0 - }, // Format_ARGB32_Premultiplied - - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_RGB16 - - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_ARGB8565_Premultiplied - - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_RGB666 - - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_ARGB6666_Premultiplied - - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_RGB555 + Q_ASSERT(src->format == QImage::Format_RGB32 || + src->format == QImage::Format_ARGB32 || + src->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_CMYK8888); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_ARGB8555_Premultiplied + const uchar *src_data = src->data; + uchar *dest_data = dest->data; + for (int y = 0; y < src->height; ++y) { + const QRgb *srcRgba = reinterpret_cast<const QRgb *>(src_data); + uint *destCmyk = reinterpret_cast<uint *>(dest_data); - { - 0, - 0, - 0, - 0, - convert_RGB888_to_RGB<false>, - convert_RGB888_to_RGB<false>, - convert_RGB888_to_RGB<false>, - 0, - 0, - 0, - 0, - 0, - 0, - 0, // self - 0, - 0, - convert_RGB888_to_RGB<true>, - convert_RGB888_to_RGB<true>, - convert_RGB888_to_RGB<true>, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - convert_rgbswap_generic, - }, // Format_RGB888 + for (int x = 0; x < src->width; ++x) { + QRgb sourcePixel = srcRgba[x]; + if constexpr (SourceIsPremultiplied) + sourcePixel = qUnpremultiply(sourcePixel); - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_RGB444 + destCmyk[x] = QCmyk32::fromRgba(sourcePixel).toUint(); + } - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_ARGB4444_Premultiplied - { - 0, - 0, - 0, - 0, - convert_RGBA_to_RGB, - convert_RGBA_to_ARGB, - convert_RGBA_to_ARGB, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_passthrough, - convert_passthrough, - 0, - 0, - 0, - 0, - 0, 0, - 0, 0, 0, 0, 0 - }, // Format_RGBX8888 - { - 0, - 0, - 0, - 0, - convert_RGBA_to_RGB, - convert_RGBA_to_ARGB, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - mask_alpha_converter_RGBx, - 0, - 0, - 0, - convert_ARGB_to_A2RGB30<PixelOrderBGR, true>, - 0, - convert_ARGB_to_A2RGB30<PixelOrderRGB, true>, - 0, 0, - 0, - convert_ARGB32_to_RGBA64<true>, - 0, 0, 0 - }, // Format_RGBA8888 + src_data += src->bytes_per_line;; + dest_data += dest->bytes_per_line; + } +} - { - 0, - 0, - 0, - 0, - 0, - 0, - convert_RGBA_to_ARGB, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_RGBA8888_Premultiplied +// first index source, second dest +Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats] = {}; +InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats] = {}; - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_passthrough, - convert_rgbswap_generic, - convert_rgbswap_generic, - 0, 0, - 0, 0, 0, 0, 0 - }, // Format_BGR30 - { - 0, - 0, - 0, - 0, - 0, - convert_A2RGB30_PM_to_ARGB<PixelOrderBGR, false>, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_A2RGB30_PM_to_ARGB<PixelOrderBGR, true>, - 0, - convert_A2RGB30_PM_to_RGB30<false>, - 0, - convert_A2RGB30_PM_to_RGB30<true>, - convert_rgbswap_generic, - 0, 0, - 0, 0, 0, 0, 0 - }, // Format_A2BGR30_Premultiplied - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_rgbswap_generic, - convert_rgbswap_generic, - 0, - convert_passthrough, - 0, 0, 0, 0, 0, 0, 0 - }, // Format_RGB30 - { - 0, - 0, - 0, - 0, - 0, - convert_A2RGB30_PM_to_ARGB<PixelOrderRGB, false>, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_A2RGB30_PM_to_ARGB<PixelOrderRGB, true>, - 0, - convert_A2RGB30_PM_to_RGB30<true>, - convert_rgbswap_generic, - convert_A2RGB30_PM_to_RGB30<false>, - 0, - 0, 0, - 0, 0, 0, 0, 0 - }, // Format_A2RGB30_Premultiplied - { - 0, - 0, - 0, - convert_Alpha8_to_Indexed8, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_Alpha8 - { - 0, - 0, - 0, - convert_Grayscale8_to_Indexed8, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_Grayscale8 - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, // self - convert_passthrough, - convert_passthrough, - convert_RGBA64_to_gray16, - 0 - }, // Format_RGBX64 - { - 0, - 0, - 0, - 0, - 0, - convert_RGBA64_to_ARGB32<false>, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_RGBA64_to_ARGB32<true>, - 0, - 0, 0, 0, 0, - 0, 0, - convert_RGBA64_to_RGBx64, - 0, // self - convert_RGBA64_to_RGBA64PM, - 0, - 0 - }, // Format_RGBA64 - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, - 0, 0, - convert_RGBA64PM_to_RGBA64<true>, - convert_RGBA64PM_to_RGBA64<false>, - 0, // self - convert_RGBA64_to_gray16, - 0 - }, // Format_RGBA64_Premultiplied - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, - convert_gray16_to_RGBA64, - convert_gray16_to_RGBA64, - convert_gray16_to_RGBA64, - 0, // self - 0 - }, // Format_Grayscale16 - { - 0, - 0, - 0, - 0, - 0, 0, 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_rgbswap_generic, - 0, - 0, +static void qInitImageConversions() +{ + // Some conversions can not be generic, other are just hard to make as fast in the generic converter. + + // All conversions to and from indexed formats can not be generic and needs to go over RGB32 or ARGB32 + qimage_converter_map[QImage::Format_Mono][QImage::Format_MonoLSB] = swap_bit_order; + qimage_converter_map[QImage::Format_Mono][QImage::Format_Indexed8] = convert_Mono_to_Indexed8; + qimage_converter_map[QImage::Format_Mono][QImage::Format_RGB32] = convert_Mono_to_X32; + qimage_converter_map[QImage::Format_Mono][QImage::Format_ARGB32] = convert_Mono_to_X32; + qimage_converter_map[QImage::Format_Mono][QImage::Format_ARGB32_Premultiplied] = convert_Mono_to_X32; + + qimage_converter_map[QImage::Format_MonoLSB][QImage::Format_Mono] = swap_bit_order; + qimage_converter_map[QImage::Format_MonoLSB][QImage::Format_Indexed8] = convert_Mono_to_Indexed8; + qimage_converter_map[QImage::Format_MonoLSB][QImage::Format_RGB32] = convert_Mono_to_X32; + qimage_converter_map[QImage::Format_MonoLSB][QImage::Format_ARGB32] = convert_Mono_to_X32; + qimage_converter_map[QImage::Format_MonoLSB][QImage::Format_ARGB32_Premultiplied] = convert_Mono_to_X32; + + qimage_converter_map[QImage::Format_Indexed8][QImage::Format_Mono] = convert_X_to_Mono; + qimage_converter_map[QImage::Format_Indexed8][QImage::Format_MonoLSB] = convert_X_to_Mono; + qimage_converter_map[QImage::Format_Indexed8][QImage::Format_RGB32] = convert_Indexed8_to_X32; + qimage_converter_map[QImage::Format_Indexed8][QImage::Format_ARGB32] = convert_Indexed8_to_X32; + qimage_converter_map[QImage::Format_Indexed8][QImage::Format_ARGB32_Premultiplied] = convert_Indexed8_to_X32; + // Indexed8, Alpha8 and Grayscale8 have a special relationship that can be short-cut. + qimage_converter_map[QImage::Format_Indexed8][QImage::Format_Grayscale8] = convert_Indexed8_to_Grayscale8; + qimage_converter_map[QImage::Format_Indexed8][QImage::Format_Alpha8] = convert_Indexed8_to_Alpha8; + + qimage_converter_map[QImage::Format_RGB32][QImage::Format_Mono] = convert_X_to_Mono; + qimage_converter_map[QImage::Format_RGB32][QImage::Format_MonoLSB] = convert_X_to_Mono; + qimage_converter_map[QImage::Format_RGB32][QImage::Format_Indexed8] = convert_RGB_to_Indexed8; + qimage_converter_map[QImage::Format_RGB32][QImage::Format_ARGB32] = mask_alpha_converter; + qimage_converter_map[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = mask_alpha_converter; + qimage_converter_map[QImage::Format_RGB32][QImage::Format_Grayscale8] = convert_ARGB_to_gray8<false>; + qimage_converter_map[QImage::Format_RGB32][QImage::Format_Grayscale16] = convert_ARGB_to_gray16<false>; + + qimage_converter_map[QImage::Format_ARGB32][QImage::Format_Mono] = convert_X_to_Mono; + qimage_converter_map[QImage::Format_ARGB32][QImage::Format_MonoLSB] = convert_X_to_Mono; + qimage_converter_map[QImage::Format_ARGB32][QImage::Format_Indexed8] = convert_ARGB_to_Indexed8; + qimage_converter_map[QImage::Format_ARGB32][QImage::Format_RGB32] = mask_alpha_converter; + qimage_converter_map[QImage::Format_ARGB32][QImage::Format_RGBX8888] = convert_ARGB_to_RGBx; + qimage_converter_map[QImage::Format_ARGB32][QImage::Format_RGBA8888] = convert_ARGB_to_RGBA; + // ARGB32 has higher precision than ARGB32PM and needs explicit conversions to other higher color-precision formats with alpha + qimage_converter_map[QImage::Format_ARGB32][QImage::Format_A2BGR30_Premultiplied] = convert_ARGB_to_A2RGB30<PixelOrderBGR, false>; + qimage_converter_map[QImage::Format_ARGB32][QImage::Format_A2RGB30_Premultiplied] = convert_ARGB_to_A2RGB30<PixelOrderRGB, false>; + qimage_converter_map[QImage::Format_ARGB32][QImage::Format_RGBA64] = convert_ARGB32_to_RGBA64<false>; + qimage_converter_map[QImage::Format_ARGB32][QImage::Format_Grayscale8] = convert_ARGB_to_gray8<false>; + qimage_converter_map[QImage::Format_ARGB32][QImage::Format_Grayscale16] = convert_ARGB_to_gray16<false>; + + qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_Mono] = convert_ARGB_PM_to_Mono; + qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_MonoLSB] = convert_ARGB_PM_to_Mono; + qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_Indexed8] = convert_ARGB_PM_to_Indexed8; + qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = convert_ARGB_to_RGBA; + qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_Grayscale8] = convert_ARGB_to_gray8<true>; + qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_Grayscale16] = convert_ARGB_to_gray16<true>; + + qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB<false>; + qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB<false>; + qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB<false>; + qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGBX8888] = convert_RGB888_to_RGB<true>; + qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGBA8888] = convert_RGB888_to_RGB<true>; + qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGBA8888_Premultiplied] = convert_RGB888_to_RGB<true>; + qimage_converter_map[QImage::Format_RGB888][QImage::Format_BGR888] = convert_rgbswap_generic; + + qimage_converter_map[QImage::Format_RGBX8888][QImage::Format_RGB32] = convert_RGBA_to_RGB; + qimage_converter_map[QImage::Format_RGBX8888][QImage::Format_ARGB32] = convert_RGBA_to_ARGB; + qimage_converter_map[QImage::Format_RGBX8888][QImage::Format_ARGB32_Premultiplied] = convert_RGBA_to_ARGB; + qimage_converter_map[QImage::Format_RGBX8888][QImage::Format_RGBA8888] = convert_passthrough; + qimage_converter_map[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = convert_passthrough; + + qimage_converter_map[QImage::Format_RGBA8888][QImage::Format_RGB32] = convert_RGBA_to_RGB; + qimage_converter_map[QImage::Format_RGBA8888][QImage::Format_ARGB32] = convert_RGBA_to_ARGB; + qimage_converter_map[QImage::Format_RGBA8888][QImage::Format_RGBX8888] = mask_alpha_converter_RGBx; + qimage_converter_map[QImage::Format_RGBA8888][QImage::Format_A2BGR30_Premultiplied] = convert_ARGB_to_A2RGB30<PixelOrderBGR, true>; + qimage_converter_map[QImage::Format_RGBA8888][QImage::Format_A2RGB30_Premultiplied] = convert_ARGB_to_A2RGB30<PixelOrderRGB, true>; + qimage_converter_map[QImage::Format_RGBA8888][QImage::Format_RGBA64] = convert_ARGB32_to_RGBA64<true>; + + qimage_converter_map[QImage::Format_RGBA8888_Premultiplied][QImage::Format_ARGB32_Premultiplied] = convert_RGBA_to_ARGB; + + qimage_converter_map[QImage::Format_BGR30][QImage::Format_A2BGR30_Premultiplied] = convert_passthrough; + qimage_converter_map[QImage::Format_BGR30][QImage::Format_RGB30] = convert_rgbswap_generic; + qimage_converter_map[QImage::Format_BGR30][QImage::Format_A2RGB30_Premultiplied] = convert_rgbswap_generic; + + qimage_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_ARGB32] = convert_A2RGB30_PM_to_ARGB<PixelOrderBGR, false>; + qimage_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGBA8888] = convert_A2RGB30_PM_to_ARGB<PixelOrderBGR, true>; + qimage_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_BGR30] = convert_A2RGB30_PM_to_RGB30<false>; + qimage_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGB30] = convert_A2RGB30_PM_to_RGB30<true>; + qimage_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_A2RGB30_Premultiplied] = convert_rgbswap_generic; + + qimage_converter_map[QImage::Format_RGB30][QImage::Format_BGR30] = convert_rgbswap_generic; + qimage_converter_map[QImage::Format_RGB30][QImage::Format_A2BGR30_Premultiplied] = convert_rgbswap_generic; + qimage_converter_map[QImage::Format_RGB30][QImage::Format_A2RGB30_Premultiplied] = convert_passthrough; + + qimage_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_ARGB32] = convert_A2RGB30_PM_to_ARGB<PixelOrderRGB, false>; + qimage_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGBA8888] = convert_A2RGB30_PM_to_ARGB<PixelOrderRGB, true>; + qimage_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_BGR30] = convert_A2RGB30_PM_to_RGB30<true>; + qimage_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_A2BGR30_Premultiplied] = convert_rgbswap_generic; + qimage_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGB30] = convert_A2RGB30_PM_to_RGB30<false>; + + qimage_converter_map[QImage::Format_Grayscale8][QImage::Format_Indexed8] = convert_Grayscale8_to_Indexed8; + qimage_converter_map[QImage::Format_Alpha8][QImage::Format_Indexed8] = convert_Alpha8_to_Indexed8; + + qimage_converter_map[QImage::Format_RGBX64][QImage::Format_RGBA64] = convert_passthrough; + qimage_converter_map[QImage::Format_RGBX64][QImage::Format_RGBA64_Premultiplied] = convert_passthrough; + qimage_converter_map[QImage::Format_RGBX64][QImage::Format_Grayscale8] = convert_RGBA64_to_gray8<false>; + qimage_converter_map[QImage::Format_RGBX64][QImage::Format_Grayscale16] = convert_RGBA64_to_gray16<false>; + + qimage_converter_map[QImage::Format_RGBA64][QImage::Format_ARGB32] = convert_RGBA64_to_ARGB32<false>; + qimage_converter_map[QImage::Format_RGBA64][QImage::Format_RGBA8888] = convert_RGBA64_to_ARGB32<true>; + qimage_converter_map[QImage::Format_RGBA64][QImage::Format_RGBX64] = convert_RGBA64_to_RGBx64; + qimage_converter_map[QImage::Format_RGBA64][QImage::Format_Grayscale8] = convert_RGBA64_to_gray8<false>; + qimage_converter_map[QImage::Format_RGBA64][QImage::Format_Grayscale16] = convert_RGBA64_to_gray16<false>; + + qimage_converter_map[QImage::Format_RGBA64_Premultiplied][QImage::Format_Grayscale8] = convert_RGBA64_to_gray8<true>; + qimage_converter_map[QImage::Format_RGBA64_Premultiplied][QImage::Format_Grayscale16] = convert_RGBA64_to_gray16<true>; + + qimage_converter_map[QImage::Format_Grayscale16][QImage::Format_RGBX64] = convert_gray16_to_RGBA64; + qimage_converter_map[QImage::Format_Grayscale16][QImage::Format_RGBA64] = convert_gray16_to_RGBA64; + qimage_converter_map[QImage::Format_Grayscale16][QImage::Format_RGBA64_Premultiplied] = convert_gray16_to_RGBA64; + + qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGB888] = convert_rgbswap_generic; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - convert_RGB888_to_RGB<false>, - convert_RGB888_to_RGB<false>, - convert_RGB888_to_RGB<false>, -#else - 0, 0, 0, + qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBX8888] = convert_RGB888_to_RGB<false>; + qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBA8888] = convert_RGB888_to_RGB<false>; + qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBA8888_Premultiplied] = convert_RGB888_to_RGB<false>; #endif - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, // self - }, // Format_BGR888 -}; -InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats] = -{ - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_Mono - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_MonoLSB - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, - convert_Indexed8_to_Alpha8_inplace, - convert_Indexed8_to_Grayscale8_inplace, - 0, 0, 0, 0, 0 - }, // Format_Indexed8 - { - 0, - 0, - 0, - 0, - 0, - mask_alpha_converter_inplace<QImage::Format_ARGB32>, - mask_alpha_converter_inplace<QImage::Format_ARGB32_Premultiplied>, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, - 0, 0, 0, 0, 0 - }, // Format_RGB32 - { - 0, - 0, - 0, - 0, - mask_alpha_converter_inplace<QImage::Format_RGB32>, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_ARGB_to_RGBA_inplace<QImage::Format_RGBX8888>, - convert_ARGB_to_RGBA_inplace<QImage::Format_RGBA8888>, - 0, - 0, - convert_ARGB_to_A2RGB30_inplace<PixelOrderBGR, false>, - 0, - convert_ARGB_to_A2RGB30_inplace<PixelOrderRGB, false>, - 0, 0, - 0, 0, 0, 0, 0 - }, // Format_ARGB32 - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_ARGB_to_RGBA_inplace<QImage::Format_RGBA8888_Premultiplied>, - 0, 0, 0, 0, - 0, 0, - 0, 0, 0, 0, 0 - }, // Format_ARGB32_Premultiplied - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_RGB16 - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_ARGB8565_Premultiplied - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_RGB666 - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_ARGB6666_Premultiplied - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_RGB555 - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_ARGB8555_Premultiplied - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - convert_rgbswap_generic_inplace - }, // Format_RGB888 - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_RGB444 - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_ARGB4444_Premultiplied - { - 0, - 0, - 0, - 0, - convert_RGBA_to_ARGB_inplace<QImage::Format_RGB32>, - convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32>, - convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32_Premultiplied>, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_passthrough_inplace<QImage::Format_RGBA8888>, - convert_passthrough_inplace<QImage::Format_RGBA8888_Premultiplied>, - 0, - 0, - 0, - 0, - 0, 0, - 0, 0, 0, 0, 0 - }, // Format_RGBX8888 - { - 0, - 0, - 0, - 0, - convert_RGBA_to_ARGB_inplace<QImage::Format_RGB32>, - convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32>, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - mask_alpha_converter_rgbx_inplace, - 0, - 0, - 0, - convert_ARGB_to_A2RGB30_inplace<PixelOrderBGR, true>, - 0, - convert_ARGB_to_A2RGB30_inplace<PixelOrderRGB, true>, - 0, 0, - 0, 0, 0, 0, 0 - }, // Format_RGBA8888 - { - 0, - 0, - 0, - 0, - 0, - 0, - convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32_Premultiplied>, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_RGBA8888_Premultiplied - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, // self - convert_passthrough_inplace<QImage::Format_A2BGR30_Premultiplied>, - convert_rgbswap_generic_inplace, - convert_BGR30_to_A2RGB30_inplace, - 0, 0, - 0, 0, 0, 0, 0 - }, // Format_BGR30 - { - 0, - 0, - 0, - 0, - 0, - convert_A2RGB30_PM_to_ARGB_inplace<PixelOrderBGR, false>, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_A2RGB30_PM_to_ARGB_inplace<PixelOrderBGR, true>, - 0, - convert_A2RGB30_PM_to_RGB30_inplace<false>, - 0, // self - convert_A2RGB30_PM_to_RGB30_inplace<true>, - convert_rgbswap_generic_inplace, - 0, 0, 0, 0, 0, 0, 0 - }, // Format_A2BGR30_Premultiplied - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_rgbswap_generic_inplace, - convert_BGR30_to_A2RGB30_inplace, - 0, // self - convert_passthrough_inplace<QImage::Format_A2RGB30_Premultiplied>, - 0, 0, 0, 0, 0, 0, 0 - }, // Format_RGB30 - { - 0, - 0, - 0, - 0, - 0, - convert_A2RGB30_PM_to_ARGB_inplace<PixelOrderRGB, false>, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_A2RGB30_PM_to_ARGB_inplace<PixelOrderRGB, true>, - 0, - convert_A2RGB30_PM_to_RGB30_inplace<true>, - convert_rgbswap_generic_inplace, - convert_A2RGB30_PM_to_RGB30_inplace<false>, - 0, // self - 0, 0, - 0, 0, 0, 0, 0 - }, // Format_A2RGB30_Premultiplied - { - 0, - 0, - 0, - convert_Alpha8_to_Indexed8_inplace, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, - 0, // self - 0, - 0, 0, 0, 0, 0 - }, // Format_Alpha8 - { - 0, - 0, - 0, - convert_Grayscale8_to_Indexed8_inplace, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, - 0, - 0, // self - 0, 0, 0, 0, 0 - }, // Format_Grayscale8 - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, // self - convert_passthrough_inplace<QImage::Format_RGBA64>, - convert_passthrough_inplace<QImage::Format_RGBA64_Premultiplied>, - 0, 0 - }, // Format_RGBX64 - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - convert_RGBA64_to_RGBx64_inplace, - 0, // self - convert_RGBA64_to_RGBA64PM_inplace, - 0, 0 - }, // Format_RGBA64 - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - convert_RGBA64PM_to_RGBA64_inplace<true>, - convert_RGBA64PM_to_RGBA64_inplace<false>, - 0, // self - 0, 0 - }, // Format_RGBA64_Premultiplied - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_Grayscale16 - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - convert_rgbswap_generic_inplace, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_BGR888 -}; - -static void qInitImageConversions() -{ + qimage_converter_map[QImage::Format_RGBX16FPx4][QImage::Format_RGBA16FPx4] = convert_passthrough; + qimage_converter_map[QImage::Format_RGBX16FPx4][QImage::Format_RGBA16FPx4_Premultiplied] = convert_passthrough; + + qimage_converter_map[QImage::Format_RGBX32FPx4][QImage::Format_RGBA32FPx4] = convert_passthrough; + qimage_converter_map[QImage::Format_RGBX32FPx4][QImage::Format_RGBA32FPx4_Premultiplied] = convert_passthrough; + + qimage_converter_map[QImage::Format_CMYK8888][QImage::Format_CMYK8888] = convert_passthrough; + qimage_converter_map[QImage::Format_RGB32][QImage::Format_CMYK8888] = convert_ARGB32_to_CMYK8888<false>; + qimage_converter_map[QImage::Format_ARGB32][QImage::Format_CMYK8888] = convert_ARGB32_to_CMYK8888<false>; + qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_CMYK8888] = convert_ARGB32_to_CMYK8888<true>; + + // Inline converters: + qimage_inplace_converter_map[QImage::Format_Indexed8][QImage::Format_Grayscale8] = + convert_Indexed8_to_Grayscale8_inplace; + qimage_inplace_converter_map[QImage::Format_Indexed8][QImage::Format_Alpha8] = + convert_Indexed8_to_Alpha8_inplace; + + qimage_inplace_converter_map[QImage::Format_RGB32][QImage::Format_ARGB32] = + mask_alpha_converter_inplace<QImage::Format_ARGB32>; + qimage_inplace_converter_map[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = + mask_alpha_converter_inplace<QImage::Format_ARGB32_Premultiplied>; + + qimage_inplace_converter_map[QImage::Format_ARGB32][QImage::Format_RGB32] = + mask_alpha_converter_inplace<QImage::Format_RGB32>; + qimage_inplace_converter_map[QImage::Format_ARGB32][QImage::Format_RGBX8888] = + convert_ARGB_to_RGBA_inplace<QImage::Format_RGBX8888>; + qimage_inplace_converter_map[QImage::Format_ARGB32][QImage::Format_RGBA8888] = + convert_ARGB_to_RGBA_inplace<QImage::Format_RGBA8888>; + qimage_inplace_converter_map[QImage::Format_ARGB32][QImage::Format_A2BGR30_Premultiplied] = + convert_ARGB_to_A2RGB30_inplace<PixelOrderBGR, false>; + qimage_inplace_converter_map[QImage::Format_ARGB32][QImage::Format_A2RGB30_Premultiplied] = + convert_ARGB_to_A2RGB30_inplace<PixelOrderRGB, false>; + + qimage_inplace_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = + convert_ARGB_to_RGBA_inplace<QImage::Format_RGBA8888_Premultiplied>; + + qimage_inplace_converter_map[QImage::Format_RGB888][QImage::Format_BGR888] = + convert_rgbswap_generic_inplace; + + qimage_inplace_converter_map[QImage::Format_RGBX8888][QImage::Format_RGB32] = + convert_RGBA_to_ARGB_inplace<QImage::Format_RGB32>; + qimage_inplace_converter_map[QImage::Format_RGBX8888][QImage::Format_ARGB32] = + convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32>; + qimage_inplace_converter_map[QImage::Format_RGBX8888][QImage::Format_ARGB32_Premultiplied] = + convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32_Premultiplied>; + qimage_inplace_converter_map[QImage::Format_RGBX8888][QImage::Format_RGBA8888] = + convert_passthrough_inplace<QImage::Format_RGBA8888>; + qimage_inplace_converter_map[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = + convert_passthrough_inplace<QImage::Format_RGBA8888_Premultiplied>; + + qimage_inplace_converter_map[QImage::Format_RGBA8888][QImage::Format_RGB32] = + convert_RGBA_to_ARGB_inplace<QImage::Format_RGB32>; + qimage_inplace_converter_map[QImage::Format_RGBA8888][QImage::Format_ARGB32] = + convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32>; + qimage_inplace_converter_map[QImage::Format_RGBA8888][QImage::Format_RGBX8888] = + mask_alpha_converter_rgbx_inplace; + qimage_inplace_converter_map[QImage::Format_RGBA8888][QImage::Format_A2BGR30_Premultiplied] = + convert_ARGB_to_A2RGB30_inplace<PixelOrderBGR, true>; + qimage_inplace_converter_map[QImage::Format_RGBA8888][QImage::Format_A2RGB30_Premultiplied] = + convert_ARGB_to_A2RGB30_inplace<PixelOrderRGB, true>; + + qimage_inplace_converter_map[QImage::Format_RGBA8888_Premultiplied][QImage::Format_ARGB32_Premultiplied] = + convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32_Premultiplied>; + + qimage_inplace_converter_map[QImage::Format_BGR30][QImage::Format_A2BGR30_Premultiplied] = + convert_passthrough_inplace<QImage::Format_A2BGR30_Premultiplied>; + qimage_inplace_converter_map[QImage::Format_BGR30][QImage::Format_RGB30] = + convert_rgbswap_generic_inplace; + qimage_inplace_converter_map[QImage::Format_BGR30][QImage::Format_A2RGB30_Premultiplied] = + convert_BGR30_to_A2RGB30_inplace; + + qimage_inplace_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_ARGB32] = + convert_A2RGB30_PM_to_ARGB_inplace<PixelOrderBGR, false>; + qimage_inplace_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGBA8888] = + convert_A2RGB30_PM_to_ARGB_inplace<PixelOrderBGR, true>; + qimage_inplace_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_BGR30] = + convert_A2RGB30_PM_to_RGB30_inplace<false>; + qimage_inplace_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGB30] = + convert_A2RGB30_PM_to_RGB30_inplace<true>; + qimage_inplace_converter_map[QImage::Format_A2BGR30_Premultiplied][QImage::Format_A2RGB30_Premultiplied] = + convert_rgbswap_generic_inplace; + + qimage_inplace_converter_map[QImage::Format_RGB30][QImage::Format_BGR30] = + convert_rgbswap_generic_inplace; + qimage_inplace_converter_map[QImage::Format_RGB30][QImage::Format_A2BGR30_Premultiplied] = + convert_BGR30_to_A2RGB30_inplace; + qimage_inplace_converter_map[QImage::Format_RGB30][QImage::Format_A2RGB30_Premultiplied] = + convert_passthrough_inplace<QImage::Format_A2RGB30_Premultiplied>; + + qimage_inplace_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_ARGB32] = + convert_A2RGB30_PM_to_ARGB_inplace<PixelOrderRGB, false>; + qimage_inplace_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGBA8888] = + convert_A2RGB30_PM_to_ARGB_inplace<PixelOrderRGB, true>; + qimage_inplace_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_BGR30] = + convert_A2RGB30_PM_to_RGB30_inplace<true>; + qimage_inplace_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_A2BGR30_Premultiplied] = + convert_rgbswap_generic_inplace; + qimage_inplace_converter_map[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGB30] = + convert_A2RGB30_PM_to_RGB30_inplace<false>; + + qimage_inplace_converter_map[QImage::Format_Grayscale8][QImage::Format_Indexed8] = + convert_Grayscale8_to_Indexed8_inplace; + qimage_inplace_converter_map[QImage::Format_Alpha8][QImage::Format_Indexed8] = + convert_Alpha8_to_Indexed8_inplace; + + qimage_inplace_converter_map[QImage::Format_RGBX64][QImage::Format_RGBA64] = + convert_passthrough_inplace<QImage::Format_RGBA64>; + qimage_inplace_converter_map[QImage::Format_RGBX64][QImage::Format_RGBA64_Premultiplied] = + convert_passthrough_inplace<QImage::Format_RGBA64_Premultiplied>; + + qimage_inplace_converter_map[QImage::Format_RGBA64][QImage::Format_RGBX64] = + convert_RGBA64_to_RGBx64_inplace; + + qimage_inplace_converter_map[QImage::Format_BGR888][QImage::Format_RGB888] = + convert_rgbswap_generic_inplace; + + qimage_inplace_converter_map[QImage::Format_RGBX16FPx4][QImage::Format_RGBA16FPx4] = + convert_passthrough_inplace<QImage::Format_RGBA16FPx4>; + qimage_inplace_converter_map[QImage::Format_RGBX16FPx4][QImage::Format_RGBA16FPx4_Premultiplied] = + convert_passthrough_inplace<QImage::Format_RGBA16FPx4_Premultiplied>; + + qimage_inplace_converter_map[QImage::Format_RGBX32FPx4][QImage::Format_RGBA32FPx4] = + convert_passthrough_inplace<QImage::Format_RGBA32FPx4>; + qimage_inplace_converter_map[QImage::Format_RGBX32FPx4][QImage::Format_RGBA32FPx4_Premultiplied] = + convert_passthrough_inplace<QImage::Format_RGBA32FPx4_Premultiplied>; + + // Now architecture specific conversions: #if defined(__SSE2__) && defined(QT_COMPILER_SUPPORTS_SSSE3) if (qCpuHasFeature(SSSE3)) { extern void convert_RGB888_to_RGB32_ssse3(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); |