pub const FONT_WIDTH: usize = 5;
pub const FONT_HEIGHT: usize = 7;
pub type GlyphData = [u8; FONT_HEIGHT];
pub fn glyph(c: char) -> Option<GlyphData> {
Some(match c {
' ' => [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
'!' => [0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x06],
'"' => [0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00],
'#' => [0x0A, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x0A],
'$' => [0x04, 0x0F, 0x14, 0x0E, 0x05, 0x1E, 0x04],
'%' => [0x18, 0x19, 0x02, 0x04, 0x08, 0x13, 0x03],
'&' => [0x08, 0x14, 0x14, 0x08, 0x15, 0x12, 0x0D],
'\'' => [0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00],
'(' => [0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02],
')' => [0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08],
'*' => [0x00, 0x04, 0x15, 0x0E, 0x15, 0x04, 0x00],
'+' => [0x00, 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00],
',' => [0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x08],
'-' => [0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00],
'.' => [0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06],
'/' => [0x01, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00],
'0' => [0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E],
'1' => [0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E],
'2' => [0x0E, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1F],
'3' => [0x0E, 0x11, 0x01, 0x06, 0x01, 0x11, 0x0E],
'4' => [0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02],
'5' => [0x1F, 0x10, 0x1E, 0x01, 0x01, 0x11, 0x0E],
'6' => [0x06, 0x08, 0x10, 0x1E, 0x11, 0x11, 0x0E],
'7' => [0x1F, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08],
'8' => [0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E],
'9' => [0x0E, 0x11, 0x11, 0x0F, 0x01, 0x02, 0x0C],
':' => [0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00],
';' => [0x00, 0x00, 0x04, 0x00, 0x04, 0x08, 0x00],
'<' => [0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02],
'=' => [0x00, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x00],
'>' => [0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08],
'?' => [0x0E, 0x11, 0x01, 0x02, 0x04, 0x00, 0x04],
'@' => [0x0E, 0x11, 0x17, 0x15, 0x17, 0x10, 0x0E],
'A' => [0x0E, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11],
'B' => [0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E],
'C' => [0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E],
'D' => [0x1C, 0x12, 0x11, 0x11, 0x11, 0x12, 0x1C],
'E' => [0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x1F],
'F' => [0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x10],
'G' => [0x0E, 0x11, 0x10, 0x17, 0x11, 0x11, 0x0F],
'H' => [0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11],
'I' => [0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E],
'J' => [0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0C],
'K' => [0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11],
'L' => [0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F],
'M' => [0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11],
'N' => [0x11, 0x19, 0x15, 0x13, 0x11, 0x11, 0x11],
'O' => [0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E],
'P' => [0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10],
'Q' => [0x0E, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0D],
'R' => [0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11],
'S' => [0x0E, 0x11, 0x10, 0x0E, 0x01, 0x11, 0x0E],
'T' => [0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04],
'U' => [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E],
'V' => [0x11, 0x11, 0x11, 0x11, 0x0A, 0x0A, 0x04],
'W' => [0x11, 0x11, 0x11, 0x15, 0x15, 0x1B, 0x11],
'X' => [0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11],
'Y' => [0x11, 0x11, 0x0A, 0x04, 0x04, 0x04, 0x04],
'Z' => [0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F],
'[' => [0x0E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0E],
'\\' => [0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00],
']' => [0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E],
'^' => [0x04, 0x0A, 0x11, 0x00, 0x00, 0x00, 0x00],
'_' => [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F],
'`' => [0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00],
'a' => [0x08, 0x04, 0x0E, 0x01, 0x0F, 0x11, 0x0F],
'b' => [0x18, 0x10, 0x1E, 0x11, 0x11, 0x11, 0x1E],
'c' => [0x00, 0x00, 0x0E, 0x11, 0x10, 0x11, 0x0E],
'd' => [0x03, 0x01, 0x0F, 0x11, 0x11, 0x11, 0x0F],
'e' => [0x00, 0x00, 0x0E, 0x11, 0x1F, 0x10, 0x0E],
'f' => [0x03, 0x04, 0x08, 0x1E, 0x08, 0x08, 0x08],
'g' => [0x00, 0x0F, 0x11, 0x11, 0x0F, 0x01, 0x0E],
'h' => [0x18, 0x10, 0x1E, 0x11, 0x11, 0x11, 0x11],
'i' => [0x00, 0x0C, 0x00, 0x0E, 0x04, 0x04, 0x0E],
'j' => [0x00, 0x06, 0x00, 0x06, 0x02, 0x12, 0x0C],
'k' => [0x10, 0x10, 0x12, 0x14, 0x18, 0x14, 0x12],
'l' => [0x06, 0x0C, 0x04, 0x04, 0x04, 0x0C, 0x06],
'm' => [0x00, 0x00, 0x1A, 0x15, 0x15, 0x15, 0x15],
'n' => [0x00, 0x00, 0x1E, 0x11, 0x11, 0x11, 0x11],
'o' => [0x00, 0x00, 0x0E, 0x11, 0x11, 0x11, 0x0E],
'p' => [0x00, 0x00, 0x1E, 0x11, 0x11, 0x1E, 0x10],
'q' => [0x00, 0x00, 0x0F, 0x11, 0x11, 0x0F, 0x01],
'r' => [0x00, 0x00, 0x16, 0x19, 0x10, 0x10, 0x10],
's' => [0x00, 0x00, 0x0E, 0x10, 0x0E, 0x01, 0x0E],
't' => [0x08, 0x08, 0x1E, 0x08, 0x08, 0x08, 0x06],
'u' => [0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x0F],
'v' => [0x00, 0x00, 0x11, 0x11, 0x11, 0x0A, 0x04],
'w' => [0x00, 0x00, 0x11, 0x11, 0x15, 0x15, 0x0A],
'x' => [0x00, 0x00, 0x11, 0x0A, 0x04, 0x0A, 0x11],
'y' => [0x00, 0x00, 0x11, 0x11, 0x0F, 0x01, 0x0E],
'z' => [0x00, 0x00, 0x1F, 0x02, 0x04, 0x08, 0x1F],
'{' => [0x02, 0x04, 0x04, 0x08, 0x04, 0x04, 0x02],
'|' => [0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04],
'}' => [0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08],
'~' => [0x00, 0x00, 0x08, 0x15, 0x02, 0x00, 0x00],
_ => return None,
})
}
pub fn glyph_to_pixels(data: &GlyphData) -> [[bool; FONT_WIDTH]; FONT_HEIGHT] {
let mut pixels = [[false; FONT_WIDTH]; FONT_HEIGHT];
for y in 0..FONT_HEIGHT {
for x in 0..FONT_WIDTH {
pixels[y][x] = (data[y] >> (FONT_WIDTH - 1 - x)) & 1 == 1;
}
}
pixels
}
pub fn supported_chars() -> &'static [char] {
&[
' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
':', ';', '<', '=', '>', '?', '@',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'[', '\\', ']', '^', '_', '`',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'{', '|', '}', '~',
]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn all_supported_chars_have_glyphs() {
for &c in supported_chars() {
assert!(glyph(c).is_some(), "missing glyph for '{}'", c);
}
}
#[test]
fn glyph_pixel_roundtrip() {
let data = glyph('A').unwrap();
let pixels = glyph_to_pixels(&data);
assert_eq!(pixels[0], [false, true, true, true, false]);
assert_eq!(pixels[3], [true, true, true, true, true]);
}
#[test]
fn space_is_all_zeros() {
let data = glyph(' ').unwrap();
assert!(data.iter().all(|&b| b == 0));
}
#[test]
fn unsupported_char_returns_none() {
assert!(glyph('á').is_none());
assert!(glyph('中').is_none());
}
}