DS-Pokemon-Rom-Editor/DS_Map/Editors/Utils/IndexedBitmapHandler.cs
2025-07-29 11:23:52 +02:00

437 lines
16 KiB
C#

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows;
namespace DSPRE.Editors.Utils
{
public class IndexedBitmapHandler
{
public IndexedBitmapHandler()
{
}
public Bitmap Convert(Bitmap source, PixelFormat target)
{
if ((source.PixelFormat == target) || (target == PixelFormat.DontCare))
return source;
Bitmap image = new Bitmap(source.Width, source.Height, target);
if ((source.PixelFormat == PixelFormat.Format4bppIndexed) && (target == PixelFormat.Format8bppIndexed))
{
byte[] array = GetArray(source);
byte[] array2 = new byte[(array.Length * 2)];
byte current;
for (int i = 0; i < array.Length; i++)
{
current = array[i];
array2[2 * i] = (byte)((current & 0xF0) >> 4);
array2[2 * i + 1] = (byte)((current & 0x0F));
}
image = MakeImage(source.Width, source.Height, array2, target);
image.Palette = source.Palette;
}
if (((source.PixelFormat == PixelFormat.Format24bppRgb) || (source.PixelFormat == PixelFormat.Format32bppArgb)) && (target == PixelFormat.Format8bppIndexed))
{
int skip = 3;
if (source.PixelFormat == PixelFormat.Format32bppArgb)
skip = 4;
Color[] newPalette = new Color[256];
byte[] array = new byte[source.Width * source.Height];
byte[] sourceArray = GetArray(source);
Color Pixel = Color.FromArgb(sourceArray[2], sourceArray[1], sourceArray[0]);
newPalette[0] = Pixel;
int index = 1;
array[0] = 0;
byte r = 0;
byte g = 0;
byte b = 0;
bool match = false;
for (int i = 1; i < (source.Width * source.Height); i++)
{
b = sourceArray[(i * skip)];
g = sourceArray[(i * skip + 1)];
r = sourceArray[(i * skip + 2)];
Pixel = Color.FromArgb(r, g, b);
for (int j = 0; j < index; j++)
{
if (Pixel == newPalette[j])
{
array[i] = (byte)j;
match = true;
break;
}
}
if (!match)
{
if (index >= 256)
{
MessageBox.Show("Conversion failed");
return null;
}
newPalette[index] = Pixel;
array[i] = (byte)index;
index++;
}
match = false;
}
image = MakeImage(source.Width, source.Height, array, target);
ColorPalette oldPalette = image.Palette;
for (int i = 0; i < index; i++)
{
oldPalette.Entries[i] = newPalette[i];
}
image.Palette = oldPalette;
}
return image;
}
public Bitmap Resize(Bitmap source, int top, int bottom, int left, int right)
{
int newWidth = source.Width + left + right;
int newHeight = source.Height + top + bottom;
int arraysize = newWidth * newHeight;
ColorPalette palette = source.Palette;
byte[] source_array = GetArray(source);
byte[] byte_array = new byte[arraysize];
byte background = source_array[0];
int source_index = 0;
int index = 0;
for (int j = 0; j < newHeight; j++)
{
for (int i = 0; i < newWidth; i++)
{
if (i < left || i >= (left + source.Width) || j < top || j >= (top + source.Height))
byte_array[index] = background;
else
{
source_index = ((j - top) * source.Width) + i - left;
byte_array[index] = source_array[source_index];
}
index++;
}
}
Bitmap newImage = MakeImage(newWidth, newHeight, byte_array, PixelFormat.Format8bppIndexed);
newImage.Palette = palette;
return newImage;
}
public Bitmap Concat(Bitmap first, Bitmap second)
{
int newWidth = first.Width + second.Width;
int newHeight = first.Height;
if (first.Height < second.Height)
newHeight = second.Height;
int arraysize = newWidth * newHeight;
ColorPalette palette = first.Palette;
byte[] first_array = GetArray(first);
byte[] second_array = GetArray(second);
byte[] byte_array = new byte[arraysize];
byte background = first_array[0];
int source_index = 0;
int index = 0;
for (int j = 0; j < newHeight; j++)
{
for (int i = 0; i < first.Width; i++)
{
if (j > first.Height)
byte_array[index] = background;
else
{
source_index = ((j * first.Width) + i);
byte_array[index] = first_array[source_index];
}
index++;
}
for (int i = 0; i < second.Width; i++)
{
if (j > second.Height)
byte_array[index] = background;
else
{
source_index = ((j * second.Width) + i);
byte_array[index] = second_array[source_index];
}
index++;
}
}
Bitmap newImage = MakeImage(newWidth, newHeight, byte_array, PixelFormat.Format8bppIndexed);
newImage.Palette = palette;
return newImage;
}
public Bitmap[] Split(Bitmap source, int tilewidth, int tileheight)
{
int maxTiles = (source.Width / tilewidth) * (source.Height / tileheight);
Bitmap[] tiles = new Bitmap[maxTiles];
int index = 0;
int x_index = 0;
int y_index = 0;
while (y_index + tileheight <= source.Height)
{
if (x_index + tilewidth <= source.Width)
{
tiles[index] = Resize(source, (y_index * -1), ((source.Height - y_index - tileheight) * -1), (x_index * -1), ((source.Width - x_index - tilewidth) * -1));
index++;
}
x_index += tilewidth;
if (x_index + tilewidth > source.Width)
{
y_index += tileheight;
x_index = 0;
}
}
return tiles;
}
public Bitmap ShrinkImage(Bitmap image, int x_scale, int y_scale)
{
byte[] array = GetArray(image);
ColorPalette palette = image.Palette;
int new_width = image.Width / x_scale;
int new_height = image.Height / y_scale;
byte[] array2 = new byte[new_width * new_height];
for (int j = 0; j < new_height; j++)
{
for (int i = 0; i < new_width; i++)
{
array2[j * new_width + i] = array[y_scale * j * image.Width + i * x_scale];
}
}
Bitmap temp = MakeImage(new_width, new_height, array2, image.PixelFormat);
temp.Palette = palette;
return temp;
}
public ColorPalette AlternatePalette(Bitmap parent, Bitmap child)
{
Bitmap temp = new Bitmap(1, 1, parent.PixelFormat);
ColorPalette newPalette = temp.Palette;
ColorPalette ChildPalette = child.Palette;
byte[] ParentArray = GetArray(parent);
byte[] ChildArray = GetArray(child);
if (ParentArray.Length != ChildArray.Length)
return null;
for (int i = 0; i < ChildPalette.Entries.Length; i++)
{
for (int j = 0; j < ParentArray.Length; j++)
{
if (ParentArray[j] == i)
{
newPalette.Entries[i] = ChildPalette.Entries[ChildArray[j]];
break;
}
}
}
return newPalette;
}
public Bitmap PaletteMatch(ColorPalette parent, Bitmap child, bool[] used = null)
{
if (parent.Entries == child.Palette.Entries)
return child;
if (used == null)
{
used = new bool[parent.Entries.Length];
for (int i = 0; i < parent.Entries.Length; i++)
used[i] = true;
}
Bitmap image = ShrinkPalette(child);
Bitmap temp = new Bitmap(1, 1, child.PixelFormat);
ColorPalette childPalette = image.Palette;
ColorPalette newPalette = temp.Palette;
int size = PaletteSize(image);
byte[] array = GetArray(image);
byte[] indexof = new byte[size];
bool[] NotFound = new bool[size];
for (int i = 0; i < size; i++)
NotFound[i] = true;
for (int i = 0; i < size; i++)
{
for (int j = 0; j < parent.Entries.Length; j++)
{
if (parent.Entries[j] == childPalette.Entries[i])
{
indexof[i] = (byte)j;
NotFound[i] = false;
break;
}
}
}
int maxsize = 0;
for (int i = 0; i < parent.Entries.Length; i++)
{
if (used[i])
{
newPalette.Entries[i] = parent.Entries[i];
maxsize++;
}
}
for (int i = 0; i < size; i++)
{
if (NotFound[i])
maxsize++;
}
for (int i = 0; i < maxsize; i++)
{
if ((i < used.Length) && (used[i]))
continue;
for (int j = 0; j < size; j++)
{
if (NotFound[j])
{
indexof[j] = (byte)i;
newPalette.Entries[i] = childPalette.Entries[j];
NotFound[j] = false;
break;
}
}
}
byte[] newArray = new byte[array.Length];
for (int i = 0; i < array.Length; i++)
{
newArray[i] = indexof[array[i]];
}
image = MakeImage(child.Width, child.Height, newArray, child.PixelFormat);
image.Palette = newPalette;
return image;
}
public Bitmap ShrinkPalette(Bitmap image, bool[] used = null)
{
used = IsUsed(image, used);
byte[] array = GetArray(image);
ColorPalette oldPalette = image.Palette;
Bitmap temp = new Bitmap(image.Width, image.Height, image.PixelFormat);
ColorPalette newPalette = temp.Palette;
int size = oldPalette.Entries.Length;
int index = 0;
int unused = 0;
byte[] indexof = new byte[size];
for (int i = 0; i < size; i++)
{
if (used[i])
{
newPalette.Entries[index] = oldPalette.Entries[i];
indexof[i] = (byte)index;
index++;
}
else
unused++;
}
if (unused == 0 || unused == size)
return image;
byte[] newArray = new byte[array.Length];
for (int i = 0; i < array.Length; i++)
{
newArray[i] = indexof[array[i]];
}
image = MakeImage(image.Width, image.Height, newArray, image.PixelFormat);
image.Palette = newPalette;
return image;
}
public bool[] IsUsed(Bitmap image, bool[] used = null)
{
byte[] array = GetArray(image);
int size = image.Palette.Entries.Length;
if (used == null)
{
used = new bool[size];
for (int i = 0; i < size; i++)
{
used[i] = false;
}
}
if (size > used.Length)
{
bool[] temp = new bool[size];
for (int i = 0; i < size; i++)
{
if (i < used.Length)
temp[i] = used[i];
else
temp[i] = false;
}
used = temp;
}
for (int i = 0; i < array.Length; i++)
{
used[array[i]] = true;
}
return used;
}
public byte PaletteSize(Bitmap image)
{
byte[] array = GetArray(image);
byte max = 0;
for (int i = 0; i < array.Length; i++)
{
if (array[i] > max)
max = array[i];
}
return (byte)(max + 1);
}
public bool PaletteEquals(ColorPalette parent, Bitmap child)
{
bool Match = true;
int max = PaletteSize(child);
for (int i = 0; i < max; i++)
{
if (parent.Entries[i] != child.Palette.Entries[i])
Match = false;
}
return Match;
}
public ColorPalette CleanPalette(Bitmap image)
{
int used = PaletteSize(image);
ColorPalette temp = image.Palette;
for (int i = used; i < image.Palette.Entries.Length; i++)
temp.Entries[i] = Color.FromArgb(0, 0, 0);
return temp;
}
public byte[] GetArray(Bitmap target)
{
int Width = target.Width;
if (target.PixelFormat == PixelFormat.Format1bppIndexed)
Width = Width / 8;
if (target.PixelFormat == PixelFormat.Format4bppIndexed)
Width = Width / 2;
if ((target.PixelFormat == PixelFormat.Format16bppArgb1555) || (target.PixelFormat == PixelFormat.Format16bppGrayScale) || (target.PixelFormat == PixelFormat.Format16bppRgb555) || (target.PixelFormat == PixelFormat.Format16bppRgb565))
Width = Width * 2;
if (target.PixelFormat == PixelFormat.Format24bppRgb)
Width = Width * 3;
if ((target.PixelFormat == PixelFormat.Format32bppRgb) || (target.PixelFormat == PixelFormat.Format32bppArgb) || (target.PixelFormat == PixelFormat.Format32bppPArgb))
Width = Width * 4;
byte[] array = new byte[Width * target.Height];
Rectangle rect = new Rectangle(0, 0, target.Width, target.Height);
BitmapData sourceData = target.LockBits(rect, ImageLockMode.ReadOnly, target.PixelFormat);
IntPtr scan = sourceData.Scan0;
Marshal.Copy(scan, array, 0, Width * target.Height);
target.UnlockBits(sourceData);
return array;
}
public Bitmap MakeImage(int width, int height, byte[] array, PixelFormat format)
{
Bitmap image = new Bitmap(width, height, format);
Rectangle rect = new Rectangle(0, 0, width, height);
BitmapData imageData = image.LockBits(rect, ImageLockMode.WriteOnly, image.PixelFormat);
IntPtr scan = imageData.Scan0;
Marshal.Copy(array, 0, scan, (width * height));
image.UnlockBits(imageData);
return image;
}
}
}