1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
extern crate font_atlas;
extern crate glyph_packer;
extern crate image;
extern crate freetype;
use std::collections::HashMap;
use font_atlas::{RenderedFont, CharInfo};
struct Advance(i32, i32);
struct BitmapOffset(i32, i32);
pub type FreetypeError = freetype::error::Error;
pub type FreetypeResult<T> = Result<T, FreetypeError>;
pub fn render<I: Iterator<Item=char>>(face: &mut freetype::Face, chars: I, kerning: bool)
-> FreetypeResult<font_atlas::RenderedFont<image::DynamicImage>> {
let chars_vec: Vec<_> = chars.collect();
let (image, char_info) = try!(merge_all(chars_vec.iter().cloned().map(|c| (c, char_to_img(face, c)))));
let line_height: Option<u32> = face.size_metrics().map(|m| m.height as u32 / 64);
let line_height = try!(line_height.ok_or(freetype::error::Error::MissingProperty));
let max_width: Option<u32> = face.size_metrics().map(|m| m.max_advance as u32 / 64);
let max_width = try!(max_width.ok_or(freetype::error::Error::MissingProperty));
let kerning = if kerning {
let mut map = HashMap::new();
for c1 in chars_vec.iter().cloned() {
for c2 in chars_vec.iter().cloned() {
let k = try!(face.get_kerning(
face.get_char_index(c1 as usize),
face.get_char_index(c2 as usize),
freetype::face::KerningMode::KerningDefault));
let (dx, dy) = (k.x, k.y);
let (dx, dy) = (dx / 64, dy / 64);
if dx != 0 || dy != 0 {
map.insert((c1, c2), (dx as i32, dy as i32));
}
}
}
map
} else {
HashMap::new()
};
Ok(RenderedFont::new(
face.family_name(),
face.style_name(),
image,
line_height,
max_width,
char_info,
kerning
))
}
fn char_to_img(face: &freetype::Face, c: char) -> FreetypeResult<(image::DynamicImage, Advance, BitmapOffset)> {
fn buf_to_vec(bf: &[u8], width: u32, height: u32) -> image::DynamicImage {
let mut v = Vec::with_capacity((width * height * 2) as usize);
for &p in bf {
v.push(p);
v.push(p);
}
image::DynamicImage::ImageLumaA8(
image::ImageBuffer::from_vec(width, height, v).unwrap())
}
try!(face.load_char(c as usize, freetype::face::RENDER));
let glyph = face.glyph();
let bit = glyph.bitmap();
let advance = glyph.advance();
let advance = Advance(advance.x as i32 / 64, advance.y as i32 / 64);
let offset = BitmapOffset(glyph.bitmap_left() as i32, glyph.bitmap_top() as i32);
Ok((buf_to_vec(bit.buffer(), bit.width() as u32, bit.rows() as u32), advance, offset))
}
fn merge_all<I>(images: I) -> FreetypeResult<(image::DynamicImage, HashMap<char, CharInfo>)>
where I: Iterator<Item=(char, FreetypeResult<(image::DynamicImage, Advance, BitmapOffset)>)>,
{
use glyph_packer::{Packer, GrowingPacker};
let size = 256u32;
let mut packer: glyph_packer::SkylinePacker<_> = {
let bf = image::DynamicImage::new_luma_a8(size, size);
Packer::new(bf)
};
let mut mapping = HashMap::new();
packer.set_margin(5);
for (chr, comp) in images {
let (img, adv, offset) = try!(comp);
let rect = packer.pack_resize(&img, |(x, y)| (x * 2, y * 2));
let ci = CharInfo {
image_position: (rect.x, rect.y),
image_size: (rect.w, rect.h),
advance: (adv.0, adv.1),
pixel_offset: (offset.0, offset.1)
};
mapping.insert(chr, ci);
}
let buf = packer.into_buf();
Ok((buf, mapping))
}