aseprite_loader/binary/
palette.rs

1use thiserror::Error;
2
3use super::{
4    chunk::Chunk,
5    chunks::{old_palette::OldPaletteChunk, palette::PaletteChunk},
6    header::Header,
7    raw_frame::RawFrame,
8    scalars::Color,
9};
10
11#[derive(Debug)]
12pub struct Palette {
13    pub colors: [Color; 256],
14}
15
16impl Default for Palette {
17    fn default() -> Self {
18        Palette {
19            colors: [Color::default(); 256],
20        }
21    }
22}
23
24pub fn create_palette(header: &Header, frames: &[RawFrame<'_>]) -> Result<Palette, PaletteError> {
25    let mut palette = Palette::default();
26    let palette_chunks: Vec<_> = frames
27        .iter()
28        .flat_map(|frame| {
29            frame.chunks.iter().filter_map(|chunk| {
30                if let Chunk::Palette(palette) = chunk {
31                    Some(palette)
32                } else {
33                    None
34                }
35            })
36        })
37        .collect();
38    if !palette_chunks.is_empty() {
39        process_palette_chunks(header.transparent_index, &palette_chunks, &mut palette)?;
40        return Ok(palette);
41    }
42    let palette0004_chunks: Vec<_> = frames
43        .iter()
44        .flat_map(|frame| {
45            frame.chunks.iter().filter_map(|chunk| {
46                if let Chunk::Palette0004(palette) = chunk {
47                    Some(palette)
48                } else {
49                    None
50                }
51            })
52        })
53        .collect();
54    if !palette0004_chunks.is_empty() {
55        process_old_palette_chunks(header.transparent_index, &palette0004_chunks, &mut palette)?;
56        return Ok(palette);
57    }
58    let palette0011_chunks: Vec<_> = frames
59        .iter()
60        .flat_map(|frame| {
61            frame.chunks.iter().filter_map(|chunk| {
62                if let Chunk::Palette0011(palette) = chunk {
63                    Some(palette)
64                } else {
65                    None
66                }
67            })
68        })
69        .collect();
70    if !palette0011_chunks.is_empty() {
71        process_old_palette_chunks(header.transparent_index, &palette0011_chunks, &mut palette)?;
72        return Ok(palette);
73    }
74    Err(PaletteError::Missing)
75}
76
77fn process_palette_chunks(
78    transparent_index: u8,
79    chunks: &[&PaletteChunk<'_>],
80    palette: &mut Palette,
81) -> Result<(), PaletteError> {
82    let mut ok = false;
83    for chunk in chunks.iter() {
84        // The aseprite palette chunk is a bit weird. Both the palette size
85        // and the color indices use `DWORD` (u32) as data type. Indexed
86        // colors use `BYTE` (u8) though.
87        for (entry, color_idx) in chunk.entries.iter().zip(chunk.indices.clone()) {
88            palette.colors[usize::from(color_idx)] = entry.color;
89            ok = true;
90        }
91    }
92    if ok {
93        palette.colors[usize::from(transparent_index)].alpha = 0;
94        Ok(())
95    } else {
96        Err(PaletteError::Empty)
97    }
98}
99
100fn process_old_palette_chunks(
101    transparent_index: u8,
102    chunks: &[&OldPaletteChunk],
103    palette: &mut Palette,
104) -> Result<(), PaletteError> {
105    let mut ok = false;
106    for chunk in chunks.iter() {
107        let mut color_idx = 0usize;
108        for packet in &chunk.packets {
109            color_idx += usize::from(packet.entries_to_skip);
110            if color_idx + packet.colors.len() > 256 {
111                return Err(PaletteError::IndexOutOfBounds);
112            }
113            for color in &packet.colors {
114                palette.colors[color_idx] = Color {
115                    red: color.red,
116                    green: color.green,
117                    blue: color.blue,
118                    alpha: 255,
119                };
120                color_idx += 1;
121                ok = true;
122            }
123        }
124    }
125    if ok {
126        palette.colors[usize::from(transparent_index)].alpha = 0;
127        Ok(())
128    } else {
129        Err(PaletteError::Empty)
130    }
131}
132
133#[derive(Debug, Copy, Clone, Error)]
134pub enum PaletteError {
135    #[error("Palette is missing")]
136    Missing,
137    #[error("Palette is empty")]
138    Empty,
139    #[error("First color index not in range 0..255")]
140    FirstColorIndexOutOfBounds,
141    #[error("Last color index not in range 0..255")]
142    LastColorIndexOutOfBounds,
143    #[error("First color index > last color index")]
144    FirstColorIndexGreaterThanLastColorIndex,
145    #[error("Palette index out of bounds")]
146    IndexOutOfBounds,
147}