using System; using System.IO; using System.Text; using Syroot.IO; using Syroot.Maths; using Syroot.Worms.Core; namespace Syroot.Worms.Gen2 { /// /// 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 Image : ILoadableFile { // ---- CONSTANTS ---------------------------------------------------------------------------------------------- private const int _signature = 0x1A474D49; // "IMG", 0x1A // ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------ /// /// Initializes a new instance of the class. /// public Image() { } /// /// Initializes a new instance of the class, loading the data from the given /// . /// /// The to load the data from. public Image(Stream stream) { Load(stream); } /// /// Initializes a new instance of the class, loading the data from the given file. /// /// The name of the file to load the data from. public Image(string fileName) { Load(fileName); } // ---- PROPERTIES --------------------------------------------------------------------------------------------- /// /// Gets an optional description of the image contents. /// public string Description { get; private set; } /// /// Gets the number of bits required to describe a color per pixel. /// public int BitsPerPixel { get; private set; } /// /// Gets the color palette of the image. The first color must always be black. /// public Color[] Palette { get; private set; } /// /// Gets the size of the image in pixels. /// public Vector2 Size { get; private set; } /// /// Gets the data of the image pixels. /// public byte[] Data { get; private set; } // ---- METHODS (PUBLIC) --------------------------------------------------------------------------------------- /// /// Loads the data from the given . /// /// The to load the data from. public void Load(Stream stream) { using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true)) { // Read the header. if (reader.ReadInt32() != _signature) { throw new InvalidDataException("Invalid IMG file signature."); } int fileSize = reader.ReadInt32(); // Read an optional string describing the image contents or the bits per pixel. BitsPerPixel = reader.ReadByte(); if (BitsPerPixel == 0) { Description = String.Empty; BitsPerPixel = reader.ReadByte(); } else if (BitsPerPixel > 32) { Description = (char)BitsPerPixel + reader.ReadString(BinaryStringFormat.ZeroTerminated); BitsPerPixel = reader.ReadByte(); } // Read image flags describing the format and availability of the following contents. Flags flags = (Flags)reader.ReadByte(); // Read the image palette if available. The first color of the palette is implicitly black. if (flags.HasFlag(Flags.Palettized)) { int colorCount = reader.ReadInt16(); Palette = new Color[colorCount + 1]; Palette[0] = Color.Black; for (int i = 1; i <= colorCount; i++) { Palette[i] = new Color(reader.ReadByte(), reader.ReadByte(), reader.ReadByte()); } } Size = new Vector2(reader.ReadInt16(), reader.ReadInt16()); // Read the bytes, which might be compressed. byte[] data = new byte[Size.X * Size.Y * BitsPerPixel / 8]; if (flags.HasFlag(Flags.Compressed)) { Team17Compression.Decompress(reader.BaseStream, ref data); } else { data = reader.ReadBytes(data.Length); } Data = data; } } /// /// Loads the data from the given file. /// /// The name of the file to load the data from. public void Load(string fileName) { using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { Load(stream); } } // ---- ENUMERATIONS ------------------------------------------------------------------------------------------- [Flags] private enum Flags { Compressed = 1 << 6, Palettized = 1 << 7 } } }