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
use std::io::Read;
use crate::{reader::AseReader, user_data::UserData, Result};
/// A slice is a region of the sprite with some attributes.
///
/// They are created using the slice tool and can be animated over frames. See
/// the [official docs on slices](https://www.aseprite.org/docs/slices/) for
/// details.
#[derive(Debug, Clone)]
pub struct Slice {
/// The name of the slice. Not guaranteed to be unique.
pub name: String,
/// A sequence of [SliceKey]s. Together, these describe the shape and
/// position of a slice during animation.
pub keys: Vec<SliceKey>,
/// User data associated with this slice.
pub user_data: Option<UserData>,
}
/// A devision of a [Slice] into nine regions for 9-slice scaling.
#[derive(Debug, Clone)]
pub struct Slice9 {
/// X position of the center area (relative to slice bounds).
pub center_x: i32,
/// Y position of the center area (relative to slice bounds).
pub center_y: i32,
/// Width of the center area.
pub center_width: u32,
/// Height of the center area.
pub center_height: u32,
}
impl Slice9 {
fn read<R: Read>(reader: &mut AseReader<R>) -> Result<Self> {
let center_x = reader.long()?;
let center_y = reader.long()?;
let center_width = reader.dword()?;
let center_height = reader.dword()?;
Ok(Self {
center_x,
center_y,
center_width,
center_height,
})
}
}
/// The position and shape of a [Slice], starting at a given frame.
#[derive(Debug, Clone)]
pub struct SliceKey {
/// Starting frame number for this slice key. This slice is valid from this
/// frame to the end of the animation or the next slice key.
pub from_frame: u32,
/// Origin of the slice.
pub origin: (i32, i32),
/// Size of the slice.
pub size: (u32, u32),
/// 9-slicing information.
pub slice9: Option<Slice9>,
/// Pivot information. Relative to the origin.
pub pivot: Option<(i32, i32)>,
}
impl SliceKey {
fn read<R: Read>(reader: &mut AseReader<R>, flags: u32) -> Result<Self> {
let from_frame = reader.dword()?;
let origin_x = reader.long()?;
let origin_y = reader.long()?;
let origin = (origin_x, origin_y);
let slice_width = reader.dword()?;
let slice_height = reader.dword()?;
let size = (slice_width, slice_height);
let slice9 = if flags & 1 != 0 {
Some(Slice9::read(reader)?)
} else {
None
};
let pivot = if flags & 2 != 0 {
let x = reader.long()?;
let y = reader.long()?;
Some((x, y))
} else {
None
};
Ok(Self {
from_frame,
origin,
size,
slice9,
pivot,
})
}
}
pub(crate) fn parse_chunk(data: &[u8]) -> Result<Slice> {
let mut reader = AseReader::new(data);
let num_slice_keys = reader.dword()?;
let flags = reader.dword()?;
let _reserved = reader.dword()?;
let name = reader.string()?;
let slice_keys: Result<Vec<SliceKey>> = (0..num_slice_keys)
.map(|_id| SliceKey::read(&mut reader, flags))
.collect();
Ok(Slice {
name,
keys: slice_keys?,
user_data: None,
})
}