use rimage::{
config::{Codec, EncoderConfig},
image::load_from_memory,
Decoder, Encoder,
};
use std::{fs, fs::File, path::Path};
use uuid::Uuid;
use crate::utils::{create_directory_if_not_exists, resize_by_width};
#[derive(Debug, Clone)]
pub struct ImgCompConfig {
pub img_type: ImgType,
pub resize_width: Option<u32>,
pub quality: u32,
}
#[derive(Debug, Clone)]
pub enum ImgType {
Jpg,
Png,
}
pub fn img_comp_with_path(
input: impl AsRef<Path>,
output: impl AsRef<Path>,
config: &ImgCompConfig,
) -> anyhow::Result<()> {
let decoder = Decoder::from_path(input)?;
let image = decoder.decode()?;
let image = if let Some(w) = config.resize_width {
resize_by_width(image, w)?
} else {
image
};
let config = match config.img_type {
ImgType::Jpg => EncoderConfig::new(Codec::MozJpeg).with_quality(config.quality as f32)?,
ImgType::Png => EncoderConfig::new(Codec::OxiPng).with_quality(config.quality as f32)?,
};
let file = File::create(output)?;
let encoder = Encoder::new(file, image).with_config(config);
encoder.encode()?;
Ok(())
}
pub fn img_comp_with_buf(buf: Vec<u8>, config: &ImgCompConfig) -> anyhow::Result<Vec<u8>> {
let temp_dir = ".img_comp_temp".to_string();
let image = load_from_memory(buf.as_slice())?;
let image = if let Some(w) = config.resize_width {
resize_by_width(image, w)?
} else {
image
};
let encode_config = match config.img_type {
ImgType::Jpg => EncoderConfig::new(Codec::MozJpeg).with_quality(config.quality as f32)?,
ImgType::Png => EncoderConfig::new(Codec::OxiPng).with_quality(config.quality as f32)?,
};
create_directory_if_not_exists(&temp_dir)?;
let id_rand = Uuid::new_v4().to_string();
let file_path = match config.img_type {
ImgType::Jpg => temp_dir + "/" + &id_rand + ".jpg",
ImgType::Png => temp_dir + "/" + &id_rand + ".png",
};
let file = match config.img_type {
ImgType::Jpg => File::create(&file_path)?,
ImgType::Png => File::create(&file_path)?,
};
let encoder = Encoder::new(file, image).with_config(encode_config);
encoder.encode()?;
let buffer = fs::read(&file_path)?;
fs::remove_file(&file_path)?;
Ok(buffer)
}
#[cfg(test)]
mod test {
use super::*;
use std::fs::File;
use std::io::Read;
#[test]
fn test_img_comp_path() {
let config = ImgCompConfig {
img_type: ImgType::Jpg,
resize_width: Some(200),
quality: 80,
};
img_comp_with_path("w.png", "w_mini.png", &config).unwrap();
let config = ImgCompConfig {
img_type: ImgType::Jpg,
resize_width: Some(200),
quality: 80,
};
img_comp_with_path("2.png", "2_mini.png", &config).unwrap();
}
#[test]
fn test_img_comp_buf() {
let config = ImgCompConfig {
img_type: ImgType::Jpg,
resize_width: Some(200),
quality: 80,
};
let mut file = File::open("1.jpg").unwrap();
let mut buffer = Vec::new();
file.read_to_end(&mut buffer).unwrap();
let buf = img_comp_with_buf(buffer, &config).unwrap();
println!("buf.l {}", buf.len());
}
}