diff options
Diffstat (limited to 'src/gui/painting/qcolortransform.cpp')
-rw-r--r-- | src/gui/painting/qcolortransform.cpp | 511 |
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; |