static void Main(string[] args) { // This program works by having a file dragged onto it. If this program is launched without a file arg, exit if (args.Length == 0) { return; } byte[] tm2file = File.ReadAllBytes(args[0]); byte[] imageBuf = TM2ToBitMap.GetImageBuffer(tm2file); TM2Header header = TM2Header.GetHeader(tm2file); unsafe { fixed(byte *ptr = imageBuf) { using (Bitmap image = new Bitmap(header.Width, header.Height, header.Width * 4, PixelFormat.Format32bppArgb, new IntPtr(ptr))) { image.Save(@"export.png"); } } } }
public static TM2Header GetHeader(byte[] file) { // Read header of TM2 into struct byte[] headerBuf = new byte[Marshal.SizeOf <TM2Header>()]; Array.Copy(file, headerBuf, headerBuf.Length); GCHandle handle = GCHandle.Alloc(headerBuf, GCHandleType.Pinned); TM2Header header = (TM2Header)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(TM2Header)); handle.Free(); return(header); }
public static byte[][] GetPalette(byte[] file, TM2Header header) { byte[][] result; switch (header.TM2ImageFormat) { case TM2ImageFormat.Format8bbp: result = getPalette8bbp(file, header); break; default: throw new ArgumentException("Unimplemented image format"); } return(result); }
public static byte[] GetImageBuffer(byte[] tm2file) { TM2Header header = TM2Header.GetHeader(tm2file); byte[][] palette = Palette.GetPalette(tm2file, header); // TODO -- different images based on image type byte[] imageBuf = new byte[4 * header.Width * header.Height]; for (int y = 0; y < header.Height; ++y) { for (int x = 0; x < header.Width; ++x) { byte c = tm2file[0x40 + GetAddress8BppSwizzle(header.Width, header.Height, x, y)]; Array.Copy(palette[c], 0, imageBuf, (x * 4) + (header.Width * y) * 4, 4); } } return(imageBuf); }
private static byte[][] getPalette8bbp(byte[] file, TM2Header header) { byte[][] palette = new byte[256][]; for (int i = 0; i < 256; ++i) { byte[] rgba = new byte[4]; Array.Copy(file, 0x40 + header.ImageSize + i * 4, rgba, 0, 4); // Correct alpha channel (0-128) -> (0-255) rgba[3] = (byte)(Math.Min((int)((int)rgba[3] << 1), 0xFF)); // Swap color channels (RGBA -> BGRA) byte temp = rgba[2]; rgba[2] = rgba[0]; rgba[0] = temp; palette[(i & 0xe7) | ((i & 0x10) >> 1) | ((i & 0x08) << 1)] = rgba; } return(palette); }