public Bitmap LoadBitmap(TableEntry entry) { var result = new Bitmap(entry.Width, entry.Height, PixelFormat.Format16bppRgb565); Width = (ushort)result.Width; Height = (ushort)result.Height; int size = result.Width * result.Height, idx = 0; var pixels = new short[size]; using (FileStream fs = new FileStream(Path, FileMode.Open, FileAccess.Read)) using (BinaryReader br = new BinaryReader(fs)) { fs.Position = entry.Offset; while (idx < size) { var data = ReverseBytes(br.ReadUInt32()); var reps = data & RepetitionMask; for (uint i = 0; i < reps; i++, idx++) { if (idx >= size) { lock (_consoleLock) Console.WriteLine($"WARNING! {entry.Id} image with expected size {size} overwrites itself by {reps - i} pixels!"); break; } pixels[idx] = (short)((data >> 16) | (data << 12 >> 28)); } } } var bmp = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.WriteOnly, result.PixelFormat); for (int y = 0; y < result.Height; y++) { Marshal.Copy(pixels, y * result.Width, IntPtr.Add(bmp.Scan0, y * bmp.Stride), result.Width); } result.UnlockBits(bmp); return(result); }
private static void EncodeBitmaps(string inputDirectory, bool optimize, bool ignoreConstraits) { var reg = new Regex("(\\d+)_.*"); var files = Directory.EnumerateFiles(inputDirectory, "*_*.bmp", SearchOption.TopDirectoryOnly) .Where(f => reg.IsMatch(f)) .Select(f => new { Path = f, Identifier = ushort.Parse(reg.Match(Path.GetFileName(f)).Groups[1].Value, CultureInfo.InvariantCulture) }) .OrderBy(f => f.Identifier) // order by identifier, as th screens checks if identifier match an index .ToArray(); if (!ignoreConstraits && !EncoderInputIsOkay(files.Select(f => f.Identifier))) { return; } var result = true; var outputDir = Directory.CreateDirectory(ResourcesOutputDir).FullName; uint curOffset = 0; using (FileStream fsTable = new FileStream(Path.Combine(outputDir, DescriptorsTableFileName), FileMode.Create, FileAccess.Write)) using (FileStream fsImage = new FileStream(Path.Combine(outputDir, BitmapDataFileName), FileMode.Create, FileAccess.Write)) using (BinaryWriter bwTable = new BinaryWriter(fsTable)) using (BinaryWriter bwImage = new BinaryWriter(fsImage)) { if (optimize) { var numBytesSaved = 0; try { var images = files.Select(file => { var img = new ImageData(file.Path); var data = img.CompressImage(); return(new { Id = file.Identifier, Img = img, Data = data }); }).ToList(); var table = new TableEntry[images.Count]; for (int i = 0, j = 0; i < images.Count; i++) { var found = false; var id = images[i].Id; var img = images[i].Img; var data = images[i].Data; for (j = 0; j < i; j++) { var oimg = images[j].Img; var odata = images[j].Data; if (oimg.Width == img.Width && oimg.Height == img.Height && odata.SequenceEqual(data)) { found = true; break; } } if (i == 0 || !found) // first or not found { var entry = new TableEntry(id, img.Width, img.Height, curOffset); table[i] = entry; entry.Write(bwTable); for (int k = 0; k < data.Length; k++) { bwImage.Write(data[k]); } curOffset += (uint)(data.Length * 4); } else { var entry = new TableEntry(id, img.Width, img.Height, table[j].Offset); table[i] = entry; entry.Write(bwTable); numBytesSaved += data.Length * 4; } } Console.WriteLine($"Saved {numBytesSaved} bytes!"); } catch (Exception ex) { Console.WriteLine($"ERROR! Failed to compress!{Environment.NewLine}{ex}"); result = false; } } else { foreach (var file in files) { try { var img = new ImageData(file.Path); var data = img.CompressImage(); new TableEntry(file.Identifier, img.Width, img.Height, curOffset).Write(bwTable); for (int i = 0; i < data.Length; i++) { bwImage.Write(data[i]); } curOffset += (uint)(data.Length * 4); } catch (Exception ex) { Console.WriteLine($"ERROR! Failed to compress a file {file.Path}!{Environment.NewLine}{ex}"); result = false; break; } } } } if (!ignoreConstraits && curOffset >= MaxBitmapSize) { Console.WriteLine($"ERROR! Output file is too big {curOffset}, max {MaxBitmapSize} bytes!"); File.Delete(Path.Combine(outputDir, DescriptorsTableFileName)); File.Delete(Path.Combine(outputDir, BitmapDataFileName)); } Console.WriteLine($"Encoding {(result ? "finished" : "failed")}"); }