Package net.sourceforge.jiu.color.dithering

# Class ErrorDiffusionDithering

java.lang.Object
net.sourceforge.jiu.ops.Operation
net.sourceforge.jiu.ops.ImageToImageOperation
net.sourceforge.jiu.color.dithering.ErrorDiffusionDithering

All Implemented Interfaces:
  `RGBIndex`

public class ErrorDiffusionDithering extends ImageToImageOperation implements RGBIndex
This class is used to apply error diffusion dithering to images that are being reduced in their color depth. Works with `GrayIntegerImage` and `RGBIntegerImage` objects. For RGB images, a quantizer must be specified via `setQuantizer(net.sourceforge.jiu.color.quantization.RGBQuantizer)`. That quantizer must have been initialized (it must have searched for / given a palette that it can map to).

This class offers six predefined types of error diffusion dithering. In addition, user-defined types can be integrated by providing a information on how the error is to be distributed; see the description of `setTemplateData(int[][])`.

### Usage examples

#### Color

This small program maps some RGB24Image object to a Paletted8Image with 120 entries in its palette, using Stucki error diffusion dithering in combination with an octree color quantizer.

     MemoryRGB24Image image = ...; // some RGB image
     OctreeColorQuantizer quantizer = new OctreeColorQuantizer();
     quantizer.setInputImage(image);
     quantizer.setPaletteSize(120);
     quantizer.init();
     ErrorDiffusionDithering edd = new ErrorDiffusionDithering();
     edd.setTemplateType(ErrorDiffusionDithering.TYPE_STUCKI);
     edd.setQuantizer(quantizer);
     edd.setInputImage(image);
     edd.process();
     PixelImage quantizedImage = edd.getOutputImage();

#### Grayscale to black and white

In this example, a `Gray8Image` object is reduced to black and white using Floyd-Steinberg dithering.

     Gray8Image image = ...; // some grayscale image
     ErrorDiffusionDithering edd = new ErrorDiffusionDithering();
     edd.setGrayscaleOutputBits(1);
     edd.setInputImage(image);
     edd.process();
     PixelImage ditheredImage = edd.getOutputImage();
     // if you need something more specific than PixelImage:
     BilevelImage output = null;
     // ditheredImage should be a BilevelImage...
     if (ditheredImage instanceof BilevelImage
     {
       // ... and it is!
       output = (BilevelImage)ditheredImage;
     }

### TODO

Adjust this class to be able to process 16 bits per sample.

### Theoretical background

The predefined templates were taken from the book Bit-mapped graphics (2nd edition) by Steve Rimmer, published by Windcrest / McGraw-Hill, ISBN 0-8306-4208-0. The part on error diffusion dithering starts on page 375.

Several sources recommend Robert Ulichney's book Digital Halftoning for this topic (published by The MIT Press, ISBN 0-262-21009-6). Unfortunately, I wasn't able to get a copy (or the CD-ROM version published by Dr. Dobb's Journal).

Since:
  0.5.0
Author:
  Marco Schmidt

## Field Summary

Fields
Modifier and Type
Field
Description
`private static final int[][]`
`BURKES_DATA`
`static final int`
`DEFAULT_TYPE`
The default error diffusion type, to be used if none is specified by the user: (@link #TYPE_FLOYD_STEINBERG}.
`private int[]`
`errorDen`
`private int[]`
`errorNum`
`private static final int[][]`
`FLOYD_STEINBERG_DATA`
`private int`
`grayBits`
`private int`
`imageWidth`
`static final int`
`INDEX_ERROR_DENOMINATOR`
The index of the denominator of the relative part of the error of a neighbor pixel.
`static final int`
`INDEX_ERROR_NUMERATOR`
The index of the numerator of the relative part of the error of a neighbor pixel.
`static final int`
`INDEX_X_POS`
The index for the horizontal position of a neighbor pixel.
`static final int`
`INDEX_Y_POS`
The index for the vertical position of a neighbor pixel.
`private int[]`
`indexLut`
`private static final int[][]`
`JARVIS_JUDICE_NINKE_DATA`
`private int`
`leftColumns`
`private int`
`newWidth`
`private int`
`numRows`
`private RGBQuantizer`
`quantizer`
`private int`
`rightColumns`
`private static final int[][]`
`SIERRA_DATA`
`private static final int[][]`
`STEVENSON_ARCE_DATA`
`private static final int[][]`
`STUCKI_DATA`
`private int[][]`
`templateData`
`static final int`
`TYPE_BURKES`
Constant for Burkes error diffusion.
`static final int`
`TYPE_FLOYD_STEINBERG`
Constant for Floyd-Steinberg error diffusion.
`static final int`
`TYPE_JARVIS_JUDICE_NINKE`
Constant for Burkes error diffusion.
`static final int`
`TYPE_SIERRA`
Constant for Burkes error diffusion.
`static final int`
`TYPE_STEVENSON_ARCE`
Constant for Burkes error diffusion.
`static final int`
`TYPE_STUCKI`
Constant for Stucki error diffusion.
`private boolean`
`useTruecolorOutput`

### Fields inherited from interface net.sourceforge.jiu.data.RGBIndex

`INDEX_BLUE, INDEX_GREEN, INDEX_RED`

## Constructor Summary

Constructors
Constructor
Description
`ErrorDiffusionDithering()`
Creates a new object of this class and set the dithering type to `DEFAULT_TYPE`.

## Method Summary

Modifier and Type
Method
Description
`private static int`
`adjust(int value, int max)`
Clamps the argument value to interval 0..max.
`private void`
`fillBuffer(int channelIndex, int rowIndex, int[] dest, int destOffset)`
Copies data from input image to argument buffer.
`private void`
`init(int[][] data, int imageWidth)`
`void`
`process()`
Quantizes the input image, distributing quantization errors to neighboring pixels.
`private void`
`process(Gray8Image in, BilevelImage out)`
`private void`
`process(Gray8Image in, Gray8Image out)`
`private void`
`process(RGB24Image in, Paletted8Image out)`
`private void`
`process(RGB24Image in, RGB24Image out)`
`void`
`setGrayscaleOutputBits(int numBits)`
Sets the number of bits to be in the output image when a grayscale image is quantized.
`void`
`setQuantizer(RGBQuantizer q)`
Sets the color quantizer to be used (if the input image is a truecolor image).
`void`
`setTemplateData(int[][] data)`
Set information on how errors are to be distributed by this error diffusion dithering operation.
`void`
`setTemplateType(int type)`
Sets a new template type.
`void`
`setTruecolorOutput(boolean truecolor)`
When dithering an RGB input image, this method specifies whether the output will be an `RGBIntegerImage` (`true`) or a `Paletted8Image` (`false`).

### Methods inherited from class net.sourceforge.jiu.ops.ImageToImageOperation

`canInputAndOutputBeEqual, ensureImagesHaveSameResolution, ensureInputImageIsAvailable, ensureOutputImageResolution, getInputImage, getOutputImage, setCanInputAndOutputBeEqual, setInputImage, setOutputImage`

### Methods inherited from class net.sourceforge.jiu.ops.Operation

`addProgressListener, addProgressListeners, getAbort, removeProgressListener, setAbort, setProgress, setProgress`

### Methods inherited from class java.lang.Object

`clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

## Field Details

### TYPE_FLOYD_STEINBERG

public static final int TYPE_FLOYD_STEINBERG
Constant for Floyd-Steinberg error diffusion. The quantization error is distributed to four neighboring pixels.

See Also:
  - Constant Field Values

### TYPE_STUCKI

public static final int TYPE_STUCKI
Constant for Stucki error diffusion. The quantization error is distributed to twelve neighboring pixels.

See Also:
  - Constant Field Values

### TYPE_BURKES

public static final int TYPE_BURKES
Constant for Burkes error diffusion. The quantization error is distributed to seven neighboring pixels.

See Also:
  - Constant Field Values

### TYPE_SIERRA

public static final int TYPE_SIERRA
Constant for Burkes error diffusion. The quantization error is distributed to ten neighboring pixels.

See Also:
  - Constant Field Values

### TYPE_JARVIS_JUDICE_NINKE

public static final int TYPE_JARVIS_JUDICE_NINKE
Constant for Burkes error diffusion. The quantization error is distributed to twelve neighboring pixels.

See Also:
  - Constant Field Values

### TYPE_STEVENSON_ARCE

public static final int TYPE_STEVENSON_ARCE
Constant for Burkes error diffusion. The quantization error is distributed to twelve neighboring pixels.

See Also:
  - Constant Field Values

### DEFAULT_TYPE

public static final int DEFAULT_TYPE
The default error diffusion type, to be used if none is specified by the user: (@link #TYPE_FLOYD_STEINBERG}.

See Also:
  - Constant Field Values

### INDEX_X_POS

public static final int INDEX_X_POS
The index for the horizontal position of a neighbor pixel. For a description, see the constructor `setTemplateData(int[][])`.

See Also:
  - Constant Field Values

### INDEX_Y_POS

public static final int INDEX_Y_POS
The index for the vertical position of a neighbor pixel. For a description, see the constructor `setTemplateData(int[][])`.

See Also:
  - Constant Field Values

### INDEX_ERROR_NUMERATOR

public static final int INDEX_ERROR_NUMERATOR
The index of the numerator of the relative part of the error of a neighbor pixel. For a description, see the constructor `setTemplateData(int[][])`.

See Also:
  - Constant Field Values

### INDEX_ERROR_DENOMINATOR

public static final int INDEX_ERROR_DENOMINATOR
The index of the denominator of the relative part of the error of a neighbor pixel. For a description, see the constructor `setTemplateData(int[][])`.

See Also:
  - Constant Field Values

### FLOYD_STEINBERG_DATA

private static final int[][] FLOYD_STEINBERG_DATA

### STUCKI_DATA

private static final int[][] STUCKI_DATA

### BURKES_DATA

private static final int[][] BURKES_DATA

### SIERRA_DATA

private static final int[][] SIERRA_DATA

### JARVIS_JUDICE_NINKE_DATA

private static final int[][] JARVIS_JUDICE_NINKE_DATA

### STEVENSON_ARCE_DATA

private static final int[][] STEVENSON_ARCE_DATA

### grayBits

private int grayBits

### imageWidth

private int imageWidth

### leftColumns

private int leftColumns

### rightColumns

private int rightColumns

### newWidth

private int newWidth

### numRows

private int numRows

### templateData

private int[][] templateData

### errorNum

private int[] errorNum

### errorDen

private int[] errorDen

### indexLut

private int[] indexLut

### quantizer

private RGBQuantizer quantizer

### useTruecolorOutput

private boolean useTruecolorOutput

## Constructor Details

### ErrorDiffusionDithering

public ErrorDiffusionDithering()
Creates a new object of this class and set the dithering type to `DEFAULT_TYPE`.

## Method Details

### adjust

private static int adjust(int value, int max)
Clamps the argument value to interval 0..max.

Parameters:
  `value` - the value to be adjusted
  `max` - the maximum allowed value (minimum is always 0)
Returns:
  the adjusted value

### fillBuffer

private void fillBuffer(int channelIndex, int rowIndex, int[] dest, int destOffset)
Copies data from input image to argument buffer.

Parameters:
  `channelIndex` - index of the channel of the input image from which data is to be copied
  `rowIndex` - index of the row of the input image from which data is to be copied
  `dest` - the array to which data is to be copied
  `destOffset` - index of the first element in the dest array to which data will be copied

### init

private void init(int[][] data, int imageWidth)

### process

public void process() throws MissingParameterException, WrongParameterException
Quantizes the input image, distributing quantization errors to neighboring pixels. Works for `Gray8Image` (then `setGrayscaleOutputBits(int)` must have been called to set a number of output bits between 1 and 7) objects and `RGB24Image` (then a quantizer must be specified using `setQuantizer(RGBQuantizer)`) objects.

Overrides:
  `process` in class `Operation`
Throws:
  `MissingParameterException` - if any mandatory parameter was not given to the operation
  `WrongParameterException` - if at least one of the input parameters was not initialized appropriately (values out of the valid interval, etc.)

### process

private void process(Gray8Image in, BilevelImage out)

### process

private void process(Gray8Image in, Gray8Image out)

### process

private void process(RGB24Image in, Paletted8Image out)

### process

private void process(RGB24Image in, RGB24Image out)

### setGrayscaleOutputBits

public void setGrayscaleOutputBits(int numBits)
Sets the number of bits to be in the output image when a grayscale image is quantized. If the input image is of type `Gray8Image`, only values between 1 and 7 are valid.

Parameters:
  `numBits` - the number of bits in the output image

### setQuantizer

public void setQuantizer(RGBQuantizer q)
Sets the color quantizer to be used (if the input image is a truecolor image).

Parameters:
  `q` - an object of a class implementing the RGBQuantizer interface

### setTemplateData

public void setTemplateData(int[][] data)
Set information on how errors are to be distributed by this error diffusion dithering operation.

Error diffusion dithering works by quantizing each pixel and distributing the resulting error to neighboring pixels. Quantizing maps a pixel to another pixel. Each pixel is made up of one or more samples (as an example, three samples rorig, gorig and borig for the original pixel of an RGB image and rquant, gquant and bquant for the quantized pixel).

The process of quantization attempts to find a quantized pixel that is as close to the original as possible. In the ideal case, the difference between original and quantized pixel is zero for each sample. Otherwise, this quantization error is non-zero, positive or negative. Example: original pixel (12, 43, 33), quantized pixel (10, 47, 40); the error is (12 - 10, 43 - 47, 40 - 33) = (2, -4, 7). The error (2, -4, 7) is to be distributed to neighboring pixels.

The `data` argument of this constructor describes how to do that. It is a two-dimensional array of int values. Each of the one-dimensional int arrays of `data` describe one neighboring pixel and the relative amount of the error that it gets. That is why `data.length` specifies the number of neighboring pixels involved in distributing the error. Let's call the pixel that was just quantized the current pixel. It is at image position (x, y).

Each of the one-dimensional arrays that are part of `data` must have a length of 4. The meaning of these four values is now described. The values can be accessed by the INDEX_xyz constants of this class. These four values describe the position of one neighboring pixel and the relative amount of the error that will be added to or subtracted from it.

- `INDEX_X_POS` (0): the difference between the horizontal position of the current pixel, x, and the neighboring pixel; can take a positive or negative value, or zero; exception: the y position of the current pixel is zero; in that case, this value must be larger than zero, because neighboring pixels that get part of the error must be to the right of or below the current pixel
- `INDEX_Y_POS` (1): the difference between the vertical position of the current pixel, y, and the neighboring pixel; must be equal to or larger than 0
- `INDEX_ERROR_NUMERATOR` (2): the numerator of the relative part of the error that wil be added to this neighboring pixel; must not be equal to 0
- `INDEX_ERROR_DENOMINATOR` (3): the denominator of the relative part of the error that wil be added to this neighboring pixel; must not be equal to 0

Example: the predefined dithering type Floyd-Steinberg. It has the following `data` array:

     int[][] FLOYD_STEINBERG = {{ 1,  0, 7, 16},
       {-1,  1, 3, 16},
       { 0,  1, 5, 16},
       { 1,  1, 1, 16}};

Each of the one-dimensional arrays is of length 4. Accidentally, there are also four one-dimensional arrays. The number of arrays is up to the designer. The first array {1, 0, 7, 16} is interpreted as follows--go to the pixel with a horizontal difference of 1 and a vertical difference of 0 (so, the pixel to the right of the current pixel) and add 7 / 16th of the quantization error to it. Then go to the pixel at position (-1, 1) (one to the left, one row below the current row) and add 3 / 16th of the error to it. The other two one-dimensional arrays are processed just like that.

As you can see, the four relative errors 1/16, 3/16, 5/16 and 7/16 sum up to 1 (or 16/16); this is in a precondition to make sure that the error is distributed completely.

Parameters:
  `data` - contains a description of how the error is to be distributed

### setTruecolorOutput

public void setTruecolorOutput(boolean truecolor)
When dithering an RGB input image, this method specifies whether the output will be an `RGBIntegerImage` (`true`) or a `Paletted8Image` (`false`).

Parameters:
  `truecolor` - true if truecolor output is wanted

### setTemplateType

public void setTemplateType(int type)
Sets a new template type. The argument must be one of the TYPE_xyz constants of this class.

Parameters:
  `type` - int value, one of the TYPE_xyz constants of this class
Throws:
  `IllegalArgumentException` - if the argument is not of the TYPE_xyz constants