scaled rainbow
This commit is contained in:
parent
6d22aa0065
commit
8155efe2e8
1 changed files with 70 additions and 33 deletions
91
src/main.rs
91
src/main.rs
|
@ -1,4 +1,7 @@
|
|||
use std::{collections::HashMap, env};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
env,
|
||||
};
|
||||
|
||||
use hsl::HSL;
|
||||
use image::{GenericImage, GenericImageView, Pixel, Rgb, Rgba};
|
||||
|
@ -11,56 +14,78 @@ fn main() {
|
|||
let in_path = args.next().expect("i need a PATH. now!");
|
||||
let start_x = args
|
||||
.next()
|
||||
.and_then(|n| n.parse::<i32>().ok())
|
||||
.and_then(|n| n.parse::<u32>().ok())
|
||||
.expect("start x");
|
||||
let start_y = args
|
||||
.next()
|
||||
.and_then(|n| n.parse::<i32>().ok())
|
||||
.and_then(|n| n.parse::<u32>().ok())
|
||||
.expect("start y");
|
||||
let out_path = args.next().expect("out path");
|
||||
|
||||
let mut img = image::open(in_path).expect("i wanna open an image");
|
||||
|
||||
// let's just hsl-rotate floodfill first
|
||||
let mut covered = HashMap::new();
|
||||
covered.insert((start_x, start_y), HSL::from_rgb(&[255, 0, 0]));
|
||||
// get length of path, find covered
|
||||
// jk we can't precompute covered
|
||||
let mut covered: HashSet<(u32, u32)> = HashSet::new();
|
||||
let mut front = HashSet::new();
|
||||
front.insert((start_x, start_y));
|
||||
let mut step: u32 = 0;
|
||||
|
||||
// TODO: hold front and covered. duh
|
||||
// scale based on longest path (ez)
|
||||
loop {
|
||||
let mut front = HashMap::new();
|
||||
for ((x, y), hsl) in &covered {
|
||||
for (dx, dy) in (-1..=1).cartesian_product(-1..=1) {
|
||||
let (x, y) = (x + dx, y + dy);
|
||||
let Ok(x_idx) = x.try_into() else {
|
||||
break;
|
||||
};
|
||||
let Ok(y_idx) = y.try_into() else {
|
||||
break;
|
||||
};
|
||||
let mut new_front = HashSet::new();
|
||||
for (x, y) in &front {
|
||||
for (x, y) in adjacent(*x, *y) {
|
||||
if img.in_bounds(x, y)
|
||||
&& !is_dark(img.get_pixel(x, y).to_rgb())
|
||||
&& !covered.contains(&(x, y))
|
||||
{
|
||||
new_front.insert((x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if img.in_bounds(x_idx, y_idx)
|
||||
&& !is_dark(img.get_pixel(x_idx, y_idx).to_rgb())
|
||||
&& !covered.contains_key(&(x, y))
|
||||
if new_front.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
covered.extend(new_front.iter());
|
||||
front = new_front;
|
||||
step += 1;
|
||||
}
|
||||
|
||||
// color :D
|
||||
let change_per_step = 360. / f64::from(step).max(1.);
|
||||
|
||||
let mut covered: HashSet<(u32, u32)> = HashSet::new();
|
||||
let mut front = HashMap::new();
|
||||
front.insert((start_x, start_y), HSL::from_rgb(&[255, 0, 0]));
|
||||
loop {
|
||||
let mut new_front = HashMap::new();
|
||||
for ((x, y), hsl) in &front {
|
||||
for (x, y) in adjacent(*x, *y) {
|
||||
if img.in_bounds(x, y)
|
||||
&& !is_dark(img.get_pixel(x, y).to_rgb())
|
||||
&& !covered.contains(&(x, y))
|
||||
{
|
||||
let mut color = *hsl;
|
||||
color.h += 1.;
|
||||
color.h += change_per_step;
|
||||
if color.h >= 360. {
|
||||
color.h = 0.;
|
||||
}
|
||||
|
||||
let (r, g, b) = color.to_rgb();
|
||||
|
||||
img.put_pixel(x_idx, y_idx, Rgba([r, g, b, 255]));
|
||||
front.insert((x, y), color);
|
||||
new_front.insert((x, y), color);
|
||||
img.put_pixel(x, y, Rgba([r, g, b, 255]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if front.is_empty() {
|
||||
if new_front.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
covered.extend(front);
|
||||
covered.extend(new_front.keys());
|
||||
front = new_front;
|
||||
}
|
||||
|
||||
img.save(out_path).expect("tried to save :(");
|
||||
|
@ -70,3 +95,15 @@ fn is_dark(pixel: Rgb<u8>) -> bool {
|
|||
let Rgb([r, g, b]) = pixel;
|
||||
r < 127 && g < 127 && b < 127
|
||||
}
|
||||
|
||||
fn adjacent(x: u32, y: u32) -> impl Iterator<Item = (u32, u32)> {
|
||||
(-1..=1)
|
||||
.cartesian_product(-1..=1)
|
||||
.filter_map(move |(dx, dy): (i32, i32)| {
|
||||
if (dx == -1 && x == 0) || (dy == -1 && y == 0) {
|
||||
None
|
||||
} else {
|
||||
Some(((x as i32 + dx) as u32, (y as i32 + dy) as u32))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue