/// .ase & .aseprite file format specs:
/// https://github.com/aseprite/aseprite/blob/main/docs/ase-file-specs.md
using System;
using System.Collections.ObjectModel;
using System.IO;
using UnityEngine.Assertions;
namespace UnityEditor.U2D.Aseprite
{
///
/// Parsed representation of an Aseprite file.
/// Should be disposed after use.
///
public class AsepriteFile : IDisposable
{
///
/// File size in bytes.
///
public uint fileSize { get; private set; }
///
/// Number of frames in the file.
///
public ushort noOfFrames { get; private set; }
///
/// Canvas width in pixels.
///
public ushort width { get; private set; }
///
/// Canvas height in pixels.
///
public ushort height { get; private set; }
///
/// Color depth (bits per pixel).
///
public ushort colorDepth { get; private set; }
internal uint flags { get; private set; }
///
/// Time per frame in milliseconds.
///
public ushort animSpeed { get; private set; }
///
/// Palette entry (index) which represent transparent color
/// in all non-background layers (only for Indexed sprites).
///
public byte alphaPaletteEntry { get; private set; }
///
/// Number of colors (0 means 256 for old sprites).
///
public ushort noOfColors { get; private set; }
///
/// Pixel width (pixel ratio is "pixel width/pixel height").
/// If this or pixel height field is zero, pixel ratio is 1:1.
///
public byte pixelWidth { get; private set; }
///
/// Pixel height (pixel ratio is "pixel width/pixel height").
/// If this or pixel width field is zero, pixel ratio is 1:1.
///
public byte pixelHeight { get; private set; }
///
/// X position of the grid.
///
public short gridPosX { get; private set; }
///
/// Y position of the grid.
///
public short gridPosY { get; private set; }
///
/// Grid width (zero if there is no grid, grid size is 16x16 on Aseprite by default).
///
public ushort gridWidth { get; private set; }
///
/// Grid height (zero if there is no grid).
///
public ushort gridHeight { get; private set; }
///
/// Parsed data of each frame.
///
public ReadOnlyCollection frameData => Array.AsReadOnly(m_FrameData);
FrameData[] m_FrameData;
internal void Read(BinaryReader reader)
{
fileSize = reader.ReadUInt32();
var misc0 = reader.ReadUInt16();
noOfFrames = reader.ReadUInt16();
width = reader.ReadUInt16();
height = reader.ReadUInt16();
colorDepth = reader.ReadUInt16();
flags = reader.ReadUInt32();
animSpeed = reader.ReadUInt16();
var misc1 = reader.ReadUInt32();
var misc2 = reader.ReadUInt32();
alphaPaletteEntry = reader.ReadByte();
var miscByte0 = reader.ReadByte();
var miscByte1 = reader.ReadByte();
var miscByte2 = reader.ReadByte();
noOfColors = reader.ReadUInt16();
pixelWidth = reader.ReadByte();
pixelHeight = reader.ReadByte();
gridPosX = reader.ReadInt16();
gridPosY = reader.ReadInt16();
gridWidth = reader.ReadUInt16();
gridHeight = reader.ReadUInt16();
Assert.IsTrue(misc0 == 0xA5E0, "Unexpected file content. The file is most likely corrupt.");
// Unused 84 bytes
for (var i = 0; i < 84; ++i)
reader.ReadByte();
m_FrameData = new FrameData[noOfFrames];
}
internal void SetFrameData(int index, FrameData data)
{
if (index < 0 || index >= m_FrameData.Length)
return;
m_FrameData[index] = data;
}
public void Dispose()
{
for (var i = 0; i < m_FrameData.Length; ++i)
m_FrameData[i].Dispose();
}
}
}