Understanding Screentone Generator

Hello,
Hope to find everyone well and healthy.

A lengthy explanation of why

I currently have a personal project that will use procedural generated screentone. While there is a healthy amount of papers discussing halftone, screentone and dithering, there isn’t many tutorials (that I know of) on how to code an robust halftone filter.

This leaves me with two options: Try to understand the theory behind the technique and implement ‘from scratch’, or use example from others. Like GLSL shaders, the awesome Newspaper plugin for halftoning, and obviously Krita’s Screentone Generator.

I decided to go with Krita’s code just because.

While digging throughout the Screentone code base and trying to understand its inner works, I thought of transcribing the C++ code in a more familiar language (GDScript). This to see which values the code expect to receive, what it passes around and how it interact with the image.

I believe that @Deif_Lou was the one to write the whole code right?
In the file: KisScreentoneBrightnessContrastFunctions.cpp we have the following snippet

if (contrast > 0.0) {
        if (qFuzzyCompare(contrast, 1.0)) {
            m_m = 10000.0;
        } else {
            m_m = 1.0 / (1.0 - contrast);
        }
        m_b = -m_m * (contrast / 2.0);
    } else {
        m_m = 1.0 + contrast;
        m_b = -contrast / 2.0;
    }
    m_b += (1.0 - m_b) * brightness;

From what I understood if the contrast value is (practically) 1 we default the variable m_m to a default value.
The m_m value with a contrast of .95 = 20 and .98 = 50. However why such a high value of 10000 (ten thousand) when the contrast is 1?

Cheers.

Well 1.0 / (1.0 - contrast) goes to infinity as contrast approaches 1.0.
Assuming this variable is the contrast you can adjust in th UI, it is presented as percentage with two decimals, so you can set it to 99.99%.
1.0/(1.0 - 0.9999) happens to be 10000.

1 Like

Thanks. That point in time you’re so engrossed in the overall that you ignore the basic mathematics right in your face.
I thought there was something more profound in that weird scaling based on a contrast nearing 1.0.

1 Like

Yes, @Lynx3d is right. The brightness and contrast values are used there to set up linear functions in the form y = mx + b. You can transform that code into formulas to put in desmos or geogebra to see better visually how the values affect the linear function. For example, m_m = 1.0 / (1.0 - contrast) is the slope, which makes a vertical line as contrast approaches 1, which is similar to a threshold filter (the effect of maximum contrast).

Thanks for the help.

Trying to read a mature and broad code base like Krita’s is always so difficult to me. Especially because I don’t really know C++, and its .h and .cpp dichotomy is low key annoying in my head. Not to mention the daunting sight when you see a dozen #include, and just get lost in the sauce.

On another note. The documentation don’t talk about the setting Hardness, and I still didn’t found the relevant code about it. Could be easy and quick to explain what it does?

Hardness is used in the halftone filter. It’s similar to contrast in the screentone generator but works for any generator you use in the halftone filter (one could say that the brightness is given by the image being “halftoned” itself, so it varies per pixel, contrary to the screentone which produces constant brightness). For best results, when using the screentone with the halftone filter, better leave the brightness/contrast with default values and use the hardness.

1 Like

This topic was automatically closed 4 days after the last reply. New replies are no longer allowed.