use image::{Rgb, RgbImage};
use std::collections::HashMap;
pub fn draw_simple_text(
image: &mut RgbImage,
text: &str,
start_x: u32,
start_y: u32,
color: Rgb<u8>,
) {
let font_map = get_simple_font_map();
let mut x_offset = 0;
for ch in text.chars() {
if let Some(bitmap) = font_map.get(&ch) {
draw_character(image, bitmap, start_x + x_offset, start_y, color);
x_offset += 6; } else {
draw_character(
image,
&UNKNOWN_CHAR_BITMAP,
start_x + x_offset,
start_y,
color,
);
x_offset += 6;
}
}
}
pub fn draw_character(
image: &mut RgbImage,
bitmap: &[u8; 7], start_x: u32,
start_y: u32,
color: Rgb<u8>,
) {
for (y, &row) in bitmap.iter().enumerate() {
for x in 0..5 {
if (row >> (4 - x)) & 1 == 1 {
let pixel_x = start_x + x as u32;
let pixel_y = start_y + y as u32;
if pixel_x < image.width() && pixel_y < image.height() {
image.put_pixel(pixel_x, pixel_y, color);
}
}
}
}
}
pub fn get_simple_font_map() -> HashMap<char, [u8; 7]> {
let mut map = HashMap::new();
map.insert(
'A',
[
0b01110, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b00000,
],
);
map.insert(
'B',
[
0b11110, 0b10001, 0b11110, 0b11110, 0b10001, 0b11110, 0b00000,
],
);
map.insert(
'C',
[
0b01111, 0b10000, 0b10000, 0b10000, 0b10000, 0b01111, 0b00000,
],
);
map.insert(
'D',
[
0b11110, 0b10001, 0b10001, 0b10001, 0b10001, 0b11110, 0b00000,
],
);
map.insert(
'E',
[
0b11111, 0b10000, 0b11110, 0b11110, 0b10000, 0b11111, 0b00000,
],
);
map.insert(
'F',
[
0b11111, 0b10000, 0b11110, 0b11110, 0b10000, 0b10000, 0b00000,
],
);
map.insert(
'G',
[
0b01111, 0b10000, 0b10011, 0b10001, 0b10001, 0b01111, 0b00000,
],
);
map.insert(
'H',
[
0b10001, 0b10001, 0b11111, 0b11111, 0b10001, 0b10001, 0b00000,
],
);
map.insert(
'I',
[
0b11111, 0b00100, 0b00100, 0b00100, 0b00100, 0b11111, 0b00000,
],
);
map.insert(
'J',
[
0b11111, 0b00001, 0b00001, 0b00001, 0b10001, 0b01110, 0b00000,
],
);
map.insert(
'K',
[
0b10001, 0b10010, 0b11100, 0b11100, 0b10010, 0b10001, 0b00000,
],
);
map.insert(
'L',
[
0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b11111, 0b00000,
],
);
map.insert(
'M',
[
0b10001, 0b11011, 0b10101, 0b10001, 0b10001, 0b10001, 0b00000,
],
);
map.insert(
'N',
[
0b10001, 0b11001, 0b10101, 0b10011, 0b10001, 0b10001, 0b00000,
],
);
map.insert(
'O',
[
0b01110, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110, 0b00000,
],
);
map.insert(
'P',
[
0b11110, 0b10001, 0b11110, 0b10000, 0b10000, 0b10000, 0b00000,
],
);
map.insert(
'Q',
[
0b01110, 0b10001, 0b10001, 0b10101, 0b10010, 0b01101, 0b00000,
],
);
map.insert(
'R',
[
0b11110, 0b10001, 0b11110, 0b10100, 0b10010, 0b10001, 0b00000,
],
);
map.insert(
'S',
[
0b01111, 0b10000, 0b01110, 0b00001, 0b00001, 0b11110, 0b00000,
],
);
map.insert(
'T',
[
0b11111, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00000,
],
);
map.insert(
'U',
[
0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110, 0b00000,
],
);
map.insert(
'V',
[
0b10001, 0b10001, 0b10001, 0b01010, 0b01010, 0b00100, 0b00000,
],
);
map.insert(
'W',
[
0b10001, 0b10001, 0b10001, 0b10101, 0b11011, 0b10001, 0b00000,
],
);
map.insert(
'X',
[
0b10001, 0b01010, 0b00100, 0b00100, 0b01010, 0b10001, 0b00000,
],
);
map.insert(
'Y',
[
0b10001, 0b01010, 0b00100, 0b00100, 0b00100, 0b00100, 0b00000,
],
);
map.insert(
'Z',
[
0b11111, 0b00010, 0b00100, 0b01000, 0b10000, 0b11111, 0b00000,
],
);
map.insert(
'0',
[
0b01110, 0b10001, 0b10011, 0b10101, 0b11001, 0b01110, 0b00000,
],
);
map.insert(
'1',
[
0b00100, 0b01100, 0b00100, 0b00100, 0b00100, 0b01110, 0b00000,
],
);
map.insert(
'2',
[
0b01110, 0b10001, 0b00010, 0b00100, 0b01000, 0b11111, 0b00000,
],
);
map.insert(
'3',
[
0b01110, 0b10001, 0b00110, 0b00110, 0b10001, 0b01110, 0b00000,
],
);
map.insert(
'4',
[
0b00010, 0b00110, 0b01010, 0b11111, 0b00010, 0b00010, 0b00000,
],
);
map.insert(
'5',
[
0b11111, 0b10000, 0b11110, 0b00001, 0b10001, 0b01110, 0b00000,
],
);
map.insert(
'6',
[
0b01110, 0b10000, 0b11110, 0b10001, 0b10001, 0b01110, 0b00000,
],
);
map.insert(
'7',
[
0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b10000, 0b00000,
],
);
map.insert(
'8',
[
0b01110, 0b10001, 0b01110, 0b01110, 0b10001, 0b01110, 0b00000,
],
);
map.insert(
'9',
[
0b01110, 0b10001, 0b01111, 0b00001, 0b00001, 0b01110, 0b00000,
],
);
map.insert(
' ',
[
0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000,
],
);
map.insert(
'.',
[
0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00100, 0b00000,
],
);
map.insert(
',',
[
0b00000, 0b00000, 0b00000, 0b00000, 0b00100, 0b01000, 0b00000,
],
);
map.insert(
':',
[
0b00000, 0b00100, 0b00000, 0b00000, 0b00100, 0b00000, 0b00000,
],
);
map.insert(
'-',
[
0b00000, 0b00000, 0b11111, 0b00000, 0b00000, 0b00000, 0b00000,
],
);
map
}
pub const UNKNOWN_CHAR_BITMAP: [u8; 7] = [
0b01110, 0b10001, 0b00010, 0b00100, 0b00000, 0b00100, 0b00000,
];
pub fn calculate_text_width(text: &str) -> u32 {
if text.is_empty() {
return 0;
}
(text.chars().count() as u32 * 6).saturating_sub(1)
}
pub fn calculate_text_height() -> u32 {
7 }
pub fn is_character_supported(ch: char) -> bool {
let font_map = get_simple_font_map();
font_map.contains_key(&ch)
}
pub fn draw_text_with_background(
image: &mut RgbImage,
text: &str,
start_x: u32,
start_y: u32,
text_color: Rgb<u8>,
bg_color: Option<Rgb<u8>>,
padding: u32,
) {
if let Some(bg) = bg_color {
let text_width = calculate_text_width(text);
let text_height = calculate_text_height();
let bg_x = start_x.saturating_sub(padding);
let bg_y = start_y.saturating_sub(padding);
let bg_width = text_width + 2 * padding;
let bg_height = text_height + 2 * padding;
for y in bg_y..=(bg_y + bg_height).min(image.height() - 1) {
for x in bg_x..=(bg_x + bg_width).min(image.width() - 1) {
image.put_pixel(x, y, bg);
}
}
}
draw_simple_text(image, text, start_x, start_y, text_color);
}
#[cfg(test)]
mod tests {
use super::*;
use image::{Rgb, RgbImage};
#[test]
fn test_character_support() {
assert!(is_character_supported('A'));
assert!(is_character_supported('Z'));
assert!(is_character_supported('0'));
assert!(is_character_supported('9'));
assert!(is_character_supported(' '));
assert!(is_character_supported('.'));
assert!(!is_character_supported('@'));
assert!(!is_character_supported('a')); }
#[test]
fn test_text_width_calculation() {
assert_eq!(calculate_text_width(""), 0);
assert_eq!(calculate_text_width("A"), 5);
assert_eq!(calculate_text_width("AB"), 11); assert_eq!(calculate_text_width("ABC"), 17); }
#[test]
fn test_text_height() {
assert_eq!(calculate_text_height(), 7);
}
#[test]
fn test_draw_simple_text() {
let mut image = RgbImage::new(50, 20);
let white = Rgb([255, 255, 255]);
draw_simple_text(&mut image, "ABC", 0, 0, white);
draw_simple_text(&mut image, "123", 0, 10, white);
}
#[test]
fn test_draw_character() {
let mut image = RgbImage::new(10, 10);
let red = Rgb([255, 0, 0]);
let test_bitmap = [
0b11111, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b11111,
];
draw_character(&mut image, &test_bitmap, 0, 0, red);
}
#[test]
fn test_unknown_character() {
let mut image = RgbImage::new(20, 10);
let blue = Rgb([0, 0, 255]);
draw_simple_text(&mut image, "@#$", 0, 0, blue);
}
#[test]
fn test_text_with_background() {
let mut image = RgbImage::new(100, 30);
let white = Rgb([255, 255, 255]);
let black = Rgb([0, 0, 0]);
draw_text_with_background(&mut image, "TEST", 10, 10, white, Some(black), 2);
draw_text_with_background(&mut image, "NO BG", 10, 20, white, None, 0);
}
}