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