File indexing completed on 2024-05-12 15:59:30
0001 /* 0002 * SPDX-FileCopyrightText: 2006-2007 Cyrille Berger <cberger@cberger.net> 0003 * SPDX-FileCopyrightText: 2016, 2017, 2020 L. E. Segovia <amy@amyspark.me> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.1-or-later 0006 */ 0007 0008 #ifndef _KO_CMYK_COLORSPACE_TRAITS_H_ 0009 #define _KO_CMYK_COLORSPACE_TRAITS_H_ 0010 0011 #include <KoCmykColorSpaceMaths.h> 0012 0013 /** 0014 * Base class for CMYK traits, it provides some convenient functions to 0015 * access CMYK channels through an explicit API. 0016 */ 0017 template<typename _channels_type_> 0018 struct KoCmykTraits : public KoColorSpaceTrait<_channels_type_, 5, 4> { 0019 typedef _channels_type_ channels_type; 0020 typedef KoColorSpaceTrait<_channels_type_, 5, 4> parent; 0021 0022 static const qint32 c_pos = 0; 0023 static const qint32 m_pos = 1; 0024 static const qint32 y_pos = 2; 0025 static const qint32 k_pos = 3; 0026 0027 /** 0028 * An CMYK pixel 0029 */ 0030 struct Pixel { 0031 channels_type cyan; 0032 channels_type magenta; 0033 channels_type yellow; 0034 channels_type black; 0035 channels_type alpha; 0036 }; 0037 /// @return the Cyan component 0038 inline static channels_type C(quint8* data) { 0039 channels_type* d = parent::nativeArray(data); 0040 return d[c_pos]; 0041 } 0042 /// Set the Cyan component 0043 inline static void setC(quint8* data, channels_type nv) { 0044 channels_type* d = parent::nativeArray(data); 0045 d[c_pos] = nv; 0046 } 0047 /// @return the Magenta component 0048 inline static channels_type M(quint8* data) { 0049 channels_type* d = parent::nativeArray(data); 0050 return d[m_pos]; 0051 } 0052 /// Set the Magenta component 0053 inline static void setM(quint8* data, channels_type nv) { 0054 channels_type* d = parent::nativeArray(data); 0055 d[m_pos] = nv; 0056 } 0057 /// @return the Yellow component 0058 inline static channels_type Y(quint8* data) { 0059 channels_type* d = parent::nativeArray(data); 0060 return d[y_pos]; 0061 } 0062 /// Set the Yellow component 0063 inline static void setY(quint8* data, channels_type nv) { 0064 channels_type* d = parent::nativeArray(data); 0065 d[y_pos] = nv; 0066 } 0067 /// @return the Key component 0068 inline static channels_type k(quint8* data) { 0069 channels_type* d = parent::nativeArray(data); 0070 return d[k_pos]; 0071 } 0072 /// Set the Key component 0073 inline static void setK(quint8* data, channels_type nv) { 0074 channels_type* d = parent::nativeArray(data); 0075 d[k_pos] = nv; 0076 } 0077 }; 0078 0079 struct KoCmykU8Traits : public KoCmykTraits<quint8> { 0080 }; 0081 0082 struct KoCmykU16Traits : public KoCmykTraits<quint16> { 0083 }; 0084 0085 #include <KoConfig.h> 0086 #ifdef HAVE_OPENEXR 0087 #include <half.h> 0088 0089 struct KoCmykF16Traits : public KoCmykTraits<half> { 0090 0091 inline static QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) { 0092 if (channelIndex > parent::channels_nb) return QString("Error"); 0093 channels_type c = nativeArray(pixel)[channelIndex]; 0094 switch (channelIndex) { 0095 case c_pos: 0096 case m_pos: 0097 case y_pos: 0098 case k_pos: 0099 return QString().setNum(100.0 * qBound((qreal)0, 0100 ((qreal)c) / KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK, 0101 (qreal)KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK)); 0102 case 4: 0103 return QString().setNum(100.0 * qBound((qreal)0, 0104 ((qreal)c) / KoCmykColorSpaceMathsTraits<channels_type>::unitValue, 0105 (qreal)KoCmykColorSpaceMathsTraits<channels_type>::unitValue)); 0106 default: 0107 return QString("Error"); 0108 } 0109 } 0110 0111 inline static void normalisedChannelsValue(const quint8 *pixel, QVector<float> &v) 0112 { 0113 Q_ASSERT((int)v.count() == (int)parent::channels_nb); 0114 channels_type c; 0115 float *channels = v.data(); 0116 for (uint i = 0; i < parent::channels_nb; i++) { 0117 c = nativeArray(pixel)[i]; 0118 switch (i) { 0119 case c_pos: 0120 case m_pos: 0121 case y_pos: 0122 case k_pos: 0123 channels[i] = qBound((qreal)0, 0124 ((qreal)c) / KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK, 0125 (qreal)KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK); 0126 break; 0127 // As per KoChannelInfo alpha channels are [0..1] 0128 case 4: 0129 default: 0130 channels[i] = qBound((qreal)0, 0131 ((qreal)c) / KoCmykColorSpaceMathsTraits<channels_type>::unitValue, 0132 (qreal)KoCmykColorSpaceMathsTraits<channels_type>::unitValue); 0133 break; 0134 } 0135 } 0136 } 0137 0138 inline static void fromNormalisedChannelsValue(quint8 *pixel, const QVector<float> &values) { 0139 Q_ASSERT((int)values.count() == (int)parent::channels_nb); 0140 channels_type c; 0141 for (uint i = 0; i < parent::channels_nb; i++) { 0142 float b = 0; 0143 switch(i) { 0144 case c_pos: 0145 case m_pos: 0146 case y_pos: 0147 case k_pos: 0148 b = qBound((float)0, 0149 (float)KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK * values[i], 0150 (float)KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK); 0151 break; 0152 default: 0153 b = qBound((float)KoCmykColorSpaceMathsTraits<channels_type>::min, 0154 (float)KoCmykColorSpaceMathsTraits<channels_type>::unitValue * values[i], 0155 (float)KoCmykColorSpaceMathsTraits<channels_type>::max); 0156 break; 0157 } 0158 c = (channels_type)b; 0159 parent::nativeArray(pixel)[i] = c; 0160 } 0161 } 0162 }; 0163 0164 #endif 0165 0166 struct KoCmykF32Traits : public KoCmykTraits<float> { 0167 0168 inline static QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) { 0169 if (channelIndex > parent::channels_nb) return QString("Error"); 0170 channels_type c = nativeArray(pixel)[channelIndex]; 0171 switch (channelIndex) { 0172 case c_pos: 0173 case m_pos: 0174 case y_pos: 0175 case k_pos: 0176 return QString().setNum(100.0 * qBound((qreal)0, 0177 ((qreal)c) / KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK, 0178 (qreal)KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK)); 0179 case 4: 0180 return QString().setNum(100.0 * qBound((qreal)0, 0181 ((qreal)c) / KoCmykColorSpaceMathsTraits<channels_type>::unitValue, 0182 (qreal)KoCmykColorSpaceMathsTraits<channels_type>::unitValue)); 0183 default: 0184 return QString("Error"); 0185 } 0186 } 0187 0188 inline static void normalisedChannelsValue(const quint8 *pixel, QVector<float> &v) 0189 { 0190 Q_ASSERT((int)v.count() == (int)parent::channels_nb); 0191 channels_type c; 0192 float *channels = v.data(); 0193 for (uint i = 0; i < parent::channels_nb; i++) { 0194 c = nativeArray(pixel)[i]; 0195 switch (i) { 0196 case c_pos: 0197 case m_pos: 0198 case y_pos: 0199 case k_pos: 0200 channels[i] = qBound((qreal)0, 0201 ((qreal)c) / KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK, 0202 (qreal)KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK); 0203 break; 0204 // As per KoChannelInfo alpha channels are [0..1] 0205 case 4: 0206 default: 0207 channels[i] = qBound((qreal)0, 0208 ((qreal)c) / KoCmykColorSpaceMathsTraits<channels_type>::unitValue, 0209 (qreal)KoCmykColorSpaceMathsTraits<channels_type>::unitValue); 0210 break; 0211 } 0212 } 0213 } 0214 0215 inline static void fromNormalisedChannelsValue(quint8 *pixel, const QVector<float> &values) { 0216 Q_ASSERT((int)values.count() == (int)parent::channels_nb); 0217 channels_type c; 0218 for (uint i = 0; i < parent::channels_nb; i++) { 0219 float b = 0; 0220 switch(i) { 0221 case c_pos: 0222 case m_pos: 0223 case y_pos: 0224 case k_pos: 0225 b = qBound((float)0, 0226 (float)KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK * values[i], 0227 (float)KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK); 0228 break; 0229 default: 0230 b = qBound((float)KoCmykColorSpaceMathsTraits<channels_type>::min, 0231 (float)KoCmykColorSpaceMathsTraits<channels_type>::unitValue * values[i], 0232 (float)KoCmykColorSpaceMathsTraits<channels_type>::max); 0233 break; 0234 } 0235 c = (channels_type)b; 0236 parent::nativeArray(pixel)[i] = c; 0237 } 0238 } 0239 }; 0240 0241 struct KoCmykF64Traits : public KoCmykTraits<double> { 0242 0243 inline static QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) { 0244 if (channelIndex > parent::channels_nb) return QString("Error"); 0245 channels_type c = nativeArray(pixel)[channelIndex]; 0246 switch (channelIndex) { 0247 case c_pos: 0248 case m_pos: 0249 case y_pos: 0250 case k_pos: 0251 return QString().setNum(100.0 * qBound((qreal)0, 0252 ((qreal)c) / KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK, 0253 (qreal)KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK)); 0254 case 4: 0255 return QString().setNum(100.0 * qBound((qreal)0, 0256 ((qreal)c) / KoCmykColorSpaceMathsTraits<channels_type>::unitValue, 0257 (qreal)KoCmykColorSpaceMathsTraits<channels_type>::unitValue)); 0258 default: 0259 return QString("Error"); 0260 } 0261 } 0262 0263 inline static void normalisedChannelsValue(const quint8 *pixel, QVector<float> &v) 0264 { 0265 Q_ASSERT((int)v.count() == (int)parent::channels_nb); 0266 channels_type c; 0267 float *channels = v.data(); 0268 for (uint i = 0; i < parent::channels_nb; i++) { 0269 c = nativeArray(pixel)[i]; 0270 switch (i) { 0271 case c_pos: 0272 case m_pos: 0273 case y_pos: 0274 case k_pos: 0275 channels[i] = qBound((qreal)0, 0276 ((qreal)c) / KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK, 0277 (qreal)KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK); 0278 break; 0279 // As per KoChannelInfo alpha channels are [0..1] 0280 case 4: 0281 default: 0282 channels[i] = qBound((qreal)0, 0283 ((qreal)c) / KoCmykColorSpaceMathsTraits<channels_type>::unitValue, 0284 (qreal)KoCmykColorSpaceMathsTraits<channels_type>::unitValue); 0285 break; 0286 } 0287 } 0288 } 0289 0290 inline static void fromNormalisedChannelsValue(quint8 *pixel, const QVector<float> &values) { 0291 Q_ASSERT((int)values.count() == (int)parent::channels_nb); 0292 channels_type c; 0293 for (uint i = 0; i < parent::channels_nb; i++) { 0294 float b = 0; 0295 switch(i) { 0296 case c_pos: 0297 case m_pos: 0298 case y_pos: 0299 case k_pos: 0300 b = qBound((float)0, 0301 (float)KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK * values[i], 0302 (float)KoCmykColorSpaceMathsTraits<channels_type>::unitValueCMYK); 0303 break; 0304 default: 0305 b = qBound((float)KoCmykColorSpaceMathsTraits<channels_type>::min, 0306 (float)KoCmykColorSpaceMathsTraits<channels_type>::unitValue * values[i], 0307 (float)KoCmykColorSpaceMathsTraits<channels_type>::max); 0308 break; 0309 } 0310 c = (channels_type)b; 0311 parent::nativeArray(pixel)[i] = c; 0312 } 0313 } 0314 }; 0315 0316 0317 0318 #endif 0319