Meet us at PRINT 19. Chicago, IL. Oct. 3 - 5.
This documentation is for the old version. Go to the latest Graphics Mill docs

Basic Concepts of Color Reduction

Most color image printing and displaying devices do not have the capability to reproduce true color images. Consequently, the number of colors has to be reduced drastically to produce a color image with a limited palette. During the process of translation a true color image into a palette-based image reduction of color count takes place. An image becomes "poor", "color layers" come into particular prominence. You can notice the difference between the original true color image and the 256 color palette-based image.

Original true color image 32 color palette-based image without dithering
Original true color image 32 color palette-based
image without dithering

This article describes two main pecularities of color reducing which you will need to take into account when converting images.

Dithering

There is a class of algorithms, known as dithering, which allow to reduce the influence of this effect and to save the coloring of the original image. The main idea of these algorithms is redistribution of colors of neighbour pixels into some patterns. The eye averages two or more colors in a neighborhood of the point of interest and creates an illusion of another color. The resulting image of these patterns is percieved by a human eye as a new color which is not in the palette.

Another dithering parameter is its intensity - the ratio between the images with and without dithering. When 0% intensity is used, no dithering is visible (the same as disabled dithering).

There are 3 main classes of the dithering algorithms:

Noise Dithering

In this algorithm dithering patterns are built randomly. So a white random number in the range [-A;A] is added to each pixel of the original image. The following example illustrates the application of noise dithering during the process of creating a 32 color image.

Noise dithering
Noise dithering

Ordered Dithering

This dithering algorithm represents a fixed way of building dithering patterns. For the sake of simplicity let's imagine that output fixed-palette image has only two colors. We know that the human visual system tends to average a region around a pixel instead of treating each pixel individually, thus it is possible to create the illusion of many gray levels in a binary image, even though there are actually only two gray levels. With 2x2 binary pixel patterns, we can represent 5 different gray colors.

Different gray colors using 2x2 binary pixel patterns

The same method is used when the count of colors in palette is more than two. The patterns of the ordered dithering are predefined. The following example illustrates the application of the ordered dithering with Bayer pattern during the process of creating a 32 color image.

Bayer ordered dithering Spiral ordered dithering
Bayer ordered dithering Spiral ordered dithering

Error Diffusion

Error diffusion algorithms build dithering patterns dynamically basing on each pixel. After conversion of true color image pixels can differ from the same pixels of output palette-based image. This difference is called "quantization error". The error diffusion achieves the effect of color emulation by distributing this error encountered in quantizing a pixel to neighboring pixels, ensuring in effect, that the neighboring pixels are biased in the reverse direction. In practice the following error diffusion filters are used: Floyd-Steinberg, Fan, Burkes, Stucki, Sierra, Jarvice, Stephenson. These error diffusion filters use a fixed kernel: the coefficients of the error diffusion filter are preset. The following examples illustrate different diffusion filters.

Original dithering Floyd-Steinberg dithering Fan dithering Jarvis dithering
Original dithering Floyd-Steinberg
dithering
Fan dithering Jarvis dithering
Stucki dithering Sierra dithering Burkes dithering Stephenson dithering
Stucki dithering Sierra dithering Burkes dithering Stephenson dithering

How to Reduce Color in Graphics Mill for .NET

Noise dithering works very quickly but produces "noisy" images. Ordered dithering approximates color blends using fixed patterns; as a result, solid colors are emphasized and edges appear harder. Error diffusion scatters pixels irregularly, making edges and colors softer. Graphics Mill for .NET supports all these dithering techniques.

There are several ways to convert pixels to indexed pixel format:

Here is a simple example which converts an image to an 8-bit indexed image with default dithering parameters:

Visual Basic
'Convert to indexed image with default settings 
'(256 colors, Floyd-Steinberg dithering)
bitmap.ColorManagement.ConvertToIndexed(8, _
 Aurigma.GraphicsMill.ColorPaletteType.WebSafe, Nothing)
C#
//Convert to indexed image with default settings 
//(256 colors, Floyd-Steinberg dithering)
bitmap.ColorManagement.ConvertToIndexed(8, 
    Aurigma.GraphicsMill.ColorPaletteType.WebSafe, null);

The code below demonstrates how to modify all dithering settings. All images on this page where generated with it.

Visual Basic
Dim bitmap As New Aurigma.GraphicsMill.Bitmap("C:\Parrot.jpg")

Dim result As New Aurigma.GraphicsMill.Bitmap

Dim pixelFormatConverter As New Aurigma.GraphicsMill.Transforms.PixelFormatConverter

'Reduce color count to 32
pixelFormatConverter.PaletteEntryCount = 32
pixelFormatConverter.DestinationPixelFormat = _
 Aurigma.GraphicsMill.PixelFormat.Format8bppIndexed
pixelFormatConverter.Opacity = 1

'Without dithering
pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.None
pixelFormatConverter.ApplyTransform(bitmap, result)
result.Save("C:\Dithering_None_x_x_x_32.png")

'White noise
pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Noise
pixelFormatConverter.DitheringIntensity = 0.5
pixelFormatConverter.ApplyTransform(bitmap, result)
result.Save("C:\Dithering_Noise_50_x_x_32.png")

'Ordered dithering
pixelFormatConverter.DitheringIntensity = 1

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.OrderedBayer2
pixelFormatConverter.ApplyTransform(bitmap, result)
result.Save("C:\Dithering_Ordered_100_Bayer_2_32.png")

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.OrderedBayer4
pixelFormatConverter.ApplyTransform(bitmap, result)
result.Save("C:\Dithering_Ordered_100_Bayer_4_32.png")

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.OrderedSpiral4
pixelFormatConverter.ApplyTransform(bitmap, result)
result.Save("C:\Dithering_Ordered_100_Spiral_4_32.png")

'Error diffusion
pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Original
pixelFormatConverter.ApplyTransform(bitmap, result)
result.Save("C:\Dithering_Original_100_x_x_32.png")

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.FloydSteinberg
pixelFormatConverter.ApplyTransform(bitmap, result)
result.Save("C:\Dithering_FloydSteinberg_100_x_x_32.png")

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Fan
pixelFormatConverter.ApplyTransform(bitmap, result)
result.Save("C:\Dithering_Fan_100_x_x_32.png")

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Jarvis
pixelFormatConverter.ApplyTransform(bitmap, result)
result.Save("C:\Dithering_Jarvis_100_x_x_32.png")

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Stucki
pixelFormatConverter.ApplyTransform(bitmap, result)
result.Save("C:\Dithering_Stucki_100_x_x_32.png")

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Sierra
pixelFormatConverter.ApplyTransform(bitmap, result)
result.Save("C:\Dithering_Sierra_100_x_x_32.png")

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Burkes
pixelFormatConverter.ApplyTransform(bitmap, result)
result.Save("C:\Dithering_Burkes_100_x_x_32.png")

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Stephenson
pixelFormatConverter.ApplyTransform(bitmap, result)
result.Save("C:\Dithering_Stephenson_100_x_x_32.png")
C#
Aurigma.GraphicsMill.Bitmap bitmap = 
    new Aurigma.GraphicsMill.Bitmap(@"C:\Parrot.jpg");

Aurigma.GraphicsMill.Bitmap result = 
    new Aurigma.GraphicsMill.Bitmap();

Aurigma.GraphicsMill.Transforms.PixelFormatConverter pixelFormatConverter  = 
    new Aurigma.GraphicsMill.Transforms.PixelFormatConverter();

//Reduce color count to 32
pixelFormatConverter.PaletteEntryCount = 32;
pixelFormatConverter.DestinationPixelFormat = 
    Aurigma.GraphicsMill.PixelFormat.Format8bppIndexed;
pixelFormatConverter.Opacity = 1;

//Without dithering
pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.None;
pixelFormatConverter.ApplyTransform(bitmap, result);
result.Save(@"C:\Dithering_None_x_x_x_32.png");

//White noise
pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Noise;
pixelFormatConverter.DitheringIntensity = 0.5f;
pixelFormatConverter.ApplyTransform(bitmap, result);
result.Save(@"C:\Dithering_Noise_50_x_x_32.png");

//Ordered dithering
pixelFormatConverter.DitheringIntensity = 1;

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.OrderedBayer2;
pixelFormatConverter.ApplyTransform(bitmap, result);
result.Save(@"C:\Dithering_Ordered_100_Bayer_2_32.png");

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.OrderedBayer4;
pixelFormatConverter.ApplyTransform(bitmap, result);
result.Save(@"C:\Dithering_Ordered_100_Bayer_4_32.png");

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.OrderedSpiral4;
pixelFormatConverter.ApplyTransform(bitmap, result);
result.Save(@"C:\Dithering_Ordered_100_Spiral_4_32.png");

//Error diffusion
pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Original;
pixelFormatConverter.ApplyTransform(bitmap, result);
result.Save(@"C:\Dithering_Original_100_x_x_32.png");

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.FloydSteinberg;
pixelFormatConverter.ApplyTransform(bitmap, result);
result.Save(@"C:\Dithering_FloydSteinberg_100_x_x_32.png");

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Fan;
pixelFormatConverter.ApplyTransform(bitmap, result);
result.Save(@"C:\Dithering_Fan_100_x_x_32.png");

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Jarvis;
pixelFormatConverter.ApplyTransform(bitmap, result);
result.Save(@"C:\Dithering_Jarvis_100_x_x_32.png");

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Stucki;
pixelFormatConverter.ApplyTransform(bitmap, result);
result.Save(@"C:\Dithering_Stucki_100_x_x_32.png");

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Sierra;
pixelFormatConverter.ApplyTransform(bitmap, result);
result.Save(@"C:\Dithering_Sierra_100_x_x_32.png");

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Burkes;
pixelFormatConverter.ApplyTransform(bitmap, result);
result.Save(@"C:\Dithering_Burkes_100_x_x_32.png");

pixelFormatConverter.Dithering = Aurigma.GraphicsMill.Transforms.DitheringType.Stephenson;
pixelFormatConverter.ApplyTransform(bitmap, result);
result.Save(@"C:\Dithering_Stephenson_100_x_x_32.png");

See Also

Manual