This commit is contained in:
2025-07-18 16:36:13 +02:00
parent 33f577718e
commit bd3cc2e612
2 changed files with 49 additions and 39 deletions

View File

@@ -6,9 +6,11 @@ use std::thread;
use std::sync::mpsc::{self, Receiver, Sender};
use hound::{WavSpec, WavWriter, SampleFormat};
use image::{Rgba, RgbaImage};
use rusttype::{Font, Scale, point};
// Simple 8x8 bitmap font implementation
mod builtin_font {
use image::{Rgba, RgbaImage};
// Each character is 8 bytes (8x8 pixels)
const FONT_DATA: &[u8] = include_bytes!("../font8x8_basic.bin");
@@ -18,9 +20,10 @@ mod builtin_font {
y: u32,
text: &str,
color: Rgba<u8>,
scale: u32, // scale factor for font size
) {
let char_width = 8;
let char_height = 8;
let char_width = 8u32;
let char_height = 8u32;
for (i, c) in text.chars().enumerate() {
let char_index = c as usize;
@@ -28,15 +31,21 @@ mod builtin_font {
continue;
}
let font_data = &FONT_DATA[char_index * char_width..(char_index + 1) * char_width];
let font_data = &FONT_DATA[char_index * char_width as usize..(char_index + 1) * char_width as usize];
for row in 0..char_height {
for col in 0..char_width {
if font_data[row as usize] & (1 << (7 - col)) != 0 {
let px = x + (i as u32 * char_width) + col;
let py = y + row;
if px < image.width() && py < image.height() {
image.put_pixel(px, py, color);
let px = x + (i as u32 * char_width * scale) + col * scale;
let py = y + row * scale;
for dx in 0..scale {
for dy in 0..scale {
let fx = px + dx;
let fy = py + dy;
if fx < image.width() && fy < image.height() {
image.put_pixel(fx, fy, color);
}
}
}
}
}
@@ -169,6 +178,38 @@ impl Robot36EncoderApp {
}
}
fn draw_callsign_with_rusttype(image: &mut RgbaImage, text: &str) {
// Path to a common system font found on this system
let font_data = std::fs::read("/usr/share/fonts/TTF/VictorMonoNerdFont-Thin.ttf")
.expect("Failed to load system font");
let font = Font::try_from_vec(font_data).expect("Error constructing Font");
let scale = Scale::uniform(32.0); // Adjust size as needed
let start = point(5.0, 32.0); // x, y baseline
let color = Rgba([0u8, 0u8, 0u8, 255u8]);
// Draw each glyph
let v_metrics = font.v_metrics(scale);
let glyphs: Vec<_> = font.layout(text, scale, start).collect();
for glyph in glyphs {
if let Some(bb) = glyph.pixel_bounding_box() {
glyph.draw(|gx, gy, gv| {
let x = gx as i32 + bb.min.x;
let y = gy as i32 + bb.min.y;
if x >= 0 && y >= 0 && (x as u32) < image.width() && (y as u32) < image.height() {
let alpha = (gv * 255.0) as u8;
let pixel = image.get_pixel_mut(x as u32, y as u32);
*pixel = Rgba([
color[0],
color[1],
color[2],
alpha,
]);
}
});
}
}
}
fn encode_image_impl(
input_path: PathBuf,
output_path: PathBuf,
@@ -184,22 +225,7 @@ impl Robot36EncoderApp {
// Add callsign overlay if provided
if !callsign.is_empty() {
// Draw black background for text
for y in 0..16 {
for x in 0..(callsign.len() as u32 * 8).min(image.width()) {
if x < image.width() && y < image.height() {
image.put_pixel(x, y, Rgba([0u8, 0u8, 0u8, 200u8]));
}
}
}
// Draw text
builtin_font::draw_text(
&mut image,
5, 5, // x, y position
&callsign,
Rgba([255u8, 255u8, 255u8, 255u8]), // white text
);
Self::draw_callsign_with_rusttype(&mut image, &callsign);
}
// Calculate target size while maintaining aspect ratio