aseprite_loader/binary/chunks/
color_profile.rs

1use bitflags::bitflags;
2use nom::{
3    bytes::complete::take,
4    combinator::{flat_map, map},
5};
6use strum::FromRepr;
7
8use crate::binary::{
9    errors::ParseResult,
10    scalars::{dword, fixed, word, Fixed, Word},
11};
12
13#[derive(Debug)]
14pub struct ColorProfileChunk<'a> {
15    pub fixed_gamma: Option<Fixed>,
16    pub profile: ColorProfile<'a>,
17}
18
19#[derive(Debug, Copy, Clone, FromRepr)]
20pub enum ColorProfileType {
21    NoColorProfile,
22    Srgb,
23    EmbeddedICC,
24    Unknown(Word),
25}
26
27bitflags! {
28    pub struct ColorProfileFlags: Word {
29        const FIXED_GAMMA = 0x01;
30    }
31}
32
33#[derive(Debug)]
34pub enum ColorProfile<'a> {
35    NoColorProfile,
36    Srgb,
37    EmbeddedICC(&'a [u8]),
38    Unknown(Word),
39}
40
41pub fn parse_color_profile(input: &[u8]) -> ParseResult<'_, ColorProfileChunk<'_>> {
42    let (input, profile_type) = word(input)?;
43    let profile_type = ColorProfileType::from_repr(profile_type.into())
44        .unwrap_or(ColorProfileType::Unknown(profile_type));
45    let (input, flags) = word(input)?;
46    let flags = ColorProfileFlags::from_bits_truncate(flags);
47    let (input, fixed_gamma) = fixed(input)?;
48    let (input, _) = take(8usize)(input)?;
49    let (input, profile) = match profile_type {
50        ColorProfileType::NoColorProfile => (input, ColorProfile::NoColorProfile),
51        ColorProfileType::Srgb => (input, ColorProfile::Srgb),
52        ColorProfileType::EmbeddedICC => {
53            map(flat_map(dword, take), ColorProfile::EmbeddedICC)(input)?
54        }
55        ColorProfileType::Unknown(word) => (input, ColorProfile::Unknown(word)),
56    };
57    Ok((
58        input,
59        ColorProfileChunk {
60            fixed_gamma: if flags.contains(ColorProfileFlags::FIXED_GAMMA) {
61                Some(fixed_gamma)
62            } else {
63                None
64            },
65            profile,
66        },
67    ))
68}