Krita Source Code Documentation
Loading...
Searching...
No Matches
KisDitherOpImpl.h
Go to the documentation of this file.
1/*
2 * This file is part of Krita
3 *
4 * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#pragma once
10
11#include <type_traits>
12
13#include "DebugPigment.h"
14#include "KoConfig.h"
15
16#ifdef HAVE_OPENEXR
17#include "half.h"
18#endif
19
21#include <KoColorSpace.h>
22#include <KoColorSpaceMaths.h>
23#include <KoColorSpaceTraits.h>
24
25#include "KisDitherOp.h"
26#include "KisDitherMaths.h"
27
28template<typename srcCSTraits, typename dstCSTraits, DitherType dType> class KisDitherOpImpl : public KisDitherOp
29{
30 using srcChannelsType = typename srcCSTraits::channels_type;
31 using dstChannelsType = typename dstCSTraits::channels_type;
32
33public:
34 KisDitherOpImpl(const KoID &srcId, const KoID &dstId)
35 : m_srcDepthId(srcId)
36 , m_dstDepthId(dstId)
37 {
38 }
39
40 void dither(const quint8 *src, quint8 *dst, int x, int y) const override
41 {
42 ditherImpl(src, dst, x, y);
43 }
44
45 void dither(const quint8 *srcRowStart, int srcRowStride, quint8 *dstRowStart, int dstRowStride, int x, int y, int columns, int rows) const override
46 {
47 ditherImpl(srcRowStart, srcRowStride, dstRowStart, dstRowStride, x, y, columns, rows);
48 }
49
50 KoID sourceDepthId() const override
51 {
52 return m_srcDepthId;
53 }
54
55 KoID destinationDepthId() const override
56 {
57 return m_dstDepthId;
58 }
59
60 DitherType type() const override
61 {
62 return dType;
63 }
64
65private:
67
68 template<DitherType t = dType, typename std::enable_if<t == DITHER_NONE && std::is_same<srcCSTraits, dstCSTraits>::value, void>::type * = nullptr> inline void ditherImpl(const quint8 *src, quint8 *dst, int, int) const
69 {
70 memcpy(dst, src, srcCSTraits::pixelSize);
71 }
72
73 template<DitherType t = dType, typename std::enable_if<t == DITHER_NONE && !std::is_same<srcCSTraits, dstCSTraits>::value, void>::type * = nullptr> inline void ditherImpl(const quint8 *src, quint8 *dst, int, int) const
74 {
75 const srcChannelsType *nativeSrc = srcCSTraits::nativeArray(src);
76 dstChannelsType *nativeDst = dstCSTraits::nativeArray(dst);
77
78 for (uint channelIndex = 0; channelIndex < srcCSTraits::channels_nb; ++channelIndex) {
79 nativeDst[channelIndex] = KoColorSpaceMaths<srcChannelsType, dstChannelsType>::scaleToA(nativeSrc[channelIndex]);
80 }
81 }
82
83 template<DitherType t = dType, typename std::enable_if<t != DITHER_NONE, void>::type * = nullptr>
84 inline void ditherImpl(const quint8 *src, quint8 *dst, int x, int y) const
85 {
86 const srcChannelsType *nativeSrc = srcCSTraits::nativeArray(src);
87 dstChannelsType *nativeDst = dstCSTraits::nativeArray(dst);
88
89 float f = factor(x, y);
90 float s = scale();
91
92 for (uint channelIndex = 0; channelIndex < srcCSTraits::channels_nb; ++channelIndex) {
93 float c = KoColorSpaceMaths<srcChannelsType, float>::scaleToA(nativeSrc[channelIndex]);
95 nativeDst[channelIndex] = KoColorSpaceMaths<float, dstChannelsType>::scaleToA(c);
96 }
97 }
98
99 template<DitherType t = dType, typename std::enable_if<t == DITHER_NONE && std::is_same<srcCSTraits, dstCSTraits>::value, void>::type * = nullptr>
100 inline void ditherImpl(const quint8 *srcRowStart, int srcRowStride, quint8 *dstRowStart, int dstRowStride, int, int, int columns, int rows) const
101 {
102 const quint8 *nativeSrc = srcRowStart;
103 quint8 *nativeDst = dstRowStart;
104
105 for (int y = 0; y < rows; ++y) {
106 memcpy(nativeDst, nativeSrc, srcCSTraits::pixelSize * columns);
107
108 nativeSrc += srcRowStride;
109 nativeDst += dstRowStride;
110 }
111 }
112
113 template<DitherType t = dType, typename std::enable_if<t == DITHER_NONE && !std::is_same<srcCSTraits, dstCSTraits>::value, void>::type * = nullptr>
114 inline void ditherImpl(const quint8 *srcRowStart, int srcRowStride, quint8 *dstRowStart, int dstRowStride, int, int, int columns, int rows) const
115 {
116 const quint8 *nativeSrc = srcRowStart;
117 quint8 *nativeDst = dstRowStart;
118
119 for (int y = 0; y < rows; ++y) {
120 const srcChannelsType *srcPtr = srcCSTraits::nativeArray(nativeSrc);
121 dstChannelsType *dstPtr = dstCSTraits::nativeArray(nativeDst);
122
123 for (int x = 0; x < columns; ++x) {
124 for (uint channelIndex = 0; channelIndex < srcCSTraits::channels_nb; ++channelIndex) {
125 dstPtr[channelIndex] = KoColorSpaceMaths<srcChannelsType, dstChannelsType>::scaleToA(srcPtr[channelIndex]);
126 }
127
128 srcPtr += srcCSTraits::channels_nb;
129 dstPtr += dstCSTraits::channels_nb;
130 }
131
132 nativeSrc += srcRowStride;
133 nativeDst += dstRowStride;
134 }
135 }
136
137 template<DitherType t = dType, typename std::enable_if<t != DITHER_NONE, void>::type * = nullptr>
138 inline void ditherImpl(const quint8 *srcRowStart, int srcRowStride, quint8 *dstRowStart, int dstRowStride, int x, int y, int columns, int rows) const
139 {
140 const quint8 *nativeSrc = srcRowStart;
141 quint8 *nativeDst = dstRowStart;
142
143 float s = scale();
144
145 for (int a = 0; a < rows; ++a) {
146 const srcChannelsType *srcPtr = srcCSTraits::nativeArray(nativeSrc);
147 dstChannelsType *dstPtr = dstCSTraits::nativeArray(nativeDst);
148
149 for (int b = 0; b < columns; ++b) {
150 float f = factor(x + b, y + a);
151
152 for (uint channelIndex = 0; channelIndex < srcCSTraits::channels_nb; ++channelIndex) {
153 float c = KoColorSpaceMaths<srcChannelsType, float>::scaleToA(srcPtr[channelIndex]);
154 c = KisDitherMaths::apply_dither(c, f, s);
156 }
157
158 srcPtr += srcCSTraits::channels_nb;
159 dstPtr += dstCSTraits::channels_nb;
160 }
161
162 nativeSrc += srcRowStride;
163 nativeDst += dstRowStride;
164 }
165 }
166
167 template<typename U = typename dstCSTraits::channels_type, typename std::enable_if<!std::numeric_limits<U>::is_integer, void>::type * = nullptr> constexpr float scale() const
168 {
169 return 0.f; // no dithering for floating point
170 }
171
172 template<typename U = typename dstCSTraits::channels_type, typename std::enable_if<std::numeric_limits<U>::is_integer, void>::type * = nullptr> constexpr float scale() const
173 {
174 return 1.f / static_cast<float>(1 << dstCSTraits::depth);
175 }
176
177 template<DitherType t = dType, typename std::enable_if<t == DITHER_BAYER, void>::type * = nullptr> inline float factor(int x, int y) const
178 {
180 }
181
182 template<DitherType t = dType, typename std::enable_if<t == DITHER_BLUE_NOISE, void>::type * = nullptr> inline float factor(int x, int y) const
183 {
185 }
186};
187
188template<typename srcCSTraits, class dstCSTraits> inline void addDitherOpsByDepth(KoColorSpace *cs, const KoID &dstDepth)
189{
190 const KoID &srcDepth {cs->colorDepthId()};
194}
void addDitherOpsByDepth(KoColorSpace *cs, const KoID &dstDepth)
DitherType
Definition KisDitherOp.h:21
unsigned int uint
typename dstCSTraits::channels_type dstChannelsType
void dither(const quint8 *srcRowStart, int srcRowStride, quint8 *dstRowStart, int dstRowStride, int x, int y, int columns, int rows) const override
DitherType type() const override
constexpr float scale() const
KoID destinationDepthId() const override
KisDitherOpImpl(const KoID &srcId, const KoID &dstId)
void ditherImpl(const quint8 *src, quint8 *dst, int, int) const
typename srcCSTraits::channels_type srcChannelsType
void ditherImpl(const quint8 *srcRowStart, int srcRowStride, quint8 *dstRowStart, int dstRowStride, int x, int y, int columns, int rows) const
void dither(const quint8 *src, quint8 *dst, int x, int y) const override
float factor(int x, int y) const
const KoID m_dstDepthId
void ditherImpl(const quint8 *srcRowStart, int srcRowStride, quint8 *dstRowStart, int dstRowStride, int, int, int columns, int rows) const
const KoID m_srcDepthId
KoID sourceDepthId() const override
void ditherImpl(const quint8 *src, quint8 *dst, int x, int y) const
static _Tdst scaleToA(_T a)
virtual void addDitherOp(KisDitherOp *op)
virtual KoID colorDepthId() const =0
Definition KoID.h:30
float apply_dither(float f, float d, float s)
float dither_factor_bayer_8(int x, int y)
float dither_factor_blue_noise_64(int x, int y)