diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2023-10-18 18:42:01 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2024-04-03 18:31:36 +0100 |
commit | 2a54229f90b5abcca04763834aa5b9d48e19131f (patch) | |
tree | e86a2b6dd440f2919c7a1f7dac1a8c71e75f3c14 /src/gui/painting | |
parent | 9a92e26dcdb40215f2f5d187a09b6b2b73934809 (diff) |
GUI: add CMYK painting support
This commit adds a CMYK 8bpp format to QImage. The idea is to enable the
transport of CMYK images inside Qt, for instance to be loaded/saved from
files or painted on CMYK capable paint devices (e.g. PDF).
Also, rasterization support *from* a CMYK image is added (on top of a
RGB surface), as well as CMYK image scaling/conversion.
Conversion and rasterization between CMYK and RGB isn't particularly
optimized nor it honors any colorspaces yet. The overall idea is to
match 1:1 the existing behavior of CMYK QColor (which get naively
changed to RGB; there isn't colorspace support in QPainter yet).
There are no plans to add rasterization *towards* CMYK.
Image save/load in native CMYK formats will be added in future commits.
This work has been kindly sponsored by the QGIS project
(https://qgis.org/).
[ChangeLog][QtGui] Support for 8-bit CMYK images has been added.
Change-Id: I4b024cd4c15119c669b6ddd450418a9e425587f8
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'src/gui/painting')
-rw-r--r-- | src/gui/painting/qcmyk_p.h | 88 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper.cpp | 73 | ||||
-rw-r--r-- | src/gui/painting/qpainter.cpp | 9 | ||||
-rw-r--r-- | src/gui/painting/qpixellayout.cpp | 106 |
4 files changed, 256 insertions, 20 deletions
diff --git a/src/gui/painting/qcmyk_p.h b/src/gui/painting/qcmyk_p.h new file mode 100644 index 0000000000..d00a4b5a6e --- /dev/null +++ b/src/gui/painting/qcmyk_p.h @@ -0,0 +1,88 @@ +// Copyright (C) 2023 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 + +#ifndef QCMYK_P_H +#define QCMYK_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtGui/private/qtguiglobal_p.h> +#include <QtGui/qcolor.h> + +QT_BEGIN_NAMESPACE + +class QCmyk32 +{ +private: + uint m_cmyk = 0; + +public: + QCmyk32() = default; + + constexpr QCmyk32(int cyan, int magenta, int yellow, int black) : +#if QT_BYTE_ORDER == Q_BIG_ENDIAN + m_cmyk(cyan << 24 | magenta << 16 | yellow << 8 | black) +#else + m_cmyk(cyan | magenta << 8 | yellow << 16 | black << 24) +#endif + { + } + +#if QT_BYTE_ORDER == Q_BIG_ENDIAN + constexpr int cyan() const noexcept { return (m_cmyk >> 24) & 0xff; } + constexpr int magenta() const noexcept { return (m_cmyk >> 16) & 0xff; } + constexpr int yellow() const noexcept { return (m_cmyk >> 8) & 0xff; } + constexpr int black() const noexcept { return (m_cmyk ) & 0xff; } +#else + constexpr int cyan() const noexcept { return (m_cmyk ) & 0xff; } + constexpr int magenta() const noexcept { return (m_cmyk >> 8) & 0xff; } + constexpr int yellow() const noexcept { return (m_cmyk >> 16) & 0xff; } + constexpr int black() const noexcept { return (m_cmyk >> 24) & 0xff; } +#endif + + QColor toColor() const noexcept + { + return QColor::fromCmyk(cyan(), magenta(), yellow(), black()); + } + + constexpr uint toUint() const noexcept + { + return m_cmyk; + } + + constexpr static QCmyk32 fromCmyk32(uint cmyk) noexcept + { + QCmyk32 result; + result.m_cmyk = cmyk; + return result; + } + + static QCmyk32 fromRgba(QRgb rgba) noexcept + { + const QColor c = QColor(rgba).toCmyk(); + return QCmyk32(c.cyan(), c.magenta(), c.yellow(), c.black()); + } + + static QCmyk32 fromColor(const QColor &color) noexcept + { + QColor c = color.toCmyk(); + return QCmyk32(c.cyan(), c.magenta(), c.yellow(), c.black()); + } +}; + +static_assert(sizeof(QCmyk32) == sizeof(int)); +static_assert(alignof(QCmyk32) == alignof(int)); +static_assert(std::is_standard_layout_v<QCmyk32>); + +QT_END_NAMESPACE + +#endif // QCMYK_P_H diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 218c9d1656..1ffe88e459 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -176,7 +176,7 @@ static void QT_FASTCALL convertRGBA32FPMToRGBA64PM(QRgba64 *buffer, int count) } } -static Convert64Func convert64ToRGBA64PM[QImage::NImageFormats] = { +static Convert64Func convert64ToRGBA64PM[] = { nullptr, nullptr, nullptr, @@ -213,7 +213,10 @@ static Convert64Func convert64ToRGBA64PM[QImage::NImageFormats] = { convertRGBA32FPMToRGBA64PM, convertRGBA32FToRGBA64PM, convertRGBA32FPMToRGBA64PM, + nullptr, }; + +static_assert(std::size(convert64ToRGBA64PM) == QImage::NImageFormats); #endif #if QT_CONFIG(raster_fp) @@ -247,7 +250,7 @@ static void QT_FASTCALL convertRGBA16FToRGBA32F(QRgbaFloat32 *buffer, const quin qFloatFromFloat16((float *)buffer, (const qfloat16 *)src, count * 4); } -static Convert64ToFPFunc convert64ToRGBA32F[QImage::NImageFormats] = { +static Convert64ToFPFunc convert64ToRGBA32F[] = { nullptr, nullptr, nullptr, @@ -284,8 +287,11 @@ static Convert64ToFPFunc convert64ToRGBA32F[QImage::NImageFormats] = { nullptr, nullptr, nullptr, + nullptr, }; +static_assert(std::size(convert64ToRGBA32F) == QImage::NImageFormats); + static void convertRGBA32FToRGBA32FPM(QRgbaFloat32 *buffer, int count) { for (int i = 0; i < count; ++i) @@ -353,7 +359,7 @@ static uint *QT_FASTCALL destFetchUndefined(uint *buffer, QRasterBuffer *, int, return buffer; } -static DestFetchProc destFetchProc[QImage::NImageFormats] = +static DestFetchProc destFetchProc[] = { nullptr, // Format_Invalid destFetchMono, // Format_Mono, @@ -391,8 +397,11 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] = destFetch, // Format_RGBX32FPx4 destFetch, // Format_RGBA32FPx4 destFetch, // Format_RGBA32FPx4_Premultiplied + destFetch, // Format_CMYK32 }; +static_assert(std::size(destFetchProc) == QImage::NImageFormats); + #if QT_CONFIG(raster_64bit) static QRgba64 *QT_FASTCALL destFetch64(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) { @@ -410,7 +419,7 @@ static QRgba64 * QT_FASTCALL destFetch64Undefined(QRgba64 *buffer, QRasterBuffer return buffer; } -static DestFetchProc64 destFetchProc64[QImage::NImageFormats] = +static DestFetchProc64 destFetchProc64[] = { nullptr, // Format_Invalid nullptr, // Format_Mono, @@ -448,7 +457,10 @@ static DestFetchProc64 destFetchProc64[QImage::NImageFormats] = destFetch64, // Format_RGBX32FPx4 destFetch64, // Format_RGBA32FPx4 destFetch64, // Format_RGBA32FPx4_Premultiplied + destFetch64, // Format_CMYK32 }; + +static_assert(std::size(destFetchProc64) == QImage::NImageFormats); #endif #if QT_CONFIG(raster_fp) @@ -466,7 +478,7 @@ static QRgbaFloat32 *QT_FASTCALL destFetchFPUndefined(QRgbaFloat32 *buffer, QRas { return buffer; } -static DestFetchProcFP destFetchProcFP[QImage::NImageFormats] = +static DestFetchProcFP destFetchProcFP[] = { nullptr, // Format_Invalid nullptr, // Format_Mono, @@ -504,7 +516,10 @@ static DestFetchProcFP destFetchProcFP[QImage::NImageFormats] = destFetchRGBFP, // Format_RGBX32FPx4 destFetchFP, // Format_RGBA32FPx4 destFetchRGBFP, // Format_RGBA32FPx4_Premultiplied + destFetchFP, // Format_CMYK32 }; + +static_assert(std::size(destFetchProcFP) == QImage::NImageFormats); #endif /* @@ -657,7 +672,7 @@ static void QT_FASTCALL destStoreGray16(QRasterBuffer *rasterBuffer, int x, int } } -static DestStoreProc destStoreProc[QImage::NImageFormats] = +static DestStoreProc destStoreProc[] = { nullptr, // Format_Invalid destStoreMono, // Format_Mono, @@ -695,8 +710,11 @@ static DestStoreProc destStoreProc[QImage::NImageFormats] = destStore, // Format_RGBX32FPx4 destStore, // Format_RGBA32FPx4 destStore, // Format_RGBA32FPx4_Premultiplied + destStore, // Format_CMYK32 }; +static_assert(std::size(destStoreProc) == QImage::NImageFormats); + #if QT_CONFIG(raster_64bit) static void QT_FASTCALL destStore64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) { @@ -757,7 +775,7 @@ static void QT_FASTCALL destStore64Gray16(QRasterBuffer *rasterBuffer, int x, in } } -static DestStoreProc64 destStoreProc64[QImage::NImageFormats] = +static DestStoreProc64 destStoreProc64[] = { nullptr, // Format_Invalid nullptr, // Format_Mono, @@ -795,7 +813,10 @@ static DestStoreProc64 destStoreProc64[QImage::NImageFormats] = destStore64, // Format_RGBX32FPx4 destStore64, // Format_RGBA32FPx4 destStore64, // Format_RGBA32FPx4_Premultiplied + destStore64, // Format_CMYK32 }; + +static_assert(std::size(destStoreProc64) == QImage::NImageFormats); #endif #if QT_CONFIG(raster_fp) @@ -3070,7 +3091,7 @@ static const QRgbaFloat32 *QT_FASTCALL fetchTransformedBilinearFP(QRgbaFloat32 * #endif // QT_CONFIG(raster_fp) // FetchUntransformed can have more specialized methods added depending on SIMD features. -static SourceFetchProc sourceFetchUntransformed[QImage::NImageFormats] = { +static SourceFetchProc sourceFetchUntransformed[] = { nullptr, // Invalid fetchUntransformed, // Mono fetchUntransformed, // MonoLsb @@ -3107,9 +3128,12 @@ static SourceFetchProc sourceFetchUntransformed[QImage::NImageFormats] = { fetchUntransformed, // RGBX32Px4 fetchUntransformed, // RGBA32FPx4 fetchUntransformed, // RGBA32FPx4_Premultiplied + fetchUntransformed, // CMYK32 }; -static const SourceFetchProc sourceFetchGeneric[NBlendTypes] = { +static_assert(std::size(sourceFetchUntransformed) == QImage::NImageFormats); + +static const SourceFetchProc sourceFetchGeneric[] = { fetchUntransformed, // Untransformed fetchUntransformed, // Tiled fetchTransformed<BlendTransformed, QPixelLayout::BPPNone>, // Transformed @@ -3118,7 +3142,9 @@ static const SourceFetchProc sourceFetchGeneric[NBlendTypes] = { fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPPNone> // TransformedBilinearTiled }; -static SourceFetchProc sourceFetchARGB32PM[NBlendTypes] = { +static_assert(std::size(sourceFetchGeneric) == NBlendTypes); + +static SourceFetchProc sourceFetchARGB32PM[] = { fetchUntransformedARGB32PM, // Untransformed fetchUntransformedARGB32PM, // Tiled fetchTransformed<BlendTransformed, QPixelLayout::BPP32>, // Transformed @@ -3127,7 +3153,9 @@ static SourceFetchProc sourceFetchARGB32PM[NBlendTypes] = { fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled> // BilinearTiled }; -static SourceFetchProc sourceFetchAny16[NBlendTypes] = { +static_assert(std::size(sourceFetchARGB32PM) == NBlendTypes); + +static SourceFetchProc sourceFetchAny16[] = { fetchUntransformed, // Untransformed fetchUntransformed, // Tiled fetchTransformed<BlendTransformed, QPixelLayout::BPP16>, // Transformed @@ -3136,7 +3164,9 @@ static SourceFetchProc sourceFetchAny16[NBlendTypes] = { fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPP16> // TransformedBilinearTiled }; -static SourceFetchProc sourceFetchAny32[NBlendTypes] = { +static_assert(std::size(sourceFetchAny16) == NBlendTypes); + +static SourceFetchProc sourceFetchAny32[] = { fetchUntransformed, // Untransformed fetchUntransformed, // Tiled fetchTransformed<BlendTransformed, QPixelLayout::BPP32>, // Transformed @@ -3145,6 +3175,8 @@ static SourceFetchProc sourceFetchAny32[NBlendTypes] = { fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPP32> // TransformedBilinearTiled }; +static_assert(std::size(sourceFetchAny32) == NBlendTypes); + static inline SourceFetchProc getSourceFetch(TextureBlendType blendType, QImage::Format format) { if (format == QImage::Format_RGB32 || format == QImage::Format_ARGB32_Premultiplied) @@ -3159,7 +3191,7 @@ static inline SourceFetchProc getSourceFetch(TextureBlendType blendType, QImage: } #if QT_CONFIG(raster_64bit) -static const SourceFetchProc64 sourceFetchGeneric64[NBlendTypes] = { +static const SourceFetchProc64 sourceFetchGeneric64[] = { fetchUntransformed64, // Untransformed fetchUntransformed64, // Tiled fetchTransformed64<BlendTransformed>, // Transformed @@ -3168,7 +3200,9 @@ static const SourceFetchProc64 sourceFetchGeneric64[NBlendTypes] = { fetchTransformedBilinear64<BlendTransformedBilinearTiled> // BilinearTiled }; -static const SourceFetchProc64 sourceFetchRGBA64PM[NBlendTypes] = { +static_assert(std::size(sourceFetchGeneric64) == NBlendTypes); + +static const SourceFetchProc64 sourceFetchRGBA64PM[] = { fetchUntransformedRGBA64PM, // Untransformed fetchUntransformedRGBA64PM, // Tiled fetchTransformed64<BlendTransformed>, // Transformed @@ -3177,6 +3211,8 @@ static const SourceFetchProc64 sourceFetchRGBA64PM[NBlendTypes] = { fetchTransformedBilinear64<BlendTransformedBilinearTiled> // BilinearTiled }; +static_assert(std::size(sourceFetchRGBA64PM) == NBlendTypes); + static inline SourceFetchProc64 getSourceFetch64(TextureBlendType blendType, QImage::Format format) { if (format == QImage::Format_RGBX64 || format == QImage::Format_RGBA64_Premultiplied) @@ -3186,7 +3222,7 @@ static inline SourceFetchProc64 getSourceFetch64(TextureBlendType blendType, QIm #endif #if QT_CONFIG(raster_fp) -static const SourceFetchProcFP sourceFetchGenericFP[NBlendTypes] = { +static const SourceFetchProcFP sourceFetchGenericFP[] = { fetchUntransformedFP, // Untransformed fetchUntransformedFP, // Tiled fetchTransformedFP<BlendTransformed>, // Transformed @@ -3195,6 +3231,8 @@ static const SourceFetchProcFP sourceFetchGenericFP[NBlendTypes] = { fetchTransformedBilinearFP<BlendTransformedBilinearTiled> // BilinearTiled }; +static_assert(std::size(sourceFetchGenericFP) == NBlendTypes); + static inline SourceFetchProcFP getSourceFetchFP(TextureBlendType blendType, QImage::Format /*format*/) { return sourceFetchGenericFP[blendType]; @@ -3612,7 +3650,6 @@ static inline Operator getOperator(const QSpanData *data, const QT_FT_Span *span { Operator op; bool solidSource = false; - switch(data->type) { case QSpanData::Solid: solidSource = data->solidColor.alphaF() >= 1.0f; @@ -5962,7 +5999,7 @@ static void qt_rectfill_fp32x4(QRasterBuffer *rasterBuffer, // Map table for destination image format. Contains function pointers // for blends of various types unto the destination -DrawHelper qDrawHelper[QImage::NImageFormats] = +DrawHelper qDrawHelper[] = { // Format_Invalid, { nullptr, nullptr, nullptr, nullptr, nullptr }, @@ -6239,6 +6276,8 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = }, }; +static_assert(std::size(qDrawHelper) == QImage::NImageFormats); + #if !defined(Q_PROCESSOR_X86) void qt_memfill64(quint64 *dest, quint64 color, qsizetype count) { diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 5b4a6b05ea..148cc6c5dd 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -1765,9 +1765,12 @@ bool QPainter::begin(QPaintDevice *pd) qWarning("QPainter::begin: Cannot paint on a null image"); qt_cleanup_painter_state(d); return false; - } else if (img->format() == QImage::Format_Indexed8) { - // Painting on indexed8 images is not supported. - qWarning("QPainter::begin: Cannot paint on an image with the QImage::Format_Indexed8 format"); + } else if (img->format() == QImage::Format_Indexed8 || + img->format() == QImage::Format_CMYK32) { + // Painting on these formats is not supported. + qWarning() << "QPainter::begin: Cannot paint on an image with the" + << img->format() + << "format"; qt_cleanup_painter_state(d); return false; } diff --git a/src/gui/painting/qpixellayout.cpp b/src/gui/painting/qpixellayout.cpp index e6dc774b2d..e94fbbff15 100644 --- a/src/gui/painting/qpixellayout.cpp +++ b/src/gui/painting/qpixellayout.cpp @@ -7,6 +7,7 @@ #include "qpixellayout_p.h" #include "qrgba64_p.h" #include <QtCore/private/qsimd_p.h> +#include <QtGui/private/qcmyk_p.h> QT_BEGIN_NAMESPACE @@ -1657,6 +1658,66 @@ static const QRgba64 *QT_FASTCALL fetchRGBA32FPMToRGBA64PM(QRgba64 *buffer, cons return buffer; } +inline const uint *qt_convertCMYK32ToARGB32PM(uint *buffer, const uint *src, int count) +{ + UNALIASED_CONVERSION_LOOP(buffer, src, count, [](uint s) { + const QColor color = QCmyk32::fromCmyk32(s).toColor(); + return color.rgba(); + }); + return buffer; +} + +static void QT_FASTCALL convertCMYK32ToARGB32PM(uint *buffer, int count, const QList<QRgb> *) +{ + qt_convertCMYK32ToARGB32PM(buffer, buffer, count); +} + +static const QRgba64 *QT_FASTCALL convertCMYK32ToToRGBA64PM(QRgba64 *buffer, const uint *src, int count, + const QList<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qPremultiply(QCmyk32::fromCmyk32(src[i]).toColor().rgba64()); + return buffer; +} + +static const uint *QT_FASTCALL fetchCMYK32ToARGB32PM(uint *buffer, const uchar *src, int index, int count, + const QList<QRgb> *, QDitherInfo *) +{ + const uint *s = reinterpret_cast<const uint *>(src) + index; + for (int i = 0; i < count; ++i) + buffer[i] = qPremultiply(QCmyk32::fromCmyk32(s[i]).toColor().rgba()); + return buffer; +} + +static const QRgba64 *QT_FASTCALL fetchCMYK32ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, + const QList<QRgb> *, QDitherInfo *) +{ + const uint *s = reinterpret_cast<const uint *>(src) + index; + for (int i = 0; i < count; ++i) + buffer[i] = qPremultiply(QCmyk32::fromCmyk32(s[i]).toColor().rgba64()); + return buffer; +} + +static void QT_FASTCALL storeCMYKFromARGB32PM(uchar *dest, const uint *src, int index, int count, + const QList<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + for (int i = 0; i < count; ++i) { + QColor c = qUnpremultiply(src[i]); + d[i] = QCmyk32::fromColor(c).toUint(); + } +} + +static void QT_FASTCALL storeCMYKFromRGB32(uchar *dest, const uint *src, int index, int count, + const QList<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + for (int i = 0; i < count; ++i) { + QColor c = src[i]; + d[i] = QCmyk32::fromColor(c).toUint(); + } +} + // Note: // convertToArgb32() assumes that no color channel is less than 4 bits. // storeRGBFromARGB32PM() assumes that no color channel is more than 8 bits. @@ -1779,6 +1840,10 @@ QPixelLayout qPixelLayouts[] = { convertPassThrough, nullptr, fetchRGB32FToRGB32, fetchRGBA32FPMToRGBA64PM, storeRGB32FFromRGB32, storeRGB32FFromRGB32 }, // Format_RGBA32FPx4_Premultiplied + { false, false, QPixelLayout::BPP32, nullptr, + convertCMYK32ToARGB32PM, convertCMYK32ToToRGBA64PM, + fetchCMYK32ToARGB32PM, fetchCMYK32ToRGBA64PM, + storeCMYKFromARGB32PM, storeCMYKFromRGB32 }, // Format_CMYK32 }; static_assert(std::size(qPixelLayouts) == QImage::NImageFormats); @@ -1916,6 +1981,14 @@ static void QT_FASTCALL storeRGBA32FPMFromRGBA64PM(uchar *dest, const QRgba64 *s d[i] = qConvertRgb64ToRgbaF32(src[i]); } +static void QT_FASTCALL storeCMYKFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, + const QList<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + for (int i = 0; i < count; ++i) + d[i] = QCmyk32::fromColor(QColor(src[i])).toUint(); +} + ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[] = { nullptr, nullptr, @@ -1953,6 +2026,7 @@ ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[] = { storeRGBX32FFromRGBA64PM, storeRGBA32FFromRGBA64PM, storeRGBA32FPMFromRGBA64PM, + storeCMYKFromRGBA64PM, }; static_assert(std::size(qStoreFromRGBA64PM) == QImage::NImageFormats); @@ -2002,6 +2076,15 @@ static const QRgbaFloat32 * QT_FASTCALL convertRGB30ToRGBA32F(QRgbaFloat32 *buff return buffer; } +static const QRgbaFloat32 * QT_FASTCALL convertCMYKToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count, + const QList<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) + QRgbaFloat32::fromArgb32(QCmyk32::fromCmyk32(src[i]).toColor().rgba()); + + return buffer; +} + ConvertToFPFunc qConvertToRGBA32F[] = { nullptr, convertIndexedTo<QRgbaFloat32>, @@ -2039,6 +2122,7 @@ ConvertToFPFunc qConvertToRGBA32F[] = { nullptr, nullptr, nullptr, + convertCMYKToRGBA32F, }; static_assert(std::size(qConvertToRGBA32F) == QImage::NImageFormats); @@ -2107,6 +2191,16 @@ static const QRgbaFloat32 *QT_FASTCALL fetchRGBA32F(QRgbaFloat32 *, const uchar return s; } +static const QRgbaFloat32 *QT_FASTCALL fetchCMYKToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count, + const QList<QRgb> *, QDitherInfo *) +{ + const uint *s = reinterpret_cast<const uint *>(src) + index; + for (int i = 0; i < count; ++i) + buffer[i] = QRgbaFloat32::fromArgb32(QCmyk32::fromCmyk32(s[i]).toColor().rgba()); + + return buffer; +} + FetchAndConvertPixelsFuncFP qFetchToRGBA32F[] = { nullptr, fetchIndexedToRGBA32F<QPixelLayout::BPP1MSB>, @@ -2144,6 +2238,7 @@ FetchAndConvertPixelsFuncFP qFetchToRGBA32F[] = { fetchRGBA32F, fetchRGBA32FToRGBA32F, fetchRGBA32F, + fetchCMYKToRGBA32F, }; static_assert(std::size(qFetchToRGBA32F) == QImage::NImageFormats); @@ -2284,6 +2379,16 @@ static void QT_FASTCALL storeRGBA32FPMFromRGBA32F(uchar *dest, const QRgbaFloat3 } } +static void QT_FASTCALL storeCMYKFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count, + const QList<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + for (int i = 0; i < count; ++i) { + // Yikes, this really needs enablers in QColor and friends + d[i] = QCmyk32::fromColor(QColor(src[i].toArgb32())).toUint(); + } +} + ConvertAndStorePixelsFuncFP qStoreFromRGBA32F[] = { nullptr, nullptr, @@ -2321,6 +2426,7 @@ ConvertAndStorePixelsFuncFP qStoreFromRGBA32F[] = { storeRGBX32FFromRGBA32F, storeRGBA32FFromRGBA32F, storeRGBA32FPMFromRGBA32F, + storeCMYKFromRGBA32F, }; static_assert(std::size(qStoreFromRGBA32F) == QImage::NImageFormats); |