ttf_parser/tables/
cpal.rs

1//! A [Color Palette Table](
2//! https://docs.microsoft.com/en-us/typography/opentype/spec/cpal) implementation.
3
4use core::num::NonZeroU16;
5
6use crate::parser::{FromData, LazyArray16, Offset, Offset32, Stream};
7use crate::RgbaColor;
8
9/// A [Color Palette Table](
10/// https://docs.microsoft.com/en-us/typography/opentype/spec/cpal).
11#[derive(Clone, Copy, Debug)]
12pub struct Table<'a> {
13    color_indices: LazyArray16<'a, u16>,
14    colors: LazyArray16<'a, BgraColor>,
15}
16
17impl<'a> Table<'a> {
18    /// Parses a table from raw data.
19    pub fn parse(data: &'a [u8]) -> Option<Self> {
20        let mut s = Stream::new(data);
21
22        let version = s.read::<u16>()?;
23        if version > 1 {
24            return None;
25        }
26
27        s.skip::<u16>(); // number of palette entries
28
29        let num_palettes = s.read::<u16>()?;
30        if num_palettes == 0 {
31            return None; // zero palettes is an error
32        }
33
34        let num_colors = s.read::<u16>()?;
35        let color_records_offset = s.read::<Offset32>()?;
36        let color_indices = s.read_array16::<u16>(num_palettes)?;
37
38        let colors = Stream::new_at(data, color_records_offset.to_usize())?
39            .read_array16::<BgraColor>(num_colors)?;
40
41        Some(Self {
42            color_indices,
43            colors,
44        })
45    }
46
47    /// Returns the number of palettes.
48    pub fn palettes(&self) -> NonZeroU16 {
49        // Already checked during parsing.
50        NonZeroU16::new(self.color_indices.len()).unwrap()
51    }
52
53    /// Returns the color at the given index into the given palette.
54    pub fn get(&self, palette_index: u16, palette_entry: u16) -> Option<RgbaColor> {
55        let index = self
56            .color_indices
57            .get(palette_index)?
58            .checked_add(palette_entry)?;
59        self.colors.get(index).map(|c| c.to_rgba())
60    }
61}
62
63#[derive(Clone, Copy, PartialEq, Eq, Debug)]
64struct BgraColor {
65    blue: u8,
66    green: u8,
67    red: u8,
68    alpha: u8,
69}
70
71impl BgraColor {
72    #[inline]
73    fn to_rgba(self) -> RgbaColor {
74        RgbaColor::new(self.red, self.green, self.blue, self.alpha)
75    }
76}
77
78impl FromData for BgraColor {
79    const SIZE: usize = 4;
80
81    fn parse(data: &[u8]) -> Option<Self> {
82        let mut s = Stream::new(data);
83        Some(Self {
84            blue: s.read::<u8>()?,
85            green: s.read::<u8>()?,
86            red: s.read::<u8>()?,
87            alpha: s.read::<u8>()?,
88        })
89    }
90}