157 lines
5.6 KiB
C#
Raw Normal View History

2017-04-17 22:01:27 +02:00
using System;
2017-04-18 14:32:43 +02:00
using System.IO;
2017-04-17 22:01:27 +02:00
using System.Text;
2017-04-18 14:32:43 +02:00
using Syroot.IO;
using Syroot.Maths;
using Syroot.Worms.Core;
2017-04-17 22:01:27 +02:00
namespace Syroot.Worms.Gen2
{
2017-04-18 14:32:43 +02:00
/// <summary>
/// Represents a (palettized) graphical image stored in an IMG file, possibly compressed.
/// Used by W2, WA and WWP. S. https://worms2d.info/Image_file.
/// </summary>
2017-04-18 18:14:03 +02:00
public class Image : ILoadableFile
2017-04-17 22:01:27 +02:00
{
2017-04-18 14:32:43 +02:00
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private const int _signature = 0x1A474D49; // "IMG", 0x1A
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class, loading the data from the given
/// <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public Image(Stream stream)
{
Load(stream);
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class, loading the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public Image(string fileName)
{
Load(fileName);
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets an optional description of the image contents.
/// </summary>
public string Description { get; private set; }
/// <summary>
/// Gets the number of bits required to describe a color per pixel.
/// </summary>
public int BitsPerPixel { get; private set; }
/// <summary>
/// Gets the color palette of the image. The first color must always be black.
/// </summary>
public Color[] Palette { get; private set; }
/// <summary>
/// Gets the width of the image in pixels.
/// </summary>
public int Width { get; private set; }
/// <summary>
/// Gets the height of the image in pixels.
/// </summary>
public int Height { get; private set; }
/// <summary>
/// Gets the data of the image pixels.
/// </summary>
public byte[] Data { get; private set; }
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads the data from the given <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII))
{
// Read the header.
if (reader.ReadInt32() != _signature)
2017-04-18 14:32:43 +02:00
{
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());
}
}
Width = reader.ReadInt16();
Height = reader.ReadInt16();
// Read the image data, which might be compressed.
byte[] data = new byte[Width * Height * (BitsPerPixel / 8)];
if (flags.HasFlag(Flags.Compressed))
{
2017-04-18 16:08:29 +02:00
Team17Compression.Decompress(reader.BaseStream, ref data);
2017-04-18 14:32:43 +02:00
}
else
{
data = reader.ReadBytes(data.Length);
}
Data = data;
}
}
/// <summary>
/// Loads the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
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
}
2017-04-17 22:01:27 +02:00
}
}