font_atlas/rasterize/
mod.rs

1#![deny(missing_docs)]
2
3use std::collections::HashMap;
4use std::slice::Chunks;
5
6use super::glyph_packer;
7use super::rusttype::{self, Scale};
8use glyph_packer::{Packer, GrowingPacker};
9
10/// A single font loaded from a file.
11#[derive(Clone)]
12pub struct Font {
13    font: rusttype::Font<'static>
14}
15
16impl ::std::fmt::Debug for Font {
17    fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
18        formatter.write_str("Font()")
19    }
20}
21
22/// Information about a character from a font rendered
23/// at a specific scale.
24#[derive(Debug, Copy, Clone)]
25pub struct CharInfo {
26    /// The character in question
27    pub chr: char,
28    /// The scale that the character was rendered at
29    pub scale: f32,
30    /// The size of the character
31    pub bounding_box: glyph_packer::Rect,
32    /// The amount of (x, y) that the pen should move
33    /// after drawing the character
34    pub post_draw_advance: (f32, f32),
35    /// The amount of (x, y) that the pen should move
36    /// before drawing the character
37    pub pre_draw_advance: (f32, f32),
38    /// The amount of y that the pen should move for drawing
39    /// this specific character.  This value gets reset after
40    /// drawing.
41    pub height_offset: f32,
42}
43
44/// A mapping from chars to CharInfo.
45#[derive(Debug)]
46pub struct Atlas {
47    char_info: HashMap<char, CharInfo>
48}
49
50/// A rectangular 2d-array of u8 where
51/// the values 0 through 255 represent
52/// shades of grey.
53#[derive(Debug)]
54pub struct Bitmap {
55    bytes: Vec<u8>,
56    width: usize
57}
58
59impl Bitmap {
60    /// Construct a new empty (all zeros) bitmap
61    /// of the given dimensions.
62    fn new(w: usize, h: usize) -> Bitmap {
63        Bitmap {
64            bytes: vec![0; w * h],
65            width: w,
66        }
67    }
68
69    /// Return an iterator over the lines of the bitmap
70    /// going from top to bottom.
71    pub fn lines(&self) -> Chunks<u8> {
72        self.bytes.chunks(self.width)
73    }
74
75    /// The width of this bitmap
76    pub fn width(&self) -> usize {
77        self.width
78    }
79
80    /// The height of this bitmap
81    pub fn height(&self) -> usize {
82        self.bytes.len() / self.width()
83    }
84
85    /// Gain access to the underlying slice of u8.
86    pub fn raw(&self) -> &[u8] {
87        &self.bytes
88    }
89
90    /// Get the underlying buffer of u8
91    pub fn into_raw(self) -> Vec<u8> {
92        self.bytes
93    }
94}
95
96impl glyph_packer::Buffer2d for Bitmap {
97    type Pixel = u8;
98
99    fn width(&self) -> u32 {
100        self.width as u32
101    }
102
103    fn height(&self) -> u32 {
104        (self.bytes.len() / self.width) as u32
105    }
106
107    fn get(&self, x: u32, y: u32) -> Option<Self::Pixel> {
108        let x = x as usize;
109        let y = y as usize;
110        let width = self.width() as usize;
111        self.bytes.get(x + width * y).cloned()
112    }
113
114    fn set(&mut self, x: u32, y: u32, val: Self::Pixel) {
115        let x = x as usize;
116        let y = y as usize;
117        let width = self.width() as usize;
118        if let Some(p) = self.bytes.get_mut(x + width * y) {
119            *p = val;
120        }
121    }
122}
123
124impl glyph_packer::ResizeBuffer for Bitmap {
125    fn resize(&mut self, width: u32, height: u32) {
126        use glyph_packer::Buffer2d;
127        assert!(self.width() <= width as usize && self.height() <= height as usize,
128               "resizable buffers should only grow.");
129        let mut o_new = Bitmap::new(width as usize, height as usize);
130        o_new.patch(0, 0, self);
131        *self = o_new;
132    }
133}
134
135impl Font {
136    /// Construct a new Font from a rusttype::Font.
137    pub fn new(rusttype_font: rusttype::Font<'static>) -> Font {
138        Font {
139            font: rusttype_font
140        }
141    }
142
143    /// Renders a character from this font at a given scale into a pair of (CharInfo, Bitmap).
144    ///
145    /// If the character isn't handled by the font, None is returned.
146    pub fn render_char(&self, chr: char, scale: f32) -> Option<(CharInfo, Bitmap)> {
147        use glyph_packer::Buffer2d;
148        let glyph = match self.font.glyph(chr) {
149            Some(a) => a,
150            None => return None,
151        };
152        let glyph = glyph.scaled(rusttype::Scale::uniform(scale));
153        let h_metrics = glyph.h_metrics();
154        let glyph = glyph.positioned(rusttype::Point { x: 0.0, y:0.0 });
155        let bb = match glyph.pixel_bounding_box() {
156            Some(a) => a,
157            None => return None
158        };
159        let mut out = Bitmap::new(bb.width() as usize, bb.height() as usize);
160        glyph.draw(|x, y, v| {
161            out.set(x, y, (v * 255.0) as u8);
162        });
163
164        let info = CharInfo {
165            chr: chr,
166            scale: scale,
167            bounding_box: glyph_packer::Rect{
168                x: bb.min.x as u32,
169                y: bb.min.y as u32,
170                w: bb.width() as u32,
171                h: bb.height() as u32
172            },
173            post_draw_advance: (h_metrics.advance_width, 0.0),
174            pre_draw_advance: (h_metrics.left_side_bearing, 0.0),
175            height_offset: glyph.position().y,
176        };
177
178        Some((info, out))
179    }
180
181    /// Creates an atlas for a set of characters rendered at a given scale.
182    ///
183    /// `margin` is the distance between characters in pixels.
184    /// `width` and `height` denote the starting size of the bitmap.
185    ///
186    /// The resulting bitmap may be larger than width x height in order to
187    /// fit all of the characters.
188    pub fn make_atlas<I: Iterator<Item=char>>(&self, i: I, scale: f32, margin: u32, width: usize, height: usize) -> (Atlas, Bitmap, f32) {
189        let mut atlas = Atlas { char_info: HashMap::new() };
190        let mut packer = glyph_packer::SkylinePacker::new(Bitmap::new(width, height));
191        packer.set_margin(margin);
192
193        for c in i {
194            if let Some((mut info, rendered)) = self.render_char(c, scale) {
195                let r: glyph_packer::Rect = packer.pack_resize(&rendered, |(ow, oh)| (ow * 2, oh * 2));
196                info.bounding_box = r;
197                atlas.char_info.insert(c, info);
198            } else if c == ' ' {
199                let (mut info, _) = self.render_char('-', scale).unwrap();
200                let empty_bitmap = Bitmap::new(1, 1);
201                let r = packer.pack_resize(&empty_bitmap, |(ow, oh)| (ow * 2, oh * 2));
202                info.bounding_box = r;
203                atlas.char_info.insert(c, info);
204            } else {
205                panic!("can not renderer char {}", c);
206            }
207        }
208        let v_metrics = self.font.v_metrics(Scale::uniform(scale));
209        let line_height = v_metrics.ascent + v_metrics.descent + v_metrics.line_gap;
210        (atlas, packer.into_buf(), line_height)
211    }
212}
213
214impl Atlas {
215    /// Returns the information about a rendered character if one exists
216    pub fn info(&self, c: char) -> Option<CharInfo> {
217        self.char_info.get(&c).cloned()
218    }
219}