File indexing completed on 2024-06-23 04:27:08
0001 /* 0002 * KDE. Krita Project. 0003 * 0004 * SPDX-FileCopyrightText: 2020 Deif Lou <ginoba@gmail.com> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #ifndef KISSCREENTONESCREENTONEFUNCTIONS_H 0010 #define KISSCREENTONESCREENTONEFUNCTIONS_H 0011 0012 #include <QtGlobal> 0013 0014 #include "KisScreentoneGeneratorTemplate.h" 0015 0016 namespace KisScreentoneScreentoneFunctions { 0017 0018 // NOTE: Screentone functions must return a value in the range [0.0, 1.0] 0019 // It must be a 2d function and you can think of it as a height map that is 0020 // later transformed using the brightness and contrast parameters. 0021 0022 // NOTE: The current functions are periodic. They use the concepts of screen 0023 // grid and grid cells. In each cell the shape is repeated. Each cell of the 0024 // screen should have a size of one unit in each direction. The size (scaling) 0025 // in the transformations dictates the final scaling of the pattern. 0026 0027 // NOTE: The normal spot functions just create a 2d function that makes the 0028 // shape in a simple way, but the area of the shape when the function is 0029 // thresholded may not have any connection with the threshold value itself 0030 // (which would be derived from the brightness). This can result in the visual 0031 // appearance of the screentone not corresponding with the lightness value 0032 // chosen. To solve that, the area of the shape inside the cell (in other 0033 // words, the coverage of the shape) must equal the threshold (lightness) value. 0034 // This is achieved in two different ways: 0035 // 1. The spot function is equalized. This is the same process as the one 0036 // used in image processing via histogram equalization: the histogram is 0037 // first computed and then a cumulative function is derived from it. If 0038 // we use the original image with this cumulative function, it would end 0039 // having a uniform value distribution. 0040 // Since we know here how the original functions look like before hand, 0041 // we also know their histogram so we don't have to compute it. Here the 0042 // the equalized versions of the functions just use the original 0043 // functions and pass them through a precomputed cumulative function 0044 // that equalizes them. Some of these cumulative functions were derived 0045 // analytically, but others, due to the complexity of the original 0046 // function, had to be empirically approximate as piecewise functions 0047 // using cubic functions for each piece. 0048 // 2. The second method is derived from traditional halftone screen 0049 // construction using a template. The template is filled with increasing 0050 // numbers from 0 to 1. For example, if the template is 10x10 pixels, 0051 // each of the 100 pixels will have a different value starting with 0 and 0052 // increasing by 1/100 through 1. This alone ensures the uniform 0053 // distribution, since there is exactly one pixel with the same value. 0054 // Now, to have the template resemble the original function's shape, we 0055 // have to evaluate the original function in each template pixel, and 0056 // then assign an index to each one based on the function's value (from 0057 // lower to higher; sort them in other words). Then the new value can be 0058 // computed as index/total_number_of_pixels_in_template. 0059 // These two modes and the original function can be chosen by the user and each 0060 // one has its pros/cons. 0061 0062 // NOTE: the linear variants of line patterns are already equalized in the 0063 // original functions so a typedef is used. Also, the equalized sinusoidal 0064 // variants of line patterns give the same results as the un-equalized linear 0065 // variants, so a typedef is also used 0066 0067 qreal sin(qreal x); 0068 qreal triangle(qreal x); 0069 qreal sawTooth(qreal x); 0070 0071 class DotsRoundLinear 0072 { 0073 public: 0074 qreal operator()(qreal x, qreal y) const; 0075 }; 0076 0077 class DotsRoundLinearEqualized : public DotsRoundLinear 0078 { 0079 public: 0080 qreal operator()(qreal x, qreal y) const; 0081 }; 0082 0083 class DotsRoundSinusoidal 0084 { 0085 public: 0086 qreal operator()(qreal x, qreal y) const; 0087 }; 0088 0089 class DotsRoundSinusoidalEqualized : public DotsRoundSinusoidal 0090 { 0091 public: 0092 qreal operator()(qreal x, qreal y) const; 0093 }; 0094 0095 class DotsEllipseLinear 0096 { 0097 public: 0098 qreal operator()(qreal x, qreal y) const; 0099 }; 0100 0101 class DotsEllipseLinearEqualized : public DotsEllipseLinear 0102 { 0103 public: 0104 qreal operator()(qreal x, qreal y) const; 0105 }; 0106 0107 class DotsEllipseSinusoidal 0108 { 0109 public: 0110 qreal operator()(qreal x, qreal y) const; 0111 }; 0112 0113 class DotsEllipseSinusoidalEqualized : public DotsEllipseSinusoidal 0114 { 0115 public: 0116 qreal operator()(qreal x, qreal y) const; 0117 }; 0118 0119 class DotsEllipseLinear_Legacy 0120 { 0121 public: 0122 qreal operator()(qreal x, qreal y) const; 0123 }; 0124 0125 using DotsEllipseLinearEqualized_Legacy = DotsEllipseLinear_Legacy; 0126 0127 using DotsEllipseSinusoidal_Legacy = DotsEllipseSinusoidal; 0128 0129 using DotsEllipseSinusoidalEqualized_Legacy = DotsEllipseSinusoidal; 0130 0131 class DotsDiamond 0132 { 0133 public: 0134 qreal operator()(qreal x, qreal y) const; 0135 }; 0136 0137 class DotsDiamondEqualized : public DotsDiamond 0138 { 0139 public: 0140 qreal operator()(qreal x, qreal y) const; 0141 }; 0142 0143 class DotsSquare 0144 { 0145 public: 0146 qreal operator()(qreal x, qreal y) const; 0147 }; 0148 0149 class DotsSquareEqualized : public DotsSquare 0150 { 0151 public: 0152 qreal operator()(qreal x, qreal y) const; 0153 }; 0154 0155 class LinesStraightLinear 0156 { 0157 public: 0158 qreal operator()(qreal x, qreal y) const; 0159 }; 0160 0161 using LinesStraightLinearEqualized = LinesStraightLinear; 0162 0163 class LinesStraightSinusoidal 0164 { 0165 public: 0166 qreal operator()(qreal x, qreal y) const; 0167 }; 0168 0169 using LinesStraightSinusoidalEqualized = LinesStraightLinear; 0170 0171 class LinesSineWaveLinear 0172 { 0173 public: 0174 qreal operator()(qreal x, qreal y) const; 0175 }; 0176 0177 using LinesSineWaveLinearEqualized = LinesSineWaveLinear; 0178 0179 class LinesSineWaveSinusoidal 0180 { 0181 public: 0182 qreal operator()(qreal x, qreal y) const; 0183 }; 0184 0185 using LinesSineWaveSinusoidalEqualized = LinesSineWaveLinear; 0186 0187 class LinesTriangularWaveLinear 0188 { 0189 public: 0190 qreal operator()(qreal x, qreal y) const; 0191 }; 0192 0193 using LinesTriangularWaveLinearEqualized = LinesTriangularWaveLinear; 0194 0195 class LinesTriangularWaveSinusoidal 0196 { 0197 public: 0198 qreal operator()(qreal x, qreal y) const; 0199 }; 0200 0201 using LinesTriangularWaveSinusoidalEqualized = LinesTriangularWaveLinear; 0202 0203 class LinesSawToothWaveLinear 0204 { 0205 public: 0206 qreal operator()(qreal x, qreal y) const; 0207 }; 0208 0209 using LinesSawToothWaveLinearEqualized = LinesSawToothWaveLinear; 0210 0211 class LinesSawToothWaveSinusoidal 0212 { 0213 public: 0214 qreal operator()(qreal x, qreal y) const; 0215 }; 0216 0217 using LinesSawToothWaveSinusoidalEqualized = LinesSawToothWaveLinear; 0218 0219 class LinesCurtainsLinear 0220 { 0221 public: 0222 qreal operator()(qreal x, qreal y) const; 0223 }; 0224 0225 using LinesCurtainsLinearEqualized = LinesCurtainsLinear; 0226 0227 class LinesCurtainsSinusoidal 0228 { 0229 public: 0230 qreal operator()(qreal x, qreal y) const; 0231 }; 0232 0233 using LinesCurtainsSinusoidalEqualized = LinesCurtainsLinear; 0234 0235 // The name "TemplateBasedFunction" has nothing to do with c++ templates even if 0236 // this class is templated. Here "Template" means that precomputed values are 0237 // used somehow. The class is templated to allow extensibility in the future 0238 template <typename T> 0239 class TemplateBasedFunction 0240 { 0241 public: 0242 TemplateBasedFunction(const T &the_template) 0243 : m_template(the_template) 0244 {} 0245 0246 qreal operator()(qreal x, qreal y) const 0247 { 0248 return m_template(x, y); 0249 } 0250 0251 private: 0252 const T& m_template; 0253 }; 0254 0255 } 0256 0257 #endif