Skip to content

Screentone generator improvements

Deif Lou requested to merge deiflou/krita:deiflou/screentone_improvements into master

This MR improves the screentone generator. It adds some fatures and fixes some bugs.

NOTE: This is marked as draft because I want the users to test it first after reviewing and before merging.

Bug Fixes

  • Fix incorrect sampling of the screentone functions. Previously the functions were sampled at the top-left position of the pixel. Now they are sampled at the center of the pixel.
    screentone-sampling-before screentone-sampling-after
    First: previous behavior. Second: new behavior

  • Use a threshold function when the contrast is 100%. A ramp function is used for the contrast adjustement whose slope increments with the contrast. Idealy at 100% contrast the slope should go to infinity (a step function) but it doesn't to prevent divisions by 0. That produced that in some cases some gray pixels appeared when the contrast was 100%. Now a theshold function is used for the common case of 100% contrast which produces only "black" or "white" values.


  • Add new, more correct, ellipse spot function. The old one produced too big ellipses in the linear interpolation mode. The new one is more similar to the round shape in terms of area. The old one is kept and renamed to "Ellipse (Legacy)" for retro-compatibility.

  • Add new resolution/lpi based mode for setting the size in the transformations. Now the users can choose between a resolution based mode and an pixel based mode. In the resolution mode they set a resolution and change the frequency of the patterns in lines per inch/cm. The pixel mode is the old one in which you set the size of the cells manually. Those two modes are synched so changing the frequency will change the cell size and viceversa. This allows to always have the size in pixels available so that an older Krita can open the file. The default now is to use the resolution/frequency based size mode.

  • Align the screentone grid to pixel coordinates. If this option is set the geometric transformations set by the users will be used as usual to transform the screentone grid but they will be changed slightly so that the resulting corners of the cells will fall on integer coordinates. The effect is that all the cells will have the same shape in terms of pixels, producing a more pleasant and regular tiled structure. The user can set every how many cells the grid should be aligned horizontaly and verticaly. The new default is to set on the alignment every 1 cell.

    • Pros: The moire patterns are reduced and the shapes look nicer, more regular, specialy when small sizes are used.
    • Cons: The amount of geometric configurations is decreased since two or more different, but close, sets of transformation parameters will produce the same final aligned grid (for example, a cell corner at position (7.25, 4.3) and a cell corner at position (7.4, 4.0) will be rounded both to (7, 4). This is normal and well known in the halftone literature. It also happens on Photoshop and Clip Studio Paint. To improve this situation slightly the user can set every how many cells the grid should be aligned horizontaly and verticaly (the greater the spacing the more range of transformations, but also the more probable is the appearance of moire patterns).
      screentone-alignment-none screentone-alignment-1x1 screentone-alignment-2x2
      First: No alignment. Second: Aligned every 1 cell verticaly and horizontaly. Third: Aligned every 2 cells verticaly and horizontaly
  • Apply equalization to the spot functions. The spot functions are simple periodic 2D functions that output a value in the range [0, 1]. Every 1 cycle in the x and y directions forms a screentone cell and all the cells combined form the screentone grid. The spot functions are designed to be simple and fast to compute, but for some functions this mean that they don't have an uniform distribution of values. Suppose we threshold the function (contrast value equal to 100%, the usual in traditional digital halftoning). Then not having an uniform distribution of values has the downside of not producing shapes that have a direct relation between the selected brightness and the coverage of the black areas. The effect is a mismatch between the brightness parameter and the perceived brightness. If the function has an uniform distribution of values, for example choosing a brightness of 40% will produce a shape that has 40% of the pixels white and 60% black. To solve this now the user can select between three equalization modes:

    • None: by selecting this mode the generator will use the functions as is, it will not enforce an uniform distribution of values if the function is not already equalized. This is the same behavior as before.
      • Pros:
        • It is the fastest mode.
        • Nice smoothing of the edges.
      • Cons:
        • There is a missmatch between the brightness parameter and the perceived brightness.
        • Since it is an analitycal approach it may not produce a wide range of brightness variations when the cells are small. For example, the round dot shape grows radially. This means that if the radius grows 1px, then a bunch of pixels are added all around the dot. This produces a big jump on the perceived brightness.
      • When to use: use this mode when you need the most speed and don't care about the perceived brightness or the shapes at small cell sizes.
    • Function based equalization: this mode will perform something similar to histogram equalization to the spot function: a cumulative function is computed from the values of the spot function and it's used to equalize that. Since we know beforehand the spot function, we don't need to actualy compute the cumulative function in runtime, they are already precomputed in the code. So in this mode the precomputed cumulative function is applied to the original spot function, giving as a result an equalized version.
      • Pros:
        • It produces better perceived tones.
        • Nice smoothing of the edges.
      • Cons: Since it is still an analitycal approach it may not produce a wide range of brightness variations when the cells are small.
      • When to use: use this mode if you need accurate tone representation and you use big cell sizes, or if you need nice smoothing. For example if you use the screentone on graphic design works.
    • Template based equalization: this mode is a bit more involved. It tries to replicate the traditional screen generation methods on digital halftoning. It achieves equalization in a very different way. First the original spot function is used along with the transformation parameters to create a template (a small image) that contains a set of one or more contiguous cells. That set of cells is usualy called macrocell and is used as a reference later to paint the screentone grid. The size of the macrocell depends on two factors: the alignment properties and the smaller number of cells whose pixels combined can reproduce the whole brightness range (8bit, 256 values. I'm supposing binary pixels, the result of thresholding, the operation used in traditional digital halftoning). For example a 10x10px cell only has 100 pixels and no matter how you set them you only can have 100 different coverages (in terms of number of pixels set to black). So, to be able to reproduce the different 256 brightnesses, a macrocell of 2x2 cells is used (2x2x10x10 = 400. The optimal would be 3 cells but we enforce a square-as-possible macrocell to avoid biasing one direction over another). If we use the described template as is, the result might not be equalized (since the original spot function is used) and there would be sudden jumps on the perceived brightness. It would look similar as the none equalization mode. To equalize the template, all the pixels in the macrocell are then sorted from darker to lighter over all the macrocell and from top-left to bottom-right over each cell and an increasing value in the range [0, 1] is assigned to each of them acording to the sorting. This step will produce an equalized macrocell that grows 1 pixel at a time (or a bit more if the number of pixels in it is greater than 256), avoiding the sudden jumps in brightness.
      • Pros:
        • It produces better perceived tones.
        • No sudden jumps in perceived brightness.
      • Cons:
        • The shape may not be as correct as in the other cases, although it is difficult to perceive.
        • The smoothing of the edges is worst.
      • When to use:
        • Use this mode whenever possible, specialy if you want small cell sizes or if you want smooth transitions between perceived brightness values.
        • Use this mode if you use 100% contrast.
        • Use this mode if you use the screentone generator with the halftone filter.

    screentone-equalization-none screentone-equalization-function screentone-equalization-template
    These images show a screentone with 75% brightness and 100% contrast. On the left of each image there is the resulting pattern; on the center there is a blurred version of it; and on the right there is a reference solid color with 75% value. First image: no equalization. Second image: function based equalization. Third image: template based equalization

    This image shows the use of the screentone generator with the halftone filter. From top to bottom: the halftone filter applied to the image with 5x5px cell size; a blurred version of it; and the reference image. From left to right: no equalization; template based equalization; function based equalization. As can be seen, the template based equalization is capable of a wider perceived range of tones when small cell sizes are used

Internal Stuff

  • Now the generator uses a custom configuration class.
  • The plugin related classes were moved to new files.
  • The generator now uses the concept of samplers which are classes that can sample some function, image etc for any position in the image. This makes the generator class simpler and moves the responsability of sampling to independent pieces of code. Also it should be easier code-wise in the future adding new kinds of methods to generate patterns.
  • The tests were fixed.
  • Set better defaults for the generator and the halftone filter. The new default interpolation mode in the generator is sinusoidal and when changing the pattern or shape that is not reset, it will remember the interpolation mode set before. The halftone filter will try to set the best defaults when the screentone generator is used.

Formalities Checklist

  • I confirmed this builds.
  • I confirmed Krita ran and the relevant functions work.
  • I tested the relevant unit tests and can confirm they are not broken. (If not possible, don't hesitate to ask for help!)
  • I made sure my commits build individually and have good descriptions as per KDE guidelines.
  • I made sure my code conforms to the standards set in the HACKING file.
  • I can confirm the code is licensed and attributed appropriately, and that unattributed code is mine, as per KDE Licensing Policy.
Edited by Deif Lou

Merge request reports