summaryrefslogtreecommitdiffstats
path: root/src/gui/painting/qcolortransform.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/painting/qcolortransform.cpp')
-rw-r--r--src/gui/painting/qcolortransform.cpp511
1 files changed, 223 insertions, 288 deletions
diff --git a/src/gui/painting/qcolortransform.cpp b/src/gui/painting/qcolortransform.cpp
index b1231c3820..f54dac9f26 100644
--- a/src/gui/painting/qcolortransform.cpp
+++ b/src/gui/painting/qcolortransform.cpp
@@ -22,16 +22,6 @@
QT_BEGIN_NAMESPACE
-std::shared_ptr<QColorTrcLut> lutFromTrc(const QColorTrc &trc)
-{
- if (trc.m_type == QColorTrc::Type::Table)
- return QColorTrcLut::fromTransferTable(trc.m_table);
- if (trc.m_type == QColorTrc::Type::Function)
- return QColorTrcLut::fromTransferFunction(trc.m_fun);
- qWarning() << "TRC uninitialized";
- return nullptr;
-}
-
void QColorTransformPrivate::updateLutsIn() const
{
if (colorSpaceIn->lut.generated.loadAcquire())
@@ -46,12 +36,12 @@ void QColorTransformPrivate::updateLutsIn() const
}
if (colorSpaceIn->trc[0] == colorSpaceIn->trc[1] && colorSpaceIn->trc[0] == colorSpaceIn->trc[2]) {
- colorSpaceIn->lut[0] = lutFromTrc(colorSpaceIn->trc[0]);
+ colorSpaceIn->lut[0] = QColorTrcLut::fromTrc(colorSpaceIn->trc[0]);
colorSpaceIn->lut[1] = colorSpaceIn->lut[0];
colorSpaceIn->lut[2] = colorSpaceIn->lut[0];
} else {
for (int i = 0; i < 3; ++i)
- colorSpaceIn->lut[i] = lutFromTrc(colorSpaceIn->trc[i]);
+ colorSpaceIn->lut[i] = QColorTrcLut::fromTrc(colorSpaceIn->trc[i]);
}
colorSpaceIn->lut.generated.storeRelease(1);
@@ -70,12 +60,12 @@ void QColorTransformPrivate::updateLutsOut() const
}
if (colorSpaceOut->trc[0] == colorSpaceOut->trc[1] && colorSpaceOut->trc[0] == colorSpaceOut->trc[2]) {
- colorSpaceOut->lut[0] = lutFromTrc(colorSpaceOut->trc[0]);
+ colorSpaceOut->lut[0] = QColorTrcLut::fromTrc(colorSpaceOut->trc[0]);
colorSpaceOut->lut[1] = colorSpaceOut->lut[0];
colorSpaceOut->lut[2] = colorSpaceOut->lut[0];
} else {
for (int i = 0; i < 3; ++i)
- colorSpaceOut->lut[i] = lutFromTrc(colorSpaceOut->trc[i]);
+ colorSpaceOut->lut[i] = QColorTrcLut::fromTrc(colorSpaceOut->trc[i]);
}
colorSpaceOut->lut.generated.storeRelease(1);
@@ -390,6 +380,14 @@ template<>
inline int getAlpha<QRgba64>(const QRgba64 &p)
{ return p.alpha(); }
+template<typename T>
+static inline constexpr int getFactor();
+template<>
+inline constexpr int getFactor<QRgb>()
+{ return 255; }
+template<>
+inline constexpr int getFactor<QRgba64>()
+{ return 65535; }
#endif
template<typename T>
@@ -823,8 +821,9 @@ static void storePremultiplied(D *dst, const S *src, const QColorVector *buffer,
const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256));
constexpr bool isARGB = isArgb<D>();
+ static_assert(getFactor<D>() >= getFactor<S>());
for (qsizetype i = 0; i < len; ++i) {
- const int a = getAlpha<S>(src[i]);
+ const int a = getAlpha<S>(src[i]) * (getFactor<D>() / getFactor<S>());
__m128 vf = _mm_loadu_ps(&buffer[i].x);
__m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
__m128 va = _mm_mul_ps(_mm_set1_ps(a), iFF00);
@@ -905,8 +904,9 @@ static void storeUnpremultiplied(D *dst, const S *src, const QColorVector *buffe
{
const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
constexpr bool isARGB = isArgb<D>();
+ static_assert(getFactor<D>() >= getFactor<S>());
for (qsizetype i = 0; i < len; ++i) {
- const int a = getAlpha<S>(src[i]);
+ const int a = getAlpha<S>(src[i]) * (getFactor<D>() / getFactor<S>());
__m128 vf = _mm_loadu_ps(&buffer[i].x);
__m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
const int ridx = _mm_extract_epi16(v, 0);
@@ -1029,8 +1029,9 @@ static void storePremultiplied(D *dst, const S *src, const QColorVector *buffer,
{
const float iFF00 = 1.0f / (255 * 256);
constexpr bool isARGB = isArgb<D>();
+ static_assert(getFactor<D>() >= getFactor<S>());
for (qsizetype i = 0; i < len; ++i) {
- const int a = getAlpha<S>(src[i]);
+ const int a = getAlpha<S>(src[i]) * (getFactor<D>() / getFactor<S>());
float32x4_t vf = vld1q_f32(&buffer[i].x);
uint32x4_t v = vcvtq_u32_f32(vaddq_f32(vmulq_n_f32(vf, float(QColorTrcLut::Resolution)), vdupq_n_f32(0.5f)));
const int ridx = vgetq_lane_u32(v, 0);
@@ -1073,8 +1074,9 @@ static void storeUnpremultiplied(D *dst, const S *src, const QColorVector *buffe
const QColorTransformPrivate *d_ptr)
{
constexpr bool isARGB = isArgb<D>();
+ static_assert(getFactor<D>() >= getFactor<S>());
for (qsizetype i = 0; i < len; ++i) {
- const int a = getAlpha<S>(src[i]);
+ const int a = getAlpha<S>(src[i]) * (getFactor<D>() / getFactor<S>());
float32x4_t vf = vld1q_f32(&buffer[i].x);
uint16x4_t v = vmovn_u32(vcvtq_u32_f32(vaddq_f32(vmulq_n_f32(vf, float(QColorTrcLut::Resolution)), vdupq_n_f32(0.5f))));
const int ridx = vget_lane_u16(v, 0);
@@ -1219,17 +1221,41 @@ static void storeOpaque(QRgbaFloat32 *dst, const QColorVector *buffer, const qsi
static void loadGray(QColorVector *buffer, const quint8 *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
{
- for (qsizetype i = 0; i < len; ++i) {
- const float y = d_ptr->colorSpaceIn->lut[0]->u8ToLinearF32(src[i]);
- buffer[i] = d_ptr->colorSpaceIn->whitePoint * y;
+ if (d_ptr->colorSpaceIn->colorModel == QColorSpace::ColorModel::Gray ||
+ (d_ptr->colorSpaceIn->lut[0] == d_ptr->colorSpaceIn->lut[1] &&
+ d_ptr->colorSpaceIn->lut[0] == d_ptr->colorSpaceIn->lut[2])) {
+ for (qsizetype i = 0; i < len; ++i) {
+ const float y = d_ptr->colorSpaceIn->lut[0]->u8ToLinearF32(src[i]);
+ buffer[i] = d_ptr->colorSpaceIn->whitePoint * y;
+ }
+ } else {
+ for (qsizetype i = 0; i < len; ++i) {
+ QColorVector v;
+ v.x = d_ptr->colorSpaceIn->lut[0]->u8ToLinearF32(src[i]);
+ v.y = d_ptr->colorSpaceIn->lut[1]->u8ToLinearF32(src[i]);
+ v.z = d_ptr->colorSpaceIn->lut[2]->u8ToLinearF32(src[i]);
+ buffer[i] = d_ptr->colorSpaceIn->toXyz.map(v);
+ }
}
}
static void loadGray(QColorVector *buffer, const quint16 *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
{
- for (qsizetype i = 0; i < len; ++i) {
- const float y = d_ptr->colorSpaceIn->lut[0]->u16ToLinearF32(src[i]);
- buffer[i] = d_ptr->colorSpaceIn->whitePoint * y;
+ if (d_ptr->colorSpaceIn->colorModel == QColorSpace::ColorModel::Gray ||
+ (d_ptr->colorSpaceIn->lut[0] == d_ptr->colorSpaceIn->lut[1] &&
+ d_ptr->colorSpaceIn->lut[0] == d_ptr->colorSpaceIn->lut[2])) {
+ for (qsizetype i = 0; i < len; ++i) {
+ const float y = d_ptr->colorSpaceIn->lut[0]->u16ToLinearF32(src[i]);
+ buffer[i] = d_ptr->colorSpaceIn->whitePoint * y;
+ }
+ } else {
+ for (qsizetype i = 0; i < len; ++i) {
+ QColorVector v;
+ v.x = d_ptr->colorSpaceIn->lut[0]->u16ToLinearF32(src[i]);
+ v.y = d_ptr->colorSpaceIn->lut[1]->u16ToLinearF32(src[i]);
+ v.z = d_ptr->colorSpaceIn->lut[2]->u16ToLinearF32(src[i]);
+ buffer[i] = d_ptr->colorSpaceIn->toXyz.map(v);
+ }
}
}
@@ -1258,6 +1284,28 @@ private:
alignas(T) char data[sizeof(T) * Count];
};
+void loadUnpremultipliedLUT(QColorVector *buffer, const uchar *src, const qsizetype len)
+{
+ const float f = 1.0f / 255.f;
+ for (qsizetype i = 0; i < len; ++i) {
+ const float p = src[i] * f;
+ buffer[i].x = p;
+ buffer[i].y = p;
+ buffer[i].z = p;
+ }
+}
+
+void loadUnpremultipliedLUT(QColorVector *buffer, const quint16 *src, const qsizetype len)
+{
+ const float f = 1.0f / 65535.f;
+ for (qsizetype i = 0; i < len; ++i) {
+ const float p = src[i] * f;
+ buffer[i].x = p;
+ buffer[i].y = p;
+ buffer[i].z = p;
+ }
+}
+
void loadUnpremultipliedLUT(QColorVector *buffer, const QRgb *src, const qsizetype len)
{
const float f = 1.0f / 255.f;
@@ -1300,6 +1348,16 @@ void loadUnpremultipliedLUT(QColorVector *buffer, const QRgbaFloat32 *src, const
}
}
+void loadPremultipliedLUT(QColorVector *, const uchar *, const qsizetype)
+{
+ Q_UNREACHABLE();
+}
+
+void loadPremultipliedLUT(QColorVector *, const quint16 *, const qsizetype)
+{
+ Q_UNREACHABLE();
+}
+
void loadPremultipliedLUT(QColorVector *buffer, const QRgb *src, const qsizetype len)
{
for (qsizetype i = 0; i < len; ++i) {
@@ -1420,7 +1478,15 @@ static void storeUnpremultipliedLUT(QRgbaFloat32 *dst, const T *src,
}
template<typename T>
-static void storePremultipliedLUT(QRgb *, const T *, const QColorVector *, const qsizetype);
+static void storePremultipliedLUT(QRgb *dst, const T *, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int r = buffer[i].x * 255.f;
+ const int g = buffer[i].y * 255.f;
+ const int b = buffer[i].z * 255.f;
+ dst[i] = 0xff000000 | (r << 16) | (g << 8) | (b << 0);
+ }
+}
template<>
void storePremultipliedLUT(QRgb *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len)
@@ -1434,18 +1500,6 @@ void storePremultipliedLUT(QRgb *dst, const QRgb *src, const QColorVector *buffe
}
}
-template<>
-void storePremultipliedLUT(QRgb *dst, const QCmyk32 *, const QColorVector *buffer, const qsizetype len)
-{
- for (qsizetype i = 0; i < len; ++i) {
- const int r = buffer[i].x * 255.f;
- const int g = buffer[i].y * 255.f;
- const int b = buffer[i].z * 255.f;
- dst[i] = 0xff000000 | (r << 16) | (g << 8) | (b << 0);
- }
-}
-
-
template<typename T>
static void storePremultipliedLUT(QCmyk32 *dst, const T *src, const QColorVector *buffer, const qsizetype len)
{
@@ -1453,7 +1507,15 @@ static void storePremultipliedLUT(QCmyk32 *dst, const T *src, const QColorVector
}
template<typename T>
-static void storePremultipliedLUT(QRgba64 *, const T *, const QColorVector *, const qsizetype);
+static void storePremultipliedLUT(QRgba64 *dst, const T *, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int r = buffer[i].x * 65535.f;
+ const int g = buffer[i].y * 65535.f;
+ const int b = buffer[i].z * 65535.f;
+ dst[i] = qRgba64(r, g, b, 65535);
+ }
+}
template<>
void storePremultipliedLUT(QRgba64 *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len)
@@ -1468,17 +1530,6 @@ void storePremultipliedLUT(QRgba64 *dst, const QRgb *src, const QColorVector *bu
}
template<>
-void storePremultipliedLUT(QRgba64 *dst, const QCmyk32 *, const QColorVector *buffer, const qsizetype len)
-{
- for (qsizetype i = 0; i < len; ++i) {
- const int r = buffer[i].x * 65535.f;
- const int g = buffer[i].y * 65535.f;
- const int b = buffer[i].z * 65535.f;
- dst[i] = qRgba64(r, g, b, 65535);
- }
-}
-
-template<>
void storePremultipliedLUT(QRgba64 *dst, const QRgba64 *src, const QColorVector *buffer, const qsizetype len)
{
for (qsizetype i = 0; i < len; ++i) {
@@ -1628,11 +1679,43 @@ QColorVector QColorTransformPrivate::mapExtended(QColorVector c) const
return c;
}
+template<typename T>
+constexpr bool IsGrayscale = std::is_same_v<T, uchar> || std::is_same_v<T, quint16>;
+template<typename T>
+constexpr bool IsAlwaysOpaque = std::is_same_v<T, QCmyk32> || IsGrayscale<T>;
+template<typename T>
+constexpr bool CanUseThreeComponent = !std::is_same_v<T, QCmyk32>;
+template<typename T>
+constexpr bool UnclampedValues = std::is_same_v<T, QRgbaFloat16> || std::is_same_v<T, QRgbaFloat32>;
+
+// Possible combos for data and color spaces:
+// DataCM ColorSpaceCM ColorSpacePM Notes
+// Gray Gray ThreeMatrix
+// Gray Rgb ThreeMatrix Invalid colorMatrix
+// Rgb Rgb ThreeMatrix
+// Rgb Rgb ElementProc
+// Gray Rgb ElementProc Only possible for input data
+// Cmyk Cmyk ElementProc
+//
+// Gray data can be uchar, quint16, and is always Opaque
+// Rgb data can be QRgb, QRgba64, or QRgbaFloat32, and is Unpremultiplied, Premultiplied, or Opaque
+// Cmyk data can be Cmyk32, and is always Opaque
+//
+// colorMatrix as setup for Gray on Gray or Rgb on Rgb, but not Gray data on Rgb colorspace.
+
template<typename S>
void QColorTransformPrivate::applyConvertIn(const S *src, QColorVector *buffer, qsizetype len, TransformFlags flags) const
{
- // Avoid compiling this part for S=QCmyk32:
- if constexpr (!std::is_same_v<S, QCmyk32>) {
+ if constexpr (IsGrayscale<S>) {
+ if (colorSpaceIn->isThreeComponentMatrix()) {
+ loadGray(buffer, src, len, this);
+ if (!colorSpaceOut->isThreeComponentMatrix() || colorSpaceIn->colorModel != QColorSpace::ColorModel::Gray) {
+ if (!colorSpaceIn->chad.isNull())
+ applyMatrix<DoClamp>(buffer, len, colorSpaceIn->chad);
+ }
+ return;
+ }
+ } else if constexpr (CanUseThreeComponent<S>) {
if (colorSpaceIn->isThreeComponentMatrix()) {
if (flags & InputPremultiplied)
loadPremultiplied(buffer, src, len, this);
@@ -1640,35 +1723,63 @@ void QColorTransformPrivate::applyConvertIn(const S *src, QColorVector *buffer,
loadUnpremultiplied(buffer, src, len, this);
if (!colorSpaceOut->isThreeComponentMatrix())
- applyMatrix<DoClamp>(buffer, len, colorMatrix); // colorMatrix should have the first half only.
+ applyMatrix<DoClamp>(buffer, len, colorMatrix);
return;
}
}
- if (!colorSpaceIn->isThreeComponentMatrix()) {
- if (flags & InputPremultiplied)
- loadPremultipliedLUT(buffer, src, len);
- else
- loadUnpremultipliedLUT(buffer, src, len);
+ Q_ASSERT(!colorSpaceIn->isThreeComponentMatrix());
- if constexpr (std::is_same_v<S, QRgbaFloat16> || std::is_same_v<S, QRgbaFloat32>)
- clampIfNeeded<DoClamp>(buffer, len);
+ if (flags & InputPremultiplied)
+ loadPremultipliedLUT(buffer, src, len);
+ else
+ loadUnpremultipliedLUT(buffer, src, len);
- // Do element based conversion
- for (auto &&element : colorSpaceIn->mAB)
- std::visit([&buffer, len](auto &&elm) { visitElement(elm, buffer, len); }, element);
- }
+ // Do element based conversion
+ for (auto &&element : colorSpaceIn->mAB)
+ std::visit([&buffer, len](auto &&elm) { visitElement(elm, buffer, len); }, element);
}
template<typename D, typename S>
void QColorTransformPrivate::applyConvertOut(D *dst, const S *src, QColorVector *buffer, qsizetype len, TransformFlags flags) const
{
- constexpr ApplyMatrixForm doClamp = (std::is_same_v<D, QRgbaFloat16> || std::is_same_v<D, QRgbaFloat32>) ? DoNotClamp : DoClamp;
- // Avoid compiling this part for D=QCmyk32:
- if constexpr (!std::is_same_v<D, QCmyk32>) {
+ constexpr ApplyMatrixForm doClamp = UnclampedValues<D> ? DoNotClamp : DoClamp;
+ if constexpr (IsGrayscale<D>) {
+ Q_UNUSED(src); // dealing with buggy warnings in gcc 9
+ Q_UNUSED(flags);
+ // Calculate the matrix for grayscale conversion
+ QColorMatrix grayMatrix;
+ if (colorSpaceIn == colorSpaceOut ||
+ (colorSpaceIn->colorModel == QColorSpace::ColorModel::Gray &&
+ colorSpaceOut->colorModel == QColorSpace::ColorModel::Gray)) {
+ // colorMatrix already has the right form
+ grayMatrix = colorMatrix;
+ } else {
+ if constexpr (IsGrayscale<S>) {
+ if (colorSpaceIn->colorModel == QColorSpace::ColorModel::Gray)
+ grayMatrix = colorSpaceIn->chad;
+ else
+ grayMatrix = QColorMatrix::identity(); // Otherwise already handled in applyConvertIn
+ } else {
+ if (colorSpaceIn->isThreeComponentMatrix())
+ grayMatrix = colorSpaceIn->toXyz;
+ else
+ grayMatrix = QColorMatrix::identity();
+ }
+ if (!colorSpaceOut->chad.isNull())
+ grayMatrix = colorSpaceOut->chad.inverted() * grayMatrix;
+ }
+
+ applyMatrix<doClamp>(buffer, len, grayMatrix);
+ storeOpaque(dst, buffer, len, this);
+ return;
+ } else if constexpr (CanUseThreeComponent<D>) {
if (colorSpaceOut->isThreeComponentMatrix()) {
- applyMatrix<doClamp>(buffer, len, colorMatrix); // colorMatrix should have the latter half only.
+ if (IsGrayscale<S> && colorSpaceIn->colorModel != QColorSpace::ColorModel::Gray)
+ applyMatrix<doClamp>(buffer, len, colorSpaceOut->toXyz.inverted()); // colorMatrix wasnt prepared for gray input
+ else
+ applyMatrix<doClamp>(buffer, len, colorMatrix);
- if constexpr (std::is_same_v<S, QCmyk32>) {
+ if constexpr (IsAlwaysOpaque<S>) {
storeOpaque(dst, buffer, len, this);
} else {
if (flags & InputOpaque)
@@ -1681,7 +1792,9 @@ void QColorTransformPrivate::applyConvertOut(D *dst, const S *src, QColorVector
return;
}
}
- if (!colorSpaceOut->isThreeComponentMatrix()) {
+ if constexpr (!IsGrayscale<D>) {
+ Q_ASSERT(!colorSpaceOut->isThreeComponentMatrix());
+
// Do element based conversion
for (auto &&element : colorSpaceOut->mBA)
std::visit([&buffer, len](auto &&elm) { visitElement(elm, buffer, len); }, element);
@@ -1692,80 +1805,24 @@ void QColorTransformPrivate::applyConvertOut(D *dst, const S *src, QColorVector
storePremultipliedLUT(dst, src, buffer, len);
else
storeUnpremultipliedLUT(dst, src, buffer, len);
+ } else {
+ Q_UNREACHABLE();
}
}
-template<typename D, typename S>
-void QColorTransformPrivate::applyElementListTransform(D *dst, const S *src, qsizetype count, TransformFlags flags) const
-{
- Q_ASSERT(!colorSpaceIn->isThreeComponentMatrix() || !colorSpaceOut->isThreeComponentMatrix());
-
- if (!colorMatrix.isValid())
- return;
-
- if (colorSpaceIn->isThreeComponentMatrix())
- updateLutsIn();
- if (colorSpaceOut->isThreeComponentMatrix())
- updateLutsOut();
-
- QUninitialized<QColorVector, WorkBlockSize> buffer;
- qsizetype i = 0;
- while (i < count) {
- const qsizetype len = qMin(count - i, WorkBlockSize);
-
- applyConvertIn(src + i, buffer, len, flags);
-
- // Match Profile Connection Spaces (PCS):
- if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab) {
- for (qsizetype j = 0; j < len; ++j)
- buffer[j] = buffer[j].xyzToLab();
- } else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab) {
- for (qsizetype j = 0; j < len; ++j)
- buffer[j] = buffer[j].labToXyz();
- }
-
- applyConvertOut(dst + i, src + i, buffer, len, flags);
-
- i += len;
- }
-}
-
-template<typename D, typename S>
-void QColorTransformPrivate::applyThreeComponentMatrix(D *dst, const S *src, qsizetype count, TransformFlags flags) const
+/*!
+ \internal
+ Adapt Profile Connection Spaces.
+*/
+void QColorTransformPrivate::pcsAdapt(QColorVector *buffer, qsizetype count) const
{
- Q_ASSERT(colorSpaceIn->isThreeComponentMatrix() && colorSpaceOut->isThreeComponentMatrix());
-
- if (!colorMatrix.isValid())
- return;
-
- updateLutsIn();
- updateLutsOut();
-
- bool doApplyMatrix = !colorMatrix.isIdentity();
- constexpr ApplyMatrixForm doClamp = (std::is_same_v<D, QRgbaFloat16> || std::is_same_v<D, QRgbaFloat32>) ? DoNotClamp : DoClamp;
-
- QUninitialized<QColorVector, WorkBlockSize> buffer;
- qsizetype i = 0;
- while (i < count) {
- const qsizetype len = qMin(count - i, WorkBlockSize);
- if (flags & InputPremultiplied)
- loadPremultiplied(buffer, src + i, len, this);
- else
- loadUnpremultiplied(buffer, src + i, len, this);
-
- if (doApplyMatrix)
- applyMatrix<doClamp>(buffer, len, colorMatrix);
- else
- clampIfNeeded<doClamp>(buffer, len);
-
- if (flags & InputOpaque)
- storeOpaque(dst + i, buffer, len, this);
- else if (flags & OutputPremultiplied)
- storePremultiplied(dst + i, src + i, buffer, len, this);
- else
- storeUnpremultiplied(dst + i, src + i, buffer, len, this);
-
- i += len;
+ // Match Profile Connection Spaces (PCS):
+ if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab) {
+ for (qsizetype j = 0; j < count; ++j)
+ buffer[j] = buffer[j].xyzToLab();
+ } else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab) {
+ for (qsizetype j = 0; j < count; ++j)
+ buffer[j] = buffer[j].labToXyz();
}
}
@@ -1781,137 +1838,23 @@ void QColorTransformPrivate::applyThreeComponentMatrix(D *dst, const S *src, qsi
template<typename D, typename S>
void QColorTransformPrivate::apply(D *dst, const S *src, qsizetype count, TransformFlags flags) const
{
- if constexpr (!std::is_same_v<D, QCmyk32> && !std::is_same_v<S, QCmyk32>) {
- if (isThreeComponentMatrix())
- return applyThreeComponentMatrix<D, S>(dst, src, count, flags);
- }
- applyElementListTransform<D, S>(dst, src, count, flags);
-}
-
-/*!
- \internal
- Is to be called on a color-transform to XYZ, returns only luminance values.
-
- */
-template<typename D, typename S>
-void QColorTransformPrivate::applyReturnGray(D *dst, const S *src, qsizetype count, TransformFlags flags) const
-{
- Q_ASSERT(colorSpaceOut->isThreeComponentMatrix());
- updateLutsOut();
- if (!colorSpaceIn->isThreeComponentMatrix()) {
- QUninitialized<QColorVector, WorkBlockSize> buffer;
-
- qsizetype i = 0;
- while (i < count) {
- const qsizetype len = qMin(count - i, WorkBlockSize);
-
- applyConvertIn(src, buffer, len, flags);
-
- // Match Profile Connection Spaces (PCS):
- if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab) {
- for (qsizetype j = 0; j < len; ++j)
- buffer[j] = buffer[j].xyzToLab();
- } else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab) {
- for (qsizetype j = 0; j < len; ++j)
- buffer[j] = buffer[j].labToXyz();
- }
-
- applyMatrix<DoClamp>(buffer, len, colorMatrix);
- storeOpaque(dst + i, buffer, len, this);
-
- i += len;
- }
- return;
- }
- if constexpr (!std::is_same_v<S, QCmyk32>) {
- if (!colorMatrix.isValid())
- return;
-
+ if (colorSpaceIn->isThreeComponentMatrix())
updateLutsIn();
-
- QUninitialized<QColorVector, WorkBlockSize> buffer;
-
- qsizetype i = 0;
- while (i < count) {
- const qsizetype len = qMin(count - i, WorkBlockSize);
- if (flags & InputPremultiplied)
- loadPremultiplied(buffer, src + i, len, this);
- else
- loadUnpremultiplied(buffer, src + i, len, this);
-
- applyMatrix<DoClamp>(buffer, len, colorMatrix);
-
- storeOpaque(dst + i, buffer, len, this);
-
- i += len;
- }
- } else {
- Q_UNREACHABLE();
- }
-}
-
-/*!
- \internal
-*/
-template<typename D, typename S>
-void QColorTransformPrivate::applyGray(D *dst, const S *src, qsizetype count, TransformFlags) const
-{
- Q_ASSERT(colorSpaceIn->isThreeComponentMatrix());
- updateLutsIn();
- if constexpr (std::is_same_v<D, QRgb> || std::is_same_v<D, QRgba64> || std::is_same_v<D, QRgbaFloat32> || std::is_same_v<D, QCmyk32>) {
- if (!colorSpaceOut->isThreeComponentMatrix()) {
- QUninitialized<QColorVector, WorkBlockSize> buffer;
-
- qsizetype i = 0;
- while (i < count) {
- const qsizetype len = qMin(count - i, WorkBlockSize);
- loadGray(buffer, src + i, len, this);
-
- applyMatrix<DoClamp>(buffer, len, colorMatrix);
-
- // Match Profile Connection Spaces (PCS):
- if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab) {
- for (qsizetype j = 0; j < len; ++j)
- buffer[j] = buffer[j].xyzToLab();
- } else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab) {
- for (qsizetype j = 0; j < len; ++j)
- buffer[j] = buffer[j].labToXyz();
- }
-
- // Do element based conversion
- for (auto &&element : colorSpaceOut->mBA)
- std::visit([&buffer, len](auto &&elm) { visitElement(elm, buffer, len); }, element);
-
- clampIfNeeded<DoClamp>(buffer, len);
-
- storeUnpremultipliedLUT(dst, src, buffer, len); // input is always opaque
-
- i += len;
- }
- return;
- }
- }
- Q_ASSERT(colorSpaceOut->isThreeComponentMatrix());
- if constexpr (!std::is_same_v<D, QCmyk32>) {
- if (!colorMatrix.isValid())
- return;
-
+ if (colorSpaceOut->isThreeComponentMatrix())
updateLutsOut();
- QUninitialized<QColorVector, WorkBlockSize> buffer;
+ QUninitialized<QColorVector, WorkBlockSize> buffer;
+ qsizetype i = 0;
+ while (i < count) {
+ const qsizetype len = qMin(count - i, WorkBlockSize);
- qsizetype i = 0;
- while (i < count) {
- const qsizetype len = qMin(count - i, WorkBlockSize);
- loadGray(buffer, src + i, len, this);
+ applyConvertIn(src + i, buffer, len, flags);
- applyMatrix<DoClamp>(buffer, len, colorMatrix);
+ pcsAdapt(buffer, len);
- storeOpaque(dst + i, buffer, len, this);
- i += len;
- }
- } else {
- Q_UNREACHABLE();
+ applyConvertOut(dst + i, src + i, buffer, len, flags);
+
+ i += len;
}
}
@@ -1943,25 +1886,24 @@ void QColorTransformPrivate::prepare()
updateLutsOut();
}
-// Only allow versions increasing precision
-template void QColorTransformPrivate::applyReturnGray<quint8, QRgb>(quint8 *dst, const QRgb *src, qsizetype count, TransformFlags flags) const;
-template void QColorTransformPrivate::applyReturnGray<quint8, QCmyk32>(quint8 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
-template void QColorTransformPrivate::applyReturnGray<quint16, QCmyk32>(quint16 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
-template void QColorTransformPrivate::applyReturnGray<quint16, QRgba64>(quint16 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const;
-template void QColorTransformPrivate::applyGray<quint8, quint8>(quint8 *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
-template void QColorTransformPrivate::applyGray<quint16, quint8>(quint16 *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
-template void QColorTransformPrivate::applyGray<quint16, quint16>(quint16 *dst, const quint16 *src, qsizetype count, TransformFlags flags) const;
-template void QColorTransformPrivate::applyGray<QRgb, quint8>(QRgb *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
-template void QColorTransformPrivate::applyGray<QCmyk32, quint8>(QCmyk32 *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
-template void QColorTransformPrivate::applyGray<QCmyk32, quint16>(QCmyk32 *dst, const quint16 *src, qsizetype count, TransformFlags flags) const;
-template void QColorTransformPrivate::applyGray<QRgba64, quint16>(QRgba64 *dst, const quint16 *src, qsizetype count, TransformFlags flags) const;
-
+// Only some versions increasing precision 14/36 combos
+template void QColorTransformPrivate::apply<quint8, quint8>(quint8 *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<quint8, QRgb>(quint8 *dst, const QRgb *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<quint8, QCmyk32>(quint8 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<quint16, quint8>(quint16 *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<quint16, quint16>(quint16 *dst, const quint16 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<quint16, QCmyk32>(quint16 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<quint16, QRgba64>(quint16 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgb, quint8>(QRgb *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
template void QColorTransformPrivate::apply<QRgb, QRgb>(QRgb *dst, const QRgb *src, qsizetype count, TransformFlags flags) const;
template void QColorTransformPrivate::apply<QRgb, QCmyk32>(QRgb *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QCmyk32, quint8>(QCmyk32 *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QCmyk32, quint16>(QCmyk32 *dst, const quint16 *src, qsizetype count, TransformFlags flags) const;
template void QColorTransformPrivate::apply<QCmyk32, QRgb>(QCmyk32 *dst, const QRgb *src, qsizetype count, TransformFlags flags) const;
template void QColorTransformPrivate::apply<QCmyk32, QCmyk32>(QCmyk32 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
template void QColorTransformPrivate::apply<QCmyk32, QRgba64>(QCmyk32 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const;
template void QColorTransformPrivate::apply<QCmyk32, QRgbaFloat32>(QCmyk32 *dst, const QRgbaFloat32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgba64, quint16>(QRgba64 *dst, const quint16 *src, qsizetype count, TransformFlags flags) const;
template void QColorTransformPrivate::apply<QRgba64, QRgb>(QRgba64 *dst, const QRgb *src, qsizetype count, TransformFlags flags) const;
template void QColorTransformPrivate::apply<QRgba64, QCmyk32>(QRgba64 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
template void QColorTransformPrivate::apply<QRgba64, QRgba64>(QRgba64 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const;
@@ -1970,15 +1912,6 @@ template void QColorTransformPrivate::apply<QRgbaFloat32, QCmyk32>(QRgbaFloat32
template void QColorTransformPrivate::apply<QRgbaFloat32, QRgba64>(QRgbaFloat32 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const;
template void QColorTransformPrivate::apply<QRgbaFloat32, QRgbaFloat32>(QRgbaFloat32 *dst, const QRgbaFloat32 *src, qsizetype count, TransformFlags flags) const;
-bool QColorTransformPrivate::isThreeComponentMatrix() const
-{
- if (colorSpaceIn && !colorSpaceIn->isThreeComponentMatrix())
- return false;
- if (colorSpaceOut && !colorSpaceOut->isThreeComponentMatrix())
- return false;
- return true;
-}
-
/*!
\internal
*/
@@ -1991,7 +1924,7 @@ bool QColorTransformPrivate::isIdentity() const
if (colorSpaceIn && colorSpaceOut) {
if (colorSpaceIn->equals(colorSpaceOut.constData()))
return true;
- if (!isThreeComponentMatrix())
+ if (!colorSpaceIn->isThreeComponentMatrix() || !colorSpaceOut->isThreeComponentMatrix())
return false;
if (colorSpaceIn->transferFunction != colorSpaceOut->transferFunction)
return false;
@@ -2001,7 +1934,9 @@ bool QColorTransformPrivate::isIdentity() const
&& colorSpaceIn->trc[2] == colorSpaceOut->trc[2];
}
} else {
- if (!isThreeComponentMatrix())
+ if (colorSpaceIn && !colorSpaceIn->isThreeComponentMatrix())
+ return false;
+ if (colorSpaceOut && !colorSpaceOut->isThreeComponentMatrix())
return false;
if (colorSpaceIn && colorSpaceIn->transferFunction != QColorSpace::TransferFunction::Linear)
return false;