Changes: * Added SeparatorInView() to add separators inside a ListBox or ComboBox. * Added BlendModeItem() to represent each item in the blending modes ComboBox. * Now a ComboBox can contain any kind of widgets as children (not just ListItem). This is required to add separators in the blending modes ComboBox. Feature request: https://community.aseprite.org/t/additive-blending-feature/121
12 KiB
Aseprite File Format (.ase/.aseprite) Specifications
Copyright (C) 2001-2017 by David Capello
-
References
ASE files use Intel (little-endian) byte order.
Data Type | Details |
---|---|
BYTE | An 8-bit unsigned integer value |
WORD | A 16-bit unsigned integer value |
SIGNED WORD | A 16-bit signed integer value |
DWORD | A 32-bit unsigned integer value |
FIXED | A 32-bit fixed point (16.16) value |
BYTE[n] | "n" bytes. |
STRING | WORD: string length (number of bytes) |
BYTE[length]: characters (in UTF-8) | |
The \0 character is not included. | |
PIXEL | One pixel, depending on the image pixel format: |
RGB: Each pixel have 4 bytes in this order Red, Green, Blue, Alpha. | |
Grayscale: Each pixel have 2 bytes in the order Value, Alpha. | |
Indexed: Each pixel uses 1 byte (the index). |
- Introduction
The format is much like FLI/FLC files, but with different magic number and differents chunks. Also, the color depth can be 8, 16 or 32 for Indexed, Grayscale and RGB respectively, and images are compressed images with zlib. Color palettes are in FLI color chunks (it could be type=11 or type=4). For color depths more than 8bpp, palettes are optional.
To read the sprite:
- Read the ASE header
- For each frame do (how many frames? the ASE header has that information):
- Read the frame header
- For each chunk in this frame (how many chunks? the frame header has that information)
- Read the chunk (it should be layer information, a cel or a palette)
- Header
A 128-byte header (same as FLC/FLI header, but with other magic number):
Field | Details |
---|---|
DWORD | File size |
WORD | Magic number (0xA5E0) |
WORD | Frames |
WORD | Width in pixels |
WORD | Height in pixels |
WORD | Color depth (bits per pixel) |
32 bpp = RGBA | |
16 bpp = Grayscale | |
8 bpp = Indexed | |
DWORD | Flags: |
1 = Layer opacity has valid value | |
WORD | Speed (milliseconds between frame, like in FLC files) DEPRECATED: You should use the frame duration field from each frame header |
DWORD | Set be 0 |
DWORD | Set be 0 |
BYTE | Palette entry (index) which represent transparent color in all non-background layers (only for Indexed sprites). |
BYTE[3] | Ignore these bytes |
WORD | Number of colors (0 means 256 for old sprites) |
BYTE | Pixel width (pixel ratio is "pixel width/pixel height"). If this or pixel height field is zero, pixel ratio is 1:1 |
BYTE | Pixel height |
BYTE[92] | For future (set to zero) |
- Frames
After the header come the "frames" data. Each frame has this little header of 16 bytes:
Field | Details |
---|---|
DWORD | Bytes in this frame |
WORD | Magic number (always 0xF1FA) |
WORD | Number of "chunks" in this frame |
WORD | Frame duration (in milliseconds) |
BYTE[6] | For future (set to zero) |
Then each chunk format is:
Field | Details |
---|---|
DWORD | Chunk size |
WORD | Chunk type |
BYTE[] | Chunk data |
- Chunk Types
Old palette chunk (0x0004)
Ignore this chunk if you find the new palette chunk (0x2019) Aseprite v1.1 saves both chunks 0x0004 and 0x2019 just for backward compatibility.
WORD Number of packets
+ For each packet
BYTE Number of palette entries to skip from the last packet (start from 0)
BYTE Number of colors in the packet (0 means 256)
+ For each color in the packet
BYTE Red (0-255)
BYTE Green (0-255)
BYTE Blue (0-255)
Old palette chunk (0x0011)
Ignore this chunk if you find the new palette chunk (0x2019)
WORD Number of packets
+ For each packet
BYTE Number of palette entries to skip from the last packet (start from 0)
BYTE Number of colors in the packet (0 means 256)
+ For each color in the packet
BYTE Red (0-63)
BYTE Green (0-63)
BYTE Blue (0-63)
Layer Chunk (0x2004)
In the first frame should be a set of layer chunks to determine the entire layers layout:
WORD Flags:
1 = Visible
2 = Editable
4 = Lock movement
8 = Background
16 = Prefer linked cels
32 = The layer group should be displayed collapsed
64 = The layer is a reference layer
WORD Layer type
0 = Normal (image) layer
1 = Group
WORD Layer child level (see NOTE.1)
WORD Default layer width in pixels (ignored)
WORD Default layer height in pixels (ignored)
WORD Blend mode (always 0 for layer set)
Normal = 0
Multiply = 1
Screen = 2
Overlay = 3
Darken = 4
Lighten = 5
Color Dodge = 6
Color Burn = 7
Hard Light = 8
Soft Light = 9
Difference = 10
Exclusion = 11
Hue = 12
Saturation = 13
Color = 14
Luminosity = 15
Addition = 16
Subtract = 17
Divide = 18
BYTE Opacity
Note: valid only if file header flags field has bit 1 set
BYTE[3] For future (set to zero)
STRING Layer name
Cel Chunk (0x2005)
This chunk determine where to put a cel in the specified layer/frame.
WORD Layer index (see NOTE.2)
SIGNED WORD X position
SIGNED WORD Y position
BYTE Opacity level
WORD Cel type
BYTE[7] For future (set to zero)
+ For cel type = 0 (Raw Cel):
WORD Width in pixels
WORD Height in pixels
PIXEL[] Raw pixel data: row by row from top to bottom,
for each scanline read pixels from left to right.
+ For cel type = 1 (Linked Cel):
WORD Frame position to link with
+ For cel type = 2 (Compressed Image):
WORD Width in pixels
WORD Height in pixels
BYTE[] ZLIB compressed "Raw Cel" data. Details about the
ZLIB and DEFLATE compression methods:
https://www.ietf.org/rfc/rfc1950
https://www.ietf.org/rfc/rfc1951
Some extra notes that might help you to decode the data:
http://george.chiramattel.com/blog/2007/09/deflatestream-block-length-does-not-match.html
Cel Extra Chunk (0x2006)
Adds extra information to the latest read cel.
DWORD Flags (set to zero)
1 - precise bounds are set
FIXED Precise X position
FIXED Precise Y position
FIXED Width of the cel in the sprite (scaled in real-time)
FIXED Height of the cel in the sprite
BYTE[16] For future use (set to zero)
Mask Chunk (0x2016) DEPRECATED
SIGNED WORD X position
SIGNED WORD Y position
WORD Width
WORD Height
BYTE[8] For future (set to zero)
STRING Mask name
BYTE[] Bit map data (size = height*((width+7)/8))
Each byte contains 8 pixels (the leftmost pixels are
packed into the high order bits)
Path Chunk (0x2017)
Never used.
Frame Tags Chunk (0x2018)
WORD Number of tags
BYTE[8] For future (set to zero)
+ For each tag
WORD From frame
WORD To frame
BYTE Loop animation direction
0 - Forward
1 - Reverse
2 - Ping-pong
BYTE[8] For future (set to zero)
BYTE[3] RGB values of the tag color
BYTE Extra byte (zero)
STRING Tag name
Palette Chunk (0x2019)
DWORD New palette size (total number of entries)
DWORD First color index to change
DWORD Last color index to change
BYTE[8] For future (set to zero)
+ For each palette entry in [from,to] range (to-from+1 entries)
WORD Entry flags:
1 = Has name
BYTE Red (0-255)
BYTE Green (0-255)
BYTE Blue (0-255)
BYTE Alpha (0-255)
+ If has name bit in entry flags
STRING Color name
User Data Chunk (0x2020)
Insert this user data in the last read chunk. E.g. If we've read a layer, this user data belongs to that layer, if we've read a cel, it belongs to that cel, etc.
Field | Details |
---|---|
DWORD | Flags |
1 - Has text | |
2 - Has color | |
If flags have bit 1 | |
STRING | Text |
If flags have bit 2 | |
BYTE | Color Red (0-255) |
BYTE | Color Green (0-255) |
BYTE | Color Blue (0-255) |
BYTE | Color Alpha (0-255) |
Slice Chunk (0x2022)
Field | Details |
---|---|
DWORD | Number of "slice keys" |
DWORD | Flags |
1 - It's a 9-patches slice | |
2 - Has pivot information | |
DWORD | Reserved |
STRING | Name |
For each slice key ... | |
DWORD | Frame number (this slice is valid from |
this frame to the end of the animation) | |
SIGNED WORD | Slice X origin coordinate in the sprite |
SIGNED WORD | Slice Y origin coordinate in the sprite |
WORD | Slice width (can be 0 if this slice hidden in the |
animation from the given frame) | |
WORD | Slice height |
If flags have bit 1 | |
SIGNED WORD | Center X position (relative to slice bounds) |
SIGNED WORD | Center Y position |
WORD | Center width |
WORD | Center height |
If flags have bit 2 | |
WORD | Pivot X position (relative to the slice origin) |
WORD | Pivot Y position (relative to the slice origin) |
Notes
NOTE.1
The child level is used to show the relationship of this layer with the last one read, for example:
Layer name and hierarchy Child Level
-----------------------------------------------
- Background 0
`- Layer1 1
- Foreground 0
|- My set1 1
| `- Layer2 2
`- Layer3 1
NOTE.2
The layer index is a number to identify any layer in the sprite, for example:
Layer name and hierarchy Layer index
-----------------------------------------------
- Background 0
`- Layer1 1
- Foreground 2
|- My set1 3
| `- Layer2 4
`- Layer3 5
- File Format Changes
-
The first change from the first release of the new .ase format, is the new frame duration field. This is because now each frame can have different duration.
How to read both formats (old and new one)? You should set all frames durations to the "speed" field read from the main ASE header. Then, if you found a frame with the frame-duration field > 0, you should update the duration of the frame with that value.