Dithering
---------

All dithering filters can produce a grayscale or RBG pixmap. Dithering to
palette or CMYK is not supported.

Dithering filters dither directly into the destination pixmap, the destination
must be large enough to fit the source

Allocating filters allocate destination pixmap accordingly to the pixel_type
and source size. These filters can return NULL in a case that malloc() failed
or if the operation was aborted from the callback.

Dithering filters doesn't work 'in-place' as the destination has different
pixel type than the source.

Floyd-Steinberg
~~~~~~~~~~~~~~~

[source,c]
-------------------------------------------------------------------------------
#include <gfxprim.h>
/* or */
#include <filters/gp_filters.h>

int gp_filter_floyd_steinberg(const gp_pixmap *src, gp_pixmap *dst,
                              gp_progress_cb *callback);

gp_pixmap *gp_filter_floyd_steinberg_alloc(const gp_pixmap *src,
                                           gp_pixel_type pixel_type,
                                           gp_progress_cb *callback);
-------------------------------------------------------------------------------

Classical Floyd-Steinberg. Produces good results at reasonable speed.

The error is distributed to neighbor pixels as follows:

[width="10%"]
|===================
|      |   X  | 7/16
| 3/16 | 5/16 | 1/16
|===================

And is thrown away at the image borders.

Sierra
~~~~~~

[source,c]
-------------------------------------------------------------------------------
#include <gfxprim.h>
/* or */
#include <filters/gp_filters.h>

int gp_filter_sierra_lite(const gp_pixmap *src, gp_pixmap *dst,
                          gp_progress_cb *callback);

gp_pixmap *gp_filter_sierra_lite_alloc(const gp_pixmap *src,
                                       gp_pixel_type pixel_type,
                                       gp_progress_cb *callback);
-------------------------------------------------------------------------------

Sierra-Lite is comparable to Floyd-Steinberg, sometimes the result is sharper.

The error is distributed to neighbor pixels as follows:

[width="10%"]
|================
|     |  X  | 2/4
| 1/4 | 1/4 |
|================

And is thrown away at the image borders.

[source,c]
-------------------------------------------------------------------------------
#include <gfxprim.h>
/* or */
#include <filters/gp_filters.h>

int gp_filter_sierra(const gp_pixmap *src, gp_pixmap *dst,
                     gp_progress_cb *callback);

gp_pixmap *gp_filter_sierra_alloc(const gp_pixmap *src,
                                  gp_pixel_type pixel_type,
                                  gp_progress_cb *callback);
-------------------------------------------------------------------------------

Sierra is much sharper than Floyd-Steinberg because the error is distributed
to a wider area. That results into edges are better preserved. Sierra also
produces less patterns than Floyd-Steinberg in some cases.

The error is distributed to neighbor pixels as follows:

[width="10%"]
|=================================
|      |      |   X  | 5/32 | 3/32
| 2/32 | 4/32 | 5/32 | 4/32 | 2/32
|      | 2/32 | 3/32 | 2/32 |
|=================================

And is thrown away at the image borders.

Hilbert-Peano
~~~~~~~~~~~~~

Hilbert-Peano space filling curve based dithering.

The error value is distributed along the Hilbert curve.

The result is a little more noisy, however most of the time doesn't create
repeating patterns like Floyd-Steinberg. The result looks generally better to
human eye, especially if there is more than a few bits to represent the
results. On the other hand edges tend to be less sharp and the hilbert curve
may 'leak' into the result in the case of big areas colored with a single
color.

[source,c]
-------------------------------------------------------------------------------
#include <gfxprim.h>
/* or */
#include <filters/gp_dither.h>

int gp_filter_hilbert_peano(const gp_pixmap *src, gp_pixmap *dst,
                            gp_progress_cb *callback);

gp_pixmap *gp_filter_hilbert_peano_alloc(const gp_pixmap *src,
                                         gp_pixel_type pixel_type,
                                         gp_progress_cb *callback);
-------------------------------------------------------------------------------

Ditherings
~~~~~~~~~~

[source,c]
-------------------------------------------------------------------------------
#include <gfxprim.h>
/* or */
#include <filters/gp_dither.h>

enum gp_dither_type {
        GP_DITHER_FLOYD_STEINBERG,
	GP_DITHER_SIERRA,
        GP_DITHER_SIERRA_LITE,
        GP_DITHER_HILBERT_PEANO,
        GP_DITHER_MAX,
};

gp_dither_type gp_dither_type_by_name(const char *dither_name);

const char *gp_dither_type_name(gp_dither_type dither_type);

int gp_filter_dither(gp_dither_type type,
                     const gp_pixmap *src, gp_pixmap *dst,
                     gp_progress_cb *callback);

gp_pixmap *gp_filter_dither_alloc(gp_dither_type type,
                                  const gp_pixmap *src,
                                  gp_pixel_type pixel_type,
                                  gp_progress_cb *callback);
-------------------------------------------------------------------------------

Generic dithering API, allows you to parse dithering type by string, print
dithering name by type and call dithering functions by type.

include::images/convert/images.txt[]
include::images/floyd_steinberg/images.txt[]
include::images/sierra/images.txt[]
include::images/sierra_lite/images.txt[]
include::images/hilbert_peano/images.txt[]
