public static unsafe Bitmap ToBitmap(byte[] Data, int Offset, int Width, int Height, ImageFormat Format, bool ExactSize = false) { if (Data == null || Data.Length < 1 || Offset < 0 || Offset >= Data.Length || Width < 1 || Height < 1) { return(null); } if (ExactSize && ((Width % 8) != 0 || (Height % 8) != 0)) { return(null); } int physicalwidth = Width; int physicalheight = Height; if (!ExactSize) { Width = 1 << (int)Math.Ceiling(Math.Log(Width, 2)); Height = 1 << (int)Math.Ceiling(Math.Log(Height, 2)); } Bitmap bitm = new Bitmap(physicalwidth, physicalheight); BitmapData d = bitm.LockBits(new Rectangle(0, 0, bitm.Width, bitm.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); uint * res = (uint *)d.Scan0; int offs = Offset; //0; int stride = d.Stride / 4; switch (Format) { case ImageFormat.RGBA8: for (int y = 0; y < Height; y += 8) { for (int x = 0; x < Width; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( Data[offs + pos * 4], Data[offs + pos * 4 + 3], Data[offs + pos * 4 + 2], Data[offs + pos * 4 + 1] ); } offs += 64 * 4; } } break; case ImageFormat.RGB8: for (int y = 0; y < Height; y += 8) { for (int x = 0; x < Width; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( Data[offs + pos * 3 + 2], Data[offs + pos * 3 + 1], Data[offs + pos * 3 + 0] ); } offs += 64 * 3; } } break; case ImageFormat.RGBA5551: for (int y = 0; y < Height; y += 8) { for (int x = 0; x < Width; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); res[(y + y2) * stride + x + x2] = GFXUtil.ARGB1555ToArgb(IOUtil.ReadU16LE(Data, offs + pos * 2)); } offs += 64 * 2; } } break; case ImageFormat.RGB565: for (int y = 0; y < Height; y += 8) { for (int x = 0; x < Width; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); res[(y + y2) * stride + x + x2] = GFXUtil.RGB565ToArgb(IOUtil.ReadU16LE(Data, offs + pos * 2)); } offs += 64 * 2; } } break; case ImageFormat.RGBA4: for (int y = 0; y < Height; y += 8) { for (int x = 0; x < Width; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( (byte)((Data[offs + pos * 2] & 0xF) * 0x11), (byte)((Data[offs + pos * 2 + 1] >> 4) * 0x11), (byte)((Data[offs + pos * 2 + 1] & 0xF) * 0x11), (byte)((Data[offs + pos * 2] >> 4) * 0x11) ); } offs += 64 * 2; } } break; case ImageFormat.LA8: for (int y = 0; y < Height; y += 8) { for (int x = 0; x < Width; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( Data[offs + pos * 2], Data[offs + pos * 2 + 1], Data[offs + pos * 2 + 1], Data[offs + pos * 2 + 1] ); } offs += 64 * 2; } } break; case ImageFormat.HILO8: for (int y = 0; y < Height; y += 8) { for (int x = 0; x < Width; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( Data[offs + pos * 2], Data[offs + pos * 2 + 1], Data[offs + pos * 2 + 1], Data[offs + pos * 2 + 1] ); } offs += 64 * 2; } } break; case ImageFormat.L8: for (int y = 0; y < Height; y += 8) { for (int x = 0; x < Width; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( Data[offs + pos], Data[offs + pos], Data[offs + pos] ); } offs += 64; } } break; case ImageFormat.A8: for (int y = 0; y < Height; y += 8) { for (int x = 0; x < Width; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( Data[offs + pos], 255, 255, 255 ); } offs += 64; } } break; case ImageFormat.LA4: for (int y = 0; y < Height; y += 8) { for (int x = 0; x < Width; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( (byte)((Data[offs + pos] & 0xF) * 0x11), (byte)((Data[offs + pos] >> 4) * 0x11), (byte)((Data[offs + pos] >> 4) * 0x11), (byte)((Data[offs + pos] >> 4) * 0x11) ); } offs += 64; } } break; case ImageFormat.L4: for (int y = 0; y < Height; y += 8) { for (int x = 0; x < Width; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); int shift = (pos & 1) * 4; res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( (byte)(((Data[offs + pos / 2] >> shift) & 0xF) * 0x11), (byte)(((Data[offs + pos / 2] >> shift) & 0xF) * 0x11), (byte)(((Data[offs + pos / 2] >> shift) & 0xF) * 0x11) ); } offs += 64 / 2; } } break; case ImageFormat.A4: for (int y = 0; y < Height; y += 8) { for (int x = 0; x < Width; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); int shift = (pos & 1) * 4; res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( (byte)(((Data[offs + pos / 2] >> shift) & 0xF) * 0x11), 255, 255, 255 ); } offs += 64 / 2; } } break; case ImageFormat.ETC1: //Some reference: http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt case ImageFormat.ETC1A4: { for (int y = 0; y < Height; y += 8) { for (int x = 0; x < Width; x += 8) { for (int i = 0; i < 8; i += 4) { for (int j = 0; j < 8; j += 4) { ulong alpha = 0xFFFFFFFFFFFFFFFF; if (Format == ImageFormat.ETC1A4) { alpha = IOUtil.ReadU64LE(Data, offs); offs += 8; } ulong data = IOUtil.ReadU64LE(Data, offs); bool diffbit = ((data >> 33) & 1) == 1; bool flipbit = ((data >> 32) & 1) == 1; //0: |||, 1: |-| int r1, r2, g1, g2, b1, b2; if (diffbit) //'differential' mode { int r = (int)((data >> 59) & 0x1F); int g = (int)((data >> 51) & 0x1F); int b = (int)((data >> 43) & 0x1F); r1 = (r << 3) | ((r & 0x1C) >> 2); g1 = (g << 3) | ((g & 0x1C) >> 2); b1 = (b << 3) | ((b & 0x1C) >> 2); r += (int)((data >> 56) & 0x7) << 29 >> 29; g += (int)((data >> 48) & 0x7) << 29 >> 29; b += (int)((data >> 40) & 0x7) << 29 >> 29; r2 = (r << 3) | ((r & 0x1C) >> 2); g2 = (g << 3) | ((g & 0x1C) >> 2); b2 = (b << 3) | ((b & 0x1C) >> 2); } else //'individual' mode { r1 = (int)((data >> 60) & 0xF) * 0x11; g1 = (int)((data >> 52) & 0xF) * 0x11; b1 = (int)((data >> 44) & 0xF) * 0x11; r2 = (int)((data >> 56) & 0xF) * 0x11; g2 = (int)((data >> 48) & 0xF) * 0x11; b2 = (int)((data >> 40) & 0xF) * 0x11; } int Table1 = (int)((data >> 37) & 0x7); int Table2 = (int)((data >> 34) & 0x7); for (int y3 = 0; y3 < 4; y3++) { for (int x3 = 0; x3 < 4; x3++) { if (x + j + x3 >= physicalwidth) { continue; } if (y + i + y3 >= physicalheight) { continue; } int val = (int)((data >> (x3 * 4 + y3)) & 0x1); bool neg = ((data >> (x3 * 4 + y3 + 16)) & 0x1) == 1; uint c; if ((flipbit && y3 < 2) || (!flipbit && x3 < 2)) { int add = ETC1Modifiers[Table1, val] * (neg ? -1 : 1); c = GFXUtil.ToArgb((byte)(((alpha >> ((x3 * 4 + y3) * 4)) & 0xF) * 0x11), (byte)ColorClamp(r1 + add), (byte)ColorClamp(g1 + add), (byte)ColorClamp(b1 + add)); } else { int add = ETC1Modifiers[Table2, val] * (neg ? -1 : 1); c = GFXUtil.ToArgb((byte)(((alpha >> ((x3 * 4 + y3) * 4)) & 0xF) * 0x11), (byte)ColorClamp(r2 + add), (byte)ColorClamp(g2 + add), (byte)ColorClamp(b2 + add)); } res[(i + y3) * stride + x + j + x3] = c; } } offs += 8; } } } res += stride * 8; } } break; } bitm.UnlockBits(d); return(bitm); }