some basic operations
This commit is contained in:
parent
7e974d42ae
commit
4285b7a966
14 changed files with 468 additions and 39 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
|||
/target
|
||||
/.direnv
|
||||
*.png
|
||||
|
|
|
|||
78
Cargo.lock
generated
78
Cargo.lock
generated
|
|
@ -2,6 +2,84 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fdeflate"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
|
||||
dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imgsyn"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"png",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
|
||||
|
|
|
|||
|
|
@ -4,3 +4,4 @@ version = "0.1.0"
|
|||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
png = "0.18.0"
|
||||
|
|
|
|||
|
|
@ -8,5 +8,6 @@ pkgs.mkShell {
|
|||
ffmpeg
|
||||
imagemagick
|
||||
rust-analyzer
|
||||
cargo-watch
|
||||
];
|
||||
}
|
||||
|
|
|
|||
25
src/assist.rs
Normal file
25
src/assist.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use std::f32::consts::*;
|
||||
|
||||
use crate::Canvas;
|
||||
|
||||
pub fn polar(x: f32, y: f32, meta: Canvas) -> (f32, f32) {
|
||||
let x = x - 0.5;
|
||||
let y = y - 0.5;
|
||||
let r = (x * x + y * y).sqrt();
|
||||
let mut phi = f32::atan2(y, x) + PI / 2.;
|
||||
phi = phi.rem_euclid(TAU);
|
||||
(r * 2. / corner_distance(meta), phi / TAU)
|
||||
}
|
||||
|
||||
pub fn axial(r: f32, phi: f32, meta: Canvas) -> (f32, f32) {
|
||||
let phi = phi * TAU - PI / 2.;
|
||||
let r = r / 2. * corner_distance(meta);
|
||||
let x = r * phi.cos();
|
||||
let y = r * phi.sin();
|
||||
(x + 0.5, y + 0.5)
|
||||
}
|
||||
|
||||
fn corner_distance(meta: Canvas) -> f32 {
|
||||
let corner_distance = (meta.width * meta.width + meta.height * meta.height).sqrt();
|
||||
corner_distance / meta.width.max(meta.height)
|
||||
}
|
||||
|
|
@ -2,19 +2,18 @@ use crate::{ImgSyn, pixel::Pixel};
|
|||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub struct Canvas {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub width: f32,
|
||||
pub height: f32,
|
||||
pub default_px: Pixel,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct PaintedCanvas {
|
||||
pub meta: Canvas,
|
||||
pub array: Vec<Vec<Pixel>>,
|
||||
}
|
||||
|
||||
impl Canvas {
|
||||
pub fn new(width: u32, height: u32, default_px: Pixel) -> Self {
|
||||
pub fn new(width: f32, height: f32, default_px: Pixel) -> Self {
|
||||
Self {
|
||||
width,
|
||||
height,
|
||||
|
|
@ -32,25 +31,34 @@ impl ImgSyn for Canvas {
|
|||
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))
|
||||
array: (0..height as u32)
|
||||
.map(|y| y as f32 / height)
|
||||
.map(|y| {
|
||||
(0..width as u32)
|
||||
.map(|x| x as f32 / width)
|
||||
.map(|x| function.getpx(meta, x, y))
|
||||
.collect()
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rgba255(&self) -> Vec<u8> {
|
||||
self.array
|
||||
.iter()
|
||||
.flat_map(|row| row.iter().flat_map(|pix| pix.rgba255()))
|
||||
.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]
|
||||
let x = (x * meta.width).round() as usize;
|
||||
let y = (y * meta.height).round() as usize;
|
||||
self.array[y][x]
|
||||
}
|
||||
fn paint(self, _meta: Canvas) -> PaintedCanvas {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
|||
158
src/lib.rs
158
src/lib.rs
|
|
@ -1,5 +1,6 @@
|
|||
pub mod assist;
|
||||
mod canvas;
|
||||
pub mod ops;
|
||||
mod ops;
|
||||
mod pixel;
|
||||
mod pixfn;
|
||||
|
||||
|
|
@ -7,30 +8,171 @@ pub use canvas::*;
|
|||
pub use pixel::*;
|
||||
pub use pixfn::*;
|
||||
|
||||
use crate::ops::ImgSynMap;
|
||||
use crate::ops::{
|
||||
ImgSynArea, ImgSynAxial, ImgSynMap, ImgSynMapArea, ImgSynPolar, ImgSynRect, ImgSynStretched,
|
||||
ImgSynUnmapRect,
|
||||
};
|
||||
|
||||
pub trait ImgSynPixFn: Clone {
|
||||
fn run(&self, meta: Canvas, x: f32, y: f32, pixel: Pixel) -> Pixel;
|
||||
pub trait ImgSynPixFn<T>: Clone {
|
||||
fn run(&self, meta: Canvas, x: f32, y: f32, pixel: Pixel) -> T;
|
||||
}
|
||||
|
||||
pub trait ImgSyn: Clone {
|
||||
fn getpx(&self, meta: Canvas, x: f32, y: f32) -> Pixel;
|
||||
fn map<F: ImgSynPixFn>(self, f: F) -> ImgSynMap<Self, F> {
|
||||
fn map<F: ImgSynPixFn<Pixel>>(self, f: F) -> ImgSynMap<Self, F> {
|
||||
ImgSynMap(self, f)
|
||||
}
|
||||
fn area<C: ImgSynPixFn<bool>, ImgB: ImgSyn, F: FnOnce(Self) -> ImgB>(
|
||||
self,
|
||||
condition: C,
|
||||
f: F,
|
||||
) -> ImgSynArea<Self, ImgB, C> {
|
||||
ImgSynArea(self.clone(), f(self), condition)
|
||||
}
|
||||
fn mapped_rect<ImgB: ImgSyn, F: FnOnce(ImgSynUnmapRect<Self>) -> ImgB>(
|
||||
self,
|
||||
begin_x: f32,
|
||||
begin_y: f32,
|
||||
size_x: f32,
|
||||
size_y: f32,
|
||||
f: F,
|
||||
) -> ImgSynRect<Self, ImgB> {
|
||||
let rect = (begin_x, begin_y, size_x, size_y);
|
||||
ImgSynRect(self.clone(), f(ImgSynUnmapRect(self, rect)), rect)
|
||||
}
|
||||
fn add_image<ImgB: ImgSyn>(
|
||||
self,
|
||||
begin_x: f32,
|
||||
begin_y: f32,
|
||||
size_x: f32,
|
||||
size_y: f32,
|
||||
img: ImgB,
|
||||
) -> ImgSynRect<Self, ImgB> {
|
||||
let rect = (begin_x, begin_y, size_x, size_y);
|
||||
ImgSynRect(self, img, rect)
|
||||
}
|
||||
fn map_area<C: ImgSynPixFn<bool>, F: ImgSynPixFn<Pixel>>(
|
||||
self,
|
||||
condition: C,
|
||||
f: F,
|
||||
) -> ImgSynMapArea<Self, C, F> {
|
||||
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<Self> {
|
||||
ImgSynAxial(self)
|
||||
}
|
||||
/// Makes future operations work on axial coordinates when .polar() was used previously
|
||||
///
|
||||
/// **MUST** be used after .polar()
|
||||
fn axial(self) -> ImgSynPolar<Self> {
|
||||
ImgSynPolar(self)
|
||||
}
|
||||
fn stretched_by(self, x: f32, y: f32) -> ImgSynStretched<Self> {
|
||||
ImgSynStretched(self, (x, y))
|
||||
}
|
||||
fn paint(self, meta: Canvas) -> PaintedCanvas {
|
||||
PaintedCanvas::new(meta, self)
|
||||
}
|
||||
fn rgba255(self, meta: Canvas) -> Vec<u8> {
|
||||
let painted = self.paint(meta);
|
||||
PaintedCanvas::rgba255(&painted)
|
||||
}
|
||||
fn png(self, meta: Canvas) -> Vec<u8> {
|
||||
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;
|
||||
|
||||
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)));
|
||||
let canvas = Canvas::new(1000., 1000., Pixel::new_black());
|
||||
fs::write(
|
||||
"test.png",
|
||||
canvas
|
||||
.polar()
|
||||
.map(|_, y: f32, 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, y, pix| pix.with_r(x).with_b(1. - y)))
|
||||
.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.1,
|
||||
0.0,
|
||||
0.9,
|
||||
0.9,
|
||||
Canvas::new(900., 900., Pixel::new_black()).map_area(
|
||||
|x, y, _| x < 0.7 || y > 0.3,
|
||||
|x, y, px: Pixel| px.with_r(x).with_g(1. - y),
|
||||
),
|
||||
)
|
||||
.map_area(
|
||||
|x, y, _| {
|
||||
let t = 0.004;
|
||||
(0.1 - t..0.1 + t).contains(&x) || (0.9 - t..0.9 + t).contains(&y)
|
||||
},
|
||||
|_, _, px: Pixel| px.with_rgb(1.0, 0.0, 0.0),
|
||||
)
|
||||
.mapped_rect(0.05, 0.90, 0.05, 0.05, |img| {
|
||||
img.polar()
|
||||
.map_area(
|
||||
|r: f32, phi, _| (r - 0.3).abs() < 0.04,
|
||||
|_, _, px: Pixel| px.with_rgb_of(0.0),
|
||||
)
|
||||
.axial()
|
||||
.stretched_by(1.0, 1.5)
|
||||
})
|
||||
.paint(canvas)
|
||||
.png(canvas),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
91
src/ops/area.rs
Normal file
91
src/ops/area.rs
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
use crate::{Canvas, ImgSyn, ImgSynPixFn, Pixel};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ImgSynMapArea<Prev: ImgSyn, C: ImgSynPixFn<bool>, F: ImgSynPixFn<Pixel>>(
|
||||
pub(crate) Prev,
|
||||
pub(crate) C,
|
||||
pub(crate) F,
|
||||
);
|
||||
|
||||
impl<Prev, C, F> ImgSyn for ImgSynMapArea<Prev, C, F>
|
||||
where
|
||||
Prev: ImgSyn,
|
||||
C: ImgSynPixFn<bool>,
|
||||
F: ImgSynPixFn<Pixel>,
|
||||
{
|
||||
fn getpx(&self, meta: Canvas, x: f32, y: f32) -> crate::Pixel {
|
||||
let px = self.0.getpx(meta, x, y);
|
||||
if !self.1.run(meta, x, y, px) {
|
||||
return px;
|
||||
}
|
||||
self.2.run(meta, x, y, px)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ImgSynArea<Prev: ImgSyn, ImgB: ImgSyn, C: ImgSynPixFn<bool>>(
|
||||
pub(crate) Prev,
|
||||
pub(crate) ImgB,
|
||||
pub(crate) C,
|
||||
);
|
||||
|
||||
impl<Prev, ImgB, C> ImgSyn for ImgSynArea<Prev, ImgB, C>
|
||||
where
|
||||
Prev: ImgSyn,
|
||||
ImgB: ImgSyn,
|
||||
C: ImgSynPixFn<bool>,
|
||||
{
|
||||
fn getpx(&self, meta: Canvas, x: f32, y: f32) -> crate::Pixel {
|
||||
let px = self.0.getpx(meta, x, y);
|
||||
if !self.2.run(meta, x, y, px) {
|
||||
return px;
|
||||
}
|
||||
self.1.getpx(meta, x, y)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ImgSynRect<Prev: ImgSyn, ImgB: ImgSyn>(
|
||||
pub(crate) Prev,
|
||||
pub(crate) ImgB,
|
||||
pub(crate) (f32, f32, f32, f32),
|
||||
);
|
||||
|
||||
impl<Prev, ImgB> ImgSyn for ImgSynRect<Prev, ImgB>
|
||||
where
|
||||
Prev: ImgSyn,
|
||||
ImgB: ImgSyn,
|
||||
{
|
||||
fn getpx(&self, meta: Canvas, x: f32, y: f32) -> crate::Pixel {
|
||||
let px = self.0.getpx(meta, x, y);
|
||||
let (startx, starty, sizex, sizey) = self.2;
|
||||
if x < startx || y < starty {
|
||||
return px;
|
||||
}
|
||||
if x - startx >= sizex || y - starty >= sizey {
|
||||
return px;
|
||||
}
|
||||
self.1.getpx(
|
||||
Canvas::new(sizex * meta.width, sizey * meta.height, meta.default_px),
|
||||
(x - startx) / sizex,
|
||||
(y - starty) / sizey,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ImgSynUnmapRect<Prev: ImgSyn>(pub(crate) Prev, pub(crate) (f32, f32, f32, f32));
|
||||
|
||||
impl<Prev> ImgSyn for ImgSynUnmapRect<Prev>
|
||||
where
|
||||
Prev: ImgSyn,
|
||||
{
|
||||
fn getpx(&self, meta: Canvas, x: f32, y: f32) -> crate::Pixel {
|
||||
let (startx, starty, sizex, sizey) = self.1;
|
||||
self.0.getpx(
|
||||
Canvas::new(meta.width / sizex, meta.height / sizey, meta.default_px),
|
||||
x * sizex + startx,
|
||||
y * sizey + starty,
|
||||
)
|
||||
}
|
||||
}
|
||||
29
src/ops/axial.rs
Normal file
29
src/ops/axial.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use crate::{
|
||||
Canvas, ImgSyn,
|
||||
assist::{axial, polar},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ImgSynAxial<Prev: ImgSyn>(pub(crate) Prev);
|
||||
|
||||
impl<Prev> ImgSyn for ImgSynAxial<Prev>
|
||||
where
|
||||
Prev: ImgSyn,
|
||||
{
|
||||
fn getpx(&self, meta: Canvas, x: f32, y: f32) -> crate::Pixel {
|
||||
let (x, y) = axial(x, y, meta);
|
||||
self.0.getpx(meta, x, y)
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ImgSynPolar<Prev: ImgSyn>(pub(crate) Prev);
|
||||
|
||||
impl<Prev> ImgSyn for ImgSynPolar<Prev>
|
||||
where
|
||||
Prev: ImgSyn,
|
||||
{
|
||||
fn getpx(&self, meta: Canvas, x: f32, y: f32) -> crate::Pixel {
|
||||
let (x, y) = polar(x, y, meta);
|
||||
self.0.getpx(meta, x, y)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
use crate::{ImgSyn, ImgSynPixFn};
|
||||
use crate::{ImgSyn, ImgSynPixFn, Pixel};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ImgSynMap<Prev: ImgSyn, F: ImgSynPixFn>(pub(crate) Prev, pub(crate) F);
|
||||
pub struct ImgSynMap<Prev: ImgSyn, F: ImgSynPixFn<Pixel>>(pub(crate) Prev, pub(crate) F);
|
||||
|
||||
impl<Prev: ImgSyn, F: ImgSynPixFn> ImgSyn for ImgSynMap<Prev, F> {
|
||||
impl<Prev: ImgSyn, F: ImgSynPixFn<Pixel>> ImgSyn for ImgSynMap<Prev, F> {
|
||||
fn getpx(&self, meta: crate::Canvas, x: f32, y: f32) -> crate::Pixel {
|
||||
self.1.run(meta, x, y, self.0.getpx(meta, x, y))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,8 @@
|
|||
mod map;
|
||||
pub use map::*;
|
||||
mod area;
|
||||
pub use area::*;
|
||||
mod axial;
|
||||
pub use axial::*;
|
||||
mod stretch;
|
||||
pub use stretch::*;
|
||||
|
|
|
|||
14
src/ops/stretch.rs
Normal file
14
src/ops/stretch.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
use crate::ImgSyn;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ImgSynStretched<Prev: ImgSyn>(pub(crate) Prev, pub(crate) (f32, f32));
|
||||
|
||||
impl<Prev: ImgSyn> ImgSyn for ImgSynStretched<Prev> {
|
||||
fn getpx(&self, meta: crate::Canvas, x: f32, y: f32) -> crate::Pixel {
|
||||
self.0.getpx(
|
||||
meta,
|
||||
x / self.1.0 - 0.5 / self.1.0 + 0.5,
|
||||
y / self.1.1 - 0.5 / self.1.1 + 0.5,
|
||||
)
|
||||
}
|
||||
}
|
||||
32
src/pixel.rs
32
src/pixel.rs
|
|
@ -1,9 +1,9 @@
|
|||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub struct Pixel {
|
||||
r: f32,
|
||||
g: f32,
|
||||
b: f32,
|
||||
a: f32,
|
||||
pub r: f32,
|
||||
pub g: f32,
|
||||
pub b: f32,
|
||||
pub a: f32,
|
||||
}
|
||||
|
||||
impl Pixel {
|
||||
|
|
@ -33,6 +33,10 @@ impl Pixel {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn of(r: f32, g: f32, b: f32, a: f32) -> Pixel {
|
||||
Self { r, g, b, a }
|
||||
}
|
||||
|
||||
pub fn with_r(self, x: f32) -> Pixel {
|
||||
Self { r: x, ..self }
|
||||
}
|
||||
|
|
@ -45,6 +49,17 @@ impl Pixel {
|
|||
pub fn with_a(self, x: f32) -> Pixel {
|
||||
Self { a: x, ..self }
|
||||
}
|
||||
pub fn with_rgb(self, r: f32, g: f32, b: f32) -> Pixel {
|
||||
Self { r, g, b, ..self }
|
||||
}
|
||||
pub fn with_rgb_of(self, x: f32) -> Pixel {
|
||||
Self {
|
||||
r: x,
|
||||
g: x,
|
||||
b: x,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map(self, f: impl FnOnce(Self) -> Pixel) -> Pixel {
|
||||
f(self)
|
||||
|
|
@ -66,4 +81,13 @@ impl Pixel {
|
|||
self.r = f(self.r);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rgba255(self) -> [u8; 4] {
|
||||
[
|
||||
(self.r.clamp(0.0, 1.0) * 255.) as u8,
|
||||
(self.g.clamp(0.0, 1.0) * 255.) as u8,
|
||||
(self.b.clamp(0.0, 1.0) * 255.) as u8,
|
||||
(self.a.clamp(0.0, 1.0) * 255.) as u8,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
29
src/pixfn.rs
29
src/pixfn.rs
|
|
@ -1,28 +1,37 @@
|
|||
use crate::{Canvas, ImgSynPixFn, Pixel};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct PixFnInt<T: (Fn(Canvas, u32, u32, Pixel) -> Pixel) + Copy>(pub T);
|
||||
impl<T> ImgSynPixFn for PixFnInt<T>
|
||||
pub struct PixFnInt<T: Clone + Copy, F: (Fn(Canvas, u32, u32, Pixel) -> T) + Copy>(pub F);
|
||||
impl<T: Clone + Copy, F> ImgSynPixFn<T> for PixFnInt<T, F>
|
||||
where
|
||||
T: (Fn(Canvas, u32, u32, Pixel) -> Pixel) + Copy,
|
||||
F: (Fn(Canvas, u32, u32, Pixel) -> T) + Copy,
|
||||
{
|
||||
fn run(&self, meta: Canvas, x: f32, y: f32, pixel: Pixel) -> Pixel {
|
||||
fn run(&self, meta: Canvas, x: f32, y: f32, pixel: Pixel) -> T {
|
||||
self.0(
|
||||
meta,
|
||||
(x * meta.width as f32).round() as u32,
|
||||
(y * meta.height as f32).round() as u32,
|
||||
(x * meta.width).round() as u32,
|
||||
(y * meta.height).round() as u32,
|
||||
pixel,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct PixFnFloat<T: (Fn(Canvas, f32, f32, Pixel) -> Pixel) + Copy>(pub T);
|
||||
impl<T> ImgSynPixFn for PixFnFloat<T>
|
||||
pub struct PixFnFloat<T: Clone + Copy, F: (Fn(Canvas, f32, f32, Pixel) -> T) + Copy>(pub F);
|
||||
impl<T: Clone + Copy, F> ImgSynPixFn<T> for PixFnFloat<T, F>
|
||||
where
|
||||
T: (Fn(Canvas, f32, f32, Pixel) -> Pixel) + Copy,
|
||||
F: (Fn(Canvas, f32, f32, Pixel) -> T) + Copy,
|
||||
{
|
||||
fn run(&self, meta: Canvas, x: f32, y: f32, pixel: Pixel) -> Pixel {
|
||||
fn run(&self, meta: Canvas, x: f32, y: f32, pixel: Pixel) -> T {
|
||||
self.0(meta, x, y, pixel)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Copy, F> ImgSynPixFn<T> for F
|
||||
where
|
||||
F: (Fn(f32, f32, Pixel) -> T) + Copy,
|
||||
{
|
||||
fn run(&self, _meta: Canvas, x: f32, y: f32, px: Pixel) -> T {
|
||||
self(x, y, px)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue