internal static Bitmap GetIMG_XY7(Clim bclim) { Bitmap img = new Bitmap(bclim.BaseSize, bclim.BaseSize); using (Stream bitmapStream = new MemoryStream(bclim.Data)) using (BinaryReader br = new BinaryReader(bitmapStream)) { // Fetch Color stuff. if (br.ReadUInt16() != 2) { return(null); } ushort colors = br.ReadUInt16(); Color[] ca = new Color[colors]; for (int i = 0; i < colors; i++) { ca[i] = Bclim.DecodeColor(br.ReadUInt16(), 7); } // Coordinates // Colors // Tiles Per Width int p = Bclim.Gcm(img.Width, 8) / 8; if (p == 0) { p = 1; } for (uint i = 0; i < bclim.BaseSize * bclim.BaseSize; i++) // for every pixel { Bclim.D2Xy(i % 64, out uint x, out uint y); uint tile = i / 64; // Shift Tile Coordinate into Tilemap x += (uint)(tile % p) * 8; y += (uint)(tile / p) * 8; byte val = br.ReadByte(); if (colors <= 0x10) // Handle 2 pixels at a time { img.SetPixel((int)x, (int)y, ca[val >> 4]); x++; i++; val &= 0xF; img.SetPixel((int)x, (int)y, ca[val]); } else //1bpp instead of .5, handle 2 pixels at a time the same way for no reason { img.SetPixel((int)x, (int)y, ca[val]); x++; i++; val = br.ReadByte(); img.SetPixel((int)x, (int)y, ca[val]); } } } return(img); }
internal static Bitmap GetImg(Clim bclim) { if (bclim.FileFormat == 7 && BitConverter.ToUInt16(bclim.Data, 0) == 2) // XY7 { return(Bclim.GetIMG_XY7(bclim)); } if (bclim.FileFormat == 10 || bclim.FileFormat == 11) // Use ETC1 to get image instead. { return(Bclim.GetIMG_ETC(bclim)); } // New Image int w = Bclim.Nlpo2(Bclim.Gcm(bclim.Width, 8)); int h = Bclim.Nlpo2(Bclim.Gcm(bclim.Height, 8)); int f = bclim.FileFormat; int area = w * h; if (f == 9 && area > bclim.Data.Length / 4) { w = Bclim.Gcm(bclim.Width, 8); h = Bclim.Gcm(bclim.Height, 8); } // Build Image return(Bclim.GetImg(w, h, bclim.Data, f)); }
public static Clim Analyze(string path) { Clim bclim = new Clim { FileName = Path.GetFileNameWithoutExtension(path), FilePath = Path.GetDirectoryName(path), Extension = Path.GetExtension(path) }; byte[] byteArray = File.ReadAllBytes(path); using (BinaryReader br = new BinaryReader(new MemoryStream(byteArray))) { br.BaseStream.Seek(br.BaseStream.Length - 0x28, SeekOrigin.Begin); bclim.Magic = br.ReadUInt32(); bclim.Bom = br.ReadUInt16(); bclim.ClimLength = br.ReadUInt32(); bclim.TileWidth = 2 << br.ReadByte(); bclim.TileHeight = 2 << br.ReadByte(); bclim.TotalLength = br.ReadUInt32(); bclim.Count = br.ReadUInt32(); bclim.Imag = br.ReadChars(4); bclim.ImagLength = br.ReadUInt32(); bclim.Width = br.ReadUInt16(); bclim.Height = br.ReadUInt16(); bclim.FileFormat = br.ReadInt32(); bclim.DataLength = br.ReadUInt32(); bclim.BaseSize = Math.Max(Bclim.Nlpo2(bclim.Width), Bclim.Nlpo2(bclim.Height)); br.BaseStream.Seek(0, SeekOrigin.Begin); bclim.Data = br.ReadBytes((int)bclim.DataLength); return(bclim); } }
internal static Bitmap GetIMG_ETC(Clim bclim) { Bitmap img = new Bitmap(Math.Max(Bclim.Nlpo2(bclim.Width), 16), Math.Max(Bclim.Nlpo2(bclim.Height), 16)); try { /* http://jul.rustedlogic.net/thread.php?id=17312 * Much of this code is taken/modified from Tharsis. Thank you to Tharsis's creator, xdaniel. * https://github.com/xdanieldzd/Tharsis */ /* Get compressed data & handle to it */ byte[] textureData = bclim.Data; //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 */ uint size1 = 0; ushort w = (ushort)img.Width, h = (ushort)img.Height; Etc1.ConvertETC1(IntPtr.Zero, ref size1, IntPtr.Zero, w, h, bclim.FileFormat == 0xB); // true = etc1a4, false = etc1 // System.Diagnostics.Debug.WriteLine(size1); uint[] output = new uint[size1]; GCHandle pOutput = GCHandle.Alloc(output, GCHandleType.Pinned); Etc1.ConvertETC1(pOutput.AddrOfPinnedObject(), ref size1, pInput.AddrOfPinnedObject(), w, h, bclim.FileFormat == 0xB); pOutput.Free(); pInput.Free(); /* Unscramble if needed // could probably be done in ETC1Lib.dll, it's probably pretty 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); byte[] imgData = tmp; for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { int k = (j + i * img.Height) * 4; img.SetPixel(i, j, Color.FromArgb(imgData[k + 3], imgData[k], imgData[k + 1], imgData[k + 2])); } } // Image is 13 instead of 12 // 24 34 img.RotateFlip(RotateFlipType.Rotate90FlipX); if (w > h) { // Image is now in appropriate order, but the shifting is messed up. Let's fix that. Bitmap img2 = new Bitmap(Math.Max(Bclim.Nlpo2(bclim.Width), 16), Math.Max(Bclim.Nlpo2(bclim.Height), 16)); for (int y = 0; y < Math.Max(Bclim.Nlpo2(bclim.Width), 16); y += 8) { for (int x = 0; x < Math.Max(Bclim.Nlpo2(bclim.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 } } } img = img2; } else if (h > w) { Bitmap img2 = new Bitmap(Math.Max(Bclim.Nlpo2(bclim.Width), 16), Math.Max(Bclim.Nlpo2(bclim.Height), 16)); for (int y = 0; y < Math.Max(Bclim.Nlpo2(bclim.Width), 16); y += 8) { for (int x = 0; x < Math.Max(Bclim.Nlpo2(bclim.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 } } } img = img2; } } catch { // ignored } return(img); }
internal static Image MakeBmp(string path, bool autosave = false, bool crop = true) { Clim bclim = Bclim.Analyze(path); if (bclim.Magic != 0x4D494C43) { return(null); } // Interpret data. int f = bclim.FileFormat; if (f > 13) { return(null); } Bitmap img; if (f == 7 && BitConverter.ToUInt16(bclim.Data, 0) == 2) { // PKM XY Format 7 (Color Palette) img = Bclim.GetIMG_XY7(bclim); } else if (f == 10 || f == 11) { img = Bclim.GetIMG_ETC(bclim); } else { img = Bclim.GetImg(bclim); } if (img == null) { return(null); } Rectangle cropRect = new Rectangle(0, 0, bclim.Width, bclim.Height); Bitmap cropBmp = new Bitmap(cropRect.Width, cropRect.Height); using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(cropBmp)) { g.DrawImage(img, new Rectangle(0, 0, cropBmp.Width, cropBmp.Height), cropRect, GraphicsUnit.Pixel); } if (!autosave) { return(!crop ? img : cropBmp); } using (MemoryStream ms = new MemoryStream()) { //error will throw from here cropBmp.Save(ms, ImageFormat.Png); byte[] data = ms.ToArray(); File.WriteAllBytes(bclim.FilePath + "\\" + bclim.FileName + ".png", data); } return(!crop ? img : cropBmp); }
public override void UpdateTwin(TwinModel model) { Clim clim = (Clim)model; updateTooltipText(clim.ToString()); }