Krita Source Code Documentation
Loading...
Searching...
No Matches
KoConvolutionOpImpl.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006 Cyrille Berger <cberger@cberger.net>
3 * SPDX-FileCopyrightText: 2007 Emanuele Tamponi <emanuele@valinor.it>
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6*/
7
8#ifndef KO_CONVOLUTION_OP_IMPL_H
9#define KO_CONVOLUTION_OP_IMPL_H
10
11#include "DebugPigment.h"
12#include "KoColorSpaceMaths.h"
13#include "KoConvolutionOp.h"
14#include "KoColorSpaceTraits.h"
15
16template<class _CSTrait>
18{
20 typedef typename _CSTrait::channels_type channels_type;
21public:
22
24
25 ~KoConvolutionOpImpl() override { }
26
63 void convolveColors(const quint8* const* colors, const qreal* kernelValues, quint8 *dst, qreal factor, qreal offset, qint32 nPixels, const QBitArray & channelFlags) const override {
64
65 // Create and initialize to 0 the array of totals
66 qreal totals[_CSTrait::channels_nb];
67
68 qreal totalWeight = 0;
69 qreal totalWeightTransparent = 0;
70
71 memset(totals, 0, sizeof(qreal) * _CSTrait::channels_nb);
72
73 for (; nPixels--; colors++, kernelValues++) {
74 qreal weight = *kernelValues;
75 const channels_type* color = _CSTrait::nativeArray(*colors);
76 if (weight != 0) {
77 if (_CSTrait::opacityU8(*colors) == 0) {
78 totalWeightTransparent += weight;
79 } else {
80 for (uint i = 0; i < _CSTrait::channels_nb; i++) {
81 totals[i] += color[i] * weight;
82 }
83 }
84 totalWeight += weight;
85 }
86 }
87
88 typename _CSTrait::channels_type* dstColor = _CSTrait::nativeArray(dst);
89
90 bool allChannels = channelFlags.isEmpty();
91 Q_ASSERT(allChannels || channelFlags.size() == (int)_CSTrait::channels_nb);
92 if (totalWeightTransparent == 0) {
93 // Case A)
94 for (uint i = 0; i < _CSTrait::channels_nb; i++) {
95 if (allChannels || channelFlags.testBit(i)) {
96 compositetype v = totals[i] / factor + offset;
99 }
100 }
101 } else if (totalWeightTransparent != totalWeight) {
102 if (totalWeight == factor) {
103 // Case B)
104 qint64 a = (totalWeight - totalWeightTransparent);
105 for (uint i = 0; i < _CSTrait::channels_nb; i++) {
106 if (allChannels || channelFlags.testBit(i)) {
107 if (i == (uint)_CSTrait::alpha_pos) {
108 compositetype v = totals[i] / totalWeight + offset;
111 } else {
112 compositetype v = totals[i] / a + offset;
115 }
116 }
117 }
118 } else {
119 // Case C)
120 qreal a = qreal(totalWeight) / (factor * (totalWeight - totalWeightTransparent)); // use qreal as it easily saturate
121 for (uint i = 0; i < _CSTrait::channels_nb; i++) {
122 if (allChannels || channelFlags.testBit(i)) {
123 if (i == (uint)_CSTrait::alpha_pos) {
124 compositetype v = totals[i] / factor + offset;
127 } else {
128 compositetype v = (compositetype)(totals[i] * a + offset);
131 }
132 }
133 }
134 }
135 }
136
137 }
138};
139
140#endif
qreal v
unsigned int uint
_CSTrait::channels_type channels_type
void convolveColors(const quint8 *const *colors, const qreal *kernelValues, quint8 *dst, qreal factor, qreal offset, qint32 nPixels, const QBitArray &channelFlags) const override
KoColorSpaceMathsTraits< typename_CSTrait::channels_type >::compositetype compositetype
#define CLAMP(x, l, h)