ttf_parser/tables/
cbdt.rs

1//! A [Color Bitmap Data Table](
2//! https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt) implementation.
3
4use crate::{GlyphId, RasterGlyphImage, RasterImageFormat};
5use crate::parser::{Stream, NumFrom};
6use super::cblc::{self, BitmapFormat};
7
8/// A [Color Bitmap Data Table](
9/// https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt).
10#[derive(Clone, Copy)]
11pub struct Table<'a> {
12    locations: cblc::Table<'a>,
13    data: &'a [u8],
14}
15
16impl<'a> Table<'a> {
17    /// Parses a table from raw data.
18    pub fn parse(locations: cblc::Table<'a>, data: &'a [u8]) -> Option<Self> {
19        Some(Self { locations, data })
20    }
21
22    /// Returns a raster image for the glyph.
23    pub fn get(&self, glyph_id: GlyphId, pixels_per_em: u16) -> Option<RasterGlyphImage<'a>> {
24        let location = self.locations.get(glyph_id, pixels_per_em)?;
25        let mut s = Stream::new_at(self.data, location.offset)?;
26        match location.format {
27            BitmapFormat::Format17 => {
28                let height = s.read::<u8>()?;
29                let width = s.read::<u8>()?;
30                let bearing_x = s.read::<i8>()?;
31                let bearing_y = s.read::<i8>()?;
32                s.skip::<u8>(); // advance
33                let data_len = s.read::<u32>()?;
34                let data = s.read_bytes(usize::num_from(data_len))?;
35                Some(RasterGlyphImage {
36                    x: i16::from(bearing_x),
37                    // `y` in CBDT is a bottom bound, not top one.
38                    y: i16::from(bearing_y) - i16::from(height),
39                    width: u16::from(width),
40                    height: u16::from(height),
41                    pixels_per_em: location.ppem,
42                    format: RasterImageFormat::PNG,
43                    data,
44                })
45            }
46            BitmapFormat::Format18 => {
47                let height = s.read::<u8>()?;
48                let width = s.read::<u8>()?;
49                let hor_bearing_x = s.read::<i8>()?;
50                let hor_bearing_y = s.read::<i8>()?;
51                s.skip::<u8>(); // hor_advance
52                s.skip::<i8>(); // ver_bearing_x
53                s.skip::<i8>(); // ver_bearing_y
54                s.skip::<u8>(); // ver_advance
55                let data_len = s.read::<u32>()?;
56                let data = s.read_bytes(usize::num_from(data_len))?;
57                Some(RasterGlyphImage {
58                    x: i16::from(hor_bearing_x),
59                    // `y` in CBDT is a bottom bound, not top one.
60                    y: i16::from(hor_bearing_y) - i16::from(height),
61                    width: u16::from(width),
62                    height: u16::from(height),
63                    pixels_per_em: location.ppem,
64                    format: RasterImageFormat::PNG,
65                    data,
66                })
67            }
68            BitmapFormat::Format19 => {
69                let data_len = s.read::<u32>()?;
70                let data = s.read_bytes(usize::num_from(data_len))?;
71                Some(RasterGlyphImage {
72                    x: i16::from(location.metrics.x),
73                    // `y` in CBDT is a bottom bound, not top one.
74                    y: i16::from(location.metrics.y) - i16::from(location.metrics.height),
75                    width: u16::from(location.metrics.width),
76                    height: u16::from(location.metrics.height),
77                    pixels_per_em: location.ppem,
78                    format: RasterImageFormat::PNG,
79                    data,
80                })
81            }
82        }
83    }
84}
85
86impl core::fmt::Debug for Table<'_> {
87    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
88        write!(f, "Table {{ ... }}")
89    }
90}