public Palette Combine(Palette secondPalette) { List<byte> bytes = new List<byte>(); bytes.AddRange(RawData); bytes.AddRange(secondPalette.RawData); return new Palette(-1, bytes.ToArray()); }
private static Texture ReadTextureFromTMem(TileDescriptor tile, Palette palette = null) { Texture newTexture; if (!TMEM.LoadedData.ContainsKey(tile.TMem)) return null; //if (!tile.On) //Not sure if used?? // return null; int offset = TMEM.LoadedData[tile.TMem].FileOffset; int sizeOfData = TMEM.LoadedData[tile.TMem].Size; int widthInBytes = 8 * tile.Line; double texelSize = 1; switch (tile.PixelSize) { case Texture.PixelInfo.Size_4b: texelSize = 0.5; break; case Texture.PixelInfo.Size_16b: texelSize = 2; break; case Texture.PixelInfo.Size_32b: texelSize = 4; break; } int widthInTexels = (int)Math.Round(widthInBytes / texelSize); int heightInTexels = sizeOfData / widthInBytes; byte[] data = new byte[sizeOfData]; Array.Copy(TMEM.Data, tile.TMemInBytes, data, 0, sizeOfData); if(tile.ImageFormat == Texture.ImageFormat.CI) newTexture = new Texture(offset, data, tile.ImageFormat, tile.PixelSize, widthInTexels, heightInTexels, palette, tile.Palette); else newTexture = new Texture(offset, data, tile.ImageFormat, tile.PixelSize, widthInTexels, heightInTexels, null); tile.SettingsChanged = false; return newTexture; }
private const int PALETTE_TMEM_OFFSET_IN_BYTES = 0x800; //offset * 8 private static Palette ReadPaletteFromTMem() { Palette newPalette; if (!TMEM.LoadedData.ContainsKey(PALETTE_TMEM_OFFSET)) return null; int offset = TMEM.LoadedData[PALETTE_TMEM_OFFSET].FileOffset; int sizeOfData = TMEM.LoadedData[PALETTE_TMEM_OFFSET].Size; byte[] data = new byte[sizeOfData]; Array.Copy(TMEM.Data, PALETTE_TMEM_OFFSET_IN_BYTES, data, 0, sizeOfData); newPalette = new Palette(offset, data); return newPalette; }
private static bool TryLoadExistingPalette(out Palette palette) { palette = null; if (TMEM.LoadedElements.ContainsKey(PALETTE_TMEM_OFFSET)) { palette = (TMEM.LoadedElements[PALETTE_TMEM_OFFSET] as Palette); return true; } if (!TMEM.LoadedData.ContainsKey(PALETTE_TMEM_OFFSET)) return false; LoadedTMemData tmemInfo = TMEM.LoadedData[PALETTE_TMEM_OFFSET]; if (tmemInfo.SourceFile == null || !_foundPalettes.ContainsKey(tmemInfo.SourceFile)) return false; for (int i = 0; i < _foundPalettes[tmemInfo.SourceFile].Count; i++) { if (_foundPalettes[tmemInfo.SourceFile][i].FileOffset == tmemInfo.FileOffset) { palette = _foundPalettes[tmemInfo.SourceFile][i]; return true; } } return false; }
private static void GenerateNewPalette(Palette palette, Bitmap image, int colorCount) { //This can take a long time (not optimized), so be careful List<Color> colors = new List<Color>(); for (int j = 0; j < image.Height; j++) { for (int i = 0; i < image.Width; i++) { if (!colors.Contains(image.GetPixel(i, j))) colors.Add(image.GetPixel(i, j)); } } //Now that we have a huge list of colors, let's start going through them rapidly //List<double> minDist = new List<double>(); //foreach (Color color in colors) // minDist.Add(double.MaxValue); //while (colors.Count > colorCount) //{ // for (int i = 0; i < colors.Count; i++) // { // for (int j = i + 1; j < colors.Count; j++) // { // double dist = colors[i].ColorDistanceFrom(colors[j]); // if (dist < minDist[i]) // minDist[i] = dist; // } // } // //Find smallest one, clear it out // double minvalue = minDist.Min(); // int removeIndex = minDist.IndexOf(minvalue); // colors.RemoveAt(removeIndex); // minDist.RemoveAt(removeIndex); // //start over // for (int i = 0; i < minDist.Count; i++) // minDist[i] = double.MaxValue; //} PaletteMedianCutAnalyzer analyzer = new PaletteMedianCutAnalyzer(); foreach (Color color in colors) analyzer.AddColor(color); //Now make the new palette byte[] newData = PaletteToBinary(analyzer.GetPalette(16)); palette.RawData = newData; }
public static byte[] CI8ToBinary(Bitmap bmp, Palette palette) { //Pixel size is 1 byte if (bmp == null) return null; if (palette == null || palette.Colors.Length < 1) return null; byte[] imgData = new byte[bmp.Width * bmp.Height]; int[] paletteIDs = new int[palette.Colors.Length]; for (int k = 0; k < palette.Colors.Length; k++) { paletteIDs[k] = palette.Colors[k].ToArgb(); } for (int i = 0; i < bmp.Width; i++) { for (int j = 0; j < bmp.Height; j++) { int index = i + j * bmp.Width; Color pixel = bmp.GetPixel(i, j); int pixelID = pixel.ToArgb(); byte palIndex = 0x00; bool foundExactMatch = false; double closestDist = double.MaxValue; byte closestIndex = 0; for (byte p = 0; p < paletteIDs.Length; p++) { if (paletteIDs[p] == pixelID) { palIndex = p; foundExactMatch = true; break; } else { //Get the dist to the color, and keep track of which is the best representation double dist = pixel.ColorDistanceFrom(palette.Colors[p]); if (dist < closestDist) { closestDist = dist; closestIndex = p; } } } if(foundExactMatch) ByteHelper.WriteByte(palIndex, imgData, index); else ByteHelper.WriteByte(closestIndex, imgData, index); } } return imgData; }
public static Bitmap BinaryToCI8(byte[] imgData, Palette palette, int width, int height) { //Pixel size is 1 byte if (width * height != imgData.Length) return null; if (palette == null || palette.Colors.Length < 1) return null; Bitmap bmp = new Bitmap(width, height); //NOTE: Here's some optimization code that will make it much faster, just adapt it to the BinaryToCI8 method //BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); //int stride = data.Stride; //unsafe //{ // byte* ptr = (byte*)data.Scan0; // // Check this is not a null area // if (!areaToPaint.IsEmpty) // { // // Go through the draw area and set the pixels as they should be // for (int y = areaToPaint.Top; y < areaToPaint.Bottom; y++) // { // for (int x = areaToPaint.Left; x < areaToPaint.Right; x++) // { // // layer.GetBitmap().SetPixel(x, y, m_colour); // ptr[(x * 3) + y * stride] = m_colour.B; // ptr[(x * 3) + y * stride + 1] = m_colour.G; // ptr[(x * 3) + y * stride + 2] = m_colour.R; // } // } // } //} //bmp.UnlockBits(data); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { int index = (i + j * width); byte CI = ByteHelper.ReadByte(imgData, index); if (CI > palette.Colors.Length) CI = 0; bmp.SetPixel(i, j, palette.Colors[CI]); } } return bmp; }
public static byte[] CI4ToBinary(Bitmap bmp, Palette palette, int paletteIndex, bool generateNewPalette = false) { //Pixel size is 1/2 bytes if (bmp == null) return null; if (palette == null || palette.Colors.Length < 1) return null; if (generateNewPalette) { GenerateNewPalette(palette, bmp, 16); paletteIndex = 0; } byte[] imgData = new byte[bmp.Width * bmp.Height / 2]; int[] paletteIDs = new int[palette.Colors.Length]; for (int k = 0; k < palette.Colors.Length; k++) { int colorIndex = k + 16 * paletteIndex; if (colorIndex > palette.Colors.Length) colorIndex = 0; paletteIDs[k] = palette.Colors[colorIndex].ToArgb(); } for (int i = 0; i < bmp.Width; i+=2) { for (int j = 0; j < bmp.Height; j++) { int index = (i + j * bmp.Width) / 2; Color pixel = bmp.GetPixel(i, j); int pixelID = pixel.ToArgb(); int index1 = -1; byte closestIndex = 0; double closestDist = double.MaxValue; for (byte p = 0; p < paletteIDs.Length; p++) { if (paletteIDs[p] == pixelID) { index1 = p; break; } else { //Get the dist to the color, and keep track of which is the best representation double dist = pixel.ColorDistanceFrom(palette.Colors[p + 16 * paletteIndex]); if (dist < closestDist) { closestDist = dist; closestIndex = p; } } } if (index1 == -1) index1 = closestIndex; pixel = bmp.GetPixel(i + 1, j); pixelID = pixel.ToArgb(); int index2 = -1; closestIndex = 0; closestDist = double.MaxValue; for (byte p = 0; p < paletteIDs.Length; p++) { if (paletteIDs[p] == pixelID) { index2 = p; break; } else { //Get the dist to the color, and keep track of which is the best representation double dist = pixel.ColorDistanceFrom(palette.Colors[p + 16 * paletteIndex]); if (dist < closestDist) { closestDist = dist; closestIndex = p; } } } if (index2 == -1) index2 = closestIndex; ByteHelper.WriteByte((byte)((index1 << 4) | index2), imgData, index); } } return imgData; }
//16b #endregion #region CI //4b, 8b public static Bitmap BinaryToCI4(byte[] imgData, Palette palette, int paletteIndex, int width, int height) { //Pixel size is 1/2 byte if (width / 2 * height != imgData.Length) return null; if (palette == null || palette.Colors.Length < 1) return null; Bitmap bmp = new Bitmap(width, height); for (int i = 0; i < width; i += 2) { for (int j = 0; j < height; j++) { int index = (i + j * width) / 2; byte CI = ByteHelper.ReadByte(imgData, index); byte CI1 = (byte)(CI >> 4); byte CI2 = (byte)(CI & 0x0F); int color1Index = CI1 + 16 * paletteIndex; if (color1Index >= palette.Colors.Length) color1Index = 0; int color2Index = CI2 + 16 * paletteIndex; if (color2Index >= palette.Colors.Length) color2Index = 0; bmp.SetPixel(i, j, palette.Colors[color1Index]); bmp.SetPixel(i + 1, j, palette.Colors[color2Index]); } } return bmp; }
public Texture(int index, byte[] bytes, ImageFormat format = ImageFormat.RGBA, PixelInfo pixel = PixelInfo.Size_32b, int width = 0, int height = 0, Palette palette = null, int paletteIndex = 0) : base(index, bytes) { Format = format; PixelSize = pixel; Width = width; Height = height; ImagePalette = palette; PaletteIndex = paletteIndex; //generate image _initializing = false; RawData = bytes; }