private static void BuildHistogram(Histogram histogram, ImageBuffer imageBuffer, int alphaThreshold, int alphaFader) { ColorMoment[, , ,] moments = histogram.Moments; foreach (Color32[] pixelLine in imageBuffer.PixelLines) { foreach (Color32 pixel in pixelLine) { byte pixelAlpha = pixel.A; if (pixelAlpha > alphaThreshold) { if (pixelAlpha < 255) { int alpha = pixel.A + (pixel.A % alphaFader); pixelAlpha = (byte)(alpha > 255 ? 255 : alpha); } byte pixelRed = pixel.R; byte pixelGreen = pixel.G; byte pixelBlue = pixel.B; pixelAlpha = (byte)((pixelAlpha >> 3) + 1); pixelRed = (byte)((pixelRed >> 3) + 1); pixelGreen = (byte)((pixelGreen >> 3) + 1); pixelBlue = (byte)((pixelBlue >> 3) + 1); moments[pixelAlpha, pixelRed, pixelGreen, pixelBlue].Add(pixel); } } } // Set a default pixel for images with less than 256 colors. moments[0, 0, 0, 0].Add(new Color32(0, 0, 0, 0)); }
/// <summary> /// Quantize an image and return the resulting output bitmap /// </summary> /// <param name="source"> /// The 32 bit per pixel image to quantize. /// </param> /// <param name="alphaThreshold"> /// All colors with an alpha value less than this will be considered fully transparent. /// </param> /// <param name="alphaFader"> /// Alpha values will be normalized to the nearest multiple of this value. /// </param> /// <param name="histogram"> /// The <see cref="Histogram"/> representing the distribution of color data. /// </param> /// <param name="maxColors"> /// The maximum number of colors apply to the image. /// </param> /// <returns> /// A quantized version of the image. /// </returns> public Bitmap Quantize(Image source, int alphaThreshold, int alphaFader, Histogram histogram, int maxColors) { try { ImageBuffer buffer; // The image has to be a 32 bit per pixel Argb image. if (Image.GetPixelFormatSize(source.PixelFormat) != 32) { Bitmap clone = new Bitmap(source.Width, source.Height, PixelFormat.Format32bppPArgb); clone.SetResolution(source.HorizontalResolution, source.VerticalResolution); using (Graphics graphics = Graphics.FromImage(clone)) { graphics.PageUnit = GraphicsUnit.Pixel; graphics.Clear(Color.Transparent); graphics.DrawImageUnscaled(source, new Rectangle(0, 0, clone.Width, clone.Height)); } source.Dispose(); buffer = new ImageBuffer(clone); } else { buffer = new ImageBuffer((Bitmap)source); } if (histogram == null) { histogram = new Histogram(); } else { histogram.Clear(); } BuildHistogram(histogram, buffer, alphaThreshold, alphaFader); CalculateMoments(histogram.Moments); Box[] cubes = SplitData(ref maxColors, histogram.Moments); Color32[] lookups = BuildLookups(cubes, histogram.Moments); return this.GetQuantizedImage(buffer, maxColors, lookups, alphaThreshold); } catch (Exception ex) { throw new QuantizationException(ex.Message, ex); } }