-
Notifications
You must be signed in to change notification settings - Fork 49
Expand file tree
/
Copy pathsimple.rs
More file actions
66 lines (56 loc) · 2.8 KB
/
Copy pathsimple.rs
File metadata and controls
66 lines (56 loc) · 2.8 KB
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
extern crate rusttype;
use rusttype::{FontCollection, Scale, point, PositionedGlyph};
use std::io::Write;
fn main() {
let font_data = include_bytes!("Arial Unicode.ttf");
let collection = FontCollection::from_bytes(font_data as &[u8]);
let font = collection.into_font().unwrap(); // only succeeds if collection consists of one font
// Desired font pixel height
let height: f32 = 12.4; // to get 80 chars across (fits most terminals); adjust as desired
let pixel_height = height.ceil() as usize;
// 2x scale in x direction to counter the aspect ratio of monospace characters.
let scale = Scale { x: height*2.0, y: height };
// The origin of a line of text is at the baseline (roughly where non-descending letters sit).
// We don't want to clip the text, so we shift it down with an offset when laying it out.
// v_metrics.ascent is the distance between the baseline and the highest edge of any glyph in
// the font. That's enough to guarantee that there's no clipping.
let v_metrics = font.v_metrics(scale);
let offset = point(0.0, v_metrics.ascent);
// Glyphs to draw for "RustType". Feel free to try other strings.
let glyphs: Vec<PositionedGlyph> = font.layout("RustType", scale, offset).collect();
// Find the most visually pleasing width to display
let width = glyphs.iter().rev()
.filter_map(|g| g.pixel_bounding_box()
.map(|b| b.min.x as f32 + g.unpositioned().h_metrics().advance_width))
.next().unwrap_or(0.0).ceil() as usize;
println!("width: {}, height: {}", width, pixel_height);
// Rasterise directly into ASCII art.
let mut pixel_data = vec![b'@'; width * pixel_height];
let mapping = b"@%#x+=:-. "; // The approximation of greyscale
let mapping_scale = (mapping.len()-1) as f32;
for g in glyphs {
if let Some(bb) = g.pixel_bounding_box() {
g.draw(|x, y, v| {
// v should be in the range 0.0 to 1.0
let i = (v*mapping_scale + 0.5) as usize;
// so something's wrong if you get $ in the output.
let c = mapping.get(i).cloned().unwrap_or(b'$');
let x = x as i32 + bb.min.x;
let y = y as i32 + bb.min.y;
// There's still a possibility that the glyph clips the boundaries of the bitmap
if x >= 0 && x < width as i32 && y >= 0 && y < pixel_height as i32 {
let x = x as usize;
let y = y as usize;
pixel_data[(x + y * width)] = c;
}
})
}
}
// Print it out
let stdout = ::std::io::stdout();
let mut handle = stdout.lock();
for j in 0..pixel_height {
handle.write(&pixel_data[j*width..(j+1)*width]).unwrap();
handle.write(b"\n").unwrap();
}
}