use crate::{convert_to_rgba_f32, ImageView};
pub(crate) fn for_each_f32_rgba_rows<E>(
image: ImageView,
block_height: usize,
mut f: impl FnMut(&mut [[f32; 4]]) -> Result<(), E>,
) -> Result<(), E> {
debug_assert!(block_height != 0);
let color = image.color();
let width = image.width() as usize;
let height = image.height() as usize;
let mut intermediate_buffer = vec![[0_f32; 4]; width * block_height];
let mut rows = image.rows();
let full_blocks = height / block_height;
for _ in 0..full_blocks {
for i in 0..block_height {
convert_to_rgba_f32(
color,
rows.next().expect("Image has too few rows"),
&mut intermediate_buffer[i * width..(i + 1) * width],
);
}
f(intermediate_buffer.as_mut_slice())?;
}
let rest_blocks = height % block_height;
if rest_blocks > 0 {
for i in 0..rest_blocks {
convert_to_rgba_f32(
color,
rows.next().expect("Image has too few rows"),
&mut intermediate_buffer[i * width..(i + 1) * width],
);
}
debug_assert!(rows.next().is_none());
for i in rest_blocks..block_height {
intermediate_buffer.copy_within(..width, i * width);
}
f(intermediate_buffer.as_mut_slice())?;
}
Ok(())
}
pub(crate) fn for_each_chunk<T, E>(
image: ImageView,
buffer: &mut [T],
buffer_elements_per_pixel: usize,
mut copy_to_buffer: impl FnMut(&[u8], &mut [T]),
mut process_chunk: impl FnMut(&mut [T]) -> Result<(), E>,
) -> Result<(), E> {
let buffer_pixels = buffer.len() / buffer_elements_per_pixel;
let buffer = &mut buffer[..buffer_pixels * buffer_elements_per_pixel];
let bytes_per_pixel = image.color().bytes_per_pixel() as usize;
if image.is_contiguous() {
for chunk in image.data().chunks(buffer_pixels * bytes_per_pixel) {
let pixels = chunk.len() / bytes_per_pixel;
let chunk_buffer = &mut buffer[..pixels * buffer_elements_per_pixel];
copy_to_buffer(chunk, chunk_buffer);
process_chunk(chunk_buffer)?;
}
} else {
let mut fill_pixels = 0;
for mut row in image.rows() {
while !row.is_empty() {
if fill_pixels == buffer_pixels {
process_chunk(buffer)?;
fill_pixels = 0;
}
debug_assert!(row.len() % bytes_per_pixel == 0);
let row_pixels = row.len() / bytes_per_pixel;
let write_pixels = row_pixels.min(buffer_pixels - fill_pixels);
copy_to_buffer(
&row[..write_pixels * bytes_per_pixel],
&mut buffer[fill_pixels * buffer_elements_per_pixel
..(fill_pixels + write_pixels) * buffer_elements_per_pixel],
);
fill_pixels += write_pixels;
row = &row[write_pixels * bytes_per_pixel..];
}
}
if fill_pixels > 0 {
process_chunk(&mut buffer[..fill_pixels * buffer_elements_per_pixel])?;
}
}
Ok(())
}