use image::{
DynamicImage, ImageDecoder, ImageEncoder, ImageFormat, ImageReader,
codecs::{jpeg::JpegEncoder, png::PngEncoder},
imageops::FilterType,
};
use sha2::{Digest, Sha256};
use crate::{error::Result, get_image_options::ImageType};
use std::{
fs::{File, create_dir_all},
io::{BufWriter, Write},
path::PathBuf,
};
use crate::{error::ImageEndpointError, get_image_options::GetImageOptions};
pub fn get_image_path_hash(image_path: &str) -> String {
let mut hasher = Sha256::new();
hasher.update(image_path);
let hash = hasher.finalize();
let hash = hex::encode(hash);
hash
}
pub fn create_final_image(
original_filepath: &PathBuf,
target_filepath: PathBuf,
options: &GetImageOptions,
) -> Result<()> {
let mut decoder = ImageReader::open(original_filepath)?.into_decoder()?;
let orientation = decoder.orientation()?;
let image = DynamicImage::from_decoder(decoder)?;
let image = match (options.width, options.height) {
(Some(width), Some(height)) => image.resize(width, height, FilterType::Lanczos3),
(Some(width), None) => image.resize(width, u32::MAX, FilterType::Lanczos3),
(None, Some(height)) => image.resize(u32::MAX, height, FilterType::Lanczos3),
(None, None) => image,
};
let image = match options.rotate {
Some(rotate) => match rotate {
90 => image.rotate90(),
180 => image.rotate180(),
270 => image.rotate270(),
_ => {
return Err(ImageEndpointError::Generic(
"Possible rotation values are 90, 180 or 270".into(),
));
}
},
None => image,
};
let image = match options.grayscale {
Some(true) => image.grayscale(),
_ => image,
};
let mut image = image;
image.apply_orientation(orientation);
let image_format = match options.imgtype {
Some(image_type) => match image_type {
ImageType::Jpeg | ImageType::Jpg => ImageFormat::Jpeg,
ImageType::Png => ImageFormat::Png,
ImageType::Webp => ImageFormat::WebP,
},
None => ImageFormat::from_path(original_filepath)?,
};
let Some(dir) = &target_filepath.parent() else {
return Err(ImageEndpointError::Generic(
"Was not able to read the directroy from the image path".into(),
));
};
create_dir_all(dir)?;
let mut file = BufWriter::new(File::create(target_filepath)?);
match image_format {
ImageFormat::Jpeg => {
let encoder = match options.quality {
Some(quality) => JpegEncoder::new_with_quality(file, quality),
None => JpegEncoder::new(file),
};
encoder.write_image(
image.as_bytes(),
image.width(),
image.height(),
image.color().into(),
)?;
}
ImageFormat::Png => {
let encoder = PngEncoder::new(file);
encoder.write_image(
image.as_bytes(),
image.width(),
image.height(),
image.color().into(),
)?;
}
ImageFormat::WebP => {
let encoder = webp::Encoder::from_image(&image).map_err(|_| {
ImageEndpointError::Generic(
"Was not able to create an encoder from image data".into(),
)
})?;
let webp = match options.quality {
Some(quality) => encoder.encode(f32::from(quality)),
None => encoder.encode(75f32),
};
file.write_all(&webp)?;
}
_ => {
return Err(ImageEndpointError::Generic(
"Unsupported image format".into(),
));
}
}
Ok(())
}