using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Runtime.InteropServices; using DotNetCTFDumper.GUI; using DotNetCTFDumper.Utils; using static DotNetCTFDumper.MMFParser.EXE.ChunkList; namespace DotNetCTFDumper.MMFParser.EXE.Loaders.Banks { public class ImageBank : ChunkLoader { public bool SaveImages = false; public Dictionary Images = new Dictionary(); public uint NumberOfItems; public bool PreloadOnly=true; public ImageBank(ByteReader reader) : base(reader) { } public ImageBank(Chunk chunk) : base(chunk) { } public override void Print(bool ext) { } public override string[] GetReadableData() { return new string[] { $"Number of images: {NumberOfItems}" }; } public void Read(bool load, bool save) { var cache = Settings.DumpImages; Settings.DumpImages = load; SaveImages = save; Read(); Settings.DumpImages = cache; } public void Preload() { } public void LoadByHandle(int handle) { Images[handle].Load(); } public event MainForm.SaveHandler OnImageSaved; public override void Read() { if (!Settings.DoMFA) Reader.Seek(0); //Reset the reader to avoid bugs when dumping more than once var tempImages = new Dictionary(); NumberOfItems = Reader.ReadUInt32(); Console.WriteLine($"Found {NumberOfItems} images"); //if (!Settings.DumpImages) return; for (int i = 0; i < NumberOfItems; i++) { if (MainForm.BreakImages) { break; } var item = new ImageItem(Reader); item.Read(!PreloadOnly); tempImages.Add(item.Handle, item); //if (SaveImages) item.Save($"{Settings.ImagePath}\\" + item.Handle.ToString() + ".png"); OnImageSaved?.Invoke(i,(int) NumberOfItems); if (Settings.Build >= 284) item.Handle -= 1; //images[item.handle] = item; } if (!MainForm.BreakImages) Images = tempImages; MainForm.BreakImages = false; Console.WriteLine("Len:"+Images.Keys.Count); } } public class ImageItem : ChunkLoader { public int Handle; int Position; int _checksum; int _references; int _width; int _height; int _graphicMode; public int XHotspot; public int YHotspot; public int ActionX; public int ActionY; BitDict Flags = new BitDict(new string[] { "RLE", "RLEW", "RLET", "LZX", "Alpha", "ACE", "Mac" }); public int Size; //tranparent,add later byte[] _transparent; byte[] _colorArray; int _indexed; public byte[] rawImg; public byte[] rawAlpha; public bool Debug = false; public int Debug2 = 1; private Bitmap _bitmap; public void Read(bool load) { Handle = Reader.ReadInt32() - 1; Position = (int) Reader.Tell(); if (load) Load(); else Preload(); } public override void Read() { Handle = Reader.ReadInt32() - 1; Position = (int) Reader.Tell(); Load(); } public override void Print(bool ext) { } public override string[] GetReadableData() { throw new NotImplementedException(); } public void Preload() { _bitmap = null; Reader.Seek(Position); ByteReader imageReader; // imageReader = Debug ? Reader : Decompressor.DecompressAsReader(Reader, out var a); imageReader = Debug ? Reader : Decompressor.DecompressAsReader(Reader, out var a); long start = imageReader.Tell(); _checksum = imageReader.ReadInt32(); _references = imageReader.ReadInt32(); Size = (int) imageReader.ReadUInt32(); imageReader.Seek(start+Size); } public void Load() { _bitmap = null; Reader.Seek(Position); ByteReader imageReader; // imageReader = Debug ? Reader : Decompressor.DecompressAsReader(Reader, out var a); imageReader = Debug ? Reader : Decompressor.DecompressAsReader(Reader, out var a); long start = imageReader.Tell(); _checksum = imageReader.ReadInt32(); _references = imageReader.ReadInt32(); Size = (int) imageReader.ReadUInt32(); if (Debug) { imageReader = new ByteReader(imageReader.ReadBytes(Size + 20)); } _width = imageReader.ReadInt16(); _height = imageReader.ReadInt16(); _graphicMode = imageReader.ReadByte(); //Graphic mode is always 4 for SL Flags.flag = imageReader.ReadByte(); imageReader.Skip(2); XHotspot = imageReader.ReadInt16(); YHotspot = imageReader.ReadInt16(); ActionX = imageReader.ReadInt16(); ActionY = imageReader.ReadInt16(); _transparent = imageReader.ReadBytes(4); //Logger.Log($"Loading image {Handle.ToString(),4} Size: {_width,4}x{_height,4}"); byte[] imageData; if (Flags["LZX"]) { uint decompressedSize = imageReader.ReadUInt32(); imageData = Decompressor.decompress_block(imageReader, (int) (imageReader.Size() - imageReader.Tell()), (int) decompressedSize); } else { imageData = imageReader.ReadBytes((int) (imageReader.Size() - imageReader.Tell())); } int bytesRead = 0; rawImg = imageData; if (Flags["RLE"] || Flags["RLEW"] || Flags["RLET"]) { } else { switch (_graphicMode) { case 4: { (_colorArray, bytesRead) = ImageHelper.ReadPoint(imageData, _width, _height); break; } case 6: { (_colorArray, bytesRead) = ImageHelper.ReadFifteen(imageData, _width, _height); break; } case 7: { (_colorArray, bytesRead) = ImageHelper.ReadSixteen(imageData, _width, _height); break; } } } int alphaSize = Size - bytesRead; if (Flags["Alpha"]) { byte[,] alpha = ImageHelper.ReadAlpha(imageData, _width, _height, Size - alphaSize); rawAlpha = Helper.To1DArray(alpha); int stride = _width * 4; for (int y = 0; y < _height; y++) { for (int x = 0; x < _width; x++) { _colorArray[(y * stride) + (x * 4) + 3] = alpha[x, y]; } } } return; } public void Save(string filename) { using (var bmp = new Bitmap(_width, _height, PixelFormat.Format32bppArgb)) { BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat); IntPtr pNative = bmpData.Scan0; Marshal.Copy(_colorArray, 0, pNative, _colorArray.Length); bmp.UnlockBits(bmpData); bmp.Save(filename); } } public Bitmap Bitmap { get { if (_colorArray==null) Load(); if (_bitmap == null) { _bitmap = new Bitmap(_width, _height, PixelFormat.Format32bppArgb); BitmapData bmpData = _bitmap.LockBits(new Rectangle(0, 0, _bitmap.Width, _bitmap.Height), ImageLockMode.WriteOnly, _bitmap.PixelFormat); IntPtr pNative = bmpData.Scan0; Marshal.Copy(_colorArray, 0, pNative, _colorArray.Length); _bitmap.UnlockBits(bmpData); } return _bitmap; } } // private byte[] GenerateImage() // { // Int32 pad = ImageHelper.GetPadding(_width, 3); // byte[] points = new byte[(_width * _height + pad * _height)*3]; // for (UInt32 y = 0; y < _height; y++) // { // for (UInt32 x = 0; x < _height; x++) // { // // } // } // // return points; // } public void Write(ByteWriter writer) { ByteWriter chunk = new ByteWriter(new MemoryStream()); chunk.WriteInt32(_checksum); chunk.WriteInt32(_references); byte[] compressedImg = null; if (Flags["LZX"]) { compressedImg = Decompressor.compress_block(rawImg); chunk.WriteUInt32((uint) compressedImg.Length+4); } else { chunk.WriteUInt32((uint) rawImg.Length); } chunk.WriteInt16((short) _width); chunk.WriteInt16((short) _height); chunk.WriteInt8((byte) _graphicMode); chunk.WriteInt8((byte) Flags.flag); chunk.WriteInt16(0); chunk.WriteInt16((short) XHotspot); chunk.WriteInt16((short) YHotspot); chunk.WriteInt16((short) ActionX); chunk.WriteInt16((short) ActionY); chunk.WriteBytes(_transparent); if (Flags["LZX"]) { chunk.WriteInt32(rawImg.Length); chunk.WriteBytes(compressedImg); } else { chunk.WriteBytes(rawImg); } writer.WriteInt32(Handle + 1); writer.WriteWriter(chunk); } public ImageItem(ByteReader reader) : base(reader) { } public ImageItem(Chunk chunk) : base(chunk) { } } public class TestPoint { public int Size = 3; public (byte r, byte g, byte b) Read(byte[] data, int position) { byte r = 0; byte g = 0; byte b = 0; try { b = data[position]; g = data[position + 1]; r = data[position + 2]; } catch { Console.WriteLine(position); } return (r, g, b); } } }