use magick_rust::{bindings, MagickError, PixelWand};
use str_utils::EndsWithIgnoreAsciiCaseMultiple;
use crate::{
compute_output_size_sharpen, fetch_magic_wand, ColorName, Crop, ImageConfig, ImageResource,
InterlaceType,
};
#[derive(Debug)]
pub struct JPGConfig {
pub remain_profile: bool,
pub width: u16,
pub height: u16,
pub crop: Option<Crop>,
pub shrink_only: bool,
pub sharpen: f64,
pub force_to_chroma_quartered: bool,
pub quality: u8,
pub background_color: Option<ColorName>,
pub ppi: Option<(f64, f64)>,
}
impl JPGConfig {
#[inline]
pub fn new() -> JPGConfig {
JPGConfig {
remain_profile: false,
width: 0u16,
height: 0u16,
crop: None,
shrink_only: true,
sharpen: -1f64,
force_to_chroma_quartered: true,
quality: 85u8,
background_color: None,
ppi: None,
}
}
}
impl Default for JPGConfig {
#[inline]
fn default() -> Self {
JPGConfig::new()
}
}
impl ImageConfig for JPGConfig {
#[inline]
fn is_remain_profile(&self) -> bool {
self.remain_profile
}
#[inline]
fn get_width(&self) -> u16 {
self.width
}
#[inline]
fn get_height(&self) -> u16 {
self.height
}
#[inline]
fn get_crop(&self) -> Option<Crop> {
self.crop
}
#[inline]
fn get_sharpen(&self) -> f64 {
self.sharpen
}
#[inline]
fn is_shrink_only(&self) -> bool {
self.shrink_only
}
}
pub fn to_jpg(
output: &mut ImageResource,
input: &ImageResource,
config: &JPGConfig,
) -> Result<(), MagickError> {
let (mut mw, vector) = fetch_magic_wand(input, config)?;
if let Some(background_color) = config.background_color {
let mut pw = PixelWand::new();
pw.set_color(background_color.as_str())?;
mw.set_image_background_color(&pw)?;
mw.set_image_alpha_channel(bindings::AlphaChannelOption_RemoveAlphaChannel)?;
}
if !vector {
let (width, height, sharpen) = compute_output_size_sharpen(&mw, config);
mw.resize_image(width as usize, height as usize, bindings::FilterType_LanczosFilter);
mw.sharpen_image(0f64, sharpen)?;
}
if !config.remain_profile {
mw.profile_image("*", None)?;
}
if config.force_to_chroma_quartered {
mw.set_sampling_factors(&[2f64, 1f64, 1f64])?;
}
mw.set_image_compression_quality(config.quality.clamp(1, 100) as usize)?;
mw.set_interlace_scheme(InterlaceType::LineInterlace.ordinal() as bindings::InterlaceType)?;
mw.set_image_format("JPEG")?;
if let Some((x, y)) = config.ppi {
mw.set_image_resolution(x.max(0f64), y.max(0f64))?;
mw.set_image_units(bindings::ResolutionType_PixelsPerInchResolution)?;
}
match output {
ImageResource::Path(p) => {
if p.ends_with_ignore_ascii_case_with_lowercase_multiple(&[".jpg", ".jpeg"]).is_none() {
return Err("The file extension name is not jpg or jpeg.".into());
}
mw.write_image(p.as_str())?;
}
ImageResource::Data(b) => {
let mut temp = mw.write_image_blob("JPEG")?;
b.append(&mut temp);
}
ImageResource::MagickWand(mw_2) => {
*mw_2 = mw;
}
}
Ok(())
}