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