From 7e974d42aeb1897b344e996c1366649ed31c1206 Mon Sep 17 00:00:00 2001 From: TudbuT Date: Mon, 9 Feb 2026 13:17:27 +0100 Subject: [PATCH] Initial commit --- .envrc | 1 + .gitignore | 2 ++ Cargo.lock | 7 +++++ Cargo.toml | 6 +++++ main.rs | 3 +++ shell.nix | 12 +++++++++ src/canvas.rs | 56 ++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 36 ++++++++++++++++++++++++++ src/ops/map.rs | 10 ++++++++ src/ops/mod.rs | 2 ++ src/pixel.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/pixfn.rs | 28 ++++++++++++++++++++ 12 files changed, 232 insertions(+) create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 main.rs create mode 100644 shell.nix create mode 100644 src/canvas.rs create mode 100644 src/lib.rs create mode 100644 src/ops/map.rs create mode 100644 src/ops/mod.rs create mode 100644 src/pixel.rs create mode 100644 src/pixfn.rs diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..1d953f4 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6abfe1b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/.direnv diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..96407fe --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "imgsyn" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3a9694c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "imgsyn" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/main.rs b/main.rs new file mode 100644 index 0000000..58dfaaa --- /dev/null +++ b/main.rs @@ -0,0 +1,3 @@ +fn main() { + +} diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..9457e4f --- /dev/null +++ b/shell.nix @@ -0,0 +1,12 @@ +{ pkgs ? import {} }: +pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + rustfmt + cargo + clippy + rustc + ffmpeg + imagemagick + rust-analyzer + ]; +} diff --git a/src/canvas.rs b/src/canvas.rs new file mode 100644 index 0000000..f099c44 --- /dev/null +++ b/src/canvas.rs @@ -0,0 +1,56 @@ +use crate::{ImgSyn, pixel::Pixel}; + +#[derive(Clone, Copy, PartialEq)] +pub struct Canvas { + pub width: u32, + pub height: u32, + pub default_px: Pixel, +} + +#[derive(Clone, PartialEq)] +pub struct PaintedCanvas { + pub meta: Canvas, + pub array: Vec>, +} + +impl Canvas { + pub fn new(width: u32, height: u32, default_px: Pixel) -> Self { + Self { + width, + height, + default_px, + } + } +} + +impl ImgSyn for Canvas { + fn getpx(&self, _meta: Canvas, _x: f32, _y: f32) -> Pixel { + self.default_px + } +} + +impl PaintedCanvas { + pub fn new(meta @ Canvas { width, height, .. }: Canvas, function: impl ImgSyn) -> Self { + Self { + meta, + array: (0..width) + .map(|x| x as f32 / width as f32) + .map(|x| { + (0..height) + .map(|y| y as f32 / height as f32) + .map(|y| function.getpx(meta, x, y)) + .collect() + }) + .collect(), + } + } +} + +impl ImgSyn for PaintedCanvas { + fn getpx(&self, meta: Canvas, x: f32, y: f32) -> Pixel { + // float coords -> int coords + let x = (x * meta.width as f32).round() as usize; + let y = (y * meta.height as f32).round() as usize; + self.array[x][y] + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..23cee6b --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,36 @@ +mod canvas; +pub mod ops; +mod pixel; +mod pixfn; + +pub use canvas::*; +pub use pixel::*; +pub use pixfn::*; + +use crate::ops::ImgSynMap; + +pub trait ImgSynPixFn: Clone { + fn run(&self, meta: Canvas, x: f32, y: f32, pixel: Pixel) -> Pixel; +} + +pub trait ImgSyn: Clone { + fn getpx(&self, meta: Canvas, x: f32, y: f32) -> Pixel; + fn map(self, f: F) -> ImgSynMap { + ImgSynMap(self, f) + } + fn paint(self, meta: Canvas) -> PaintedCanvas { + PaintedCanvas::new(meta, self) + } +} + +#[cfg(test)] +mod test { + use crate::{Canvas, ImgSyn, PixFnFloat, Pixel}; + + #[test] + fn test() { + Canvas::new(100, 100, Pixel::new_black()) + .map(PixFnFloat(|_, x, y, pix| pix.with_r(x).with_g(y))) + .map(PixFnFloat(|_, _, _, pix| pix.with_b(1.0))); + } +} diff --git a/src/ops/map.rs b/src/ops/map.rs new file mode 100644 index 0000000..5f1399f --- /dev/null +++ b/src/ops/map.rs @@ -0,0 +1,10 @@ +use crate::{ImgSyn, ImgSynPixFn}; + +#[derive(Clone, Copy)] +pub struct ImgSynMap(pub(crate) Prev, pub(crate) F); + +impl ImgSyn for ImgSynMap { + fn getpx(&self, meta: crate::Canvas, x: f32, y: f32) -> crate::Pixel { + self.1.run(meta, x, y, self.0.getpx(meta, x, y)) + } +} diff --git a/src/ops/mod.rs b/src/ops/mod.rs new file mode 100644 index 0000000..aa2efd9 --- /dev/null +++ b/src/ops/mod.rs @@ -0,0 +1,2 @@ +mod map; +pub use map::*; diff --git a/src/pixel.rs b/src/pixel.rs new file mode 100644 index 0000000..cb35b9e --- /dev/null +++ b/src/pixel.rs @@ -0,0 +1,69 @@ +#[derive(Clone, Copy, PartialEq)] +pub struct Pixel { + r: f32, + g: f32, + b: f32, + a: f32, +} + +impl Pixel { + pub fn new_blank_black() -> Pixel { + Self::new_black().with_a(0.0) + } + + pub fn new_blank_white() -> Pixel { + Self::new_white().with_a(0.0) + } + + pub fn new_white() -> Pixel { + Self { + r: 1.0, + g: 1.0, + b: 1.0, + a: 1.0, + } + } + + pub fn new_black() -> Pixel { + Self { + r: 0.0, + g: 0.0, + b: 0.0, + a: 1.0, + } + } + + pub fn with_r(self, x: f32) -> Pixel { + Self { r: x, ..self } + } + pub fn with_g(self, x: f32) -> Pixel { + Self { g: x, ..self } + } + pub fn with_b(self, x: f32) -> Pixel { + Self { b: x, ..self } + } + pub fn with_a(self, x: f32) -> Pixel { + Self { a: x, ..self } + } + + pub fn map(self, f: impl FnOnce(Self) -> Pixel) -> Pixel { + f(self) + } + + pub fn map_r(mut self, f: impl FnOnce(f32) -> f32) -> Pixel { + self.r = f(self.r); + self + } + pub fn map_g(mut self, f: impl FnOnce(f32) -> f32) -> Pixel { + self.r = f(self.r); + self + } + pub fn map_b(mut self, f: impl FnOnce(f32) -> f32) -> Pixel { + self.r = f(self.r); + self + } + pub fn map_a(mut self, f: impl FnOnce(f32) -> f32) -> Pixel { + self.r = f(self.r); + self + } +} diff --git a/src/pixfn.rs b/src/pixfn.rs new file mode 100644 index 0000000..8381d3a --- /dev/null +++ b/src/pixfn.rs @@ -0,0 +1,28 @@ +use crate::{Canvas, ImgSynPixFn, Pixel}; + +#[derive(Clone, Copy)] +pub struct PixFnInt Pixel) + Copy>(pub T); +impl ImgSynPixFn for PixFnInt +where + T: (Fn(Canvas, u32, u32, Pixel) -> Pixel) + Copy, +{ + fn run(&self, meta: Canvas, x: f32, y: f32, pixel: Pixel) -> Pixel { + self.0( + meta, + (x * meta.width as f32).round() as u32, + (y * meta.height as f32).round() as u32, + pixel, + ) + } +} + +#[derive(Clone, Copy)] +pub struct PixFnFloat Pixel) + Copy>(pub T); +impl ImgSynPixFn for PixFnFloat +where + T: (Fn(Canvas, f32, f32, Pixel) -> Pixel) + Copy, +{ + fn run(&self, meta: Canvas, x: f32, y: f32, pixel: Pixel) -> Pixel { + self.0(meta, x, y, pixel) + } +}