mod canvas; mod ops; mod pixel; mod pixfn; pub mod polar_math; pub use canvas::*; pub use pixel::*; pub use pixfn::*; use crate::ops::{ ImgSynArea, ImgSynAxial, ImgSynMap, ImgSynMapArea, ImgSynPolar, ImgSynRect, ImgSynStretched, ImgSynUnmapRect, }; pub trait ImgSynPixFn: Clone { fn run(&self, meta: Canvas, x: f64, y: f64, pixel: Pixel) -> T; } pub trait ImgSyn: Clone { fn getpx(&self, meta: Canvas, x: f64, y: f64) -> Pixel; fn map>(self, f: F) -> ImgSynMap { ImgSynMap(self, f) } fn area, ImgB: ImgSyn, F: FnOnce(Self) -> ImgB>( self, condition: C, f: F, ) -> ImgSynArea { ImgSynArea(self.clone(), f(self), condition) } fn mapped_rect) -> ImgB>( self, begin_x: f64, begin_y: f64, size_x: f64, size_y: f64, f: F, ) -> ImgSynRect { let rect = (begin_x, begin_y, size_x, size_y); ImgSynRect(self.clone(), f(ImgSynUnmapRect(self, rect)), rect) } fn add_image( self, begin_x: f64, begin_y: f64, size_x: f64, size_y: f64, img: ImgB, ) -> ImgSynRect { let rect = (begin_x, begin_y, size_x, size_y); ImgSynRect(self, img, rect) } fn map_area, F: ImgSynPixFn>( self, condition: C, f: F, ) -> ImgSynMapArea { ImgSynMapArea(self, condition, f) } /// Makes future operations work on polar coordinates when terminated by .axial() /// /// **MUST** be used before a subsequent .axial() fn polar(self) -> ImgSynAxial { ImgSynAxial(self) } /// Makes future operations work on axial coordinates when .polar() was used previously /// /// **MUST** be used after .polar() fn axial(self) -> ImgSynPolar { ImgSynPolar(self) } fn stretched_by(self, x: f64, y: f64) -> ImgSynStretched { ImgSynStretched(self, (x, y)) } fn paint(self, meta: Canvas) -> PaintedCanvas { PaintedCanvas::new(meta, self) } fn rgba255(self, meta: Canvas) -> Vec { let painted = self.paint(meta); PaintedCanvas::rgba255(&painted) } #[cfg(feature = "png")] fn png(self, meta: Canvas) -> Vec { let painted = self.paint(meta); let mut data = Vec::new(); { let mut encoder = png::Encoder::new(&mut data, meta.width as u32, meta.height as u32); encoder.set_color(png::ColorType::Rgba); encoder.set_depth(png::BitDepth::Eight); let mut writer = encoder.write_header().unwrap(); writer.write_image_data(&painted.rgba255(meta)).unwrap(); writer.finish().unwrap(); } data } } #[cfg(test)] mod test { use std::{fs, hint::black_box}; use crate::{Canvas, ImgSyn, PixFnFloat, Pixel, polar_math::distance_from_circle}; #[test] fn test() { let canvas = Canvas::new(1000., 1000., Pixel::new_black()); fs::write( "test.png", canvas .polar() .map(|_, y: f64, pix: Pixel| pix.with_r((y - 0.5).abs() * 2.)) .map(|_, y, pix: Pixel| pix.with_b(y)) .axial() .map(PixFnFloat(|_, _, y, pix| pix.with_g(y))) .map_area( PixFnFloat(|_, x, y, _| x < 0.2 && y < 0.2), PixFnFloat(|_, _, _, pix| pix.with_g(1.0)), ) .area(PixFnFloat(|_, _, _, px| px.g > 0.8 && px.r < 0.3), |img| { img.polar() .map(PixFnFloat(|_, x, _, pix| pix.with_r(x).with_b(0.0))) .axial() }) .mapped_rect(0.3, 0.3, 0.4, 0.4, |img| { img.map(PixFnFloat(|_, x, y, px| { let thickness = 0.01; if !(thickness..=1. - thickness).contains(&x) || !(thickness..=1. - thickness).contains(&y) { return Pixel::new_white(); } px })) }) .paint(canvas) .png(canvas), ) .unwrap(); } #[test] fn graph() { let canvas = Canvas::new(1000., 1000., Pixel::new_white()); fs::write( "graph.png", canvas .add_image( 0.07, 0.03, 0.9, 0.9, Canvas::new(900., 900., Pixel::new_black()).map_area( |x, y, _| distance_from_circle(x, y, 1.0, 0.0, 0.5, 1.0, 1.0) > 0.0, |x, y, px: Pixel| px.with_r(x).with_g(1. - y), ), ) .map_area( |x, y, _| { let xc = 0.07; let yc = 0.93; let t = 0.003; (xc - t..=xc + t).contains(&x) && y >= 0.03 || (yc - t..=yc + t).contains(&y) && x <= 0.97 }, |x, y, px: Pixel| { if (1. + x - y) % 0.03 <= 0.02 { px.with_rgb(1.0, 0.0, 0.5) } else { px.with_rgb(1.0, 1.0, 0.0) } }, ) .mapped_rect(0.02, 0.93, 0.05, 0.05, |img| { img.map_area( |x: f64, y: f64, _| { distance_from_circle(x, y, 0.6, 0.5, 0.2, 1.0, 1.4).abs() < 0.03 }, |_, _, px: Pixel| px.with_rgb_of(0.0), ) }) .paint(canvas) .png(canvas), ) .unwrap(); } #[test] fn speed() { let canvas = Canvas::new(10000., 10000., Pixel::new_white()); black_box( canvas .add_image( 0.07, 0.03, 0.9, 0.9, Canvas::new(9000., 9000., Pixel::new_black()).map_area( |x, y, _| distance_from_circle(x, y, 1.0, 0.0, 0.5, 1.0, 1.0) > 0.0, |x, y, px: Pixel| px.with_r(x).with_g(1. - y), ), ) .map_area( |x, y, _| { let xc = 0.07; let yc = 0.93; let t = 0.003; (xc - t..=xc + t).contains(&x) && y >= 0.03 || (yc - t..=yc + t).contains(&y) && x <= 0.97 }, |x, y, px: Pixel| { if (1. + x - y) % 0.03 <= 0.02 { px.with_rgb(1.0, 0.0, 0.5) } else { px.with_rgb(1.0, 1.0, 0.0) } }, ) .mapped_rect(0.02, 0.93, 0.05, 0.05, |img| { img.map_area( |x: f64, y: f64, _| { distance_from_circle(x, y, 0.6, 0.5, 0.2, 1.0, 1.4).abs() < 0.03 }, |_, _, px: Pixel| px.with_rgb_of(0.0), ) }) .paint(canvas), ); } }