just to want to add, the reason I'm guessing you are translating code from other languages, is the non idiomatic way how you use iterator to iterate through columns, yet you use an outer for
loop iterate through the rows. mis-use iterators is a common mistake for new rustaceans.
just for your reference, there's an enumerate_pixels()
iterator for Image
, you can use it like so:
// totally unnecessary, see `lerp_rgba()`
#![feature(array_zip)]
use image::{Rgba, RgbaImage};
fn dist_sqr(x1: f32, y1: f32, x2: f32, y2: f32) -> f32 {
(x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)
}
fn red_circle(cx: f32, cy: f32, r: f32) -> RgbaImage {
let mut image = RgbaImage::new(1 + 2 * cx as u32, 1 + 2 * cy as u32);
let r_sqr = r * r;
for (x, y, pixel) in image.enumerate_pixels_mut() {
let dist_sqr = dist_sqr(x as f32, y as f32, cx, cy);
if dist_sqr <= r_sqr {
*pixel = Rgba([255, 0, 0, 255]);
} else {
*pixel = Rgba([0; 4]);
}
}
image
}
if you want a gradient instead of a solid color, just do an interpolation (with an easing function if you want be fancy)
fn lerp(t: f32, a: f32, b: f32) -> f32 {
(1.0 - t) * a + t * b
}
fn lerp_rgba(t: f32, a: Rgba<u8>, b: Rgba<u8>) -> Rgba<u8> {
// `array_zip` need nightly toolchain, you can manually unroll the loop anyway
Rgba(a.0.zip(b.0).map(|(a, b)| lerp(t, a as f32, b as f32) as u8))
}
fn fancy_circle(cx: f32, cy: f32, r: f32, easing: impl Fn(f32) -> f32) -> RgbaImage {
let mut image = RgbaImage::new(1 + 2 * cx as u32, 1 + 2 * cy as u32);
let r_sqr = r * r;
for (x, y, pixel) in image.enumerate_pixels_mut() {
let dist_sqr = dist_sqr(x as f32, y as f32, cx, cy);
if dist_sqr <= r_sqr {
*pixel = lerp_rgba(
easing(dist_sqr / r_sqr),
Rgba([255, 0, 0, 255]), // center color
Rgba([0; 4]), // edge color
);
} else {
*pixel = Rgba([0; 4]);
}
}
image
}
fn main() {
fancy_circle(200, 200, 100, std::convert::identity).save("circle1.png").unwrap();
fancy_circle(200, 200, 100, |x| x * x).save("circle2.png").unwrap();
}