File indexing completed on 2024-05-19 04:27:24
0001 /* 0002 * SPDX-FileCopyrightText: 2006 Cyrille Berger <cberger@cberger.net> 0003 * SPDX-FileCopyrightText: 2007 Emanuele Tamponi <emanuele@valinor.it> 0004 * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me> 0005 * SPDX-License-Identifier: LGPL-2.1-or-later 0006 */ 0007 0008 #ifndef KOCOLORSPACEABSTRACT_H 0009 #define KOCOLORSPACEABSTRACT_H 0010 0011 #include <QBitArray> 0012 #include <klocalizedstring.h> 0013 0014 #include <KoColorSpace.h> 0015 #include <KoColorProfile.h> 0016 #include <KoColorSpaceMaths.h> 0017 #include <KoColorSpaceRegistry.h> 0018 #include "KoFallBackColorTransformation.h" 0019 #include "KoLabDarkenColorTransformation.h" 0020 #include "KoMixColorsOpImpl.h" 0021 0022 #include "KoConvolutionOpImpl.h" 0023 #include "KoInvertColorTransformation.h" 0024 #include "KoAlphaMaskApplicatorFactory.h" 0025 #include "KoColorModelStandardIdsUtils.h" 0026 0027 /** 0028 * This in an implementation of KoColorSpace which can be used as a base for colorspaces with as many 0029 * different channels of the same type. 0030 * 0031 * The template parameters must be a class which inherits KoColorSpaceTrait (or a class with the same signature). 0032 * 0033 * SOMETYPE is the type of the channel for instance (quint8, quint32...), 0034 * SOMENBOFCHANNELS is the number of channels including the alpha channel 0035 * SOMEALPHAPOS is the position of the alpha channel in the pixel (can be equal to -1 if no alpha channel). 0036 */ 0037 template<class _CSTrait> 0038 class KoColorSpaceAbstract : public KoColorSpace 0039 { 0040 public: 0041 typedef _CSTrait ColorSpaceTraits; 0042 0043 public: 0044 KoColorSpaceAbstract(const QString &id, const QString &name) 0045 : KoColorSpace(id, name, new KoMixColorsOpImpl< _CSTrait>(), new KoConvolutionOpImpl< _CSTrait>()), 0046 m_alphaMaskApplicator(KoAlphaMaskApplicatorFactory::create(colorDepthIdForChannelType<typename _CSTrait::channels_type>(), _CSTrait::channels_nb, _CSTrait::alpha_pos)) 0047 { 0048 } 0049 0050 quint32 colorChannelCount() const override { 0051 if (_CSTrait::alpha_pos == -1) 0052 return _CSTrait::channels_nb; 0053 else 0054 return _CSTrait::channels_nb - 1; 0055 } 0056 0057 quint32 channelCount() const override { 0058 return _CSTrait::channels_nb; 0059 } 0060 0061 quint32 alphaPos() const override { 0062 return _CSTrait::alpha_pos; 0063 } 0064 0065 0066 quint32 pixelSize() const override { 0067 return _CSTrait::pixelSize; 0068 } 0069 0070 QString channelValueText(const quint8 *pixel, quint32 channelIndex) const override { 0071 return _CSTrait::channelValueText(pixel, channelIndex); 0072 } 0073 0074 QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) const override { 0075 return _CSTrait::normalisedChannelValueText(pixel, channelIndex); 0076 } 0077 0078 void normalisedChannelsValue(const quint8 *pixel, QVector<float> &channels) const override { 0079 return _CSTrait::normalisedChannelsValue(pixel, channels); 0080 } 0081 0082 void fromNormalisedChannelsValue(quint8 *pixel, const QVector<float> &values) const override { 0083 return _CSTrait::fromNormalisedChannelsValue(pixel, values); 0084 } 0085 0086 quint8 scaleToU8(const quint8 * srcPixel, qint32 channelIndex) const override { 0087 typename _CSTrait::channels_type c = _CSTrait::nativeArray(srcPixel)[channelIndex]; 0088 return KoColorSpaceMaths<typename _CSTrait::channels_type, quint8>::scaleToA(c); 0089 } 0090 0091 void singleChannelPixel(quint8 *dstPixel, const quint8 *srcPixel, quint32 channelIndex) const override { 0092 _CSTrait::singleChannelPixel(dstPixel, srcPixel, channelIndex); 0093 } 0094 0095 quint8 opacityU8(const quint8 * U8_pixel) const override { 0096 return _CSTrait::opacityU8(U8_pixel); 0097 } 0098 0099 qreal opacityF(const quint8 * U8_pixel) const override { 0100 return _CSTrait::opacityF(U8_pixel); 0101 } 0102 0103 void setOpacity(quint8 * pixels, quint8 alpha, qint32 nPixels) const override { 0104 _CSTrait::setOpacity(pixels, alpha, nPixels); 0105 } 0106 0107 void setOpacity(quint8 * pixels, qreal alpha, qint32 nPixels) const override { 0108 _CSTrait::setOpacity(pixels, alpha, nPixels); 0109 } 0110 0111 void copyOpacityU8(quint8* src, quint8 *dst, qint32 nPixels) const override { 0112 _CSTrait::copyOpacityU8(src, dst, nPixels); 0113 } 0114 0115 void multiplyAlpha(quint8 * pixels, quint8 alpha, qint32 nPixels) const override { 0116 _CSTrait::multiplyAlpha(pixels, alpha, nPixels); 0117 } 0118 0119 void applyAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const override { 0120 _CSTrait::applyAlphaU8Mask(pixels, alpha, nPixels); 0121 } 0122 0123 void applyInverseAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const override { 0124 _CSTrait::applyInverseAlphaU8Mask(pixels, alpha, nPixels); 0125 } 0126 0127 void applyAlphaNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const override { 0128 _CSTrait::applyAlphaNormedFloatMask(pixels, alpha, nPixels); 0129 } 0130 0131 void applyInverseNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const override { 0132 m_alphaMaskApplicator->applyInverseNormedFloatMask(pixels, alpha, nPixels); 0133 } 0134 0135 void fillInverseAlphaNormedFloatMaskWithColor(quint8 * pixels, const float * alpha, const quint8 *brushColor, qint32 nPixels) const override { 0136 m_alphaMaskApplicator->fillInverseAlphaNormedFloatMaskWithColor(pixels, alpha, brushColor, nPixels); 0137 } 0138 0139 void fillGrayBrushWithColor(quint8 *dst, const QRgb *brush, quint8 *brushColor, qint32 nPixels) const override { 0140 m_alphaMaskApplicator->fillGrayBrushWithColor(dst, brush, brushColor, nPixels); 0141 } 0142 0143 /** 0144 * By default this does the same as toQColor 0145 */ 0146 void toQColor16(const quint8 *src, QColor *c) const override { 0147 this->toQColor(src, c); 0148 } 0149 0150 quint8 intensity8(const quint8 * src) const override { 0151 QColor c; 0152 const_cast<KoColorSpaceAbstract<_CSTrait> *>(this)->toQColor(src, &c); 0153 // Integer version of: 0154 // static_cast<quint8>(qRound(c.red() * 0.30 + c.green() * 0.59 + c.blue() * 0.11)) 0155 // The "+ 50" is used for rounding 0156 return static_cast<quint8>((c.red() * 30 + c.green() * 59 + c.blue() * 11 + 50) / 100); 0157 } 0158 0159 qreal intensityF(const quint8 * src) const override { 0160 QColor c; 0161 const_cast<KoColorSpaceAbstract<_CSTrait> *>(this)->toQColor16(src, &c); 0162 return c.redF() * 0.30 + c.greenF() * 0.59 + c.blueF() * 0.11; 0163 } 0164 0165 KoColorTransformation* createInvertTransformation() const override { 0166 return KoInvertColorTransformation::getTransformator(this); 0167 } 0168 0169 KoColorTransformation *createDarkenAdjustment(qint32 shade, bool compensate, qreal compensation) const override { 0170 return new KoFallBackColorTransformation(this, KoColorSpaceRegistry::instance()->lab16(""), new KoLabDarkenColorTransformation<quint16>(shade, compensate, compensation, KoColorSpaceRegistry::instance()->lab16(""))); 0171 } 0172 0173 void convertChannelToVisualRepresentation(const quint8 *src, quint8 *dst, quint32 nPixels, const qint32 selectedChannelIndex) const override 0174 { 0175 const int alphaPos = _CSTrait::alpha_pos; 0176 0177 for (uint pixelIndex = 0; pixelIndex < nPixels; ++pixelIndex) { 0178 0179 const quint8 *srcPtr = src + pixelIndex * _CSTrait::pixelSize; 0180 quint8 *dstPtr = dst + pixelIndex * _CSTrait::pixelSize; 0181 0182 const typename _CSTrait::channels_type *srcPixel = _CSTrait::nativeArray(srcPtr); 0183 typename _CSTrait::channels_type *dstPixel = _CSTrait::nativeArray(dstPtr); 0184 0185 typename _CSTrait::channels_type commonChannel = srcPixel[selectedChannelIndex]; 0186 0187 for (uint channelIndex = 0; channelIndex < _CSTrait::channels_nb; ++channelIndex) { 0188 0189 if (channelIndex != alphaPos) { 0190 dstPixel[channelIndex] = commonChannel; 0191 } else { 0192 dstPixel[channelIndex] = srcPixel[channelIndex]; 0193 } 0194 } 0195 } 0196 } 0197 0198 void convertChannelToVisualRepresentation(const quint8 *src, quint8 *dst, quint32 nPixels, const QBitArray selectedChannels) const override 0199 { 0200 for (uint pixelIndex = 0; pixelIndex < nPixels; ++pixelIndex) { 0201 const quint8 *srcPtr = src + pixelIndex * _CSTrait::pixelSize; 0202 quint8 *dstPtr = dst + pixelIndex * _CSTrait::pixelSize; 0203 0204 const typename _CSTrait::channels_type *srcPixel = _CSTrait::nativeArray(srcPtr); 0205 typename _CSTrait::channels_type *dstPixel = _CSTrait::nativeArray(dstPtr); 0206 0207 for (uint channelIndex = 0; channelIndex < _CSTrait::channels_nb; ++channelIndex) { 0208 if (selectedChannels.testBit(channelIndex)) { 0209 dstPixel[channelIndex] = srcPixel[channelIndex]; 0210 } else { 0211 dstPixel[channelIndex] = _CSTrait::math_trait::zeroValue; 0212 } 0213 } 0214 } 0215 } 0216 0217 private: 0218 QScopedPointer<KoAlphaMaskApplicatorBase> m_alphaMaskApplicator; 0219 }; 0220 0221 #endif // KOCOLORSPACEABSTRACT_H