Skip to content

Instantly share code, notes, and snippets.

@gitcrtn
Last active August 4, 2022 00:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gitcrtn/a9bb22408cb4906c0f2b5f0427a8e1db to your computer and use it in GitHub Desktop.
Save gitcrtn/a9bb22408cb4906c0f2b5f0427a8e1db to your computer and use it in GitHub Desktop.
Bitmap font generator
[package]
name = "font-img-gen"
version = "0.1.0"
edition = "2021"
[dependencies]
image = "0.24.2"
imageproc = "0.23.0"
rustop = "1.1.2"
rusttype = "0.9.2"
use std::fs::File;
use std::io::{BufReader, Read};
use image::{Rgb, RgbImage};
use imageproc::drawing::{draw_filled_rect_mut, draw_text_mut, text_size};
use imageproc::rect::Rect;
use rustop::opts;
use rusttype::{Font, Scale};
fn hex_to_color(color: &String) -> Rgb<u8> {
let red = u8::from_str_radix(&color[0..2], 16).unwrap();
let green = u8::from_str_radix(&color[2..4], 16).unwrap();
let blue = u8::from_str_radix(&color[4..], 16).unwrap();
Rgb([red, green, blue])
}
fn hex_to_characters(start_hex: &String, end_hex: &String, hexes: &String) -> Vec<char> {
if hexes.len() == 0 {
let start = u32::from_str_radix(start_hex, 16).unwrap();
let end = u32::from_str_radix(end_hex, 16).unwrap() + 1;
if start > end {
panic!("start hex must be smaller than end hex.");
}
(start..end)
.map(|num| char::from_u32(num).unwrap())
.collect()
} else {
hexes
.split(',')
.map(|hex| u32::from_str_radix(hex, 16).unwrap())
.map(|num| char::from_u32(num).unwrap())
.collect()
}
}
fn main() {
let (args, _rest) = opts! {
opt output:String="out.png".to_string(), desc:"output file name";
opt font:String="font.ttf".to_string(), desc:"font file path";
opt height:u32=16, desc:"font height";
opt scale:f32=1.0, desc:"font scale";
opt bgcolor:String="FFFFFF".to_string(), desc:"background color RRGGBB";
opt fgcolor:String="000000".to_string(), desc:"foreground color RRGGBB";
opt starthex:String="20".to_string(), desc:"start character hex";
opt endhex:String="7E".to_string(), desc:"end character hex";
opt hexes:String="".to_string(), desc:"character hex list with comma as delimiter";
}.parse_or_exit();
let characters = hex_to_characters(&args.starthex, &args.endhex, &args.hexes);
let current_dir = std::env::current_dir().unwrap();
let output_path = current_dir.join(args.output);
let font_path = current_dir.join(args.font);
let bg_color = hex_to_color(&args.bgcolor);
let fg_color = hex_to_color(&args.fgcolor);
let scale = Scale {
x: args.height as f32 * args.scale,
y: args.height as f32 * args.scale,
};
let width = args.height * (characters.len() as u32);
let height = args.height;
let font_file = File::open(font_path).unwrap();
let mut reader = BufReader::new(font_file);
let mut buffer = Vec::new();
reader.read_to_end(&mut buffer).unwrap();
let font = Font::try_from_bytes(&buffer).unwrap();
let mut image = RgbImage::new(width, height);
draw_filled_rect_mut(&mut image, Rect::at(0, 0).of_size(width, height), bg_color);
let height = height as i32;
for (i, char) in characters.iter().enumerate() {
let text1 = char.to_string();
let (w, _h) = text_size(scale, &font, &text1);
let offset = (height - w) / 2;
let offset = if offset < 0 { 0 } else { offset };
let offset = height * (i as i32) + offset;
draw_text_mut(&mut image, fg_color, offset, 0, scale, &font, &text1);
}
let _ = image.save(output_path).unwrap();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment