Skip to content

Instantly share code, notes, and snippets.

@devinacker
Last active August 29, 2015 14:24
Show Gist options
  • Save devinacker/717b0f40180dea48c369 to your computer and use it in GitHub Desktop.
Save devinacker/717b0f40180dea48c369 to your computer and use it in GitHub Desktop.
paint.net plugin for Nippon Ichi Software .tx2 images
/* this is unfinished */
using System;
using System.Windows.Forms;
using PaintDotNet;
using System.Drawing;
public class TX2FileType : FileType {
public TX2FileType() : base ("TX2", FileTypeFlags.SupportsLoading,
new string[] { ".tx2" })
{
}
private ushort ReadUShort(System.IO.Stream stream) {
return (ushort)(stream.ReadByte() + (stream.ReadByte() << 8));
}
private uint ReadUInt(System.IO.Stream stream) {
return (uint)(stream.ReadByte() + (stream.ReadByte() << 8) + (stream.ReadByte() << 16) + (stream.ReadByte() << 24));
}
protected override Document OnLoad(System.IO.Stream input) {
ushort width = ReadUShort(input);
ushort height = ReadUShort(input);
if (width * height == 0) {
MessageBox.Show("Invalid image dimensions.");
return null;
}
ushort colors = ReadUShort(input); /* only values 16 and 256 have been observed */
if (colors != 16 && colors != 256) {
MessageBox.Show("Unsupported color depth. Image must be either 16 or 256 colors.");
return null;
}
ushort unknown = ReadUShort(input);
ushort colors2 = ReadUShort(input); /* purpose unknown, but always seems to be the same as colors */
ushort palettes = ReadUShort(input); /* number of palettes. only 1 and 16 observed thus far */
if (palettes > 1) {
MessageBox.Show("Image contains multiple palettes. Only the first palette will be used for now.");
} else if (palettes == 0) {
MessageBox.Show("Image must contain at least one palette.");
return null;
}
// TODO: this assumes a max of 16 palettes and 256 colors
var palette = new Color[16, 256];
// TODO: use multiple bitmaps (one per palette)
// TODO: use actual paletted bitmaps? (does paint.NET care about this?)
var bitmap = new Bitmap(width, height);
// read all palettes
input.Seek(0x10, System.IO.SeekOrigin.Begin);
for (uint p = 0; p < palettes; p++) {
for (uint c = 0; c < colors; c++) {
uint ci = c;
// 256 color images have some weird bit switching going on for color indexes
if (colors == 256) {
ci = (c & 0xE7) | ((c & 8) << 1) | ((c & 16) >> 1);
}
uint color = ReadUInt(input);
// non-transparent images use 0x80 for all alpha bytes
// TODO: verify this with images which use transparency as well
var colorA = (int)((color & 0xFF000000) >> 23);
if (colorA > 255) colorA = 255;
var colorB = (int)((color & 0xFF0000) >> 16);
var colorG = (int)((color & 0xFF00) >> 8);
var colorR = (int)(color & 0xFF);
palette[p, ci] = Color.FromArgb(colorA, colorR, colorG, colorB);
}
}
// read actual bitmap data now
// NOTE: this assumes (possibly incorrectly) that the image width is an even number
// TODO: swizzle pixels if needed
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
byte px1, px2;
// get next two pixels
if (colors == 256) {
px1 = (byte)input.ReadByte();
px2 = (byte)input.ReadByte();
} else {
var b = input.ReadByte();
px1 = (byte)(b & 0xf);
px2 = (byte)(b >> 4);
}
// TODO: support all palettes, not just the first
bitmap.SetPixel(x, y, palette[0, px1]);
x++;
bitmap.SetPixel(x, y, palette[0, px2]);
}
}
return Document.FromImage(bitmap);
}
}
public class TX2FileTypeFactory : IFileTypeFactory {
public FileType[] GetFileTypeInstances() {
return new FileType[] { new TX2FileType() };
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment