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::cblc::{self, BitmapDataFormat, Metrics, MetricsFormat};
5use crate::parser::{NumFrom, Stream};
6use crate::{GlyphId, RasterGlyphImage, RasterImageFormat};
7
8/// A [Color Bitmap Data Table](
9/// https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt).
10///
11/// EBDT and bdat also share the same structure, so this is re-used for them.
12#[derive(Clone, Copy)]
13pub struct Table<'a> {
14    locations: cblc::Table<'a>,
15    data: &'a [u8],
16}
17
18impl<'a> Table<'a> {
19    /// Parses a table from raw data.
20    pub fn parse(locations: cblc::Table<'a>, data: &'a [u8]) -> Option<Self> {
21        Some(Self { locations, data })
22    }
23
24    /// Returns a raster image for the glyph.
25    pub fn get(&self, glyph_id: GlyphId, pixels_per_em: u16) -> Option<RasterGlyphImage<'a>> {
26        let location = self.locations.get(glyph_id, pixels_per_em)?;
27        let mut s = Stream::new_at(self.data, location.offset)?;
28        let metrics = match location.format.metrics {
29            MetricsFormat::Small => {
30                let height = s.read::<u8>()?;
31                let width = s.read::<u8>()?;
32                let bearing_x = s.read::<i8>()?;
33                let bearing_y = s.read::<i8>()?;
34                s.skip::<u8>(); // advance
35                Metrics {
36                    x: bearing_x,
37                    y: bearing_y,
38                    width,
39                    height,
40                }
41            }
42            MetricsFormat::Big => {
43                let height = s.read::<u8>()?;
44                let width = s.read::<u8>()?;
45                let hor_bearing_x = s.read::<i8>()?;
46                let hor_bearing_y = s.read::<i8>()?;
47                s.skip::<u8>(); // hor_advance
48                s.skip::<i8>(); // ver_bearing_x
49                s.skip::<i8>(); // ver_bearing_y
50                s.skip::<u8>(); // ver_advance
51                Metrics {
52                    x: hor_bearing_x,
53                    y: hor_bearing_y,
54                    width,
55                    height,
56                }
57            }
58            MetricsFormat::Shared => location.metrics,
59        };
60        match location.format.data {
61            BitmapDataFormat::ByteAligned { bit_depth } => {
62                let row_len = (u32::from(metrics.width) * u32::from(bit_depth) + 7) / 8;
63                let data_len = row_len * u32::from(metrics.height);
64                let data = s.read_bytes(usize::num_from(data_len))?;
65                Some(RasterGlyphImage {
66                    x: i16::from(metrics.x),
67                    // `y` in CBDT is a bottom bound, not top one.
68                    y: i16::from(metrics.y) - i16::from(metrics.height),
69                    width: u16::from(metrics.width),
70                    height: u16::from(metrics.height),
71                    pixels_per_em: location.ppem,
72                    format: match bit_depth {
73                        1 => RasterImageFormat::BitmapMono,
74                        2 => RasterImageFormat::BitmapGray2,
75                        4 => RasterImageFormat::BitmapGray4,
76                        8 => RasterImageFormat::BitmapGray8,
77                        32 => RasterImageFormat::BitmapPremulBgra32,
78                        _ => return None,
79                    },
80                    data,
81                })
82            }
83            BitmapDataFormat::BitAligned { bit_depth } => {
84                let data_len = {
85                    let w = u32::from(metrics.width);
86                    let h = u32::from(metrics.height);
87                    let d = u32::from(bit_depth);
88                    (w * h * d + 7) / 8
89                };
90
91                let data = s.read_bytes(usize::num_from(data_len))?;
92                Some(RasterGlyphImage {
93                    x: i16::from(metrics.x),
94                    // `y` in CBDT is a bottom bound, not top one.
95                    y: i16::from(metrics.y) - i16::from(metrics.height),
96                    width: u16::from(metrics.width),
97                    height: u16::from(metrics.height),
98                    pixels_per_em: location.ppem,
99                    format: match bit_depth {
100                        1 => RasterImageFormat::BitmapMonoPacked,
101                        2 => RasterImageFormat::BitmapGray2Packed,
102                        4 => RasterImageFormat::BitmapGray4Packed,
103                        8 => RasterImageFormat::BitmapGray8,
104                        32 => RasterImageFormat::BitmapPremulBgra32,
105                        _ => return None,
106                    },
107                    data,
108                })
109            }
110            BitmapDataFormat::PNG => {
111                let data_len = s.read::<u32>()?;
112                let data = s.read_bytes(usize::num_from(data_len))?;
113                Some(RasterGlyphImage {
114                    x: i16::from(metrics.x),
115                    // `y` in CBDT is a bottom bound, not top one.
116                    y: i16::from(metrics.y) - i16::from(metrics.height),
117                    width: u16::from(metrics.width),
118                    height: u16::from(metrics.height),
119                    pixels_per_em: location.ppem,
120                    format: RasterImageFormat::PNG,
121                    data,
122                })
123            }
124        }
125    }
126}
127
128impl core::fmt::Debug for Table<'_> {
129    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
130        write!(f, "Table {{ ... }}")
131    }
132}