CSharp (C#) versions of certain dithering algorithms. This project is .NET Standard 2.0 and .NET 8 compatible, managed and available as Nuget!
This project contains implementations of different dithering algorithms (C#). They can be used with any graphics/image API.
As Wikipedia says "Dither is an intentionally applied form of noise used to randomize quantization error, preventing large-scale patterns such as color banding in images."
In this case dithering is used help in color reduction (less banding). This reduction of colors + dithering combo can be used e.g. to reduce file sizes, make artsy images and avoid issues when displaying images on displays that have limited color range.
Inspiration for this project came from blog post made by Tanner Helland.
DitheringBase.cs contains the abstract base class that every error pushing dithering implmentation should use.
FakeDithering.cs is "fake" dithering since it doesn't do any dithering. It is used to get image with reduced colors.
Other .cs files are used for different dithering algorithms, and the files are named as SomeAlgorithmDithering.cs
Samples folder contains images that are shown in the end of this Readme file
Use Atkinson dithering with web safe color reduction for 24 bit PNG input with System.Drawing
public void DoAtkinsonDithering()
{
AtkinsonDitheringRGBByte atkinson = new AtkinsonDitheringRGBByte(TrueColorBytesToWebSafeColorBytes);
using(FileStream pngStream = new FileStream("half.png", FileMode.Open, FileAccess.Read))
using(var image = new Bitmap(pngStream))
{
byte[,,] bytes = ReadBitmapToColorBytes(image);
TempByteImageFormat temp = new TempByteImageFormat(bytes);
atkinson.DoDithering(temp);
WriteToBitmap(image, temp.GetPixelChannels);
image.Save("test.png");
}
}
private static void TrueColorBytesToWebSafeColorBytes(in byte[] input, ref byte[] output)
{
for (int i = 0; i < input.Length; i++)
{
output[i] = (byte)(Math.Round(input[i] / 51.0) * 51);
}
}
private static byte[,,] ReadBitmapToColorBytes(Bitmap bitmap)
{
byte[,,] returnValue = new byte[bitmap.Width, bitmap.Height, 3];
for (int x = 0; x < bitmap.Width; x++)
{
for (int y = 0; y < bitmap.Height; y++)
{
Color color = bitmap.GetPixel(x, y);
returnValue[x, y, 0] = color.R;
returnValue[x, y, 1] = color.G;
returnValue[x, y, 2] = color.B;
}
}
return returnValue;
}
private static void WriteToBitmap(Bitmap bitmap, Func<int, int, byte[]> reader)
{
for (int x = 0; x < bitmap.Width; x++)
{
for (int y = 0; y < bitmap.Height; y++)
{
byte[] read = reader(x, y);
Color color = Color.FromArgb(read[0], read[1], read[2]);
bitmap.SetPixel(x, y, color);
}
}
}
You have to always give color reduction method as parameter for dither constructor. You can dither multiple images with one instance by calling DoDithering again with different input.
Yes, but time moves on...
Text in this document and source code files are released into the public domain. See PUBLICDOMAIN file.
Parrot image (half.png) is made from image that comes from Kodak Lossless True Color Image Suite and it doesn't have any specific license.
I took the famous parrot image and reduced its size. Then I ran the image (which has 64655 different colors) with all dithering methods and using Web safe colors as palette (216 colors).
No dithering, just color reduction