diff --git a/t/src/canvas/_draw.rs b/t/src/canvas/_draw.rs new file mode 100644 index 0000000..a53e863 --- /dev/null +++ b/t/src/canvas/_draw.rs @@ -0,0 +1,132 @@ +use std::cmp::min; +use eframe::egui; +use eframe::egui::Color32; +use image::{GenericImage, Pixel, Rgb, Rgba}; +use rusttype::{point, Font, Scale}; +use crate::canvas::Canvas; + +impl Canvas { + + pub fn text_center( + &mut self, + font: &Font, + color: egui::Color32, + x: f32, + y: f32, + text: &str, + scale: Scale, + ) { + self.refresh(); + + let v_metrics = font.v_metrics(scale); + + let glyphs: Vec<_> = font + .layout(text, scale, point(0.0, 0.0 + v_metrics.ascent)) + .collect(); + + let (width, height) = { + let mut min_x = i32::MAX; + let mut min_y = i32::MAX; + let mut max_x = i32::MIN; + let mut max_y = i32::MIN; + + for g in glyphs.iter() + .map(|p|p.pixel_bounding_box()) + .flatten() { + min_x = min_x.min(g.min.x); + min_y = min_y.min(g.min.y); + max_x = max_x.max(g.max.x); + max_y = max_y.max(g.max.y); + // self.debug_rect( + // Color32::GREEN, + // g.min.x as _, + // g.min.y as _, + // g.max.x as _, + // g.max.y as _, + // ); + } + + // self.debug_rect( + // Color32::PURPLE, + // min_x as _, min_y as _, + // max_x as _, max_y as _); + ((max_x/* - min_x*/) as f32, + (max_y/* - min_y*/) as f32) + }; + let (x, y) = ( + x - (width / 2.0), + y - (height / 2.0) + ); + + // self.debug_rect(Color32::RED, x, y, x + width, y + height); + + let glyphs: Vec<_> = font + .layout(text, scale, point(x, y + v_metrics.ascent)) + .collect(); + + for glyph in glyphs { + if let Some(bounding_box) = glyph.pixel_bounding_box() { + + // self.debug_rect( + // Color32::RED, + // bounding_box.min.x as _, + // bounding_box.min.y as _, + // bounding_box.max.x as _, + // bounding_box.max.y as _); + + glyph.draw(|x, y, v| { + let p = self.image.get_pixel_mut( + x + bounding_box.min.x as u32, + y + bounding_box.min.y as u32, + ); + + let mut op = p.to_rgba(); + let np = Rgba([ + color.r(), + color.g(), + color.b(), + (color.a() as f32 * v) as u8 + ]); + op.blend(&np); + *p = op.to_rgb() + }); + } + } + + } + + fn debug_rect( + &mut self, + color: Color32, + mnx: f32, + mny: f32, + mxx: f32, + mxy: f32, + ) { + self.refresh(); + + // sort the values just in case + let (mnx, mxx) = (mnx.min(mxx), mxx.max(mxx)); + let (mny, mxy) = (mny.min(mxy), mxy.max(mxy)); + + let rgb = Rgb([ + color.r(), + color.g(), + color.b(), + ]); + + let w = (mxx - mnx) as u32; + let h = (mxy - mny) as u32; + for w in 0..w { + self.image.put_pixel(mnx as u32 + w, mny as u32, rgb); + self.image.put_pixel(mnx as u32 + w, mxy as u32, rgb); + self.image.put_pixel(mnx as u32 + w, mny as u32 + h, rgb); + + } + for h in 0..h { + self.image.put_pixel(mnx as u32, mny as u32 + h, rgb); + self.image.put_pixel(mxx as u32, mny as u32 + h, rgb); + } + } + +} \ No newline at end of file diff --git a/t/src/canvas/mod.rs b/t/src/canvas/mod.rs new file mode 100644 index 0000000..bd596c0 --- /dev/null +++ b/t/src/canvas/mod.rs @@ -0,0 +1,52 @@ +use std::path::Path; +use std::sync::Arc; +use eframe::egui::{Color32, ColorImage, Context, ImageData, TextureHandle, TextureOptions}; +use eframe::egui::load::SizedTexture; +use image::{RgbImage}; + +mod _draw; + + +#[derive(Clone)] +pub struct Canvas { + image: RgbImage, + handle: Option, +} + +impl Canvas { + + pub fn new(path: impl AsRef) -> Self { + Self { + image: image::open(path) + .unwrap() + .to_rgb8(), + handle: None, + } + } + + pub fn rgba(&self) -> &RgbImage { &self.image } + pub fn rgba_mut(&mut self) -> &RgbImage { &mut self.image } + + pub fn image(&mut self, ctx: &Context) -> SizedTexture { + let handle = self.handle.get_or_insert_with(|| { + let img = ColorImage::new( + [self.image.width() as _, self.image.height() as _], + self.image + .pixels() + .map(|a| Color32::from_rgb(a.0[0], a.0[1], a.0[2])) + .collect(), + ); + ctx.load_texture( + "_temp", + ImageData::Color(Arc::new(img)), + TextureOptions::LINEAR + ) + }); + SizedTexture::new(handle.id(), handle.size_vec2()) + } + + pub fn refresh(&mut self) { + self.handle = None + } + +} diff --git a/t/src/cells.rs b/t/src/cells.rs new file mode 100644 index 0000000..4a559d5 --- /dev/null +++ b/t/src/cells.rs @@ -0,0 +1,38 @@ + +const CELLS_START_X: i32 = 30; +const CELLS_START_Y: i32 = 25; +const CELLS: (i32, i32) = (20, 4); + +// 255 * 72 +// +// cells are 18x18 +// 20 x 4 cells + +pub struct Cells { + cells: Vec +} + +impl Cells { + pub(crate) fn new() -> Self { + + let mut cells = Vec::new(); + + for x in 0..CELLS.0 { + for y in 0..CELLS.1 { + cells.push(Cell { + desired_value: 0.0, + x: CELLS_START_X + (x * 18), + y: CELLS_START_Y + (y * 18), + }) + } + } + + Cells { cells, } + } +} + +pub struct Cell { + desired_value: f32, + x: i32, + y: i32, +} diff --git a/t/src/main.rs b/t/src/main.rs new file mode 100644 index 0000000..f1081b7 --- /dev/null +++ b/t/src/main.rs @@ -0,0 +1,67 @@ +use eframe::egui::{Color32, Vec2, Widget}; +use eframe::{NativeOptions, egui}; +use rusttype::Scale; +use crate::canvas::Canvas; + +mod canvas; +mod cells; + +fn main() { + let mut blank = Canvas::new("targets/blank.png"); + let mut target = Canvas::new("targets/target.png"); + let mut test = Canvas::new("targets/test.png"); + + // dbg start + use rusttype::{Font}; + + let mut test2 = test.clone(); + let font = Font::try_from_vec(std::fs::read("targets/arial.ttf").unwrap()).unwrap(); + + let mut scale = 59.5; + let mut ox = 3.0; + let mut oy = -2.0; + + let mut once = true; + // dbg end + + let cells = cells::Cells::new(); + + eframe::run_simple_native( + "jessie was here", + NativeOptions { + window_builder: Some(Box::new(|w| { + w.with_inner_size(Vec2::new(600.0,800.0)) + })), + ..Default::default() + }, + move |ctx, _frame| { + + egui::CentralPanel::default().show(&ctx, |ui| { + + ui.image(blank.image(&ctx)); + ui.image(target.image(&ctx)); + ui.image(test.image(&ctx)); + ui.image(test2.image(&ctx)); + + let c = once + | egui::Slider::new(&mut scale, 30.0..=80.0).ui(ui).changed() + | egui::Slider::new(&mut ox, -30.0..=30.0).ui(ui).changed() + | egui::Slider::new(&mut oy, -30.0..=30.0).ui(ui).changed(); + + if c { + once = false; + test2 = blank.clone(); + test2.text_center( + &font, + Color32::BLACK, + 205.0 + ox, 58.0 + oy, + "CCBXFQ7X", + Scale::uniform(scale) + ); + } + + }); + }, + ) + .unwrap(); +} diff --git a/t/targets/arial.ttf b/t/targets/arial.ttf new file mode 100644 index 0000000..8682d94 Binary files /dev/null and b/t/targets/arial.ttf differ diff --git a/t/targets/arialmt.ttf b/t/targets/arialmt.ttf new file mode 100644 index 0000000..952ef44 Binary files /dev/null and b/t/targets/arialmt.ttf differ diff --git a/t/targets/blank.png b/t/targets/blank.png new file mode 100644 index 0000000..fe4b3e5 Binary files /dev/null and b/t/targets/blank.png differ diff --git a/t/targets/target.png b/t/targets/target.png new file mode 100644 index 0000000..8079e50 Binary files /dev/null and b/t/targets/target.png differ diff --git a/t/targets/test.png b/t/targets/test.png new file mode 100644 index 0000000..74c3ed9 Binary files /dev/null and b/t/targets/test.png differ