1 /*
2  *  Copyright (c) 2006-2007 Cyrille Berger <cberger@cberger.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18 */
19 
20 #ifndef _KO_COLORSPACE_TRAITS_H_
21 #define _KO_COLORSPACE_TRAITS_H_
22 
23 #include <QVector>
24 
25 #include "KoColorSpaceConstants.h"
26 #include "KoColorSpaceMaths.h"
27 #include "DebugPigment.h"
28 
29 /**
30  * This class is the base class to define the main characteristics of a colorspace
31  * which inherits KoColorSpaceAbstract.
32  *
33  * - _channels_type_ is the type of the value use for each channel, for example quint8 for 8bits per channel
34  *                   color spaces, or quint16 for 16bits integer per channel, float for 32bits per channel
35  *                   floating point color spaces
36  * - _channels_nb_ is the total number of channels in an image (for example RGB is 3 but RGBA is four)
37  * - _alpha_pos_ is the position of the alpha channel among the channels, if there is no alpha channel,
38  *               then _alpha_pos_ is set to -1
39  *
40  * For instance a colorspace of three color channels and alpha channel in 16bits,
41  * will be defined as KoColorSpaceTrait\<quint16, 4, 3\>. The same without the alpha
42  * channel is KoColorSpaceTrait\<quint16,3,-1\>
43  *
44  */
45 template<typename _channels_type_, int _channels_nb_, int _alpha_pos_>
46 struct KoColorSpaceTrait {
47 
48     /// the type of the value of the channels of this color space
49     typedef _channels_type_ channels_type;
50 
51     /// the number of channels in this color space
52     static const quint32 channels_nb = _channels_nb_;
53 
54     /// the position of the alpha channel in the channels of the pixel (or -1 if no alpha
55     /// channel.
56     static const qint32 alpha_pos = _alpha_pos_;
57 
58     /// the number of bit for each channel
59     static const int depth = KoColorSpaceMathsTraits<_channels_type_>::bits;
60 
61     /**
62      * @return the size in byte of one pixel
63      */
64     static const quint32 pixelSize = channels_nb * sizeof(channels_type);
65 
66     /**
67      * @return the value of the alpha channel for this pixel in the 0..255 range
68      */
opacityU8KoColorSpaceTrait69     inline static quint8 opacityU8(const quint8 * U8_pixel) {
70         if (alpha_pos < 0) return OPACITY_OPAQUE_U8;
71         channels_type c = nativeArray(U8_pixel)[alpha_pos];
72         return  KoColorSpaceMaths<channels_type, quint8>::scaleToA(c);
73     }
74 
opacityFKoColorSpaceTrait75     inline static qreal opacityF(const quint8 * U8_pixel) {
76         if (alpha_pos < 0) return OPACITY_OPAQUE_F;
77         channels_type c = nativeArray(U8_pixel)[alpha_pos];
78         return  KoColorSpaceMaths<channels_type, qreal>::scaleToA(c);
79     }
80 
81     /**
82      * Set the alpha channel for this pixel from a value in the 0..255 range
83      */
setOpacityKoColorSpaceTrait84     inline static void setOpacity(quint8 * pixels, quint8 alpha, qint32 nPixels) {
85         if (alpha_pos < 0) return;
86         qint32 psize = pixelSize;
87         channels_type valpha =  KoColorSpaceMaths<quint8, channels_type>::scaleToA(alpha);
88         for (; nPixels > 0; --nPixels, pixels += psize) {
89             nativeArray(pixels)[alpha_pos] = valpha;
90         }
91     }
92 
setOpacityKoColorSpaceTrait93     inline static void setOpacity(quint8 * pixels, qreal alpha, qint32 nPixels) {
94         if (alpha_pos < 0) return;
95         qint32 psize = pixelSize;
96         channels_type valpha =  KoColorSpaceMaths<qreal, channels_type>::scaleToA(alpha);
97         for (; nPixels > 0; --nPixels, pixels += psize) {
98             nativeArray(pixels)[alpha_pos] = valpha;
99         }
100     }
101 
102     /**
103      * Convenient function for transforming a quint8* array in a pointer of the native channels type
104      */
nativeArrayKoColorSpaceTrait105     inline static const channels_type* nativeArray(const quint8 * a) {
106         return reinterpret_cast<const channels_type*>(a);
107     }
108 
109     /**
110      * Convenient function for transforming a quint8* array in a pointer of the native channels type
111      */
nativeArrayKoColorSpaceTrait112     inline static channels_type* nativeArray(quint8 * a) {
113         return reinterpret_cast< channels_type*>(a);
114     }
115 
116     /**
117      * Allocate nPixels pixels for this colorspace.
118      */
allocateKoColorSpaceTrait119     inline static quint8* allocate(quint32 nPixels) {
120         return new quint8[ nPixels * pixelSize ];
121     }
122 
singleChannelPixelKoColorSpaceTrait123     inline static void singleChannelPixel(quint8 *dstPixel, const quint8 *srcPixel, quint32 channelIndex) {
124         const channels_type* src = nativeArray(srcPixel);
125         channels_type* dst = nativeArray(dstPixel);
126         for (uint i = 0; i < channels_nb; i++) {
127             if (i != channelIndex) {
128                 dst[i] = 0;
129             } else {
130                 dst[i] = src[i];
131             }
132         }
133     }
134 
channelValueTextKoColorSpaceTrait135     inline static QString channelValueText(const quint8 *pixel, quint32 channelIndex) {
136         if (channelIndex > channels_nb) return QString("Error");
137         channels_type c = nativeArray(pixel)[channelIndex];
138         return QString().setNum(c);
139     }
140 
normalisedChannelValueTextKoColorSpaceTrait141     inline static QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) {
142         if (channelIndex > channels_nb) return QString("Error");
143         channels_type c = nativeArray(pixel)[channelIndex];
144         return QString().setNum(100. *((qreal)c) / KoColorSpaceMathsTraits< channels_type>::unitValue);
145     }
146 
normalisedChannelsValueKoColorSpaceTrait147     inline static void normalisedChannelsValue(const quint8 *pixel, QVector<qreal> &channels) {
148         Q_ASSERT((int)channels.count() == (int)channels_nb);
149         channels_type c;
150         for (uint i = 0; i < channels_nb; i++) {
151             c = nativeArray(pixel)[i];
152             channels[i] = ((qreal)c) / KoColorSpaceMathsTraits<channels_type>::unitValue;
153         }
154     }
155 
fromNormalisedChannelsValueKoColorSpaceTrait156     inline static void fromNormalisedChannelsValue(quint8 *pixel, const QVector<qreal> &values) {
157         Q_ASSERT((int)values.count() == (int)channels_nb);
158         channels_type c;
159         for (uint i = 0; i < channels_nb; i++) {
160             c = (channels_type)
161                     ((float)KoColorSpaceMathsTraits<channels_type>::unitValue * values[i]);
162             nativeArray(pixel)[i] = c;
163         }
164     }
multiplyAlphaKoColorSpaceTrait165     inline static void multiplyAlpha(quint8 * pixels, quint8 alpha, qint32 nPixels) {
166         if (alpha_pos < 0) return;
167 
168         channels_type valpha =  KoColorSpaceMaths<quint8, channels_type>::scaleToA(alpha);
169 
170         for (; nPixels > 0; --nPixels, pixels += pixelSize) {
171             channels_type* alphapixel = nativeArray(pixels) + alpha_pos;
172             *alphapixel = KoColorSpaceMaths<channels_type>::multiply(*alphapixel, valpha);
173         }
174     }
175 
applyAlphaU8MaskKoColorSpaceTrait176     inline static void applyAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) {
177         if (alpha_pos < 0) return;
178 
179         for (; nPixels > 0; --nPixels, pixels += pixelSize, ++alpha) {
180             channels_type valpha =  KoColorSpaceMaths<quint8, channels_type>::scaleToA(*alpha);
181             channels_type* alphapixel = nativeArray(pixels) + alpha_pos;
182             *alphapixel = KoColorSpaceMaths<channels_type>::multiply(*alphapixel, valpha);
183         }
184     }
185 
applyInverseAlphaU8MaskKoColorSpaceTrait186     inline static void applyInverseAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) {
187         if (alpha_pos < 0) return;
188 
189         for (; nPixels > 0; --nPixels, pixels += pixelSize, ++alpha) {
190             channels_type valpha =  KoColorSpaceMaths<quint8, channels_type>::scaleToA(OPACITY_OPAQUE_U8 - *alpha);
191             channels_type* alphapixel = nativeArray(pixels) + alpha_pos;
192             *alphapixel = KoColorSpaceMaths<channels_type>::multiply(*alphapixel, valpha);
193         }
194     }
195 
applyAlphaNormedFloatMaskKoColorSpaceTrait196     inline static void applyAlphaNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) {
197         if (alpha_pos < 0) return;
198 
199         for (; nPixels > 0; --nPixels, pixels += pixelSize, ++alpha) {
200             channels_type valpha =  channels_type(KoColorSpaceMathsTraits<channels_type>::unitValue * (*alpha));
201             channels_type* alphapixel = nativeArray(pixels) + alpha_pos;
202             *alphapixel = KoColorSpaceMaths<channels_type>::multiply(*alphapixel, valpha);
203         }
204     }
205 
applyInverseAlphaNormedFloatMaskKoColorSpaceTrait206     inline static void applyInverseAlphaNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) {
207         if (alpha_pos < 0) return;
208 
209         for (; nPixels > 0; --nPixels, pixels += pixelSize, ++alpha) {
210             channels_type valpha =  channels_type(KoColorSpaceMathsTraits<channels_type>::unitValue * (1.0f - *alpha));
211             channels_type* alphapixel = nativeArray(pixels) + alpha_pos;
212             *alphapixel = KoColorSpaceMaths<channels_type>::multiply(*alphapixel, valpha);
213         }
214     }
215 };
216 
217 #include "KoRgbColorSpaceTraits.h"
218 #include "KoBgrColorSpaceTraits.h"
219 #include "KoGrayColorSpaceTraits.h"
220 #include "KoLabColorSpaceTraits.h"
221 #include "KoXyzColorSpaceTraits.h"
222 #include "KoYcbcrColorSpaceTraits.h"
223 #include "KoCmykColorSpaceTraits.h"
224 
225 #endif
226