Krita Source Code Documentation
Loading...
Searching...
No Matches
KoAlphaColorSpace.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2004 Boudewijn Rempt <boud@valdyas.org>
3 * SPDX-FileCopyrightText: 2006 Cyrille Berger <cberger@cberger.net>
4 * SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
5 *
6 * SPDX-License-Identifier: LGPL-2.1-or-later
7 */
8#include "KoAlphaColorSpace.h"
9
10#include <limits.h>
11#include <stdlib.h>
12
13#include <QImage>
14#include <QBitArray>
15
16#include <klocalizedstring.h>
17
18#include "KoChannelInfo.h"
19#include "KoID.h"
20#include "KoIntegerMaths.h"
21#include "KoCompositeOpOver.h"
22#include "KoCompositeOpErase.h"
23#include "KoCompositeOpCopy2.h"
25#include "KoCompositeOpBase.h"
26#include "KoCompositeOps.h"
28
29namespace {
30template <typename channel_type> KoChannelInfo::enumChannelValueType channelInfoIdFromChannelType();
31template <> inline KoChannelInfo::enumChannelValueType channelInfoIdFromChannelType<quint8>() { return KoChannelInfo::UINT8; }
32template <> inline KoChannelInfo::enumChannelValueType channelInfoIdFromChannelType<quint16>() { return KoChannelInfo::UINT16; }
33#ifdef HAVE_OPENEXR
34template <> inline KoChannelInfo::enumChannelValueType channelInfoIdFromChannelType<half>() { return KoChannelInfo::FLOAT16; }
35#endif
36template <> inline KoChannelInfo::enumChannelValueType channelInfoIdFromChannelType<float>() { return KoChannelInfo::FLOAT32; }
37}
38
39template<class Traits>
40class AlphaColorSpaceMultiplyOp : public KoCompositeOpBase< Traits, AlphaColorSpaceMultiplyOp<Traits>>
41{
43 typedef typename Traits::channels_type channels_type;
44
45public:
48
49public:
50 template<bool alphaLocked, bool allChannelFlags>
52 channels_type* dst, channels_type dstAlpha, channels_type maskAlpha,
53 channels_type opacity, const QBitArray& channelFlags) {
54 using namespace Arithmetic;
55
56 Q_UNUSED(allChannelFlags);
57 Q_UNUSED(src);
58 Q_UNUSED(dst);
59 Q_UNUSED(channelFlags);
60
61 if (!alphaLocked) {
62 // use internal parallelism for multiplication!
63 srcAlpha = mul(srcAlpha, maskAlpha);
64 dstAlpha = mul(dstAlpha, opacity);
65 dstAlpha = mul(srcAlpha, dstAlpha);
66 }
67
68 return dstAlpha;
69 }
70};
71
72
73template <class _CSTrait>
77 , m_profile(new KoDummyColorProfile)
78{
79 this->addChannel(new KoChannelInfo(i18n("Alpha"), 0, 0, KoChannelInfo::ALPHA, channelInfoIdFromChannelType<channels_type>()));
80
84 this->addCompositeOp(createAlphaDarkenCompositeOp<_CSTrait>(this));
86}
87
88template <class _CSTrait>
90{
91 delete m_profile;
92 m_profile = 0;
93}
94
95template <class _CSTrait>
96void KoAlphaColorSpaceImpl<_CSTrait>::fromQColor(const QColor& c, quint8 *dst) const
97{
98 _CSTrait::nativeArray(dst)[0] = _MathsFromU8::scaleToA(c.alpha());
99}
100
101template <class _CSTrait>
102void KoAlphaColorSpaceImpl<_CSTrait>::toQColor(const quint8 * src, QColor *c) const
103{
104 c->setRgba(qRgba(255, 255, 255, _MathsToU8::scaleToA(_CSTrait::nativeArray(src)[0])));
105}
106
107template <class _CSTrait>
108quint8 KoAlphaColorSpaceImpl<_CSTrait>::difference(const quint8 *src1, const quint8 *src2) const
109{
110 return qAbs(_MathsToU8::scaleToA(_CSTrait::nativeArray(src2)[0] - _CSTrait::nativeArray(src1)[0]));
111}
112
113template <class _CSTrait>
114quint8 KoAlphaColorSpaceImpl<_CSTrait>::differenceA(const quint8 *src1, const quint8 *src2) const
115{
116 return difference(src1, src2);
117}
118
119template <class _CSTrait>
120QString KoAlphaColorSpaceImpl<_CSTrait>::channelValueText(const quint8 *pixel, quint32 channelIndex) const
121{
122 Q_ASSERT(channelIndex < this->channelCount());
123 const quint32 channelPosition = this->channels()[channelIndex]->pos();
124 return QString().setNum(_CSTrait::nativeArray(pixel)[channelPosition]);
125}
126
127template <class _CSTrait>
128QString KoAlphaColorSpaceImpl<_CSTrait>::normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) const
129{
130 Q_ASSERT(channelIndex < this->channelCount());
131 const quint32 channelPosition = this->channels()[channelIndex]->pos();
132 return QString().setNum(KoColorSpaceMaths<channels_type, float>::scaleToA(_CSTrait::nativeArray(pixel)[channelPosition]));
133}
134
135template <class _CSTrait>
136void KoAlphaColorSpaceImpl<_CSTrait>::convolveColors(quint8** colors, qreal * kernelValues, quint8 *dst, qreal factor, qreal offset, qint32 nColors, const QBitArray & channelFlags) const
137{
138 qreal totalAlpha = 0;
139
140 while (nColors--) {
141 qreal weight = *kernelValues;
142
143 if (weight != 0) {
144 totalAlpha += _CSTrait::nativeArray(*colors)[0] * weight;
145 }
146 ++colors;
147 ++kernelValues;
148 }
149
150 if (channelFlags.isEmpty() || channelFlags.testBit(0)) {
151 _CSTrait::nativeArray(dst)[0] = _Maths::clamp((totalAlpha / factor) + offset);
152 }
153}
154
155template <class _CSTrait>
156QImage KoAlphaColorSpaceImpl<_CSTrait>::convertToQImage(const quint8 *data, qint32 width, qint32 height,
157 const KoColorProfile * /*dstProfile*/,
158 KoColorConversionTransformation::Intent /*renderingIntent*/,
159 KoColorConversionTransformation::ConversionFlags /*conversionFlags*/) const
160{
161 const channels_type *srcPtr = _CSTrait::nativeArray(data);
162
163 QImage img(width, height, QImage::Format_Indexed8);
164 QVector<QRgb> table;
165 for (int i = 0; i < 256; ++i) table.append(qRgb(i, i, i));
166 img.setColorTable(table);
167
168 quint8* data_img;
169 for (int i = 0; i < height; ++i) {
170 data_img = img.scanLine(i);
171
172 for (int j = 0; j < width; ++j) {
173 data_img[j] = _MathsToU8::scaleToA(*(srcPtr++));
174 }
175 }
176
177 return img;
178}
179
180template <class _CSTrait>
181void KoAlphaColorSpaceImpl<_CSTrait>::toLabA16(const quint8 *src, quint8 *dst, quint32 nPixels) const {
182 const channels_type* srcPtr = _CSTrait::nativeArray(src);
183 quint16* dstPtr = reinterpret_cast<quint16*>(dst);
184
185 while (nPixels--) {
187 dstPtr[1] = UINT16_MAX / 2;
188 dstPtr[2] = UINT16_MAX / 2;
189 dstPtr[3] = UINT16_MAX;
190
191 srcPtr++;
192 dstPtr += 4;
193 }
194}
195
196template <class _CSTrait>
197void KoAlphaColorSpaceImpl<_CSTrait>::fromLabA16(const quint8 *src, quint8 *dst, quint32 nPixels) const {
198 const quint16* srcPtr = reinterpret_cast<const quint16*>(src);
199 channels_type* dstPtr = _CSTrait::nativeArray(dst);
200
201 while (nPixels--) {
202 dstPtr[0] = KoColorSpaceMaths<quint16, channels_type>::scaleToA(UINT16_MULT(srcPtr[0], srcPtr[3]));
203
204 dstPtr++;
205 srcPtr += 4;
206 }
207}
208
209template <class _CSTrait>
210void KoAlphaColorSpaceImpl<_CSTrait>::toRgbA16(const quint8 *src, quint8 *dst, quint32 nPixels) const {
211 const channels_type* srcPtr = _CSTrait::nativeArray(src);
212 quint16* dstPtr = reinterpret_cast<quint16*>(dst);
213
214 while (nPixels--) {
215 const quint16 gray = KoColorSpaceMaths<channels_type, quint16>::scaleToA(srcPtr[0]);
216
217 dstPtr[0] = gray;
218 dstPtr[1] = gray;
219 dstPtr[2] = gray;
220 dstPtr[3] = UINT16_MAX;
221
222 srcPtr++;
223 dstPtr += 4;
224 }
225}
226
227template <class _CSTrait>
228void KoAlphaColorSpaceImpl<_CSTrait>::fromRgbA16(const quint8 *src, quint8 *dst, quint32 nPixels) const {
229 const quint16* srcPtr = reinterpret_cast<const quint16*>(src);
230 channels_type* dstPtr = _CSTrait::nativeArray(dst);
231
232 while (nPixels--) {
233 // WARNING: we consider red channel only!
234 dstPtr[0] = KoColorSpaceMaths<quint16, channels_type>::scaleToA(UINT16_MULT(srcPtr[0], srcPtr[3]));
235
236 dstPtr++;
237 srcPtr += 4;
238 }
239}
240
241template <class _CSTrait>
246
247template <class _CSTrait>
252
255#ifdef HAVE_OPENEXR
257#endif
259
260/*********************************************************************************************/
261/* KoAlphaColorSpaceFactoryImpl */
262/*********************************************************************************************/
263
265
266template <class _CSTrait>
268{
275
276 factories << new KoColorConversionFromAlphaTransformationFactoryImpl<channels_type>(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), "Gray-D50-elle-V2-srgbtrc.icc");
277 factories << new KoColorConversionToAlphaTransformationFactoryImpl<channels_type>(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), "Gray-D50-elle-V2-srgbtrc.icc");
278
279 factories << new KoColorConversionFromAlphaTransformationFactoryImpl<channels_type>(GrayAColorModelID.id(), Integer16BitsColorDepthID.id(), "Gray-D50-elle-V2-srgbtrc.icc");
280 factories << new KoColorConversionToAlphaTransformationFactoryImpl<channels_type>(GrayAColorModelID.id(), Integer16BitsColorDepthID.id(), "Gray-D50-elle-V2-srgbtrc.icc");
281
282 factories << new KoColorConversionFromAlphaTransformationFactoryImpl<channels_type>(GrayAColorModelID.id(), Float16BitsColorDepthID.id(), "Gray-D50-elle-V2-srgbtrc.icc");
283 factories << new KoColorConversionToAlphaTransformationFactoryImpl<channels_type>(GrayAColorModelID.id(), Float16BitsColorDepthID.id(), "Gray-D50-elle-V2-srgbtrc.icc");
284
285 factories << new KoColorConversionFromAlphaTransformationFactoryImpl<channels_type>(GrayAColorModelID.id(), Float32BitsColorDepthID.id(), "Gray-D50-elle-V2-srgbtrc.icc");
286 factories << new KoColorConversionToAlphaTransformationFactoryImpl<channels_type>(GrayAColorModelID.id(), Float32BitsColorDepthID.id(), "Gray-D50-elle-V2-srgbtrc.icc");
287
288 return factories;
289}
290
293#ifdef HAVE_OPENEXR
295#endif
KoID alphaIdFromChannelType()
const KoID Float32BitsColorDepthID("F32", ki18n("32-bit float/channel"))
const KoID GrayAColorModelID("GRAYA", ki18n("Grayscale/Alpha"))
const KoID Float16BitsColorDepthID("F16", ki18n("16-bit float/channel"))
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
const QString COMPOSITE_MULT
#define UINT16_MAX
uint UINT16_MULT(uint a, uint b)
static channels_type composeColorChannels(const channels_type *src, channels_type srcAlpha, channels_type *dst, channels_type dstAlpha, channels_type maskAlpha, channels_type opacity, const QBitArray &channelFlags)
Traits::channels_type channels_type
KoCompositeOpBase< Traits, AlphaColorSpaceMultiplyOp< Traits > > base_class
AlphaColorSpaceMultiplyOp(const KoColorSpace *cs)
QList< KoColorConversionTransformationFactory * > colorConversionLinks() const override
void toQColor(const quint8 *src, QColor *c) const override
virtual KoColorSpace * clone() const
void toLabA16(const quint8 *src, quint8 *dst, quint32 nPixels) const override
void fromLabA16(const quint8 *src, quint8 *dst, quint32 nPixels) const override
void toRgbA16(const quint8 *src, quint8 *dst, quint32 nPixels) const override
_CSTrait::channels_type channels_type
void fromRgbA16(const quint8 *src, quint8 *dst, quint32 nPixels) const override
void fromQColor(const QColor &color, quint8 *dst) const override
QString channelValueText(const quint8 *pixel, quint32 channelIndex) const override
QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) const override
bool preferCompositionInSourceColorSpace() const override
QImage convertToQImage(const quint8 *data, qint32 width, qint32 height, const KoColorProfile *dstProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const override
virtual void convolveColors(quint8 **colors, qreal *kernelValues, quint8 *dst, qreal factor, qreal offset, qint32 nColors, const QBitArray &channelFlags) const
quint8 difference(const quint8 *src1, const quint8 *src2) const override
quint8 differenceA(const quint8 *src1, const quint8 *src2) const override
@ ALPHA
The channel represents the opacity of a pixel.
enumChannelValueType
enum to define the value of the channel
@ UINT8
use this for an unsigned integer 8bits channel
@ UINT16
use this for an integer 16bits channel
@ FLOAT32
use this for a float 32bits channel
@ FLOAT16
use this for a float 16bits channel
static _Tdst scaleToA(_T a)
virtual void addCompositeOp(const KoCompositeOp *op)
virtual void addChannel(KoChannelInfo *ci)
QString id() const
Definition KoID.cpp:63
static QString categoryArithmetic()