|
1 | 1 | use clap::Parser; |
2 | | -use std::path::PathBuf; |
| 2 | +use eg_bdf::BdfTextStyle; |
| 3 | +use eg_font_converter::FontConverter; |
| 4 | +use embedded_graphics::{ |
| 5 | + mono_font::MonoTextStyle, |
| 6 | + pixelcolor::Rgb888, |
| 7 | + prelude::*, |
| 8 | + primitives::{Line, PrimitiveStyle, StyledDrawable}, |
| 9 | + text::{renderer::TextRenderer, Baseline, Text}, |
| 10 | +}; |
| 11 | +use embedded_graphics_simulator::{OutputSettingsBuilder, SimulatorDisplay}; |
| 12 | +use owo_colors::OwoColorize; |
| 13 | +use std::{fs, path::PathBuf}; |
3 | 14 |
|
4 | 15 | use test_bdf_parser::*; |
5 | 16 |
|
6 | 17 | #[derive(Parser)] |
7 | 18 | struct Arguments { |
| 19 | + /// Output directory for font specimens in PNG format. |
| 20 | + #[arg(long)] |
| 21 | + png_out: Option<PathBuf>, |
| 22 | + |
| 23 | + /// Output scale for PNG images. |
| 24 | + #[arg(long, default_value = "1")] |
| 25 | + png_scale: u32, |
| 26 | + |
| 27 | + /// Path to a BDF file or a directory containing BDF files. |
8 | 28 | file_or_directory: PathBuf, |
9 | 29 | } |
10 | 30 |
|
11 | | -pub fn main() { |
12 | | - let args: Arguments = Arguments::parse(); |
| 31 | +fn draw_specimen(style: impl TextRenderer<Color = Rgb888> + Copy) -> SimulatorDisplay<Rgb888> { |
| 32 | + let single_line = Text::with_baseline( |
| 33 | + "The quick brown fox jumps over the lazy dog.", |
| 34 | + Point::zero(), |
| 35 | + style, |
| 36 | + Baseline::Top, |
| 37 | + ); |
| 38 | + |
| 39 | + // 10 px minimum line height to ensure output even if metrics are wrong. |
| 40 | + let single_line_height = single_line.bounding_box().size.height.max(10); |
| 41 | + |
| 42 | + let display_height = single_line_height * 3; |
| 43 | + let display_width = (single_line.bounding_box().size.width + 10).max(display_height); |
| 44 | + |
| 45 | + let text_position = Point::new(5, single_line_height as i32); |
13 | 46 |
|
14 | | - if args.file_or_directory.is_dir() { |
15 | | - let fonts = |
16 | | - collect_font_files(&args.file_or_directory).expect("Could not get list of fonts"); |
| 47 | + let mut display = SimulatorDisplay::<Rgb888>::new(Size::new(display_width, display_height)); |
17 | 48 |
|
18 | | - let results = fonts.iter().map(|fpath| test_font_parse(fpath)); |
| 49 | + // Draw baseline grid |
19 | 50 |
|
20 | | - let mut num_errors = 0; |
| 51 | + for offset in [Point::zero(), Point::new(0, single_line_height as i32)] { |
| 52 | + Line::with_delta( |
| 53 | + text_position.y_axis() + offset, |
| 54 | + Point::new(display_width as i32, 0), |
| 55 | + ) |
| 56 | + .draw_styled( |
| 57 | + &PrimitiveStyle::with_stroke(Rgb888::CSS_DARK_SLATE_GRAY, 1), |
| 58 | + &mut display, |
| 59 | + ) |
| 60 | + .unwrap(); |
| 61 | + } |
| 62 | + |
| 63 | + // Draw marker for X start position |
| 64 | + |
| 65 | + Line::with_delta(text_position.x_axis(), Point::new(0, display_height as i32)) |
| 66 | + .draw_styled( |
| 67 | + &PrimitiveStyle::with_stroke(Rgb888::CSS_DARK_SLATE_GRAY, 1), |
| 68 | + &mut display, |
| 69 | + ) |
| 70 | + .unwrap(); |
| 71 | + |
| 72 | + let text = Text::new( |
| 73 | + "The quick brown fox jumps over the lazy dog.\n0123456789", |
| 74 | + text_position, |
| 75 | + style, |
| 76 | + ); |
21 | 77 |
|
22 | | - for (font, result) in fonts.iter().zip(results) { |
23 | | - if result.is_err() { |
24 | | - num_errors += 1; |
25 | | - } |
| 78 | + // Draw bounding box |
26 | 79 |
|
| 80 | + text.bounding_box() |
| 81 | + .draw_styled( |
| 82 | + &PrimitiveStyle::with_stroke(Rgb888::CSS_LIGHT_SLATE_GRAY, 1), |
| 83 | + &mut display, |
| 84 | + ) |
| 85 | + .unwrap(); |
| 86 | + |
| 87 | + text.draw(&mut display).unwrap(); |
| 88 | + |
| 89 | + display |
| 90 | +} |
| 91 | + |
| 92 | +pub fn main() { |
| 93 | + let args: Arguments = Arguments::parse(); |
| 94 | + |
| 95 | + let fonts = parse_fonts(&args.file_or_directory).expect("Could not parse fonts"); |
| 96 | + let num_errors = print_parser_result(&fonts); |
| 97 | + |
| 98 | + let output_settings = OutputSettingsBuilder::new().scale(args.png_scale).build(); |
| 99 | + |
| 100 | + if let Some(png_directory) = args.png_out { |
| 101 | + for file in fonts.iter().filter(|file| file.parsed.is_ok()) { |
27 | 102 | println!( |
28 | | - "{0: <60} {1:?}", |
29 | | - font.file_name().unwrap().to_str().unwrap(), |
30 | | - result |
| 103 | + "Generating specimen: {}", |
| 104 | + file.path.relative.to_string_lossy() |
31 | 105 | ); |
32 | | - } |
33 | 106 |
|
34 | | - println!( |
35 | | - "\n{} out of {} fonts passed ({} failed)\n", |
36 | | - (fonts.len() - num_errors), |
37 | | - fonts.len(), |
38 | | - num_errors |
39 | | - ); |
40 | | - |
41 | | - assert_eq!(num_errors, 0, "Not all font files parsed successfully"); |
42 | | - } else if args.file_or_directory.is_file() { |
43 | | - test_font_parse(&args.file_or_directory).unwrap(); |
44 | | - } else { |
45 | | - panic!("Invalid path: {:?}", args.file_or_directory); |
| 107 | + let output_file = png_directory.join(&file.path.relative); |
| 108 | + let output_dir = output_file.parent().unwrap(); |
| 109 | + |
| 110 | + fs::create_dir_all(output_dir).unwrap(); |
| 111 | + |
| 112 | + let converter = FontConverter::with_file(&file.path.absolute, "FONT"); |
| 113 | + |
| 114 | + match converter.convert_eg_bdf() { |
| 115 | + Ok(converted_bdf) => { |
| 116 | + let bdf_specimen = |
| 117 | + draw_specimen(BdfTextStyle::new(&converted_bdf.as_font(), Rgb888::WHITE)); |
| 118 | + bdf_specimen |
| 119 | + .to_rgb_output_image(&output_settings) |
| 120 | + .save_png(output_file.with_extension("bdf.png")) |
| 121 | + .unwrap(); |
| 122 | + } |
| 123 | + Err(e) => println!("{} {e}", "Error (eg-bdf):".red()), |
| 124 | + }; |
| 125 | + |
| 126 | + match converter.convert_mono_font() { |
| 127 | + Ok(converted_mono) => { |
| 128 | + let mono_specimen = |
| 129 | + draw_specimen(MonoTextStyle::new(&converted_mono.as_font(), Rgb888::WHITE)); |
| 130 | + mono_specimen |
| 131 | + .to_rgb_output_image(&output_settings) |
| 132 | + .save_png(output_file.with_extension("mono.png")) |
| 133 | + .unwrap(); |
| 134 | + } |
| 135 | + Err(e) => println!("{} {e}", "Error (mono):".red()), |
| 136 | + }; |
| 137 | + } |
46 | 138 | } |
| 139 | + |
| 140 | + assert_eq!(num_errors, 0, "Not all font files parsed successfully"); |
47 | 141 | } |
0 commit comments