1 | //! A [Color Bitmap Data Table]( |
2 | //! https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt) implementation. |
3 | |
4 | use super::cblc::{self, BitmapFormat}; |
5 | use crate::parser::{NumFrom, Stream}; |
6 | use crate::{GlyphId, RasterGlyphImage, RasterImageFormat}; |
7 | |
8 | /// A [Color Bitmap Data Table]( |
9 | /// https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt). |
10 | #[derive (Clone, Copy)] |
11 | pub struct Table<'a> { |
12 | locations: cblc::Table<'a>, |
13 | data: &'a [u8], |
14 | } |
15 | |
16 | impl<'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 | |
86 | impl core::fmt::Debug for Table<'_> { |
87 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
88 | write!(f, "Table {{ ... }}" ) |
89 | } |
90 | } |
91 | |