#[cfg(feature = "parallel")]
use rayon::ThreadPool;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
use crate::config::{Config, Quality};
use crate::convert::{CHANNELS, convert_image, validate_and_compute_grid_size};
use crate::error::ImageError;
use crate::grid::Grid;
use crate::sampling::Sampler;
#[cfg(feature = "parallel")]
const CELL_CHUNK: usize = 512;
#[cfg(feature = "parallel")]
pub fn convert_with_pool(
width: u32,
height: u32,
buf: &[u8],
config: &Config,
pool: Option<&ThreadPool>,
) -> Result<Grid, ImageError> {
let (grid_width, grid_height) = validate_and_compute_grid_size(width, height, buf, config)?;
let Some(pool) = pool else {
return convert_image(width, height, buf, config);
};
let total_cells = grid_width as usize * grid_height as usize;
if total_cells < config.parallel_threshold {
return convert_image(width, height, buf, config);
}
let mut grid = Grid::new(grid_width, grid_height);
let ramp_chars: Vec<char> = config.ramp.inner().as_str().chars().collect();
let sampler = Sampler::new(
buf,
width,
height,
CHANNELS,
grid_width,
grid_height,
config,
&ramp_chars,
);
let row_width = grid_width as usize;
pool.install(|| {
if matches!(config.quality, Quality::Best) {
grid.as_mut_slice()
.par_chunks_mut(row_width)
.enumerate()
.for_each(|(row_idx, row_cells)| sampler.fill_row(row_idx as u32, row_cells));
} else {
grid.as_mut_slice()
.par_chunks_mut(CELL_CHUNK)
.enumerate()
.for_each(|(chunk_idx, chunk)| {
let start = chunk_idx * CELL_CHUNK;
let mut row = (start / row_width) as u32;
let mut col = (start % row_width) as u32;
let (mut y_start, mut y_end) = sampler.row_geometry(row);
let mut diffusion_error = 0.0f32;
for cell in chunk.iter_mut() {
*cell = sampler.cell(col, y_start, y_end, &mut diffusion_error);
col += 1;
if col as usize == row_width {
col = 0;
row += 1;
if row < grid_height {
let geom = sampler.row_geometry(row);
y_start = geom.0;
y_end = geom.1;
}
}
}
});
}
});
Ok(grid)
}