1#[macro_use]
22extern crate serde_derive;
23
24#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
25pub struct Rect {
26 pub x: u32,
27 pub y: u32,
28 pub w: u32,
29 pub h: u32,
30}
31
32
33#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
34pub struct Dimensions {
35 pub w: u32,
36 pub h: u32,
37}
38
39
40#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
41pub struct Frame {
42 pub filename: String,
43 pub frame: Rect,
44 pub rotated: bool,
45 pub trimmed: bool,
46 #[serde(rename = "spriteSourceSize")]
47 pub sprite_source_size: Rect,
48 #[serde(rename = "sourceSize")]
49 pub source_size: Dimensions,
50 pub duration: u32,
51}
52
53#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
54pub enum Direction {
55 #[serde(rename="forward")]
56 Forward,
57 #[serde(rename="reverse")]
58 Reverse,
59 #[serde(rename="pingpong")]
60 Pingpong,
61}
62
63#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
64pub struct Frametag {
65 pub name: String,
66 pub from: u32,
67 pub to: u32,
68 pub direction: Direction,
69}
70
71#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
75pub enum BlendMode {
76 #[serde(rename="normal")]
77 Normal,
78 #[serde(rename="multiply")]
79 Multiply,
80 #[serde(rename="screen")]
81 Screen,
82 #[serde(rename="overlay")]
83 Overlay,
84 #[serde(rename="darken")]
85 Darken,
86 #[serde(rename="lighten")]
87 Lighten,
88 #[serde(rename="color_dodge")]
89 ColorDodge,
90 #[serde(rename="color_burn")]
91 ColorBurn,
92 #[serde(rename="hard_light")]
93 HardLight,
94 #[serde(rename="soft_light")]
95 SoftLight,
96 #[serde(rename="difference")]
97 Difference,
98 #[serde(rename="exclusion")]
99 Exclusion,
100 #[serde(rename="hsl_hue")]
101 HslHue,
102 #[serde(rename="hsl_saturation")]
103 HslSaturation,
104 #[serde(rename="hsl_color")]
105 HslColor,
106 #[serde(rename="hsl_luminosity")]
107 HslLuminosity,
108}
109
110#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
111pub struct Layer {
112 pub name: String,
113 pub opacity: u32,
114 #[serde(rename = "blendMode")]
115 pub blend_mode: BlendMode,
116}
117
118
119#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
120pub struct Metadata {
121 pub app: String,
122 pub version: String,
123 pub format: String,
124 pub size: Dimensions,
125 pub scale: String, #[serde(rename = "frameTags")]
127 pub frame_tags: Option<Vec<Frametag>>,
128 pub layers: Option<Vec<Layer>>,
129 pub image: Option<String>,
130}
131
132
133#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
134pub struct SpritesheetData {
135 pub frames: Vec<Frame>,
136 pub meta: Metadata,
137}
138
139
140#[cfg(test)]
141mod tests {
142 extern crate serde_json;
143
144 const S: &'static str = r##"{ "frames": [
145 {
146 "filename": "boonga 0.ase",
147 "frame": { "x": 1, "y": 1, "w": 18, "h": 18 },
148 "rotated": false,
149 "trimmed": false,
150 "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 16 },
151 "sourceSize": { "w": 16, "h": 16 },
152 "duration": 250
153 },
154 {
155 "filename": "boonga 1.ase",
156 "frame": { "x": 20, "y": 1, "w": 18, "h": 18 },
157 "rotated": false,
158 "trimmed": false,
159 "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 16 },
160 "sourceSize": { "w": 16, "h": 16 },
161 "duration": 250
162 }
163 ],
164 "meta": {
165 "app": "http://www.aseprite.org/",
166 "version": "1.1.6-dev",
167 "image": "boonga.png",
168 "format": "RGBA8888",
169 "size": { "w": 39, "h": 20 },
170 "scale": "1",
171 "frameTags": [
172 { "name": "testtag", "from": 0, "to": 1, "direction": "forward" }
173 ],
174 "layers": [
175 { "name": "Layer 1", "opacity": 255, "blendMode": "normal" }
176 ]
177 }
178}
179"##;
180
181
182 const S_NO_META: &'static str = r##"{ "frames": [
183 {
184 "filename": "boonga 0.ase",
185 "frame": { "x": 1, "y": 1, "w": 18, "h": 18 },
186 "rotated": false,
187 "trimmed": false,
188 "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 16 },
189 "sourceSize": { "w": 16, "h": 16 },
190 "duration": 250
191 },
192 {
193 "filename": "boonga 1.ase",
194 "frame": { "x": 20, "y": 1, "w": 18, "h": 18 },
195 "rotated": false,
196 "trimmed": false,
197 "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 16 },
198 "sourceSize": { "w": 16, "h": 16 },
199 "duration": 250
200 }
201 ],
202 "meta": {
203 "app": "http://www.aseprite.org/",
204 "version": "1.1.6-dev",
205 "image": "boonga.png",
206 "format": "RGBA8888",
207 "size": { "w": 39, "h": 20 },
208 "scale": "1"
209 }
210}
211"##;
212
213
214 #[test]
215 fn test_sprite_load_save() {
216 let deserialized: super::SpritesheetData = serde_json::from_str(S).unwrap();
217
218 let serialized = serde_json::to_string(&deserialized).unwrap();
219 let deserialized_again: super::SpritesheetData = serde_json::from_str(&serialized).unwrap();
220
221 assert_eq!(deserialized, deserialized_again);
222 }
223
224
225 #[test]
226 fn test_less_metadata() {
227 let deserialized: super::SpritesheetData = serde_json::from_str(S_NO_META).unwrap();
228
229 let serialized = serde_json::to_string(&deserialized).unwrap();
230 let deserialized_again: super::SpritesheetData = serde_json::from_str(&serialized).unwrap();
231
232 assert_eq!(deserialized, deserialized_again);
233 }
234
235}