font_atlas/rasterize/
mod.rs1#![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#[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#[derive(Debug, Copy, Clone)]
25pub struct CharInfo {
26 pub chr: char,
28 pub scale: f32,
30 pub bounding_box: glyph_packer::Rect,
32 pub post_draw_advance: (f32, f32),
35 pub pre_draw_advance: (f32, f32),
38 pub height_offset: f32,
42}
43
44#[derive(Debug)]
46pub struct Atlas {
47 char_info: HashMap<char, CharInfo>
48}
49
50#[derive(Debug)]
54pub struct Bitmap {
55 bytes: Vec<u8>,
56 width: usize
57}
58
59impl Bitmap {
60 fn new(w: usize, h: usize) -> Bitmap {
63 Bitmap {
64 bytes: vec![0; w * h],
65 width: w,
66 }
67 }
68
69 pub fn lines(&self) -> Chunks<u8> {
72 self.bytes.chunks(self.width)
73 }
74
75 pub fn width(&self) -> usize {
77 self.width
78 }
79
80 pub fn height(&self) -> usize {
82 self.bytes.len() / self.width()
83 }
84
85 pub fn raw(&self) -> &[u8] {
87 &self.bytes
88 }
89
90 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 pub fn new(rusttype_font: rusttype::Font<'static>) -> Font {
138 Font {
139 font: rusttype_font
140 }
141 }
142
143 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 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 pub fn info(&self, c: char) -> Option<CharInfo> {
217 self.char_info.get(&c).cloned()
218 }
219}