📷 A modern, cross-platform, 2D Graphics library for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

138 lines
4.8 KiB

// -----------------------------------------------------------------------
// <copyright file="PaletteQuantizer.cs" company="James South">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------
namespace ImageProcessor.Imaging
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
/// <summary>
/// Encapsulates methods to calculate the colour palette if an image.
/// http://codebetter.com/brendantompkins/2007/06/14/gif-image-color-quantizer-now-with-safe-goodness/
/// </summary>
internal class PaletteQuantizer : Quantizer
{
/// <summary>
/// Initializes a new instance of the <see cref="PaletteQuantizer"/> class.
/// </summary>
/// <param name="palette">
/// The color palette to quantize to
/// </param>
/// <remarks>
/// Palette quantization only requires a single quantization step
/// </remarks>
public PaletteQuantizer(ArrayList palette)
: base(true)
{
_colorMap = new Hashtable();
_colors = new Color[palette.Count];
palette.CopyTo(_colors);
}
/// <summary>
/// Override this to process the pixel in the second pass of the algorithm
/// </summary>
/// <param name="pixel">The pixel to quantize</param>
/// <returns>The quantized value</returns>
protected override byte QuantizePixel(Color32 pixel)
{
byte colorIndex = 0;
int colorHash = pixel.ARGB;
// Check if the color is in the lookup table
if (_colorMap.ContainsKey(colorHash))
{
colorIndex = (byte)_colorMap[colorHash];
}
else
{
// Not found - loop through the palette and find the nearest match.
// Firstly check the alpha value - if 0, lookup the transparent color
if (0 == pixel.Alpha)
{
// Transparent. Lookup the first color with an alpha value of 0
for (int index = 0; index < _colors.Length; index++)
{
if (0 == _colors[index].A)
{
colorIndex = (byte)index;
break;
}
}
}
else
{
// Not transparent...
int leastDistance = int.MaxValue;
int red = pixel.Red;
int green = pixel.Green;
int blue = pixel.Blue;
// Loop through the entire palette, looking for the closest color match
for (int index = 0; index < _colors.Length; index++)
{
Color paletteColor = _colors[index];
int redDistance = paletteColor.R - red;
int greenDistance = paletteColor.G - green;
int blueDistance = paletteColor.B - blue;
int distance = (redDistance * redDistance) +
(greenDistance * greenDistance) +
(blueDistance * blueDistance);
if (distance < leastDistance)
{
colorIndex = (byte)index;
leastDistance = distance;
// And if it's an exact match, exit the loop
if (0 == distance)
{
break;
}
}
}
}
// Now I have the color, pop it into the hashtable for next time
_colorMap.Add(colorHash, colorIndex);
}
return colorIndex;
}
/// <summary>
/// Retrieve the palette for the quantized image
/// </summary>
/// <param name="palette">Any old palette, this is overrwritten</param>
/// <returns>The new color palette</returns>
protected override ColorPalette GetPalette(ColorPalette palette)
{
for (int index = 0; index < _colors.Length; index++)
{
palette.Entries[index] = _colors[index];
}
return palette;
}
/// <summary>
/// Lookup table for colors
/// </summary>
private Hashtable _colorMap;
/// <summary>
/// List of all colors in the palette
/// </summary>
protected Color[] _colors;
}
}