From a16d0a51463750e9b8c04642fd6d8cddb28b04d5 Mon Sep 17 00:00:00 2001 From: Ray Koopa Date: Sat, 12 Jan 2019 22:14:17 +0100 Subject: [PATCH] Use RawBitmap as image data container everywhere. --- src/Syroot.Worms.Armageddon/Team.cs | 8 +-- src/Syroot.Worms.Mgame/Igd.cs | 13 +++-- src/Syroot.Worms.Mgame/IgdImage.cs | 2 +- src/Syroot.Worms.Mgame/Ksf.cs | 10 +++- src/Syroot.Worms.Mgame/KsfImage.cs | 2 +- src/Syroot.Worms.Scratchpad/Program.cs | 4 +- src/Syroot.Worms.WorldParty/Team.cs | 8 +-- src/Syroot.Worms/Core/Algebra.cs | 16 ++++++ src/Syroot.Worms/Core/ByteExtensions.cs | 35 +++-------- src/Syroot.Worms/Core/Graphics/RawBitmap.cs | 64 +++++++++++++++++++++ src/Syroot.Worms/Img.cs | 6 +- src/Syroot.Worms/RawBitmapData.cs | 32 ----------- 12 files changed, 117 insertions(+), 83 deletions(-) create mode 100644 src/Syroot.Worms/Core/Algebra.cs create mode 100644 src/Syroot.Worms/Core/Graphics/RawBitmap.cs delete mode 100644 src/Syroot.Worms/RawBitmapData.cs diff --git a/src/Syroot.Worms.Armageddon/Team.cs b/src/Syroot.Worms.Armageddon/Team.cs index 7d6576c..6df6595 100644 --- a/src/Syroot.Worms.Armageddon/Team.cs +++ b/src/Syroot.Worms.Armageddon/Team.cs @@ -81,7 +81,7 @@ namespace Syroot.Worms.Armageddon /// /// Gets or sets the team grave bitmap if it uses a custom one. /// - public RawBitmapData Grave { get; set; } + public RawBitmap Grave { get; set; } /// /// Gets or sets the team's special weapon. @@ -151,7 +151,7 @@ namespace Syroot.Worms.Armageddon /// /// Gets or sets the bitmap of the team flag. /// - public RawBitmapData Flag { get; set; } + public RawBitmap Flag { get; set; } /// /// Gets or sets the deathmatch rank this team reached. @@ -210,7 +210,7 @@ namespace Syroot.Worms.Armageddon if (GraveSprite < 0) { GraveFileName = reader.ReadString(0x20); - Grave = new RawBitmapData() + Grave = new RawBitmap() { BitsPerPixel = 8, Size = new Size(24, 32), @@ -233,7 +233,7 @@ namespace Syroot.Worms.Armageddon MissionStatuses = reader.ReadStructs(_missionCount); FlagFileName = reader.ReadString(0x20); - Flag = new RawBitmapData() + Flag = new RawBitmap() { BitsPerPixel = 8, Size = new Size(20, 17), diff --git a/src/Syroot.Worms.Mgame/Igd.cs b/src/Syroot.Worms.Mgame/Igd.cs index 0574aaa..656ec5a 100644 --- a/src/Syroot.Worms.Mgame/Igd.cs +++ b/src/Syroot.Worms.Mgame/Igd.cs @@ -2,7 +2,7 @@ using System.Drawing; using System.IO; using Syroot.BinaryData; -using Syroot.Worms.Core.Graphics; +using Syroot.Worms.Core; namespace Syroot.Worms.Mgame { @@ -93,11 +93,12 @@ namespace Syroot.Worms.Mgame // Decompress the data. int dataSize = stream.ReadInt32(); int dataSizeCompressed = stream.ReadInt32(); - byte[] data = Decompress(stream, dataSizeCompressed, dataSize); - // The actual image width is a multiple of 4. - image.Bitmap = BitmapTools.CreateIndexed(new Size((image.Size.Width + 4 - 1) / 4 * 4, image.Size.Height), - palette, data); - + image.RawBitmap = new RawBitmap + { + Size = new Size(Algebra.NextMultiple(image.Size.Width, 4), image.Size.Height), + Palette = palette, + Data = Decompress(stream, dataSizeCompressed, dataSize) + }; Images.Add(image); } } diff --git a/src/Syroot.Worms.Mgame/IgdImage.cs b/src/Syroot.Worms.Mgame/IgdImage.cs index 6839a4a..f452794 100644 --- a/src/Syroot.Worms.Mgame/IgdImage.cs +++ b/src/Syroot.Worms.Mgame/IgdImage.cs @@ -14,6 +14,6 @@ namespace Syroot.Worms.Mgame public int UnknownC { get; set; } public Size Size { get; set; } public Point Center { get; set; } - public Bitmap Bitmap { get; set; } + public RawBitmap RawBitmap { get; set; } } } diff --git a/src/Syroot.Worms.Mgame/Ksf.cs b/src/Syroot.Worms.Mgame/Ksf.cs index 4f604ea..98b2636 100644 --- a/src/Syroot.Worms.Mgame/Ksf.cs +++ b/src/Syroot.Worms.Mgame/Ksf.cs @@ -2,7 +2,6 @@ using System.Drawing; using System.IO; using Syroot.BinaryData; -using Syroot.Worms.Core.Graphics; namespace Syroot.Worms.Mgame { @@ -95,7 +94,14 @@ namespace Syroot.Worms.Mgame int dataLength = offsets[i + 1] - offset; Size size = sizes[i]; if (!size.IsEmpty) - images[i].Bitmap = BitmapTools.CreateIndexed(size, palette.Colors, stream.ReadBytes(dataLength)); + { + images[i].RawBitmap = new RawBitmap + { + Size = size, + Palette = palette.Colors, + Data = stream.ReadBytes(dataLength) + }; + } Images.Add(images[i]); } diff --git a/src/Syroot.Worms.Mgame/KsfImage.cs b/src/Syroot.Worms.Mgame/KsfImage.cs index 8b6aec6..c844ea7 100644 --- a/src/Syroot.Worms.Mgame/KsfImage.cs +++ b/src/Syroot.Worms.Mgame/KsfImage.cs @@ -10,6 +10,6 @@ namespace Syroot.Worms.Mgame // ---- PROPERTIES --------------------------------------------------------------------------------------------- public Point Center { get; set; } - public Bitmap Bitmap { get; set; } + public RawBitmap RawBitmap { get; set; } } } \ No newline at end of file diff --git a/src/Syroot.Worms.Scratchpad/Program.cs b/src/Syroot.Worms.Scratchpad/Program.cs index e437577..0657864 100644 --- a/src/Syroot.Worms.Scratchpad/Program.cs +++ b/src/Syroot.Worms.Scratchpad/Program.cs @@ -36,7 +36,7 @@ namespace Syroot.Worms.Scratchpad { string pngFileName = Path.ChangeExtension(i.ToString(), "png"); IgdImage image = igd.Images[i]; - image.Bitmap.Save(Path.Combine(pngIgdFolder, pngFileName), ImageFormat.Png); + image.RawBitmap.ToBitmap().Save(Path.Combine(pngIgdFolder, pngFileName), ImageFormat.Png); } } } @@ -65,7 +65,7 @@ namespace Syroot.Worms.Scratchpad for (int i = 0; i < ksf.Images.Count; i++) { string pngFileName = Path.ChangeExtension(i.ToString(), "png"); - ksf.Images[i].Bitmap?.Save(Path.Combine(pngKsfFolder, pngFileName), ImageFormat.Png); + ksf.Images[i].RawBitmap?.ToBitmap().Save(Path.Combine(pngKsfFolder, pngFileName), ImageFormat.Png); } } } diff --git a/src/Syroot.Worms.WorldParty/Team.cs b/src/Syroot.Worms.WorldParty/Team.cs index 5fd01be..ffad627 100644 --- a/src/Syroot.Worms.WorldParty/Team.cs +++ b/src/Syroot.Worms.WorldParty/Team.cs @@ -79,7 +79,7 @@ namespace Syroot.Worms.WorldParty /// /// Gets or sets the team grave bitmap if it uses a custom one. /// - public RawBitmapData Grave { get; set; } + public RawBitmap Grave { get; set; } /// /// Gets or sets the team's special weapon. @@ -149,7 +149,7 @@ namespace Syroot.Worms.WorldParty /// /// Gets or sets the bitmap of the team flag. /// - public RawBitmapData Flag { get; set; } + public RawBitmap Flag { get; set; } /// /// Gets or sets an unknown value. @@ -209,7 +209,7 @@ namespace Syroot.Worms.WorldParty if (GraveSprite < 0) { GraveFileName = reader.ReadString(0x20); - Grave = new RawBitmapData() + Grave = new RawBitmap() { BitsPerPixel = 8, Size = new Size(24, 32), @@ -232,7 +232,7 @@ namespace Syroot.Worms.WorldParty MissionStatuses = reader.ReadStructs(_missionCount); FlagFileName = reader.ReadString(0x20); - Flag = new RawBitmapData() + Flag = new RawBitmap() { BitsPerPixel = 8, Size = new Size(20, 17), diff --git a/src/Syroot.Worms/Core/Algebra.cs b/src/Syroot.Worms/Core/Algebra.cs new file mode 100644 index 0000000..68c9a76 --- /dev/null +++ b/src/Syroot.Worms/Core/Algebra.cs @@ -0,0 +1,16 @@ +namespace Syroot.Worms.Core +{ + /// + /// Represents mathemtical helper utilities. + /// + public static class Algebra + { + /// + /// Gets the nearest, bigger of the given . + /// + /// The value whose nearest, bigger multiple will be returned of. + /// The multiple to return. + /// The nearest, bigger multiple. + public static int NextMultiple(int value, int multiple) => (value + multiple - 1) / multiple * multiple; + } +} diff --git a/src/Syroot.Worms/Core/ByteExtensions.cs b/src/Syroot.Worms/Core/ByteExtensions.cs index b18ee47..1ef38c9 100644 --- a/src/Syroot.Worms/Core/ByteExtensions.cs +++ b/src/Syroot.Worms/Core/ByteExtensions.cs @@ -15,10 +15,7 @@ namespace Syroot.Worms.Core /// The extended instance. /// The 0-based index of the bit to enable. /// The current byte with the bit enabled. - public static byte EnableBit(this byte self, int index) - { - return (byte)(self | (1 << index)); - } + public static byte EnableBit(this byte self, int index) => (byte)(self | (1 << index)); /// /// Returns the current byte with the bit at the cleared (being 0). @@ -26,10 +23,7 @@ namespace Syroot.Worms.Core /// The extended instance. /// The 0-based index of the bit to disable. /// The current byte with the bit disabled. - public static byte DisableBit(this byte self, int index) - { - return (byte)(self & ~(1 << index)); - } + public static byte DisableBit(this byte self, int index) => (byte)(self & ~(1 << index)); /// /// Returns a value indicating whether the bit at the in the current byte is enabled @@ -38,10 +32,7 @@ namespace Syroot.Worms.Core /// The extended instance. /// The 0-based index of the bit to check. /// true when the bit is set; otherwise false. - public static bool GetBit(this byte self, int index) - { - return (self & (1 << index)) != 0; - } + public static bool GetBit(this byte self, int index) => (self & (1 << index)) != 0; /// /// Returns the current byte with all bits rotated in the given , where positive @@ -97,10 +88,7 @@ namespace Syroot.Worms.Core /// The number of least significant bits which are used to store the /// value. /// The decoded . - public static byte DecodeByte(this byte self, int bits) - { - return DecodeByte(self, bits, 0); - } + public static byte DecodeByte(this byte self, int bits) => DecodeByte(self, bits, 0); /// /// Returns an instance represented by the given number of , starting @@ -124,10 +112,7 @@ namespace Syroot.Worms.Core /// The number of least significant bits which are used to store the /// value. /// The decoded . - public static sbyte DecodeSByte(this byte self, int bits) - { - return DecodeSByte(self, bits, 0); - } + public static sbyte DecodeSByte(this byte self, int bits) => DecodeSByte(self, bits, 0); /// /// Returns an instance represented by the given number of , starting @@ -154,10 +139,7 @@ namespace Syroot.Worms.Core /// The value to encode. /// The number of bits which are used to store the value. /// The current byte with the value encoded into it. - public static byte Encode(this byte self, byte value, int bits) - { - return Encode(self, value, bits, 0); - } + public static byte Encode(this byte self, byte value, int bits) => Encode(self, value, bits, 0); /// /// Returns the current byte with the given set into the given number of @@ -187,10 +169,7 @@ namespace Syroot.Worms.Core /// The value to encode. /// The number of bits which are used to store the value. /// The current byte with the value encoded into it. - public static byte Encode(this byte self, sbyte value, int bits) - { - return Encode(self, value, bits, 0); - } + public static byte Encode(this byte self, sbyte value, int bits) => Encode(self, value, bits, 0); /// /// Returns the current byte with the given set into the given number of diff --git a/src/Syroot.Worms/Core/Graphics/RawBitmap.cs b/src/Syroot.Worms/Core/Graphics/RawBitmap.cs new file mode 100644 index 0000000..0747852 --- /dev/null +++ b/src/Syroot.Worms/Core/Graphics/RawBitmap.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; +using Syroot.Worms.Core; + +namespace Syroot.Worms +{ + /// + /// Represents a pixel-based 2D image in different color formats. + /// + public class RawBitmap + { + // ---- PROPERTIES --------------------------------------------------------------------------------------------- + + /// + /// Gets or sets the number of bits required to describe a color per pixel. + /// + public byte BitsPerPixel { get; set; } + + /// + /// Gets or sets the colors in the palette of the bitmap, if it has one. + /// + public IList Palette { get; set; } + + /// + /// Gets or sets the size of the image in pixels. + /// + public Size Size { get; set; } + + /// + /// Gets or sets the data of the image pixels. + /// + public byte[] Data { get; set; } + + // ---- METHODS (PUBLIC) --------------------------------------------------------------------------------------- + + /// + /// Creates a from the raw data. + /// + /// The created from the raw data. + public Bitmap ToBitmap() + { + using (DisposableGCHandle dataPin = new DisposableGCHandle(Data, GCHandleType.Pinned)) + { + // Transfer the pixel data, respecting power-of-2 strides. + Bitmap bitmap = new Bitmap(Size.Width, Size.Height, PixelFormat.Format8bppIndexed); + BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, Size.Width, Size.Height), + ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); + for (int y = 0; y < Size.Height; y++) + Marshal.Copy(Data, y * Size.Width, bitmapData.Scan0 + y * bitmapData.Stride, Size.Width); + bitmap.UnlockBits(bitmapData); + + // Transfer the palette. + ColorPalette bitmapPalette = bitmap.Palette; + for (int i = 0; i < Palette.Count; i++) + bitmapPalette.Entries[i] = Palette[i]; + bitmap.Palette = bitmapPalette; + + return bitmap; + } + } + } +} diff --git a/src/Syroot.Worms/Img.cs b/src/Syroot.Worms/Img.cs index a6fb4a6..ea2645d 100644 --- a/src/Syroot.Worms/Img.cs +++ b/src/Syroot.Worms/Img.cs @@ -12,7 +12,7 @@ namespace Syroot.Worms /// Represents a (palettized) graphical image stored in an IMG file, possibly compressed. /// Used by W2, WA and WWP. S. https://worms2d.info/Image_file. /// - public class Img : RawBitmapData, ILoadableFile, ISaveableFile + public class Img : RawBitmap, ILoadableFile, ISaveableFile { // ---- CONSTANTS ---------------------------------------------------------------------------------------------- @@ -203,8 +203,8 @@ namespace Syroot.Worms // Write the image palette if available. The first color of the palette is implicitly black. if (Palette != null) { - writer.Write((short)(Palette.Length - 1)); - for (int i = 1; i < Palette.Length; i++) + writer.Write((short)(Palette.Count - 1)); + for (int i = 1; i < Palette.Count; i++) { Color color = Palette[i]; writer.Write(color.R); diff --git a/src/Syroot.Worms/RawBitmapData.cs b/src/Syroot.Worms/RawBitmapData.cs deleted file mode 100644 index 4432352..0000000 --- a/src/Syroot.Worms/RawBitmapData.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Drawing; - -namespace Syroot.Worms -{ - /// - /// Represents a pixel-based 2D image in different color formats. - /// - public class RawBitmapData - { - // ---- PROPERTIES --------------------------------------------------------------------------------------------- - - /// - /// Gets or sets the number of bits required to describe a color per pixel. - /// - public byte BitsPerPixel { get; set; } - - /// - /// Gets or sets the colors in the palette of the bitmap, if it has one. - /// - public Color[] Palette { get; set; } - - /// - /// Gets or sets the size of the image in pixels. - /// - public Size Size { get; set; } - - /// - /// Gets or sets the data of the image pixels. - /// - public byte[] Data { get; set; } - } -}