use crate::benchmark::Benchmark;
use crate::blending::{
blend_images, get_blending_algorithm, is_algorithm_multiplied, multiply_image, BlendAlgorithm,
};
use crate::errors::PConvertError;
use crate::parallelism::{ResultMessage, ThreadPool};
use crate::utils::{read_png_from_file, write_png_parallel, write_png_to_file};
use image::codecs::png::{CompressionType, FilterType};
use image::Rgba;
use std::fmt::{Display, Formatter};
use std::{fmt, sync::mpsc::Receiver};
const THREAD_POOL_SIZE: usize = 5;
#[derive(Clone)]
pub enum Background {
Alpha,
White,
Blue,
Texture,
}
impl Display for Background {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Background::Alpha => write!(f, "alpha"),
Background::White => write!(f, "white"),
Background::Blue => write!(f, "blue"),
Background::Texture => write!(f, "texture"),
}
}
}
pub fn compose(
dir: &str,
algorithm: BlendAlgorithm,
background: &Background,
compression: CompressionType,
filter: FilterType,
benchmark: &mut Benchmark,
) -> Result<String, PConvertError> {
let demultiply = is_algorithm_multiplied(&algorithm);
let algorithm_fn = get_blending_algorithm(&algorithm);
let background_file = format!("background_{}.png", background);
let png_file_names = vec![
"sole.png",
"back.png",
"front.png",
"shoelace.png",
&background_file,
];
let png_paths = png_file_names
.iter()
.map(|name| format!("{}{}", dir, name))
.collect::<Vec<String>>();
let top = benchmark.execute(Benchmark::add_read_png_time, || {
read_png_from_file(format!("{}sole.png", dir), demultiply)
})?;
let mut bot =
png_paths[..png_file_names.len() - 1]
.iter()
.fold(top, |mut composition, path| {
let layer = benchmark
.execute(Benchmark::add_read_png_time, || {
read_png_from_file(path.clone(), demultiply)
})
.unwrap();
benchmark.execute(Benchmark::add_blend_time, || {
blend_images(&mut composition, &layer, &algorithm_fn, &None)
});
composition
});
if demultiply {
benchmark.execute(Benchmark::add_blend_time, || multiply_image(&mut bot));
}
let mut composition = benchmark.execute(Benchmark::add_read_png_time, || {
read_png_from_file(format!("{}background_{}.png", dir, background), false)
})?;
benchmark.execute(Benchmark::add_blend_time, || {
blend_images(&mut composition, &bot, &algorithm_fn, &None)
});
let file_name = format!(
"result_{}_{}_{:#?}_{:#?}.png",
algorithm, background, compression, filter
);
let file_out = format!("{}{}", dir, file_name);
benchmark.execute(Benchmark::add_write_png_time, || {
write_png_to_file(file_out, &composition, compression, filter)
})?;
Ok(file_name)
}
pub fn compose_parallel(
dir: &str,
algorithm: BlendAlgorithm,
background: &Background,
compression: CompressionType,
filter: FilterType,
benchmark: &mut Benchmark,
) -> Result<String, PConvertError> {
let demultiply = is_algorithm_multiplied(&algorithm);
let algorithm_fn = get_blending_algorithm(&algorithm);
let mut thread_pool = ThreadPool::new(THREAD_POOL_SIZE)?;
thread_pool.start();
let background_file = format!("background_{}.png", background);
let png_file_names = vec![
"sole.png",
"back.png",
"front.png",
"shoelace.png",
&background_file,
];
let result_channels = png_file_names
.iter()
.map(|name| format!("{}{}", dir, name))
.map(|path| {
thread_pool
.execute(move || ResultMessage::ImageResult(read_png_from_file(path, demultiply)))
})
.collect::<Vec<Receiver<ResultMessage>>>();
let mut bot = benchmark.execute(Benchmark::add_read_png_time, || {
if let Ok(ResultMessage::ImageResult(result)) = result_channels[0].recv() {
result
} else {
panic!("failure reading 'sole.png'")
}
})?;
for i in 1..=3 {
let top = benchmark.execute(Benchmark::add_read_png_time, || {
if let Ok(ResultMessage::ImageResult(result)) = result_channels[i].recv() {
result
} else {
panic!("failure reading '{}'", png_file_names[i])
}
})?;
benchmark.execute(Benchmark::add_blend_time, || {
blend_images(&mut bot, &top, &algorithm_fn, &None)
});
}
if demultiply {
multiply_image(&mut bot);
}
let mut composition = benchmark.execute(Benchmark::add_read_png_time, || {
if let Ok(ResultMessage::ImageResult(result)) = result_channels[4].recv() {
result
} else {
panic!("failure reading '{}'", background_file)
}
})?;
benchmark.execute(Benchmark::add_blend_time, || {
blend_images(&mut composition, &bot, &algorithm_fn, &None)
});
let file_name = format!(
"result_{}_{}_{:#?}_{:#?}.png",
algorithm, background, compression, filter
);
let file_out = format!("{}{}", dir, file_name);
benchmark.execute(Benchmark::add_write_png_time, || {
write_png_parallel(file_out, &composition, compression, filter)
})?;
Ok(file_name)
}
pub fn apply_blue_filter(pixel: &mut Rgba<u8>) {
pixel[0] = 0;
pixel[1] = pixel[2];
}