Issue
use rayon::prelude::*;
use image::RgbImage;
#[inline]
fn lerp(pct: f32, a: f32, b: f32) -> f32 {
pct.mul_add(b - a, a)
}
#[inline]
fn distance(x: i32, y: i32) -> f32 {
((x * x + y * y) as f32).sqrt()
}
struct ColorCalculator {
from: [f32; 3],
to: [f32; 3],
center_x: i32,
center_y: i32,
max_dist: f32,
}
impl ColorCalculator {
fn new(from: [u8; 3], to: [u8; 3], width: u32, height: u32) -> Self {
let center_x = width as i32 / 2;
let center_y = height as i32 / 2;
Self {
from: from.map(|channel| channel as f32),
to: to.map(|channel| channel as f32),
center_x,
center_y,
max_dist: distance(center_x, center_y),
}
}
fn calculate(&self, x: u32, y: u32) -> [u8; 3] {
let x_dist = self.center_x - x as i32;
let y_dist = self.center_y - y as i32;
let t = distance(x_dist, y_dist) / self.max_dist;
}
}
pub fn radial_gradient_mirror(
geometry: [u32; 2],
inner_color: [u8; 3],
outer_color: [u8; 3],
) -> RgbImage {
let [width, height] = geometry;
let color_calculator = ColorCalculator::new(inner_color, outer_color, geometry[0], geometry[1]);
let mut buf: Vec<_> = (0..(height / 2))
.into_par_iter()
.flat_map(|y| {
let mut row: Vec<[u8; 3]> = Vec::with_capacity(width as usize);
for x in 0..(width / 2) {
row.push(color_calculator.calculate(x, y))
}
row.extend(row.clone().iter().rev());
row
})
.collect();
buf.extend(buf.clone().iter().rev());
let buf = buf.into_iter().flatten().collect();
RgbImage::from_raw(width, height, buf).unwrap()
}
I have an algorithm to generate a radial gradient. The original version would calculate the color of each pixel but because there is a horizontal and vertical line of symmetry I can calculate the colors for the top left corner and use some vector manipulation to mirror. I managed to do this by cloning and reversing the iterator buf.clone().iter().rev()
although this is slow. How can I avoid this and are there any other optimizations I could use?
Solution
You do not really need to populate the buffer as later you override it, you can use direct chained iterators for doing so (copied
is used to to have owned values), original buff will be droped at the end of the scope:
let i1 = buf.iter().copied();
let i2 = buf.iter().copied().rev();
let buf = i1.chain(i2).flatten().collect();
Full method:
pub fn radial_gradient_mirror(
geometry: [u32; 2],
inner_color: [u8; 3],
outer_color: [u8; 3],
) -> RgbImage {
let [width, height] = geometry;
let color_calculator = ColorCalculator::new(inner_color, outer_color, geometry[0], geometry[1]);
let mut buf: Vec<_> = (0..(height / 2))
.into_par_iter()
.flat_map(|y| {
let mut row: Vec<[u8; 3]> = Vec::with_capacity(width as usize);
for x in 0..(width / 2) {
row.push(color_calculator.calculate(x, y))
}
row.extend(row.clone().iter().rev());
row
})
.collect();
let i1 = buf.iter().copied();
let i2 = buf.iter().copied().rev();
let buf = i1.chain(i2).flatten().collect();
RgbImage::from_raw(width, height, buf).unwrap()
}
Answered By - Netwave Answer Checked By - Robin (PHPFixing Admin)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.