aseprite_loader/binary/
file.rs

1use itertools::Itertools;
2
3use super::{
4    chunk::Chunk,
5    chunks::{cel::CelChunk, layer::LayerChunk, slice::SliceChunk, tags::Tag},
6    color_depth::ColorDepth,
7    errors::ParseError,
8    frame::Frame,
9    header::Header,
10    palette::{create_palette, Palette},
11    raw_file::parse_raw_file,
12    scalars::Word,
13};
14
15#[derive(Debug)]
16pub struct File<'a> {
17    pub header: Header,
18    pub palette: Option<Palette>,
19    pub layers: Vec<LayerChunk<'a>>,
20    pub frames: Vec<Frame<'a>>,
21    pub tags: Vec<Tag<'a>>,
22    pub slices: Vec<SliceChunk<'a>>,
23}
24
25pub fn parse_file(input: &[u8]) -> Result<File<'_>, nom::Err<ParseError<'_>>> {
26    let raw_file = parse_raw_file(input)?;
27    let palette = match raw_file.header.color_depth {
28        ColorDepth::Indexed => Some(
29            create_palette(&raw_file.header, &raw_file.frames)
30                .map_err(|e| nom::Err::Failure(ParseError::PaletteError(e)))?,
31        ),
32        _ => None,
33    };
34    let mut frames = Vec::<(Word, Vec<CelChunk<'_>>)>::new();
35    let mut layers = Vec::<LayerChunk<'_>>::new();
36    let mut tags = Vec::<Tag<'_>>::new();
37    let mut slices = Vec::<SliceChunk<'_>>::new();
38    for raw_frame in raw_file.frames {
39        let mut cels = Vec::<CelChunk<'_>>::new();
40        for chunk in raw_frame.chunks {
41            match chunk {
42                Chunk::Palette0004(_) => {}
43                Chunk::Palette0011(_) => {}
44                Chunk::Layer(layer) => layers.push(layer),
45                Chunk::Cel(cel) => cels.push(cel),
46                Chunk::CelExtra(_) => {}
47                Chunk::ColorProfile(_) => {}
48                Chunk::ExternalFiles(_) => {}
49                Chunk::Mask(_) => {}
50                Chunk::Path => {}
51                Chunk::Tags(tags_chunk) => tags.extend(tags_chunk.tags),
52                Chunk::Palette(_) => {}
53                Chunk::UserData(_) => {}
54                Chunk::Slice(slice) => slices.push(slice),
55                Chunk::Tileset(_) => {}
56                Chunk::Unsupported(_) => {}
57            }
58        }
59        frames.push((raw_frame.duration, cels));
60    }
61    let frames = frames
62        .into_iter()
63        .map(|(duration, frame_cels)| {
64            Ok(Frame {
65                duration,
66                cels: {
67                    // Insert cels in the cels vector so that a direct lookup
68                    // by layer index is possible.
69                    let mut cels: Vec<Option<CelChunk<'_>>> = Vec::with_capacity(layers.len());
70                    for _ in 0..layers.len() {
71                        cels.push(None);
72                    }
73                    for cel in frame_cels {
74                        let layer_index: usize = cel.layer_index.into();
75                        if layer_index > layers.len() {
76                            return Err(nom::Err::Failure(ParseError::LayerIndexOutOfBounds));
77                        }
78                        cels[layer_index] = Some(cel);
79                    }
80                    cels
81                },
82            })
83        })
84        .try_collect()?;
85    Ok(File {
86        header: raw_file.header,
87        palette,
88        layers,
89        frames,
90        tags,
91        slices,
92    })
93}
94
95#[test]
96fn test_parse_file() {
97    let input = std::fs::read("./tests/default.aseprite").unwrap();
98    let file = parse_file(&input).unwrap();
99    assert_eq!(file.frames.len(), 1);
100    assert_eq!(file.frames[0].duration, 100);
101}
102
103#[test]
104fn test_palette() {
105    use crate::binary::scalars::Color;
106    let input = std::fs::read("./tests/indexed.aseprite").unwrap();
107    let file = parse_file(&input).unwrap();
108    assert_eq!(file.header.color_depth, ColorDepth::Indexed);
109    let palette = file.palette.unwrap();
110    assert_eq!(
111        palette.colors[27],
112        Color {
113            red: 172,
114            green: 50,
115            blue: 50,
116            alpha: 255
117        }
118    );
119    assert_eq!(
120        palette.colors[10],
121        Color {
122            red: 106,
123            green: 190,
124            blue: 48,
125            alpha: 255
126        }
127    );
128    assert_eq!(
129        palette.colors[17],
130        Color {
131            red: 91,
132            green: 110,
133            blue: 225,
134            alpha: 255
135        }
136    );
137}