public static void Pack(string path) { File.Copy(path, path + "new", true); path = path + "new"; var masterImages = new List <TxpMasterImage>(); var subImages = new List <TxpSubImage>(); using (var fs = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.ReadWrite))) { var typeFlag = fs.ReadInt32(); var key = fs.ReadInt32(); var count = fs.ReadInt32(); var metaCount = fs.ReadInt32(); Debug.WriteLine(string.Format("{0} {1} {2}", Path.GetFileName(path), count, metaCount)); var colorCount = fs.ReadInt32(); var header1Start = fs.ReadInt32(); var header2Start = fs.ReadInt32(); var paletteStart = fs.ReadInt32(); fs.BaseStream.Position = header1Start; for (int i = 0; i < count; i++) { var entity = new TxpMasterImage(); entity.Unknown0 = fs.ReadInt32(); entity.Unknown1 = fs.ReadInt32(); entity.Unknown2 = fs.ReadInt32(); if ((entity.Unknown0 & 0xFF) > 0x10) { entity.Unknown3 = fs.ReadInt32(); entity.PixelStart = fs.ReadInt32(); } else { entity.PixelStart = fs.ReadInt32(); entity.Unknown3 = fs.ReadInt32(); } masterImages.Add(entity); } fs.BaseStream.Position = header2Start; for (int i = 0; i < metaCount; i++) { var entity = new TxpSubImage(); entity.Unknown4 = fs.ReadInt32(); entity.Unknown5 = fs.ReadInt32(); entity.Unknown6 = fs.ReadInt32(); entity.PaletteStart = fs.ReadInt32(); entity.X = fs.ReadSingle(); entity.Y = fs.ReadSingle(); entity.RatioX = fs.ReadSingle(); entity.RatioY = fs.ReadSingle(); entity.Width = fs.ReadInt16(); entity.Height = fs.ReadInt16(); entity.OffsetX = fs.ReadInt16(); entity.OffsetY = fs.ReadInt16(); subImages.Add(entity); } fs.BaseStream.Position = subImages[0].PaletteStart; var current = 0; while (fs.BaseStream.Position < masterImages[0].PixelStart) { if (current + 1 < subImages.Count && subImages[current + 1].PaletteStart == fs.BaseStream.Position) { current++; } var colors = subImages[current].Colors; var r = fs.ReadByte(); var g = fs.ReadByte(); var b = fs.ReadByte(); var a = fs.ReadByte(); colors.Add(Color.FromArgb(a, r, g, b)); colorCount -= 4; } for (int i = 0; i < count; i++) { fs.BaseStream.Position = masterImages[i].PixelStart; var next = i + 1 < count ? masterImages[i + 1].PixelStart : (int)fs.BaseStream.Length; var length = next - masterImages[i].PixelStart; if (length <= 0) { masterImages[i].RawData = new byte[0]; } else { var raw = fs.ReadBytes(length); var pixel = masterImages[i]; pixel.RawData = raw; if (pixel.IsCompressed) { var compressedSize = BitConverter.ToInt32(raw, 0); var compressed = new byte[compressedSize]; Buffer.BlockCopy(raw, 4, compressed, 0, compressedSize); pixel.RawData = ZlibStream.UncompressBuffer(compressed); } pixel.RawHeight = pixel.Unknown1 & 0xFFF; pixel.RawWidth = pixel.RawData.Length / pixel.RawHeight; } } Dump(masterImages, subImages); int index = 0; var groups = subImages.GroupBy(x => x.PixelDataIndex).ToDictionary(x => x.Key, x => x.ToList()); foreach (var group in groups) { var first = group.Value.First(); TextureFormat format = null; if (first.Colors.Count == 16) { format = TextureFormat.Formats[(int)TexturePixelStorage.Indexed4]; } else if (first.Colors.Count == 256) { format = TextureFormat.Formats[(int)TexturePixelStorage.Indexed8]; } else { continue; } var pixel = masterImages[group.Key]; var data = ImageUtility.Unswizzle(format, pixel.RawData, pixel.RawWidth); if (format.Size == 0) { var data2 = new byte[data.Length * 2]; for (int j = 0; j < data.Length; j++) { data2[j * 2] = (byte)(data[j] & 0xF); data2[j * 2 + 1] = (byte)(data[j] >> 4); } data = data2; } foreach (var item in group.Value) { var location = Path.GetDirectoryName(path); var name = Path.GetFileNameWithoutExtension(path); var fileName = Path.Combine(location, "png", string.Format("{0}_{1}.png", name, index++)); var image = Bitmap.FromFile(fileName) as Bitmap; if (image.PixelFormat != PixelFormat.Format8bppIndexed || item.Colors.Count != image.Palette.Entries.Length) { if (item.Colors.Count < image.Palette.Entries.Length) { // Need to convert color image = ImageUtility.ConvertTo8bppFormat(image); } } var bitData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed); var newData = new byte[bitData.Stride * bitData.Height]; Marshal.Copy(bitData.Scan0, newData, 0, newData.Length); image.UnlockBits(bitData); ImageUtility.Write(data, pixel.RawWidth, newData, (int)(pixel.Width * item.X), (int)(pixel.Height * item.Y), item.Width, item.Height); item.Colors.Clear(); item.Colors.AddRange(image.Palette.Entries); } if (format.Size == 0) { var data2 = new byte[data.Length / 2]; for (int j = 0; j < data.Length; j += 2) { data2[j / 2] = (byte)((data[j] & 0xF) | (data[j + 1] >> 4)); } data = data2; } data = ImageUtility.Swizzle(format, data, (uint)pixel.RawWidth, (uint)pixel.RawHeight); if (pixel.IsCompressed) { var originalSize = pixel.RawData.Length; data = Compress(data, originalSize); fs.BaseStream.Position = pixel.PixelStart; fs.BaseStream.Write(BitConverter.GetBytes(data.Length), 0, 4); fs.BaseStream.Write(data, 0, data.Length); } else { fs.BaseStream.Position = pixel.PixelStart; fs.BaseStream.Write(data, 0, data.Length); } } foreach (var item in subImages) { fs.BaseStream.Position = item.PaletteStart; for (int i = 0; i < item.Colors.Count; i++) { var color = item.Colors[i]; fs.BaseStream.WriteByte(color.R); fs.BaseStream.WriteByte(color.G); fs.BaseStream.WriteByte(color.B); fs.BaseStream.WriteByte(color.A); } } } }
public static void Unpack(string path) { var masterImages = new List <TxpMasterImage>(); var subimages = new List <TxpSubImage>(); using (var fs = new BinaryReader(File.OpenRead(path))) { var typeFlag = fs.ReadInt32(); var key = fs.ReadInt32(); var count = fs.ReadInt32(); var metaCount = fs.ReadInt32(); Debug.WriteLine(string.Format("{0} {1} {2}", Path.GetFileName(path), count, metaCount)); var colorCount = fs.ReadInt32(); var header1Start = fs.ReadInt32(); var header2Start = fs.ReadInt32(); var paletteStart = fs.ReadInt32(); fs.BaseStream.Position = header1Start; for (int i = 0; i < count; i++) { var entity = new TxpMasterImage(); entity.Unknown0 = fs.ReadInt32(); entity.Unknown1 = fs.ReadInt32(); entity.Unknown2 = fs.ReadInt32(); if ((entity.Unknown0 & 0xFF) > 0x10) { entity.Unknown3 = fs.ReadInt32(); entity.PixelStart = fs.ReadInt32(); } else { entity.PixelStart = fs.ReadInt32(); entity.Unknown3 = fs.ReadInt32(); } masterImages.Add(entity); } fs.BaseStream.Position = header2Start; for (int i = 0; i < metaCount; i++) { var entity = new TxpSubImage(); entity.Unknown4 = fs.ReadInt32(); entity.Unknown5 = fs.ReadInt32(); entity.Unknown6 = fs.ReadInt32(); entity.PaletteStart = fs.ReadInt32(); entity.X = fs.ReadSingle(); entity.Y = fs.ReadSingle(); entity.RatioX = fs.ReadSingle(); entity.RatioY = fs.ReadSingle(); entity.Width = fs.ReadInt16(); entity.Height = fs.ReadInt16(); entity.OffsetX = fs.ReadInt16(); entity.OffsetY = fs.ReadInt16(); subimages.Add(entity); } fs.BaseStream.Position = subimages[0].PaletteStart; var current = 0; while (fs.BaseStream.Position < masterImages[0].PixelStart) { if (current + 1 < subimages.Count && subimages[current + 1].PaletteStart == fs.BaseStream.Position) { current++; } var colors = subimages[current].Colors; var r = fs.ReadByte(); var g = fs.ReadByte(); var b = fs.ReadByte(); var a = fs.ReadByte(); colors.Add(Color.FromArgb(a, r, g, b)); colorCount -= 4; } for (int i = 0; i < count; i++) { fs.BaseStream.Position = masterImages[i].PixelStart; var next = i + 1 < count ? masterImages[i + 1].PixelStart : (int)fs.BaseStream.Length; var length = next - masterImages[i].PixelStart; if (length <= 0) { masterImages[i].RawData = new byte[0]; } else { var raw = fs.ReadBytes(length); var pixel = masterImages[i]; pixel.RawData = raw; if (pixel.IsCompressed) { var compressedSize = BitConverter.ToInt32(raw, 0); var compressed = new byte[compressedSize]; Buffer.BlockCopy(raw, 4, compressed, 0, compressedSize); pixel.RawData = ZlibStream.UncompressBuffer(compressed); } pixel.RawHeight = pixel.Unknown1 & 0xFFF; pixel.RawWidth = pixel.RawData.Length / pixel.RawHeight; } } foreach (var group in subimages.GroupBy(x => x.PixelDataIndex).ToDictionary(x => x.Key, x => x.ToList())) { var whole = group.Value.First(x => x.X == 0f && x.Y == 0); var pixel = masterImages[whole.PixelDataIndex]; pixel.Width = (int)(whole.Width / whole.RatioX); pixel.Height = (int)(whole.Height / whole.RatioY); } Dump(masterImages, subimages); return; int index = 0; foreach (var group in subimages.GroupBy(x => x.PixelDataIndex).ToDictionary(x => x.Key, x => x.ToList())) { var first = group.Value.First(); TextureFormat format = null; if (first.Colors.Count == 16) { format = TextureFormat.Formats[(int)TexturePixelStorage.Indexed4]; } else if (first.Colors.Count == 256) { format = TextureFormat.Formats[(int)TexturePixelStorage.Indexed8]; } else { continue; } var pixel = masterImages[group.Key]; var data = ImageUtility.Unswizzle(format, pixel.RawData, pixel.Width); if (format.Size == 0) { var data2 = new byte[data.Length * 2]; for (int j = 0; j < data.Length; j++) { data2[j * 2] = (byte)(data[j] & 0xF); data2[j * 2 + 1] = (byte)(data[j] >> 4); } data = data2; } foreach (var item in group.Value) { var crop = ImageUtility.Crop(data, pixel.Width, (int)(pixel.Width * item.X), (int)(pixel.Height * item.Y), item.Width, item.Height); var location = Path.GetDirectoryName(path); var name = Path.GetFileNameWithoutExtension(path); var fileName = Path.Combine(location, "png", string.Format("{0}_{1}.png", name, index++)); FileUtility.PrepareFolderFile(fileName); using (var bitmap = GetBitmap(item.Colors, item.Width, item.Height, crop)) { if (bitmap != null) { bitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Png); } } } } } }