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