Ghostscript: halftoning and dithering
Tried to convert an image using Ghostscript and not happy with the result?
Tried to print the document in Linux using CUPS, and the printout has weird horizontal lines in it?
Algorithm
Ghostscript has several dithering and halftoning alrogithms. Auto selection depends on the following factors:
- DPI (resolution) of the output device: DPI >= 150 uses halftoning instead of dithering
-dDITHERPPI=xxxoption forces halftoning (despite the option name!) even for low DPI
| Output DPI | Alrogithm |
|---|---|
| < 150 | 8×8 ordered dithering |
| >= 150 | Horn's cosine line halftoning |
Dithering
By default, dithering is used only for low-DPI output devices, < 150 DPI.
Only a single dithering function is defined by default in the initialization script
Dithering is considered a low-resolution path, which toggles the following configuration:
- Screen: dithering
- Spot function: square 8×8 ordered dither (by Gregg Townsend)
- Screen angle: 0°
- Screen frequency:
DPI / 16by default - Transfer function: none ("Identity" in PDF terms)
- Stroke adjust: yes (pixel-perfect alignment, no sub-pixel processing)
Forcing 8×8 dithering for high DPI output
.setloresscreen function configures all the aforementioned options inside the initialization script, which is run after processing gs… -c option.
The easiest way to trigger auto-reconfiguration I found is to define /Install function inside Page Device.
.setloresscreen accepts DPI as an argument. The simple invocation for 300 DPI is as follows:
gs … -c '<< /Install { 300 .setloresscreen } >> setpagedevice' …
And with DPI auto-detection code, as seen in the initialization script:
gs … -c '<< /Install { 72 72 matrix defaultmatrix dtransform abs exch abs .min .setloresscreen } >> setpagedevice' …
Using ordered dithering with .genordered
Ghostscript also includes dithering + halftoning generator function based on the threshold array, called .genordered.
It performs ordered dither screening pattern with the selected DotShape pixel output.
- Screen: dithering + halftoning
- Spot function: CIRCLE, REDBOOK, INVERTED, RHOMBOID, LINE_X, LINE_Y, DIAMOND1, DIAMOND2, ROUNDSPOT, check gen_ordered.c
- Screen angle: selectable
- Screen frequency: selectable
- Transfer function: selectable
- Stroke adjust: selectable
Example:
gs … -c '<< /Frequency 150 /Angle 135 /DotShape 8 >> .genordered /Default exch /Halftone defineresource sethalftone { } settransfer 0.003 setsmoothness' …
In the example, { } settransfer removes the default { 0.8 exp } transfer function (which will make the image darker compared to the default), and also sets 0.003 setsmoothness which I'm not sure what it does, but that's what is used in gen_ordered_example.ps.
All .genordered parameters are optional, but you would probably want to set them anyway. Minimal example:
gs … -c '<< >> .genordered /Default exch /Halftone defineresource sethalftone { } settransfer 0.003 setsmoothness' …
Halftoning
Halftoning by default is used only for high-DPI output devices, >= 150 DPI.
The default halftone function, Horn's cosine spot, does not correspond to any halftone function defined in PDF standard.
Dithering is considered a high-resolution path, which toggles the following default configuration:
- Screen: rational tangent line screen
- Spot function: Berthold K.P. Horn's cosine line halftoning
- Screen angle: 45°
- Screen frequency: lookup table based on DPI, 150 max, forced with
-dDITHERPPI=xxx - Transfer function:
{ 0.8 exp }(prevent the image from being too dark) - Stroke adjust: no, not aligned to pixels
- Fill adjust:
0.5 dup .setfilladjust2, default Adobe's any-part-of-pixel rule
| DPI | Frequency (LPI) | Approx. gray levels |
|---|---|---|
| 100-199 | 46 | 6-8 |
| 200-299 | 46 | 20-26 |
| 300-399 | 60 | 26-31 |
| 400-499 | 60 | 45-55 |
| 500-599 | 60 | 70-88 |
| 600-699 | 106 | 33-39 |
| 700-799 | 106 | 44-51 |
| 800-899 | 106 | 57-68 |
| 900-999 | 106 | 72-89 |
| 1000-1099 | 133 | 57-68 |
| 1100-1499 | 133 | 69-127 |
| 1500+ | 150 | 101+ |
LPI (lines-per-inch) could be overridden with -dDITHERPPI=xxx, maximum value of which is limited by output device DPI / 4.01: min(DITHERPPI, dpi/4.01).
Note: it accepts accepts LPI, not DPI, despite the name (and it's not a dither option either!)
-dDITHERPPI= lpi
Forces all devices to be considered high-resolution, and forces use of a halftone screen or screens with lpi lines per inch, disregarding the actual device resolution. Reasonable values for lpi are N/5 to N/20, where N is the resolution in dots per inch.
The rendering options documentation additionally tells us the following:
On high-resolution devices (at least 150 dpi resolution, or
-dDITHERPPIspecified),-dCOLORSCREENforces the use of separate halftone screens with different angles for CMYK or RGB if halftones are needed (this produces the best-quality output);-dCOLORSCREEN=0uses separate screens with the same frequency and angle;-dCOLORSCREEN=falseforces the use of a single binary screen. The default ifCOLORSCREENis not specified is to use separate screens with different angles if the device has fewer than 5 bits per color, and a single binary screen (which is never actually used under normal circumstances) on all other devices.
| Condition | Angle |
|---|---|
dpi < 150 (if specifically forced) |
45° |
dpi >= 150 and -dCOLORSCREEN=false/0 |
45° |
dpi >= 150 and -dCOLORSCREEN=true (default) |
C=45° M=90° Y=15° K=75° |
Using halftone functions from PDF specification
PDF defines several common halftoning spot functions.
Check the Specification on pages 303-307.
You can use each of the spot functions as follows:
gs … -c '<< /HalftoneType 1 /Frequency 150 /Angle 45 /SpotFunction { dup mul exch dup mul add 1 exch sub } >> /Default exch /Halftone defineresource sethalftone' …
Where:
- HalftoneType: 1 for single halftone screen function (same function for each color), check Table 129 of PDF Specification for more information
- Frequency: LPI (lines-per-inch) value
- Angle: screen angle in degrees
- SpotFunction: function from the PDF specification (a copy of which could be found in pdf_gstate.c)
Using stochastic halftone
As the stocht.ps stochastic threshold-array halftoning script tells us:
% For printing technologies other than inkjet, Stochastic halftoning
% may not look better than standard screening. In particular, thermal
% transfer and direct thermal tend to be better with standard ordered
% screening methods. Some laser printers may produce "smoother"
% looking gray shades with Stochastic halftoning. Try it, and if
% you like it, use it.
This is a grainy halftoning algorithm with the output similar to classic dithering altorithms like Floyd-Steinberg, but it is not based on error diffusion.
Usage:
gs … -f stocht.ps …