Krita Source Code Documentation
Loading...
Searching...
No Matches
KoColorSpaceTraits.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2007 Cyrille Berger <cberger@cberger.net>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5*/
6
7#ifndef _KO_COLORSPACE_TRAITS_H_
8#define _KO_COLORSPACE_TRAITS_H_
9
10#include <QVector>
11#include <type_traits>
12
14#include "KoColorSpaceMaths.h"
15#include "DebugPigment.h"
16#include "kis_global.h"
17
18const int MAX_CHANNELS_TYPE_SIZE = sizeof(double);
19const int MAX_CHANNELS_NB = 5;
21
38template<typename _channels_type_, int _channels_nb_, int _alpha_pos_>
40
41 static_assert(sizeof(_channels_type_) <= MAX_CHANNELS_TYPE_SIZE, "MAX_CHANNELS_TYPE_SIZE too small");
42 static_assert(_channels_nb_ <= MAX_CHANNELS_NB, "MAX_CHANNELS_NB too small");
43
45 typedef _channels_type_ channels_type;
46
48 static const quint32 channels_nb = _channels_nb_;
49
52 static const qint32 alpha_pos = _alpha_pos_;
53
56
59
63 static const quint32 pixelSize = channels_nb * sizeof(channels_type);
64
68 inline static quint8 opacityU8(const quint8 * U8_pixel) {
69 if (alpha_pos < 0) return OPACITY_OPAQUE_U8;
70 channels_type c = nativeArray(U8_pixel)[alpha_pos];
72 }
73
74 inline static qreal opacityF(const quint8 * U8_pixel) {
75 if (alpha_pos < 0) return OPACITY_OPAQUE_F;
76 channels_type c = nativeArray(U8_pixel)[alpha_pos];
78 }
79
83 inline static void setOpacity(quint8 * pixels, quint8 alpha, qint32 nPixels) {
84 if (alpha_pos < 0) return;
85 qint32 psize = pixelSize;
87 for (; nPixels > 0; --nPixels, pixels += psize) {
88 nativeArray(pixels)[alpha_pos] = valpha;
89 }
90 }
91
92 inline static void setOpacity(quint8 * pixels, qreal alpha, qint32 nPixels) {
93 if (alpha_pos < 0) return;
94 qint32 psize = pixelSize;
96 for (; nPixels > 0; --nPixels, pixels += psize) {
97 nativeArray(pixels)[alpha_pos] = valpha;
98 }
99 }
100
104 inline static void copyOpacityU8(quint8* src, quint8* dst, qint32 nPixels) {
105 if (alpha_pos < 0) return;
106 qint32 psize = pixelSize;
107 for (; nPixels > 0; --nPixels, src += psize, dst++) {
110 }
111 }
112
116 inline static const channels_type* nativeArray(const quint8 * a) {
117 return reinterpret_cast<const channels_type*>(a);
118 }
119
123 inline static channels_type* nativeArray(quint8 * a) {
124 return reinterpret_cast< channels_type*>(a);
125 }
126
130 inline static quint8* allocate(quint32 nPixels) {
131 return new quint8[ nPixels * pixelSize ];
132 }
133
134 inline static void singleChannelPixel(quint8 *dstPixel, const quint8 *srcPixel, quint32 channelIndex) {
135 const channels_type* src = nativeArray(srcPixel);
136 channels_type* dst = nativeArray(dstPixel);
137 for (uint i = 0; i < channels_nb; i++) {
138 if (i != channelIndex) {
139 dst[i] = 0;
140 } else {
141 dst[i] = src[i];
142 }
143 }
144 }
145
146 inline static QString channelValueText(const quint8 *pixel, quint32 channelIndex) {
147 if (channelIndex > channels_nb) return QString("Error");
148 channels_type c = nativeArray(pixel)[channelIndex];
149 return QString().setNum(c);
150 }
151
152 inline static QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) {
153 if (channelIndex > channels_nb) return QString("Error");
154 channels_type c = nativeArray(pixel)[channelIndex];
155 return QString().setNum(100. *((qreal)c) / KoColorSpaceMathsTraits< channels_type>::unitValue);
156 }
157
158 inline static void normalisedChannelsValue(const quint8 *pixel, QVector<float> &v)
159 {
160 return normalisedChannelsValueImpl<channels_type>(pixel, v);
161 }
162
163 template<typename I, typename std::enable_if_t<std::numeric_limits<I>::is_integer, int> = 1>
164 inline static void normalisedChannelsValueImpl(const quint8 *pixel, QVector<float> &v)
165 {
166 Q_ASSERT((int)v.count() >= (int)channels_nb);
168 float *channels = v.data();
169 for (uint i = 0; i < channels_nb; i++) {
170 c = nativeArray(pixel)[i];
171 channels[i] = ((float)c) / KoColorSpaceMathsTraits<channels_type>::unitValue;
172 }
173 }
174
175 template<typename I, typename std::enable_if_t<!std::numeric_limits<I>::is_integer, int> = 1>
176 inline static void normalisedChannelsValueImpl(const quint8 *pixel, QVector<float> &v)
177 {
178 Q_ASSERT((int)v.count() >= (int)channels_nb);
179 float *channels = v.data();
180 for (uint i = 0; i < channels_nb; i++) {
181 channels[i] = float(nativeArray(pixel)[i]);
182 }
183 }
184
185 inline static void fromNormalisedChannelsValue(quint8 *pixel, const QVector<float> &values)
186 {
187 return fromNormalisedChannelsValueImpl<channels_type>(pixel, values);
188 }
189
190 template<typename I, typename std::enable_if_t<std::numeric_limits<I>::is_integer, int> = 1>
191 inline static void fromNormalisedChannelsValueImpl(quint8 *pixel, const QVector<float> &values)
192 {
193 Q_ASSERT((int)values.count() >= (int)channels_nb);
195 const float *v = values.data();
196 for (uint i = 0; i < channels_nb; i++) {
197 float b = qBound(
201 c = (channels_type)b;
202 nativeArray(pixel)[i] = c;
203 }
204 }
205
206 template<typename I, typename std::enable_if_t<!std::numeric_limits<I>::is_integer, int> = 1>
207 inline static void fromNormalisedChannelsValueImpl(quint8 *pixel, const QVector<float> &values)
208 {
209 Q_ASSERT((int)values.count() >= (int)channels_nb);
210 const float *v = values.data();
211 for (uint i = 0; i < channels_nb; i++) {
213 }
214 }
215
216 inline static void multiplyAlpha(quint8 * pixels, quint8 alpha, qint32 nPixels) {
217 if (alpha_pos < 0) return;
218
220
221 for (; nPixels > 0; --nPixels, pixels += pixelSize) {
222 channels_type* alphapixel = nativeArray(pixels) + alpha_pos;
223 *alphapixel = KoColorSpaceMaths<channels_type>::multiply(*alphapixel, valpha);
224 }
225 }
226
227 inline static void applyAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) {
228 if (alpha_pos < 0) return;
229
230 for (; nPixels > 0; --nPixels, pixels += pixelSize, ++alpha) {
232 channels_type* alphapixel = nativeArray(pixels) + alpha_pos;
233 *alphapixel = KoColorSpaceMaths<channels_type>::multiply(*alphapixel, valpha);
234 }
235 }
236
237 inline static void applyInverseAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) {
238 if (alpha_pos < 0) return;
239
240 for (; nPixels > 0; --nPixels, pixels += pixelSize, ++alpha) {
242 channels_type* alphapixel = nativeArray(pixels) + alpha_pos;
243 *alphapixel = KoColorSpaceMaths<channels_type>::multiply(*alphapixel, valpha);
244 }
245 }
246
247 inline static void applyAlphaNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) {
248 if (alpha_pos < 0) return;
249
250 for (; nPixels > 0; --nPixels, pixels += pixelSize, ++alpha) {
252 channels_type* alphapixel = nativeArray(pixels) + alpha_pos;
253 *alphapixel = KoColorSpaceMaths<channels_type>::multiply(*alphapixel, valpha);
254 }
255 }
256
257 inline static void applyInverseAlphaNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) {
258 if (alpha_pos < 0) return;
259
260 for (; nPixels > 0; --nPixels, pixels += pixelSize, ++alpha) {
262 channels_type* alphapixel = nativeArray(pixels) + alpha_pos;
263 *alphapixel = KoColorSpaceMaths<channels_type>::multiply(*alphapixel, valpha);
264 }
265 }
266
267 inline static void fillInverseAlphaNormedFloatMaskWithColor(quint8 * pixels, const float * alpha, const quint8 *brushColor, qint32 nPixels) {
268 if (alpha_pos < 0) return;
269
270 for (; nPixels > 0; --nPixels, pixels += pixelSize, ++alpha) {
271 memcpy(pixels, brushColor, pixelSize);
273 *(nativeArray(pixels) + alpha_pos) = valpha;
274 }
275 }
276
277
278 inline static void fillGrayBrushWithColor(quint8 *pixels, const QRgb *brush, quint8 *brushColor, qint32 nPixels) {
279 if (alpha_pos >= 0) {
280 for (; nPixels > 0; --nPixels, pixels += pixelSize, ++brush) {
281 memcpy(pixels, brushColor, pixelSize);
282 const quint8 opacity = KoColorSpaceMaths<quint8>::multiply(OPACITY_OPAQUE_U8 - quint8(qRed(*brush)), quint8(qAlpha(*brush)));
284 }
285 } else {
286 for (; nPixels > 0; --nPixels, pixels += pixelSize) {
287 memcpy(pixels, brushColor, pixelSize);
288 }
289 }
290 }
291};
292
300
301#endif
qreal v
const qreal OPACITY_OPAQUE_F
const quint8 OPACITY_OPAQUE_U8
const int MAX_PIXEL_SIZE
const int MAX_CHANNELS_NB
const int MAX_CHANNELS_TYPE_SIZE
unsigned int uint
static _Tdst multiply(_T a, _Tdst b)
static _Tdst scaleToA(_T a)
unsigned int QRgb
static const quint32 channels_nb
the number of channels in this color space
static quint8 opacityU8(const quint8 *U8_pixel)
static const qint32 alpha_pos
_channels_type_ channels_type
the type of the value of the channels of this color space
static void fromNormalisedChannelsValue(quint8 *pixel, const QVector< float > &values)
static const channels_type * nativeArray(const quint8 *a)
static QString channelValueText(const quint8 *pixel, quint32 channelIndex)
static void fillInverseAlphaNormedFloatMaskWithColor(quint8 *pixels, const float *alpha, const quint8 *brushColor, qint32 nPixels)
static void multiplyAlpha(quint8 *pixels, quint8 alpha, qint32 nPixels)
static void singleChannelPixel(quint8 *dstPixel, const quint8 *srcPixel, quint32 channelIndex)
static void applyInverseAlphaU8Mask(quint8 *pixels, const quint8 *alpha, qint32 nPixels)
static void normalisedChannelsValueImpl(const quint8 *pixel, QVector< float > &v)
static void applyAlphaU8Mask(quint8 *pixels, const quint8 *alpha, qint32 nPixels)
KoColorSpaceMathsTraits< _channels_type_ > math_trait
the associated math class
static QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex)
static const quint32 pixelSize
static void applyInverseAlphaNormedFloatMask(quint8 *pixels, const float *alpha, qint32 nPixels)
static qreal opacityF(const quint8 *U8_pixel)
static void setOpacity(quint8 *pixels, quint8 alpha, qint32 nPixels)
static quint8 * allocate(quint32 nPixels)
static const int depth
the number of bit for each channel
static channels_type * nativeArray(quint8 *a)
static void copyOpacityU8(quint8 *src, quint8 *dst, qint32 nPixels)
static void setOpacity(quint8 *pixels, qreal alpha, qint32 nPixels)
static void normalisedChannelsValue(const quint8 *pixel, QVector< float > &v)
static void fromNormalisedChannelsValueImpl(quint8 *pixel, const QVector< float > &values)
static void fillGrayBrushWithColor(quint8 *pixels, const QRgb *brush, quint8 *brushColor, qint32 nPixels)
static void applyAlphaNormedFloatMask(quint8 *pixels, const float *alpha, qint32 nPixels)