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 ----------------------------------------------------------------------------------------------
|
|
|
|
|
2017-04-22 14:05:06 +02:00
|
|
|
private const int _signature = 0x1A474D49; // "IMG", 0x1A
|
2017-04-18 14:32:43 +02:00
|
|
|
|
|
|
|
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
|
|
|
|
2017-04-22 14:05:06 +02:00
|
|
|
/// <summary>
|
|
|
|
/// Initializes a new instance of the <see cref="Image"/> class.
|
|
|
|
/// </summary>
|
|
|
|
public Image()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-04-18 14:32:43 +02:00
|
|
|
/// <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>
|
2017-04-22 14:05:06 +02:00
|
|
|
/// Gets the size of the image in pixels.
|
2017-04-18 14:32:43 +02:00
|
|
|
/// </summary>
|
2017-04-22 14:05:06 +02:00
|
|
|
public Vector2 Size { get; private set; }
|
|
|
|
|
2017-04-18 14:32:43 +02:00
|
|
|
/// <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)
|
|
|
|
{
|
2017-04-23 01:28:36 +02:00
|
|
|
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
|
2017-04-18 14:32:43 +02:00
|
|
|
{
|
|
|
|
// Read the header.
|
2017-04-21 17:59:04 +02:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-23 01:28:36 +02:00
|
|
|
Size = new Vector2(reader.ReadInt16(), reader.ReadInt16());
|
|
|
|
|
|
|
|
// Read the bytes, which might be compressed.
|
|
|
|
byte[] data = new byte[Size.X * Size.Y * BitsPerPixel / 8];
|
2017-04-18 14:32:43 +02:00
|
|
|
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);
|
|
|
|
}
|
2017-04-23 01:28:36 +02:00
|
|
|
|
2017-04-18 14:32:43 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|