use systemless::quickdraw::fonts::{font_name_for_id, FontMetrics, FONT_TABLE};
use systemless::quickdraw::text::get_glyph;
const LABEL_FONT: i16 = 0; const LABEL_SIZE: i16 = 12;
const SCALE: u32 = 4;
const PAD: i32 = 6; const ROW_GAP: i32 = 4; const LABEL_W: i32 = 78;
const SPECIMEN: &str =
"The quick brown fox jumps over the LAZY dog. name with new Cancel OK 0123456789 !?(),.";
struct Canvas {
w: i32,
h: i32,
px: Vec<u8>, }
impl Canvas {
fn new(w: i32, h: i32) -> Self {
Canvas { w, h, px: vec![0; (w * h) as usize] }
}
fn set(&mut self, x: i32, y: i32) {
if x >= 0 && x < self.w && y >= 0 && y < self.h {
self.px[(y * self.w + x) as usize] = 1;
}
}
}
fn draw_text(canvas: &mut Canvas, x: i32, baseline_y: i32, font_id: i16, size: i16, text: &str) -> i32 {
let mut pen = x;
for ch in text.chars() {
if let Some((glyph, data)) = get_glyph(font_id, size, ch) {
let left = pen + glyph.origin_x as i32;
for gy in 0..glyph.height as i32 {
let sy = baseline_y + glyph.origin_y as i32 + gy;
for gx in 0..glyph.width as i32 {
let idx = glyph.data_offset + (gy * glyph.width as i32 + gx) as usize;
if idx < data.len() && data[idx] >= 128 {
canvas.set(left + gx, sy);
}
}
}
pen += glyph.advance as i32;
} else {
pen += 6;
}
}
pen
}
fn text_width(font_id: i16, size: i16, text: &str) -> i32 {
text.chars()
.map(|ch| get_glyph(font_id, size, ch).map(|(g, _)| g.advance as i32).unwrap_or(6))
.sum()
}
fn row_height(m: &FontMetrics) -> i32 {
(m.ascent + m.descent + m.leading) as i32
}
fn main() {
let faces: Vec<&_> = FONT_TABLE.iter().collect();
let mut total_h = PAD;
let mut max_w = 0i32;
for f in &faces {
let rh = row_height(&f.metrics).max(row_height(&label_metrics()));
let specimen_w = text_width(f.font_id, f.size, SPECIMEN);
max_w = max_w.max(PAD + LABEL_W + specimen_w + PAD);
total_h += rh + ROW_GAP;
}
total_h += PAD;
let mut canvas = Canvas::new(max_w, total_h);
let mut y = PAD;
for f in &faces {
let rh = row_height(&f.metrics).max(row_height(&label_metrics()));
let baseline = y + label_metrics().ascent.max(f.metrics.ascent) as i32;
let name = font_name_for_id(f.font_id).unwrap_or("?");
let label = format!("{} {}", name, f.size);
draw_text(&mut canvas, PAD, baseline, LABEL_FONT, LABEL_SIZE, &label);
draw_text(&mut canvas, PAD + LABEL_W, baseline, f.font_id, f.size, SPECIMEN);
y += rh + ROW_GAP;
}
std::fs::create_dir_all("target/font_specimens").expect("mkdir");
save(&canvas, false, "target/font_specimens/specimen_white@1x.png", 1);
save(&canvas, true, "target/font_specimens/specimen_black@1x.png", 1);
save(&canvas, false, "target/font_specimens/specimen_white.png", SCALE);
save(&canvas, true, "target/font_specimens/specimen_black.png", SCALE);
println!(
"wrote {} faces to target/font_specimens/ ({}x{} @1x, {}x scaled)",
faces.len(),
canvas.w,
canvas.h,
SCALE
);
}
fn label_metrics() -> FontMetrics {
systemless::quickdraw::fonts::get_font_face_or_default(LABEL_FONT, LABEL_SIZE).metrics
}
fn save(canvas: &Canvas, black_bg: bool, path: &str, scale: u32) {
let (bg, ink): (u8, u8) = if black_bg { (0, 255) } else { (255, 0) };
let w = canvas.w as u32 * scale;
let h = canvas.h as u32 * scale;
let mut buf = vec![bg; (w * h) as usize];
for cy in 0..canvas.h {
for cx in 0..canvas.w {
if canvas.px[(cy * canvas.w + cx) as usize] == 1 {
for sy in 0..scale {
for sx in 0..scale {
let px = cx as u32 * scale + sx;
let py = cy as u32 * scale + sy;
buf[(py * w + px) as usize] = ink;
}
}
}
}
}
let img: image::GrayImage = image::GrayImage::from_raw(w, h, buf).expect("image");
img.save(path).expect("save png");
}