Palettizer2/src/Palette.cs

159 lines
4.4 KiB
C#

using System.Collections.Generic;
namespace Palettizer2
{
public class Palette
{
public Dictionary<byte, Color> GrayscaleToColorMap { get; }
public Dictionary<Color, byte> ColorToGrayscaleMap { get; }
public int GrayscaleCount { get; set; }
public List<byte[]> AlternateColorRows { get; }
public const int Width = 256;
public int Height => AlternateColorRows.Count + 1;
public Palette()
{
GrayscaleToColorMap = new Dictionary<byte, Color>();
ColorToGrayscaleMap = new Dictionary<Color, byte>();
GrayscaleCount = 0;
AlternateColorRows = new List<byte[]>();
}
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<int, byte>();
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;
}
}
}