1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#![warn(clippy::all)]
#![warn(missing_docs)]
/*!

Utilities for loading [Aseprite](https://www.aseprite.org/) files. This
library directly reads the binary Aseprite files ([file format
specification][spec]) and does not require you to export files to JSON. This
should make it fast enough to load your assets when the game boots up. You can
also use it to build your own asset pipelines.

Note that this library can be rather slow when compiled without optimizations.
We recommend that you override the optimization settings for this dependency
in dev mode by adding the following to your `Cargo.toml`:

```text
[profile.dev.package.asefile]
opt-level = 2  # or 3
```

This is not necessary if you already have a wildcard override. See
[Cargo profile overrides][overrides] for more info.

[spec]: https://github.com/aseprite/aseprite/blob/master/docs/ase-file-specs.md
[overrides]: https://doc.rust-lang.org/cargo/reference/profiles.html#overrides

# Basic Usage

## Load file

The easiest way is to use [AsepriteFile::read_file] to load a file.

```
use asefile::AsepriteFile;
# use std::path::Path;
# let path = Path::new("./tests/data/basic-16x16.aseprite");
let ase = AsepriteFile::read_file(&path).unwrap();

println!("Size: {}x{}", ase.width(), ase.height());
println!("Frames: {}", ase.num_frames());
println!("Layers: {}", ase.num_layers());
```

## Save frame as image

Aseprite files consist of multiple layers. Usually you just want the final
image. You can do this by using [Frame::image]. This will return an
`image::RgbaImage` from the [image](https://docs.rs/image) library.

```
# use asefile::AsepriteFile;
# use std::path::Path;
# let asefile_path = Path::new("./tests/data/basic-16x16.aseprite");
# let output_dir = Path::new("./tests/data");
# let ase = AsepriteFile::read_file(&asefile_path).unwrap();
let image = ase.frame(0).image();
let output_path = output_dir.join("example.png");
image.save(&output_path).unwrap();
```

This blends together all visible layers the same way Aseprite would.

## Layers

You can access a [Layer] by name or by ID.

```
# use asefile::AsepriteFile;
# use std::path::Path;
# let path = Path::new("./tests/data/basic-16x16.aseprite");
# let ase = AsepriteFile::read_file(&path).unwrap();
let layer = ase.layer(0);
println!("Name of layer 0: {}", layer.name());
let layer = ase.layer_by_name("Layer 1").unwrap();
println!("Layer 1 is visible? {}", layer.is_visible());
```

## Cels

A cel is the intersection of a frame and a layer. Because of this there are
multiple ways to access a cel:

```
# use asefile::AsepriteFile;
# use std::path::Path;
# let path = Path::new("./tests/data/layers_and_tags.aseprite");
# let ase = AsepriteFile::read_file(&path).unwrap();

let layer0 = ase.layer(0);
// These are all the same cel
let cel1 = layer0.frame(1);
let cel2 = ase.frame(1).layer(0);
let cel3 = ase.cel(1, 0); // or directly, which can avoid some borrowing issues

let image = cel1.image();
```

## Tilesets

Since Aseprite 1.3 you can also create tilesets and tilemaps layers.

You access each tile separately, or export them all as one image which is one
tile wide.

```
# use asefile::AsepriteFile;
# use std::path::Path;
# use image::RgbaImage;
# let path = Path::new("./tests/data/tileset.aseprite");
# let ase = AsepriteFile::read_file(&path).unwrap();

let num_tilesets = ase.tilesets().len();
let tileset = ase.tilesets().get(0).unwrap();

let all_tiles: RgbaImage = tileset.image();
let single_tile: RgbaImage = tileset.tile_image(1);
// Note: tile 0 is the empty tile
assert_eq!(
    all_tiles.dimensions().0,
    tileset.tile_size().width() as u32
);
assert_eq!(
    all_tiles.dimensions().1,
    tileset.tile_size().height() as u32 * tileset.tile_count()
)
```

## Tilemaps

Aseprite also supports tilemaps which are layers that are composed entirely out
of tiles from a tileset.

You can export those layers as a single large image or you can do some custom
processing by looking at the tile indexes in the layer.

```
# use asefile::AsepriteFile;
# use std::path::Path;
# use image::RgbaImage;
# let path = Path::new("./tests/data/tilemap_multi.aseprite");
# let ase = AsepriteFile::read_file(&path).unwrap();

let layer = ase.layer_by_name("Tilemap 1").unwrap().id();
let tilemap = ase.tilemap(layer, 0).unwrap();

// This is the same as getting the image for the cel.
let tilemap_image = tilemap.image();

let num_tiles_x = tilemap.width();
let num_tiles_y = tilemap.height();
let (tile_width, tile_height) = tilemap.tile_size();
// Get a specific tile. Always succeeds. If the tile is out of bounds returns
// the empty tile (id 0).
let tile = tilemap.tile(0, 1);
println!("tile at (0, 1) references tile from tileset: {}", tile.id());
// You can access the tileset right through the tilemap.
let image = tilemap.tileset().tile_image(tile.id());
```

## User data

Aseprite gives you the option to annotate certain entities with custom data.
Usually, that's a color and a text field. Each of those entities has a
`user_data()` method.

*/

pub(crate) mod blend;
pub(crate) mod cel;
pub(crate) mod color_profile;
pub(crate) mod error;
pub(crate) mod external_file;
pub(crate) mod file;
pub(crate) mod layer;
pub(crate) mod palette;
pub(crate) mod parse;
mod pixel;
mod reader;
pub(crate) mod slice;
pub(crate) mod tags;
#[cfg(test)]
mod tests;
mod tile;
mod tilemap;
mod tileset;
pub(crate) mod user_data;
#[cfg(feature = "utils")]
pub mod util;

/// A specialized `Result` type for Aseprite parsing functions.
pub type Result<T> = std::result::Result<T, AsepriteParseError>;

pub use cel::Cel;
// pub use color_profile::ColorProfile;
pub use error::AsepriteParseError;
pub use external_file::{ExternalFile, ExternalFileId, ExternalFilesById};
pub use file::{AsepriteFile, Frame, LayersIter, PixelFormat};
pub use layer::{BlendMode, Layer, LayerFlags, LayerType};
pub use palette::{ColorPalette, ColorPaletteEntry};
pub use slice::{Slice, Slice9, SliceKey};
pub use tags::{AnimationDirection, Tag};
pub use tile::Tile;
pub use tilemap::Tilemap;
pub use tileset::{ExternalTilesetReference, TileSize, Tileset, TilesetImageError, TilesetsById};
pub use user_data::UserData;