using System.Collections.Generic; namespace Palettizer2 { public class Palette { public Dictionary GrayscaleToColorMap { get; } public Dictionary ColorToGrayscaleMap { get; } public int GrayscaleCount { get; set; } public List AlternateColorRows { get; } public const int Width = 256; public int Height => AlternateColorRows.Count + 1; public Palette() { GrayscaleToColorMap = new Dictionary(); ColorToGrayscaleMap = new Dictionary(); GrayscaleCount = 0; AlternateColorRows = new List(); } public void AddColor(Color color) { var average = (color.R + color.G + color.B) / 3; if (GrayscaleToColorMap.ContainsKey((byte)average)) { var increment = 1; for (var i = 0; i < 256; i += 1) { average = (average + increment) % 256; if (!GrayscaleToColorMap.ContainsKey((byte)average)) { break; } increment = ((increment > 0) ? (increment + 1) : (increment - 1)) * -1; // up by 1, down by 2, up by 3, etc } } GrayscaleToColorMap.Add((byte)average, color); ColorToGrayscaleMap.Add(color, (byte)average); GrayscaleCount += 1; } public void AddAlternateRowsFromOldPalette(StbImageSharp.ImageResult paletteImage) { // map row indices to original colors var indexToGrayscaleMap = new Dictionary(); for (var i = 0; i < paletteImage.Height; i += 1) { var sourceColor = new Color { R = paletteImage.Data[i * paletteImage.Width * 4], G = paletteImage.Data[i * paletteImage.Width * 4 + 1], B = paletteImage.Data[i * paletteImage.Width * 4 + 2], A = paletteImage.Data[i * paletteImage.Width * 4 + 3] }; if (!ColorToGrayscaleMap.ContainsKey(sourceColor)) { continue; //throw new System.Exception("Color not found! " + sourceColor); } indexToGrayscaleMap[i] = ColorToGrayscaleMap[sourceColor]; } // build the rows for (var j = 1; j < paletteImage.Width; j += 1) { var paletteRow = new Color[256]; for (var i = 0; i < paletteImage.Height; i += 1) { if (!indexToGrayscaleMap.ContainsKey(i)) { continue; } var grayscale = indexToGrayscaleMap[i]; paletteRow[grayscale].R = paletteImage.Data[(j + i * paletteImage.Width) * 4]; paletteRow[grayscale].G = paletteImage.Data[(j + i * paletteImage.Width) * 4 + 1]; paletteRow[grayscale].B = paletteImage.Data[(j + i * paletteImage.Width) * 4 + 2]; paletteRow[grayscale].A = paletteImage.Data[(j + i * paletteImage.Width) * 4 + 3]; } AddAlternateColorRow(paletteRow); } } public void AddAlternateColorRow(Color[] colors) { var byteArray = new byte[256 * 4]; for (var i = 0; i < 256; i += 1) { byteArray[i * 4] = colors[i].R; byteArray[i * 4 + 1] = colors[i].G; byteArray[i * 4 + 2] = colors[i].B; byteArray[i * 4 + 3] = colors[i].A; } AlternateColorRows.Add(byteArray); } public void ClearAlternateColorRows() { AlternateColorRows.Clear(); } public byte[] CreateIndexedPaletteBitmap() { var paletteBitmap = new byte[256 * (AlternateColorRows.Count + 1) * 4]; for (var i = 0; i < 256; i += 1) { var color = new Color(); color.A = 255; if (GrayscaleToColorMap.ContainsKey((byte)i)) { color = GrayscaleToColorMap[(byte)i]; } paletteBitmap[i * 4] = color.R; paletteBitmap[i * 4 + 1] = color.G; paletteBitmap[i * 4 + 2] = color.B; paletteBitmap[i * 4 + 3] = color.A; } for (var i = 0; i < 256; i += 1) { for (var j = 0; j < AlternateColorRows.Count; j += 1) { var alpha = AlternateColorRows[j][i * 4 + 3]; if (alpha == 0) { // grab from top row paletteBitmap[(i + (256 * (j + 1))) * 4] = paletteBitmap[i * 4]; paletteBitmap[(i + (256 * (j + 1))) * 4 + 1] = paletteBitmap[i * 4 + 1]; paletteBitmap[(i + (256 * (j + 1))) * 4 + 2] = paletteBitmap[i * 4 + 2]; paletteBitmap[(i + (256 * (j + 1))) * 4 + 3] = paletteBitmap[i * 4 + 3]; } else { paletteBitmap[(i + (256 * (j + 1))) * 4] = AlternateColorRows[j][i * 4]; paletteBitmap[(i + (256 * (j + 1))) * 4 + 1] = AlternateColorRows[j][i * 4 + 1]; paletteBitmap[(i + (256 * (j + 1))) * 4 + 2] = AlternateColorRows[j][i * 4 + 2]; paletteBitmap[(i + (256 * (j + 1))) * 4 + 3] = alpha; } } } return paletteBitmap; } } }