makepad_draw/text/
glyph_raster_image.rs

1use {
2    super::{
3        geom::{Point, Rect, Size},
4        image::{Bgra, SubimageMut},
5    },
6    makepad_rustybuzz as rustybuzz,
7    rustybuzz::ttf_parser,
8};
9
10#[derive(Clone, Debug)]
11pub struct GlyphRasterImage<'a> {
12    origin_in_dpxs: Point<f32>,
13    dpxs_per_em: f32,
14    format: Format,
15    data: &'a [u8],
16}
17
18impl<'a> GlyphRasterImage<'a> {
19    pub fn from_raster_glyph_image(image: ttf_parser::RasterGlyphImage<'a>) -> Option<Self> {
20        Some(Self {
21            origin_in_dpxs: Point::new(image.x as f32, image.y as f32),
22            dpxs_per_em: image.pixels_per_em as f32,
23            format: Format::from_raster_image_format(image.format)?,
24            data: image.data,
25        })
26    }
27
28    pub fn origin_in_dpxs(&self) -> Point<f32> {
29        self.origin_in_dpxs
30    }
31
32    pub fn size_in_dpxs(&self) -> Size<f32> {
33        let size = self.decode_size();
34        Size::new(size.width as f32, size.height as f32)
35    }
36
37    pub fn bounds_in_dpxs(&self) -> Rect<f32> {
38        Rect::new(self.origin_in_dpxs(), self.size_in_dpxs())
39    }
40
41    pub fn dpxs_per_em(&self) -> f32 {
42        self.dpxs_per_em
43    }
44
45    pub fn decode_size(&self) -> Size<usize> {
46        match self.format {
47            Format::Png => self.decode_size_png(),
48        }
49    }
50
51    fn decode_size_png(&self) -> Size<usize> {
52        let decoder = png::Decoder::new(self.data);
53        let reader = decoder.read_info().unwrap();
54        let info = reader.info();
55        Size {
56            width: info.width as usize,
57            height: info.height as usize,
58        }
59    }
60
61    pub fn decode(&self, image: &mut SubimageMut<Bgra>) {
62        match self.format {
63            Format::Png => self.decode_png(image),
64        }
65    }
66
67    fn decode_png(&self, image: &mut SubimageMut<Bgra>) {
68        let decoder = png::Decoder::new(self.data);
69        let mut reader = decoder.read_info().unwrap();
70        let mut buffer = vec![0; reader.output_buffer_size()];
71        let output_info = reader.next_frame(&mut buffer).unwrap();
72        let info = reader.info();
73        let height = info.height as usize;
74        let width = info.width as usize;
75        match output_info.color_type {
76            png::ColorType::Indexed => {
77                let palette = info.palette.as_ref().unwrap();
78                let trns = info.trns.as_ref();
79                let mut set_pixel = |x, y, index| {
80                    let base = index * 3;
81                    let r = palette[base + 0];
82                    let g = palette[base + 1];
83                    let b = palette[base + 2];
84                    let a = trns.map_or(255, |trns| trns.get(index).copied().unwrap_or(255));
85                    image[Point::new(x, y)] = Bgra::new(b, g, r, a);
86                };
87                match output_info.bit_depth {
88                    png::BitDepth::Four => {
89                        let bytes_per_row = (width + 1) / 2;
90                        for y in 0..height {
91                            for x in 0..width {
92                                let byte = buffer[y * bytes_per_row + x / 2];
93                                set_pixel(
94                                    x,
95                                    y,
96                                    if x % 2 == 0 { byte >> 4 } else { byte & 0x0F } as usize,
97                                );
98                            }
99                        }
100                    }
101                    png::BitDepth::Eight => {
102                        for y in 0..height as usize {
103                            for x in 0..width as usize {
104                                set_pixel(x, y, buffer[y * width + x] as usize);
105                            }
106                        }
107                    }
108                    _ => println!("WARNING: encountered rasterized glyph with unsupported bit depth"),
109                }
110            }
111            _ => println!("WARNING: encountered rasterized glyph with unsupported color type"),
112        }
113    }
114}
115
116#[derive(Clone, Copy, Debug)]
117pub enum Format {
118    Png,
119}
120
121impl Format {
122    pub fn from_raster_image_format(format: ttf_parser::RasterImageFormat) -> Option<Self> {
123        match format {
124            ttf_parser::RasterImageFormat::PNG => Some(Self::Png),
125            _ => None,
126        }
127    }
128}