Krita Source Code Documentation
Loading...
Searching...
No Matches
KisScreentoneScreentoneFunctions.h
Go to the documentation of this file.
1/*
2 * KDE. Krita Project.
3 *
4 * SPDX-FileCopyrightText: 2020 Deif Lou <ginoba@gmail.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#ifndef KISSCREENTONESCREENTONEFUNCTIONS_H
10#define KISSCREENTONESCREENTONEFUNCTIONS_H
11
12#include <QtGlobal>
13
15
17
18// NOTE: Screentone functions must return a value in the range [0.0, 1.0]
19// It must be a 2d function and you can think of it as a height map that is
20// later transformed using the brightness and contrast parameters.
21
22// NOTE: The current functions are periodic. They use the concepts of screen
23// grid and grid cells. In each cell the shape is repeated. Each cell of the
24// screen should have a size of one unit in each direction. The size (scaling)
25// in the transformations dictates the final scaling of the pattern.
26
27// NOTE: The normal spot functions just create a 2d function that makes the
28// shape in a simple way, but the area of the shape when the function is
29// thresholded may not have any connection with the threshold value itself
30// (which would be derived from the brightness). This can result in the visual
31// appearance of the screentone not corresponding with the lightness value
32// chosen. To solve that, the area of the shape inside the cell (in other
33// words, the coverage of the shape) must equal the threshold (lightness) value.
34// This is achieved in two different ways:
35// 1. The spot function is equalized. This is the same process as the one
36// used in image processing via histogram equalization: the histogram is
37// first computed and then a cumulative function is derived from it. If
38// we use the original image with this cumulative function, it would end
39// having a uniform value distribution.
40// Since we know here how the original functions look like before hand,
41// we also know their histogram so we don't have to compute it. Here the
42// the equalized versions of the functions just use the original
43// functions and pass them through a precomputed cumulative function
44// that equalizes them. Some of these cumulative functions were derived
45// analytically, but others, due to the complexity of the original
46// function, had to be empirically approximate as piecewise functions
47// using cubic functions for each piece.
48// 2. The second method is derived from traditional halftone screen
49// construction using a template. The template is filled with increasing
50// numbers from 0 to 1. For example, if the template is 10x10 pixels,
51// each of the 100 pixels will have a different value starting with 0 and
52// increasing by 1/100 through 1. This alone ensures the uniform
53// distribution, since there is exactly one pixel with the same value.
54// Now, to have the template resemble the original function's shape, we
55// have to evaluate the original function in each template pixel, and
56// then assign an index to each one based on the function's value (from
57// lower to higher; sort them in other words). Then the new value can be
58// computed as index/total_number_of_pixels_in_template.
59// These two modes and the original function can be chosen by the user and each
60// one has its pros/cons.
61
62// NOTE: the linear variants of line patterns are already equalized in the
63// original functions so a typedef is used. Also, the equalized sinusoidal
64// variants of line patterns give the same results as the un-equalized linear
65// variants, so a typedef is also used
66
67qreal sin(qreal x);
68qreal triangle(qreal x);
69qreal sawTooth(qreal x);
70
72{
73public:
74 qreal operator()(qreal x, qreal y) const;
75};
76
78{
79public:
80 qreal operator()(qreal x, qreal y) const;
81};
82
84{
85public:
86 qreal operator()(qreal x, qreal y) const;
87};
88
90{
91public:
92 qreal operator()(qreal x, qreal y) const;
93};
94
96{
97public:
98 qreal operator()(qreal x, qreal y) const;
99};
100
102{
103public:
104 qreal operator()(qreal x, qreal y) const;
105};
106
108{
109public:
110 qreal operator()(qreal x, qreal y) const;
111};
112
114{
115public:
116 qreal operator()(qreal x, qreal y) const;
117};
118
120{
121public:
122 qreal operator()(qreal x, qreal y) const;
123};
124
126
128
130
132{
133public:
134 qreal operator()(qreal x, qreal y) const;
135};
136
138{
139public:
140 qreal operator()(qreal x, qreal y) const;
141};
142
144{
145public:
146 qreal operator()(qreal x, qreal y) const;
147};
148
150{
151public:
152 qreal operator()(qreal x, qreal y) const;
153};
154
156{
157public:
158 qreal operator()(qreal x, qreal y) const;
159};
160
162
164{
165public:
166 qreal operator()(qreal x, qreal y) const;
167};
168
170
172{
173public:
174 qreal operator()(qreal x, qreal y) const;
175};
176
178
180{
181public:
182 qreal operator()(qreal x, qreal y) const;
183};
184
186
188{
189public:
190 qreal operator()(qreal x, qreal y) const;
191};
192
194
196{
197public:
198 qreal operator()(qreal x, qreal y) const;
199};
200
202
204{
205public:
206 qreal operator()(qreal x, qreal y) const;
207};
208
210
212{
213public:
214 qreal operator()(qreal x, qreal y) const;
215};
216
218
220{
221public:
222 qreal operator()(qreal x, qreal y) const;
223};
224
226
228{
229public:
230 qreal operator()(qreal x, qreal y) const;
231};
232
234
235// The name "TemplateBasedFunction" has nothing to do with c++ templates even if
236// this class is templated. Here "Template" means that precomputed values are
237// used somehow. The class is templated to allow extensibility in the future
238template <typename T>
240{
241public:
242 TemplateBasedFunction(const T &the_template)
243 : m_template(the_template)
244 {}
245
246 qreal operator()(qreal x, qreal y) const
247 {
248 return m_template(x, y);
249 }
250
251private:
252 const T& m_template;
253};
254
255}
256
257#endif