fuk #1
@@ -1,16 +0,0 @@
|
|||||||
00000000 00 00 00 00 00 00 00 00 18 18 18 18 18 00 18 00
|
|
||||||
00000010 6c 6c 6c 00 00 00 00 00 6c 6c fe 6c fe 6c 6c 00
|
|
||||||
00000020 18 3e 60 3c 06 7c 18 00 00 c6 cc 18 30 66 c6 00
|
|
||||||
00000030 38 6c 38 76 dc cc 76 00 18 18 30 00 00 00 00 00
|
|
||||||
00000040 0c 18 30 30 30 18 0c 00 30 18 0c 0c 0c 18 30 00
|
|
||||||
00000050 00 66 3c ff 3c 66 00 00 00 18 18 7e 18 18 00 00
|
|
||||||
00000060 00 00 00 00 18 18 30 00 00 00 00 7e 00 00 00 00
|
|
||||||
00000070 00 00 00 00 00 18 18 00 06 0c 18 30 60 c0 80 00
|
|
||||||
00000080 38 6c c6 c6 c6 6c 38 00 18 38 18 18 18 18 7e 00
|
|
||||||
00000090 7c c6 06 1c 30 66 fe 00 7c c6 06 3c 06 c6 7c 00
|
|
||||||
000000a0 1c 3c 6c cc fe 0c 1e 00 fe c0 fc 06 06 c6 7c 00
|
|
||||||
000000b0 38 60 c0 fc c6 c6 7c 00 fe c6 0c 18 30 30 30 00
|
|
||||||
000000c0 7c c6 c6 7c c6 c6 7c 00 7c c6 c6 7e 06 0c 78 00
|
|
||||||
000000d0 00 18 18 00 00 18 18 00 00 18 18 00 00 18 18 30
|
|
||||||
000000e0 0c 18 30 60 30 18 0c 00 00 00 7e 00 7e 00 00 00
|
|
||||||
000000f0 30 18 0c 06 0c 18 30 00 7c c6 0c 18 18 00 18 00
|
|
||||||
72
src/main.rs
72
src/main.rs
@@ -6,9 +6,11 @@ use std::thread;
|
|||||||
use std::sync::mpsc::{self, Receiver, Sender};
|
use std::sync::mpsc::{self, Receiver, Sender};
|
||||||
use hound::{WavSpec, WavWriter, SampleFormat};
|
use hound::{WavSpec, WavWriter, SampleFormat};
|
||||||
use image::{Rgba, RgbaImage};
|
use image::{Rgba, RgbaImage};
|
||||||
|
use rusttype::{Font, Scale, point};
|
||||||
|
|
||||||
// Simple 8x8 bitmap font implementation
|
// Simple 8x8 bitmap font implementation
|
||||||
mod builtin_font {
|
mod builtin_font {
|
||||||
|
use image::{Rgba, RgbaImage};
|
||||||
// Each character is 8 bytes (8x8 pixels)
|
// Each character is 8 bytes (8x8 pixels)
|
||||||
const FONT_DATA: &[u8] = include_bytes!("../font8x8_basic.bin");
|
const FONT_DATA: &[u8] = include_bytes!("../font8x8_basic.bin");
|
||||||
|
|
||||||
@@ -18,9 +20,10 @@ mod builtin_font {
|
|||||||
y: u32,
|
y: u32,
|
||||||
text: &str,
|
text: &str,
|
||||||
color: Rgba<u8>,
|
color: Rgba<u8>,
|
||||||
|
scale: u32, // scale factor for font size
|
||||||
) {
|
) {
|
||||||
let char_width = 8;
|
let char_width = 8u32;
|
||||||
let char_height = 8;
|
let char_height = 8u32;
|
||||||
|
|
||||||
for (i, c) in text.chars().enumerate() {
|
for (i, c) in text.chars().enumerate() {
|
||||||
let char_index = c as usize;
|
let char_index = c as usize;
|
||||||
@@ -28,15 +31,21 @@ mod builtin_font {
|
|||||||
continue;
|
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 row in 0..char_height {
|
||||||
for col in 0..char_width {
|
for col in 0..char_width {
|
||||||
if font_data[row as usize] & (1 << (7 - col)) != 0 {
|
if font_data[row as usize] & (1 << (7 - col)) != 0 {
|
||||||
let px = x + (i as u32 * char_width) + col;
|
let px = x + (i as u32 * char_width * scale) + col * scale;
|
||||||
let py = y + row;
|
let py = y + row * scale;
|
||||||
if px < image.width() && py < image.height() {
|
for dx in 0..scale {
|
||||||
image.put_pixel(px, py, color);
|
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(
|
fn encode_image_impl(
|
||||||
input_path: PathBuf,
|
input_path: PathBuf,
|
||||||
output_path: PathBuf,
|
output_path: PathBuf,
|
||||||
@@ -184,22 +225,7 @@ impl Robot36EncoderApp {
|
|||||||
|
|
||||||
// Add callsign overlay if provided
|
// Add callsign overlay if provided
|
||||||
if !callsign.is_empty() {
|
if !callsign.is_empty() {
|
||||||
// Draw black background for text
|
Self::draw_callsign_with_rusttype(&mut image, &callsign);
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate target size while maintaining aspect ratio
|
// Calculate target size while maintaining aspect ratio
|
||||||
|
|||||||
Reference in New Issue
Block a user