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>
This commit is contained in:
parent
9a92e26dcd
commit
2a54229f90
@ -170,6 +170,7 @@ qt_internal_add_module(Gui
|
||||
painting/qcolortrclut.cpp painting/qcolortrclut_p.h
|
||||
painting/qcompositionfunctions.cpp
|
||||
painting/qcosmeticstroker.cpp painting/qcosmeticstroker_p.h
|
||||
painting/qcmyk_p.h
|
||||
painting/qdatabuffer_p.h
|
||||
painting/qdrawhelper_p.h
|
||||
painting/qdrawhelper_x86_p.h
|
||||
|
@ -304,6 +304,7 @@ bool QImageData::checkForAlphaPixels() const
|
||||
case QImage::Format_RGBX64:
|
||||
case QImage::Format_RGBX16FPx4:
|
||||
case QImage::Format_RGBX32FPx4:
|
||||
case QImage::Format_CMYK32:
|
||||
break;
|
||||
case QImage::Format_Invalid:
|
||||
case QImage::NImageFormats:
|
||||
@ -360,7 +361,7 @@ bool QImageData::checkForAlphaPixels() const
|
||||
refer to the \l{How to Create Qt Plugins}{Plugin HowTo}.
|
||||
|
||||
\warning Painting on a QImage with the format
|
||||
QImage::Format_Indexed8 is not supported.
|
||||
QImage::Format_Indexed8 or QImage::Format_CMYK32 is not supported.
|
||||
|
||||
\tableofcontents
|
||||
|
||||
@ -742,8 +743,9 @@ bool QImageData::checkForAlphaPixels() const
|
||||
\value Format_RGBA32FPx4 The image is stored using a 4 32-bit floating point RGBA format (32FP-32FP-32FP-32FP). (added in Qt 6.2)
|
||||
\value Format_RGBA32FPx4_Premultiplied The image is stored using a premultiplied 4 32-bit floating point
|
||||
RGBA format (32FP-32FP-32FP-32FP). (added in Qt 6.2)
|
||||
\value Format_CMYK32 The image is stored using a 32 bit CMYK format (0xCCMMYYKK). (added in Qt 6.8)
|
||||
|
||||
\note Drawing into a QImage with QImage::Format_Indexed8 is not
|
||||
\note Drawing into a QImage with format QImage::Format_Indexed8 or QImage::Format_CMYK32 is not
|
||||
supported.
|
||||
|
||||
\note Avoid most rendering directly to most of these formats using QPainter. Rendering
|
||||
@ -5727,6 +5729,19 @@ static constexpr QPixelFormat pixelformats[] = {
|
||||
/*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
|
||||
/*INTERPRETATION*/ QPixelFormat::FloatingPoint,
|
||||
/*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
|
||||
//QImage::Format_CMYK32:
|
||||
QPixelFormat(QPixelFormat::CMYK,
|
||||
/*RED*/ 8,
|
||||
/*GREEN*/ 8,
|
||||
/*BLUE*/ 8,
|
||||
/*FOURTH*/ 8,
|
||||
/*FIFTH*/ 0,
|
||||
/*ALPHA*/ 0,
|
||||
/*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
|
||||
/*ALPHA POSITION*/ QPixelFormat::AtBeginning,
|
||||
/*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
|
||||
/*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
|
||||
/*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
|
||||
};
|
||||
static_assert(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats);
|
||||
|
||||
|
@ -75,6 +75,7 @@ public:
|
||||
Format_RGBX32FPx4,
|
||||
Format_RGBA32FPx4,
|
||||
Format_RGBA32FPx4_Premultiplied,
|
||||
Format_CMYK32,
|
||||
#ifndef Q_QDOC
|
||||
NImageFormats
|
||||
#endif
|
||||
|
@ -4,6 +4,7 @@
|
||||
#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>
|
||||
@ -2454,6 +2455,34 @@ static bool convert_Grayscale8_to_Indexed8_inplace(QImageData *data, Qt::ImageCo
|
||||
return true;
|
||||
}
|
||||
|
||||
template <bool SourceIsPremultiplied>
|
||||
static void convert_ARGB32_to_CMYK32(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
|
||||
{
|
||||
Q_ASSERT(src->format == QImage::Format_RGB32 ||
|
||||
src->format == QImage::Format_ARGB32 ||
|
||||
src->format == QImage::Format_ARGB32_Premultiplied);
|
||||
Q_ASSERT(dest->format == QImage::Format_CMYK32);
|
||||
Q_ASSERT(src->width == dest->width);
|
||||
Q_ASSERT(src->height == dest->height);
|
||||
|
||||
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);
|
||||
|
||||
for (int x = 0; x < src->width; ++x) {
|
||||
QRgb sourcePixel = srcRgba[x];
|
||||
if constexpr (SourceIsPremultiplied)
|
||||
sourcePixel = qUnpremultiply(sourcePixel);
|
||||
|
||||
destCmyk[x] = QCmyk32::fromRgba(sourcePixel).toUint();
|
||||
}
|
||||
|
||||
src_data += src->bytes_per_line;;
|
||||
dest_data += dest->bytes_per_line;
|
||||
}
|
||||
}
|
||||
|
||||
// first index source, second dest
|
||||
Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats] = {};
|
||||
@ -2590,6 +2619,11 @@ static void qInitImageConversions()
|
||||
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_CMYK32][QImage::Format_CMYK32] = convert_passthrough;
|
||||
qimage_converter_map[QImage::Format_RGB32][QImage::Format_CMYK32] = convert_ARGB32_to_CMYK32<false>;
|
||||
qimage_converter_map[QImage::Format_ARGB32][QImage::Format_CMYK32] = convert_ARGB32_to_CMYK32<false>;
|
||||
qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_CMYK32] = convert_ARGB32_to_CMYK32<true>;
|
||||
|
||||
// Inline converters:
|
||||
qimage_inplace_converter_map[QImage::Format_Indexed8][QImage::Format_Grayscale8] =
|
||||
convert_Indexed8_to_Grayscale8_inplace;
|
||||
|
@ -195,6 +195,9 @@ inline int qt_depthForFormat(QImage::Format format)
|
||||
case QImage::Format_RGBA32FPx4_Premultiplied:
|
||||
depth = 128;
|
||||
break;
|
||||
case QImage::Format_CMYK32:
|
||||
depth = 32;
|
||||
break;
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
@ -248,6 +251,7 @@ inline QImage::Format qt_opaqueVersion(QImage::Format format)
|
||||
case QImage::Format_RGBX32FPx4:
|
||||
case QImage::Format_Grayscale8:
|
||||
case QImage::Format_Grayscale16:
|
||||
case QImage::Format_CMYK32:
|
||||
return format;
|
||||
case QImage::Format_Mono:
|
||||
case QImage::Format_MonoLSB:
|
||||
@ -311,6 +315,7 @@ inline QImage::Format qt_alphaVersion(QImage::Format format)
|
||||
case QImage::Format_Alpha8:
|
||||
case QImage::Format_Grayscale8:
|
||||
case QImage::Format_Invalid:
|
||||
case QImage::Format_CMYK32:
|
||||
case QImage::NImageFormats:
|
||||
break;
|
||||
}
|
||||
|
88
src/gui/painting/qcmyk_p.h
Normal file
88
src/gui/painting/qcmyk_p.h
Normal file
@ -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
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -321,7 +321,9 @@ static QLatin1String formatToString(QImage::Format format)
|
||||
return QLatin1String("RGBA32FPx4");
|
||||
case QImage::Format_RGBA32FPx4_Premultiplied:
|
||||
return QLatin1String("RGBA32FPx4pm");
|
||||
default:
|
||||
case QImage::Format_CMYK32:
|
||||
return QLatin1String("CMYK32");
|
||||
case QImage::NImageFormats:
|
||||
break;
|
||||
};
|
||||
Q_UNREACHABLE();
|
||||
@ -1507,6 +1509,8 @@ void tst_QImage::setPixelWithAlpha_data()
|
||||
continue;
|
||||
if (c == QImage::Format_Alpha8)
|
||||
continue;
|
||||
if (c == QImage::Format_CMYK32)
|
||||
continue;
|
||||
QTest::newRow(qPrintable(formatToString(QImage::Format(c)))) << QImage::Format(c);
|
||||
}
|
||||
}
|
||||
@ -2568,7 +2572,8 @@ void tst_QImage::rgbSwapped_data()
|
||||
for (int i = QImage::Format_Indexed8; i < QImage::NImageFormats; ++i) {
|
||||
if (i == QImage::Format_Alpha8
|
||||
|| i == QImage::Format_Grayscale8
|
||||
|| i == QImage::Format_Grayscale16) {
|
||||
|| i == QImage::Format_Grayscale16
|
||||
|| i == QImage::Format_CMYK32) {
|
||||
continue;
|
||||
}
|
||||
QTest::addRow("%s", formatToString(QImage::Format(i)).data()) << QImage::Format(i);
|
||||
@ -3050,13 +3055,15 @@ void tst_QImage::inplaceRgbConversion_data()
|
||||
for (int i = QImage::Format_RGB32; i < QImage::NImageFormats; ++i) {
|
||||
if (i == QImage::Format_Alpha8
|
||||
|| i == QImage::Format_Grayscale8
|
||||
|| i == QImage::Format_Grayscale16) {
|
||||
|| i == QImage::Format_Grayscale16
|
||||
|| i == QImage::Format_CMYK32) {
|
||||
continue;
|
||||
}
|
||||
for (int j = QImage::Format_RGB32; j < QImage::NImageFormats; ++j) {
|
||||
if (j == QImage::Format_Alpha8
|
||||
|| j == QImage::Format_Grayscale8
|
||||
|| j == QImage::Format_Grayscale16) {
|
||||
|| j == QImage::Format_Grayscale16
|
||||
|| j == QImage::Format_CMYK32) {
|
||||
continue;
|
||||
}
|
||||
if (i == j)
|
||||
@ -3345,7 +3352,8 @@ void tst_QImage::invertPixelsRGB_data()
|
||||
for (int i = QImage::Format_RGB32; i < QImage::NImageFormats; ++i) {
|
||||
if (i == QImage::Format_Alpha8
|
||||
|| i == QImage::Format_Grayscale8
|
||||
|| i == QImage::Format_Grayscale16) {
|
||||
|| i == QImage::Format_Grayscale16
|
||||
|| i == QImage::Format_CMYK32) {
|
||||
continue;
|
||||
}
|
||||
QTest::addRow("%s", formatToString(QImage::Format(i)).data()) << QImage::Format(i);
|
||||
|
@ -2784,7 +2784,7 @@ void tst_QPainter::monoImages()
|
||||
for (int i = 1; i < QImage::NImageFormats; ++i) {
|
||||
for (int j = 0; j < numColorPairs; ++j) {
|
||||
const QImage::Format format = QImage::Format(i);
|
||||
if (format == QImage::Format_Indexed8)
|
||||
if (format == QImage::Format_Indexed8 || format == QImage::Format_CMYK32)
|
||||
continue;
|
||||
|
||||
QImage img(2, 2, format);
|
||||
@ -3554,9 +3554,13 @@ void tst_QPainter::drawImage_data()
|
||||
|
||||
for (int srcFormat = QImage::Format_Mono; srcFormat < QImage::NImageFormats; ++srcFormat) {
|
||||
for (int dstFormat = QImage::Format_Mono; dstFormat < QImage::NImageFormats; ++dstFormat) {
|
||||
// Indexed8 can't be painted to, and Alpha8 can't hold a color.
|
||||
if (dstFormat == QImage::Format_Indexed8 || dstFormat == QImage::Format_Alpha8)
|
||||
// Indexed8 and CMYK32 can't be painted to, and Alpha8 can't hold a color.
|
||||
if (dstFormat == QImage::Format_Indexed8 ||
|
||||
dstFormat == QImage::Format_CMYK32 ||
|
||||
dstFormat == QImage::Format_Alpha8) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int odd_x = 0; odd_x <= 1; ++odd_x) {
|
||||
for (int odd_width = 0; odd_width <= 1; ++odd_width) {
|
||||
QTest::addRow("srcFormat %d, dstFormat %d, odd x: %d, odd width: %d",
|
||||
|
@ -173,6 +173,7 @@ const char *PaintCommands::imageFormatTable[] = {
|
||||
"RGBx32FPx4",
|
||||
"RGBA32FPx4",
|
||||
"RGBA32FPx4_Premultiplied",
|
||||
"CMYK32",
|
||||
};
|
||||
|
||||
const char *PaintCommands::renderHintTable[] = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user