File indexing completed on 2024-05-12 15:59:36
0001 /* 0002 * SPDX-FileCopyrightText: 2018 Iván Santa María <ghevan@gmail.com> 0003 * SPDX-FileCopyrightText: 2006 Cyrille Berger <cberger@cberger.net> 0004 * SPDX-FileCopyrightText: 2007 Emanuele Tamponi <emanuele@valinor.it> 0005 * 0006 * SPDX-License-Identifier: LGPL-2.1-or-later 0007 */ 0008 0009 #ifndef KO_INVERT_COLOR_TRANSFORMATION_H 0010 #define KO_INVERT_COLOR_TRANSFORMATION_H 0011 0012 #include "KoColorTransformation.h" 0013 0014 #include "KoColorSpace.h" 0015 #include "KoColorSpaceMaths.h" 0016 0017 #include "KoColorModelStandardIds.h" 0018 0019 #include <KoConfig.h> 0020 #ifdef HAVE_OPENEXR 0021 #include <half.h> 0022 #endif 0023 class KoInvertColorTransformationT : public KoColorTransformation { 0024 0025 public: 0026 0027 KoInvertColorTransformationT(const KoColorSpace* cs) 0028 : m_colorSpace(cs) 0029 , m_psize(cs->pixelSize()) 0030 , m_chanCount(cs->channelCount()) 0031 { 0032 // Only invert COLOR channels 0033 QList<KoChannelInfo *> channels = cs->channels(); 0034 for(quint8 i = 0; i < m_chanCount; i++){ 0035 if(channels.at(i)->channelType() == KoChannelInfo::COLOR) 0036 m_channels.append(i); 0037 } 0038 } 0039 0040 template<typename T> 0041 void transformI(const quint8 *src, quint8 *dst, qint32 nPixels) const { 0042 T *m_rgba = (T*)(src); 0043 T *m_dst = (T*)(dst); 0044 0045 while (nPixels--) { 0046 for(quint8 i : m_channels){ 0047 m_dst[i] = KoColorSpaceMaths<T>::invert(m_rgba[i]); 0048 } 0049 m_rgba += m_chanCount; 0050 m_dst += m_chanCount; 0051 } 0052 0053 } 0054 0055 void transformGen(const quint8 *src, quint8 *dst, qint32 nPixels) const { 0056 quint16 m_rgba[4]; 0057 while (nPixels--) { 0058 m_colorSpace->toRgbA16(src, reinterpret_cast<quint8 *>(m_rgba), 1); 0059 m_rgba[0] = KoColorSpaceMathsTraits<quint16>::max - m_rgba[0]; 0060 m_rgba[1] = KoColorSpaceMathsTraits<quint16>::max - m_rgba[1]; 0061 m_rgba[2] = KoColorSpaceMathsTraits<quint16>::max - m_rgba[2]; 0062 m_colorSpace->fromRgbA16(reinterpret_cast<quint8 *>(m_rgba), dst, 1); 0063 src += m_psize; 0064 dst += m_psize; 0065 } 0066 } 0067 0068 // Once CMYK and LAB 32 float are normalized, this inverts will invert properly 0069 // template<typename T> 0070 // void transformC(const quint8 *src, quint8 *dst, qint32 nPixels) const { 0071 // QVector<float> normChan(m_chanCount); 0072 0073 // float *m_rgba; 0074 // float *m_dst = (float*)(dst); 0075 // while (nPixels--) { 0076 // m_colorSpace->normalisedChannelsValue(src, normChan); 0077 // for(quint8 i : m_channels){ 0078 // normChan[i] = KoColorSpaceMaths<float>::invert(normChan[i]); 0079 // } 0080 // m_colorSpace->fromNormalisedChannelsValue(dst,normChan); 0081 // //m_rgba += m_psize; 0082 // src += m_psize; 0083 // dst += m_psize; 0084 // } 0085 // } 0086 0087 protected: 0088 QList<quint8> m_channels; 0089 private: 0090 const KoColorSpace* m_colorSpace; 0091 quint32 m_psize; 0092 quint32 m_chanCount; 0093 }; 0094 0095 class KoU8InvertColorTransformer : public KoInvertColorTransformationT { 0096 public: 0097 KoU8InvertColorTransformer(const KoColorSpace* cs) 0098 : KoInvertColorTransformationT(cs) 0099 { 0100 }; 0101 0102 void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override { 0103 transformI<quint8>(src,dst,nPixels); 0104 } 0105 }; 0106 0107 class KoU16InvertColorTransformer : public KoInvertColorTransformationT { 0108 public: 0109 KoU16InvertColorTransformer(const KoColorSpace* cs) 0110 : KoInvertColorTransformationT(cs) 0111 { 0112 }; 0113 0114 void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override { 0115 transformI<quint16>(src,dst,nPixels); 0116 } 0117 }; 0118 0119 #ifdef HAVE_OPENEXR 0120 class KoF16InvertColorTransformer : public KoInvertColorTransformationT { 0121 public: 0122 KoF16InvertColorTransformer(const KoColorSpace* cs) 0123 : KoInvertColorTransformationT(cs) 0124 { 0125 }; 0126 0127 void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override { 0128 transformI<half>(src,dst,nPixels); 0129 } 0130 }; 0131 #endif 0132 0133 class KoF32InvertColorTransformer : public KoInvertColorTransformationT { 0134 public: 0135 KoF32InvertColorTransformer(const KoColorSpace* cs) 0136 : KoInvertColorTransformationT(cs) 0137 { 0138 }; 0139 0140 void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override { 0141 transformI<float>(src,dst,nPixels); 0142 } 0143 }; 0144 0145 class KoF32GenInvertColorTransformer : public KoInvertColorTransformationT { 0146 public: 0147 KoF32GenInvertColorTransformer(const KoColorSpace* cs) 0148 : KoInvertColorTransformationT(cs) 0149 { 0150 }; 0151 0152 void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override { 0153 transformGen(src,dst,nPixels); 0154 } 0155 }; 0156 0157 0158 class KoInvertColorTransformation 0159 { 0160 public: 0161 static KoColorTransformation* getTransformator(const KoColorSpace *cs) 0162 { 0163 KoID id = cs->colorDepthId(); 0164 KoID modelId = cs->colorModelId(); 0165 if (id == Integer8BitsColorDepthID) { 0166 return new KoU8InvertColorTransformer(cs); 0167 } else if (id == Integer16BitsColorDepthID) { 0168 return new KoU16InvertColorTransformer(cs); 0169 #ifdef HAVE_OPENEXR 0170 } else if (id == Float16BitsColorDepthID) { 0171 return new KoF16InvertColorTransformer(cs); 0172 #endif 0173 } else { 0174 if(modelId == LABAColorModelID || modelId == CMYKAColorModelID){ 0175 return new KoF32GenInvertColorTransformer(cs); 0176 } 0177 return new KoF32InvertColorTransformer(cs); 0178 } 0179 } 0180 }; 0181 0182 #endif