private static Bitmap parseEntry(BCHTexture bchtex, byte[] data) { Bitmap img = new Bitmap(1, 1); if (bchtex.Format >= 0 && bchtex.Format < 0xB) { img = getIMG(bchtex, data); } else if (bchtex.Format == 0xB || bchtex.Format == 0xC || bchtex.Format == 0xD) { img = getIMG_ETC1(bchtex, data); } /*if (CHK_FLIPVERT.Checked) * { * img.RotateFlip(RotateFlipType.RotateNoneFlipY); * }*/ return(img); }
public static BCH analyze(string path, byte[] input) { BCH bch = new BCH { FileName = Path.GetFileNameWithoutExtension(path), FilePath = Path.GetDirectoryName(path), Extension = Path.GetExtension(path) }; using (MemoryStream ms = new MemoryStream()) { using (BinaryWriter bw = new BinaryWriter(ms)) { bw.Write(input); using (BinaryReader br = new BinaryReader(ms)) { br.BaseStream.Seek(0, SeekOrigin.Begin); long bchlength = br.BaseStream.Length; bch.Magic = br.ReadUInt32(); //0x00 [4]byte "BCH\x00" br.ReadUInt32(); //0x04 [4]byte 07 07 0D 97 bch.InfoOffset = br.ReadUInt32(); //0x08 InfoTable Offset bch.SymbolOffset = br.ReadUInt32(); //0x0C SymbTable Offset bch.DescOffset = br.ReadUInt32(); //0x10 DescTable Offset bch.DataOffset = br.ReadUInt32(); //0x14 DataTable Offset uint AfterDataOffset = br.ReadUInt32(); //0x18 UnknTable offset uint AADP = br.ReadUInt32(); //0x1C InfoTable size uint SymbSize = br.ReadUInt32(); //0x20 SymbTable Size uint DescSize = br.ReadUInt32(); //0x24 DescTable Size bch.DataLength = br.ReadUInt32(); //0x28 DataTable Size uint dumb = br.ReadUInt32(); //0x2C UnknTable Size if (bch.InfoOffset == 0x44) { SymbSize = DescSize; bch.DataLength = Math.Max(dumb, Math.Max(AADP, AfterDataOffset) - bch.DataOffset); } br.BaseStream.Seek(bch.InfoOffset + 0x24, SeekOrigin.Begin); bch.TableOffset = br.ReadUInt32() + bch.InfoOffset; //info+0x24 bch.TextureCount = br.ReadUInt32(); //info+0x28 bch.TexNames = new List <String>(); bch.RawNames = new Dictionary <int, string>(); br.BaseStream.Seek((bch.SymbolOffset), SeekOrigin.Begin); int ofs = 0; uint ind = 0; while (ind < SymbSize) { string curname = ""; byte b = br.ReadByte(); ind++; while (b != 0) { curname = curname + (char)b; b = br.ReadByte(); ind++; } bch.RawNames.Add(ofs, curname); ofs += curname.Length + 1; } bch.Textures = new List <BCHTexture>(); for (int i = 0; i < bch.TextureCount; i++) { BCHTexture CurTexture = new BCHTexture(); br.BaseStream.Seek(bch.TableOffset + i * 0x4, SeekOrigin.Begin); uint CurTexInfoOffset = br.ReadUInt32(); br.BaseStream.Seek(bch.InfoOffset + CurTexInfoOffset, SeekOrigin.Begin); CurTexture.DescOffset = br.ReadUInt32() + bch.DescOffset; //0x0 Location within Desc br.ReadUInt32(); //0x4 unk br.ReadUInt32(); //0x8 unk br.ReadUInt32(); //0xC unk br.ReadUInt32(); //0x10 unk br.ReadUInt32(); //0x14 unk br.ReadUInt32(); //0x18 unk; int key = (int)br.ReadUInt32(); //0x1C Name offset; not useful because we already parsed if (bch.InfoOffset == 0x44) { // key--; } string name; bch.RawNames.TryGetValue(key, out name); bch.TexNames.Add(name); br.BaseStream.Seek(CurTexture.DescOffset, SeekOrigin.Begin); CurTexture.Height = br.ReadUInt16(); //0x0 height CurTexture.Width = br.ReadUInt16(); //0x2 width br.ReadUInt32(); //0x4, unk CurTexture.DataOffset = br.ReadUInt32(); //0x8 DataOffset br.ReadUInt32(); //0xC unk CurTexture.Format = br.ReadUInt32(); //0x10 Format if (bch.InfoOffset == 0x44 || bch.InfoOffset == 0x3C) { CurTexture.DataOffset = CurTexture.Format; br.ReadUInt32(); CurTexture.Format = br.ReadUInt32(); } bch.Textures.Add(CurTexture); //OKAY DONE } for (int i = 0; i < bch.Textures.Count - 1; i++) { BCHTexture bchtex = bch.Textures[i]; bchtex.Length = bch.Textures[i + 1].DataOffset - bch.Textures[i].DataOffset; if (bch.InfoOffset == 0x44) { bchtex.Length = (uint)(FormatToBPP((int)bchtex.Format) * bchtex.Width * bchtex.Height); } bch.Textures[i] = bchtex; } if (bch.TextureCount > 0) { BCHTexture bchtex1 = bch.Textures[bch.Textures.Count - 1]; bchtex1.Length = bch.DataLength - bchtex1.DataOffset; if (bch.InfoOffset == 0x44) { bchtex1.Length = (uint)(FormatToBPP((int)bchtex1.Format) * bchtex1.Width * bchtex1.Height); } bch.Textures[bch.Textures.Count - 1] = bchtex1; } br.BaseStream.Seek(bch.DataOffset, SeekOrigin.Begin); byte[] data = new byte[bch.DataLength]; br.Read(data, 0, (int)bch.DataLength); bch.data = data; } } } return(bch); }
private static Bitmap getIMG_ETC1(BCHTexture bchtex, byte[] data) { Bitmap img = new Bitmap(Math.Max(nlpo2(bchtex.Width), 16), Math.Max(nlpo2(bchtex.Height), 16)); string dllpath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location).Replace('\\', '/') + "/ETC1.dll"; if (!File.Exists(dllpath)) { File.WriteAllBytes(dllpath, Resources.ETC1); } try { /* * Much of this code is taken/modified from Tharsis: http://jul.rustedlogic.net/thread.php?pid=436556#436556 Thank you to Tharsis's creator, xdaniel. */ byte[] temp = new byte[bchtex.Length]; Array.Copy(data, bchtex.DataOffset, temp, 0, bchtex.Length); /* Get compressed data & handle to it */ byte[] textureData = temp; //textureData = switchEndianness(textureData, 0x10); ushort[] input = new ushort[textureData.Length / sizeof(ushort)]; Buffer.BlockCopy(textureData, 0, input, 0, textureData.Length); GCHandle pInput = GCHandle.Alloc(input, GCHandleType.Pinned); /* Marshal data around, invoke ETC1.dll for conversion, etc */ UInt32 size1 = 0, size2 = 0; UInt16 wd = (ushort)img.Width, ht = (ushort)img.Height; ConvertETC1(IntPtr.Zero, ref size1, IntPtr.Zero, ref size2, wd, ht, bchtex.Format == 0xD || bchtex.Format == 0xB); //true = etc1a4, false = etc1 uint[] output = new uint[size1]; GCHandle pOutput = GCHandle.Alloc(output, GCHandleType.Pinned); ConvertETC1(pOutput.AddrOfPinnedObject(), ref size1, pInput.AddrOfPinnedObject(), ref size2, wd, ht, bchtex.Format == 0xD || bchtex.Format == 0xB); pOutput.Free(); pInput.Free(); /* Unscramble if needed // could probably be done in ETC1.dll, it's probably pretty damn ugly, but whatever... */ /* Non-square code blocks could need some cleanup, verification, etc. as well... */ uint[] finalized = new uint[output.Length]; //Act if it's square because BCLIM swizzling is stupid Buffer.BlockCopy(output, 0, finalized, 0, finalized.Length); byte[] tmp = new byte[finalized.Length]; Buffer.BlockCopy(finalized, 0, tmp, 0, tmp.Length); int h = img.Height; int w = img.Width; byte[] imgData = tmp; for (int i = 0; i < img.Width; i++) { for (int j = 0; j < img.Height; j++) { int k = (j + i * img.Height) * 4; Color c = Color.FromArgb(imgData[k + 3], imgData[k], imgData[k + 1], imgData[k + 2]); if (imgData[k] == imgData[k + 1] && imgData[k + 1] == imgData[k + 2] && imgData[k + 1] == 0) { if (imgData[k + 3] == 0) { c = Color.Transparent; } } img.SetPixel(i, j, c); /*if (bchtex.Format == 0xD) * { * img.SetPixel(i, j, Color.FromArgb(0xFF, imgData[k], imgData[k + 1], imgData[k + 2])); * }*/ } } //image is 13 instead of 12 // 24 34 img.RotateFlip(RotateFlipType.Rotate90FlipX); if (wd > ht) { //image is now in appropriate order, but the shifting done been f****d up. Let's fix that. Bitmap img2 = new Bitmap(Math.Max(nlpo2(bchtex.Width), 16), Math.Max(nlpo2(bchtex.Height), 16)); for (int y = 0; y < Math.Max(nlpo2(bchtex.Width), 16); y += 8) { for (int x = 0; x < Math.Max(nlpo2(bchtex.Height), 16); x++) { for (int j = 0; j < 8; j++) //treat every 8 vertical pixels as 1 pixel for purposes of calculation, add to offset later. { int x1 = (x + ((y / 8) * h)) % img2.Width; //reshift x int y1 = ((x + ((y / 8) * h)) / img2.Width) * 8; //reshift y img2.SetPixel(x1, y1 + j, img.GetPixel(x, y + j)); //reswizzle } } } return(img2); } else if (ht > wd) { //image is now in appropriate order, but the shifting done been f****d up. Let's fix that. Bitmap img2 = new Bitmap(Math.Max(nlpo2(bchtex.Width), 16), Math.Max(nlpo2(bchtex.Height), 16)); for (int y = 0; y < Math.Max(nlpo2(bchtex.Width), 16); y += 8) { for (int x = 0; x < Math.Max(nlpo2(bchtex.Height), 16); x++) { for (int j = 0; j < 8; j++) //treat every 8 vertical pixels as 1 pixel for purposes of calculation, add to offset later. { int x1 = x % img2.Width; //reshift x int y1 = ((x + ((y / 8) * h)) / img2.Width) * 8; //reshift y img2.SetPixel(x1, y1 + j, img.GetPixel(x, y + j)); //reswizzle } } } return(img2); } } catch (IndexOutOfRangeException) { // } catch (AccessViolationException) { // } return(img); }
// Bitmap Data Writing private static Bitmap getIMG(BCHTexture bchtex, byte[] data) { // New Image Bitmap img = new Bitmap(nlpo2(gcm(bchtex.Width, 8)), nlpo2(gcm(bchtex.Height, 8))); int f = (int)bchtex.Format; int area = img.Width * img.Height; if (f == 0 && area > bchtex.Length / 4 || (f == 3 && area > bchtex.Length / 4)) { img = new Bitmap(gcm(bchtex.Width, 8), gcm(bchtex.Height, 8)); area = img.Width * img.Height; } byte[] temp = new byte[(int)bchtex.Length]; Array.Copy(data, bchtex.DataOffset, temp, 0, temp.Length); data = temp; // Coordinates // Colors // Tiles Per Width int p = gcm(img.Width, 8) / 8; if (p == 0) { p = 1; } // Build Image using (Stream BitmapStream = new MemoryStream(data)) using (BinaryReader br = new BinaryReader(BitmapStream)) for (uint i = 0; i < area; i++) // for every pixel { uint x, y; d2xy(i % 64, out x, out y); uint tile = i / 64; // Shift Tile Coordinate into Tilemap x += (uint)(tile % p) * 8; y += (uint)(tile / p) * 8; // Get Color Color c; switch (f) { case 0: //RGBA8 - 4 bytes c = DecodeColor(br.ReadUInt32(), f); break; case 1: //RGB8 byte[] data1 = br.ReadBytes(3); Array.Resize(ref data1, 4); c = DecodeColor(BitConverter.ToUInt32(data1, 0), f); break; case 2: //RGBA5551 case 3: //RGB565 case 4: //RGBA4 case 5: //LA8 c = DecodeColor(br.ReadUInt16(), f); break; case 6: //HILO8 case 7: //L8 case 8: //A8 case 9: //LA4 c = DecodeColor(br.ReadByte(), f); break; case 0xA: //L4 case 0xB: //A4 uint val = br.ReadByte(); img.SetPixel((int)x, (int)y, DecodeColor(val & 0xF, f)); i++; x++; c = DecodeColor(val >> 4, f); break; case 0xC: // ETC1 case 0xD: // ETC1A4 default: throw new Exception("Invalid FileFormat."); } img.SetPixel((int)x, (int)y, c); } return(img); }
public static BCH analyze(string path, byte[] input) { BCH bch = new BCH { FileName = Path.GetFileNameWithoutExtension(path), FilePath = Path.GetDirectoryName(path), Extension = Path.GetExtension(path) }; using (MemoryStream ms = new MemoryStream()) { using (BinaryWriter bw = new BinaryWriter(ms)) { bw.Write(input); using (BinaryReader br = new BinaryReader(ms)) { br.BaseStream.Seek(0, SeekOrigin.Begin); long bchlength = br.BaseStream.Length; bch.Magic = br.ReadUInt32(); //0x00 [4]byte "BCH\x00" br.ReadUInt32(); //0x04 [4]byte 07 07 0D 97 bch.InfoOffset = br.ReadUInt32(); //0x08 InfoTable Offset bch.SymbolOffset = br.ReadUInt32(); //0x0C SymbTable Offset bch.DescOffset = br.ReadUInt32(); //0x10 DescTable Offset bch.DataOffset = br.ReadUInt32(); //0x14 DataTable Offset uint AfterDataOffset = br.ReadUInt32(); //0x18 UnknTable offset uint AADP = br.ReadUInt32(); //0x1C InfoTable size uint SymbSize = br.ReadUInt32(); //0x20 SymbTable Size uint DescSize = br.ReadUInt32(); //0x24 DescTable Size bch.DataLength = br.ReadUInt32(); //0x28 DataTable Size uint dumb = br.ReadUInt32(); //0x2C UnknTable Size if (bch.InfoOffset == 0x44) { SymbSize = DescSize; bch.DataLength = Math.Max(dumb, Math.Max(AADP, AfterDataOffset) - bch.DataOffset); } br.BaseStream.Seek(bch.InfoOffset + 0x24, SeekOrigin.Begin); bch.TableOffset = br.ReadUInt32() + bch.InfoOffset; //info+0x24 bch.TextureCount = br.ReadUInt32(); //info+0x28 bch.TexNames = new List<String>(); bch.RawNames = new Dictionary<int, string>(); br.BaseStream.Seek((bch.SymbolOffset), SeekOrigin.Begin); int ofs = 0; uint ind = 0; while (ind < SymbSize) { string curname = ""; byte b = br.ReadByte(); ind++; while (b != 0) { curname = curname + (char)b; b = br.ReadByte(); ind++; } bch.RawNames.Add(ofs, curname); ofs += curname.Length + 1; } bch.Textures = new List<BCHTexture>(); for (int i = 0; i < bch.TextureCount; i++) { BCHTexture CurTexture = new BCHTexture(); br.BaseStream.Seek(bch.TableOffset + i * 0x4, SeekOrigin.Begin); uint CurTexInfoOffset = br.ReadUInt32(); br.BaseStream.Seek(bch.InfoOffset + CurTexInfoOffset, SeekOrigin.Begin); CurTexture.DescOffset = br.ReadUInt32() + bch.DescOffset; //0x0 Location within Desc br.ReadUInt32(); //0x4 unk br.ReadUInt32(); //0x8 unk br.ReadUInt32(); //0xC unk br.ReadUInt32(); //0x10 unk br.ReadUInt32(); //0x14 unk br.ReadUInt32(); //0x18 unk; int key = (int)br.ReadUInt32(); //0x1C Name offset; not useful because we already parsed if (bch.InfoOffset == 0x44) { // key--; } string name; bch.RawNames.TryGetValue(key, out name); bch.TexNames.Add(name); br.BaseStream.Seek(CurTexture.DescOffset, SeekOrigin.Begin); CurTexture.Height = br.ReadUInt16(); //0x0 height CurTexture.Width = br.ReadUInt16(); //0x2 width br.ReadUInt32(); //0x4, unk CurTexture.DataOffset = br.ReadUInt32(); //0x8 DataOffset br.ReadUInt32(); //0xC unk CurTexture.Format = br.ReadUInt32(); //0x10 Format if (bch.InfoOffset == 0x44 || bch.InfoOffset == 0x3C) { CurTexture.DataOffset = CurTexture.Format; br.ReadUInt32(); CurTexture.Format = br.ReadUInt32(); } bch.Textures.Add(CurTexture); //OKAY DONE } for (int i = 0; i < bch.Textures.Count - 1; i++) { BCHTexture bchtex = bch.Textures[i]; bchtex.Length = bch.Textures[i + 1].DataOffset - bch.Textures[i].DataOffset; if (bch.InfoOffset == 0x44) { bchtex.Length = (uint)(FormatToBPP((int)bchtex.Format) * bchtex.Width * bchtex.Height); } bch.Textures[i] = bchtex; } if (bch.TextureCount > 0) { BCHTexture bchtex1 = bch.Textures[bch.Textures.Count - 1]; bchtex1.Length = bch.DataLength - bchtex1.DataOffset; if (bch.InfoOffset == 0x44) { bchtex1.Length = (uint)(FormatToBPP((int)bchtex1.Format) * bchtex1.Width * bchtex1.Height); } bch.Textures[bch.Textures.Count - 1] = bchtex1; } br.BaseStream.Seek(bch.DataOffset, SeekOrigin.Begin); byte[] data = new byte[bch.DataLength]; br.Read(data, 0, (int)bch.DataLength); bch.data = data; } } } return bch; }
private static Bitmap parseEntry(BCHTexture bchtex, byte[] data) { Bitmap img = new Bitmap(1, 1); if (bchtex.Format >= 0 && bchtex.Format < 0xB) { img = getIMG(bchtex, data); } else if (bchtex.Format == 0xB || bchtex.Format == 0xC || bchtex.Format == 0xD) { img = getIMG_ETC1(bchtex, data); } /*if (CHK_FLIPVERT.Checked) { img.RotateFlip(RotateFlipType.RotateNoneFlipY); }*/ return img; }
private static Bitmap getIMG_ETC1(BCHTexture bchtex, byte[] data) { Bitmap img = new Bitmap(Math.Max(nlpo2(bchtex.Width), 16), Math.Max(nlpo2(bchtex.Height), 16)); string dllpath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location).Replace('\\', '/') + "/ETC1.dll"; if (!File.Exists(dllpath)) File.WriteAllBytes(dllpath, Resources.ETC1); try { /* * Much of this code is taken/modified from Tharsis: http://jul.rustedlogic.net/thread.php?pid=436556#436556 Thank you to Tharsis's creator, xdaniel. */ byte[] temp = new byte[bchtex.Length]; Array.Copy(data, bchtex.DataOffset, temp, 0, bchtex.Length); /* Get compressed data & handle to it */ byte[] textureData = temp; //textureData = switchEndianness(textureData, 0x10); ushort[] input = new ushort[textureData.Length / sizeof(ushort)]; Buffer.BlockCopy(textureData, 0, input, 0, textureData.Length); GCHandle pInput = GCHandle.Alloc(input, GCHandleType.Pinned); /* Marshal data around, invoke ETC1.dll for conversion, etc */ UInt32 size1 = 0, size2 = 0; UInt16 wd = (ushort)img.Width, ht = (ushort)img.Height; ConvertETC1(IntPtr.Zero, ref size1, IntPtr.Zero, ref size2, wd, ht, bchtex.Format == 0xD || bchtex.Format == 0xB); //true = etc1a4, false = etc1 uint[] output = new uint[size1]; GCHandle pOutput = GCHandle.Alloc(output, GCHandleType.Pinned); ConvertETC1(pOutput.AddrOfPinnedObject(), ref size1, pInput.AddrOfPinnedObject(), ref size2, wd, ht, bchtex.Format == 0xD || bchtex.Format == 0xB); pOutput.Free(); pInput.Free(); /* Unscramble if needed // could probably be done in ETC1.dll, it's probably pretty damn ugly, but whatever... */ /* Non-square code blocks could need some cleanup, verification, etc. as well... */ uint[] finalized = new uint[output.Length]; //Act if it's square because BCLIM swizzling is stupid Buffer.BlockCopy(output, 0, finalized, 0, finalized.Length); byte[] tmp = new byte[finalized.Length]; Buffer.BlockCopy(finalized, 0, tmp, 0, tmp.Length); int h = img.Height; int w = img.Width; byte[] imgData = tmp; for (int i = 0; i < img.Width; i++) { for (int j = 0; j < img.Height; j++) { int k = (j + i * img.Height) * 4; Color c = Color.FromArgb(imgData[k + 3], imgData[k], imgData[k + 1], imgData[k + 2]); if (imgData[k] == imgData[k + 1] && imgData[k + 1] == imgData[k + 2] && imgData[k + 1] == 0) { if (imgData[k + 3] == 0) { c = Color.Transparent; } } img.SetPixel(i, j, c); /*if (bchtex.Format == 0xD) { img.SetPixel(i, j, Color.FromArgb(0xFF, imgData[k], imgData[k + 1], imgData[k + 2])); }*/ } } //image is 13 instead of 12 // 24 34 img.RotateFlip(RotateFlipType.Rotate90FlipX); if (wd > ht) { //image is now in appropriate order, but the shifting done been f****d up. Let's fix that. Bitmap img2 = new Bitmap(Math.Max(nlpo2(bchtex.Width), 16), Math.Max(nlpo2(bchtex.Height), 16)); for (int y = 0; y < Math.Max(nlpo2(bchtex.Width), 16); y += 8) { for (int x = 0; x < Math.Max(nlpo2(bchtex.Height), 16); x++) { for (int j = 0; j < 8; j++) //treat every 8 vertical pixels as 1 pixel for purposes of calculation, add to offset later. { int x1 = (x + ((y / 8) * h)) % img2.Width; //reshift x int y1 = ((x + ((y / 8) * h)) / img2.Width) * 8; //reshift y img2.SetPixel(x1, y1 + j, img.GetPixel(x, y + j)); //reswizzle } } } return img2; } else if (ht > wd) { //image is now in appropriate order, but the shifting done been f****d up. Let's fix that. Bitmap img2 = new Bitmap(Math.Max(nlpo2(bchtex.Width), 16), Math.Max(nlpo2(bchtex.Height), 16)); for (int y = 0; y < Math.Max(nlpo2(bchtex.Width), 16); y += 8) { for (int x = 0; x < Math.Max(nlpo2(bchtex.Height), 16); x++) { for (int j = 0; j < 8; j++) //treat every 8 vertical pixels as 1 pixel for purposes of calculation, add to offset later. { int x1 = x % img2.Width; //reshift x int y1 = ((x + ((y / 8) * h)) / img2.Width) * 8; //reshift y img2.SetPixel(x1, y1 + j, img.GetPixel(x, y + j)); //reswizzle } } } return img2; } } catch (IndexOutOfRangeException) { // } catch (AccessViolationException) { // } return img; }
// Bitmap Data Writing private static Bitmap getIMG(BCHTexture bchtex, byte[] data) { // New Image Bitmap img = new Bitmap(nlpo2(gcm(bchtex.Width, 8)), nlpo2(gcm(bchtex.Height, 8))); int f = (int)bchtex.Format; int area = img.Width * img.Height; if (f == 0 && area > bchtex.Length / 4 || (f == 3 && area > bchtex.Length / 4)) { img = new Bitmap(gcm(bchtex.Width, 8), gcm(bchtex.Height, 8)); area = img.Width * img.Height; } byte[] temp = new byte[(int)bchtex.Length]; Array.Copy(data, bchtex.DataOffset, temp, 0, temp.Length); data = temp; // Coordinates // Colors // Tiles Per Width int p = gcm(img.Width, 8) / 8; if (p == 0) p = 1; // Build Image using (Stream BitmapStream = new MemoryStream(data)) using (BinaryReader br = new BinaryReader(BitmapStream)) for (uint i = 0; i < area; i++) // for every pixel { uint x, y; d2xy(i % 64, out x, out y); uint tile = i / 64; // Shift Tile Coordinate into Tilemap x += (uint)(tile % p) * 8; y += (uint)(tile / p) * 8; // Get Color Color c; switch (f) { case 0: //RGBA8 - 4 bytes c = DecodeColor(br.ReadUInt32(), f); break; case 1: //RGB8 byte[] data1 = br.ReadBytes(3); Array.Resize(ref data1, 4); c = DecodeColor(BitConverter.ToUInt32(data1, 0), f); break; case 2: //RGBA5551 case 3: //RGB565 case 4: //RGBA4 case 5: //LA8 c = DecodeColor(br.ReadUInt16(), f); break; case 6: //HILO8 case 7: //L8 case 8: //A8 case 9: //LA4 c = DecodeColor(br.ReadByte(), f); break; case 0xA: //L4 case 0xB: //A4 uint val = br.ReadByte(); img.SetPixel((int)x, (int)y, DecodeColor(val & 0xF, f)); i++; x++; c = DecodeColor(val >> 4, f); break; case 0xC: // ETC1 case 0xD: // ETC1A4 default: throw new Exception("Invalid FileFormat."); } img.SetPixel((int)x, (int)y, c); } return img; }