mirror of https://github.com/SixLabors/ImageSharp
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
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;
|
|
}
|
|
}
|
|
|