use bytemuck::{cast_slice, cast_slice_mut};
use rgb::FromSlice;
use std::fs;
use zune_jpeg::JpegDecoder;
use zune_jpeg::zune_core::bytestream::ZCursor;
use zune_jpeg::zune_core::colorspace::ColorSpace;
use crate::cms::Profile;
use crate::convert::ToSRGBImage;
use crate::exif::parse_exif;
use crate::format::Format;
use crate::image::{Image, ImageMeta, Rotate};
use crate::loader::Loader;
use crate::pixel_format::CMYK;
impl Loader {
pub(crate) fn load_jpeg(&self, data: &[u8], fs_meta: Option<fs::Metadata>) -> Result<Image, crate::Error> {
let mut dec = JpegDecoder::new(ZCursor::new(data));
dec.decode_headers()?;
let info = dec.info().ok_or(crate::Error::UnsupportedJpeg)?;
let width = usize::from(info.width);
let height = usize::from(info.height);
self.check_dimensions(width, height)?;
let (orientation, is_adobe_1998) = dec.exif().map_or((1, false), |exif| parse_exif(exif));
let profile = dec.icc_profile().as_deref()
.or(if is_adobe_1998 { Some(crate::profiles::ADOBE1998) } else { None })
.and_then(|icc| self.process_profile(Profile::new_icc(icc)));
let out_cs = match dec.input_colorspace() {
Some(ColorSpace::CMYK) => ColorSpace::CMYK,
Some(ColorSpace::YCCK) => ColorSpace::YCCK,
Some(ColorSpace::Luma) => ColorSpace::Luma,
_ => ColorSpace::RGB,
};
if out_cs != ColorSpace::RGB {
dec.set_options(dec.options().jpeg_set_out_colorspace(out_cs));
}
let mut pixels = dec.decode()?;
let out_cs = dec.output_colorspace().unwrap_or(ColorSpace::RGB);
let meta = ImageMeta::new(Format::Jpeg, vec![], fs_meta.clone());
let img = match out_cs {
ColorSpace::CMYK => {
for v in &mut pixels {
*v = 255 - *v;
}
cast_slice::<u8, CMYK>(&pixels).to_image(profile, width, height, true, meta)
}
ColorSpace::YCCK => {
pixels.as_chunks::<4>().0.iter()
.map(|px| ycck_to_cmyk(px[0], px[1], px[2], px[3]))
.collect::<Vec<CMYK>>()
.as_slice()
.to_image(profile, width, height, true, meta)
},
ColorSpace::Luma => cast_slice_mut::<_, rgb::Gray<u8>>(&mut pixels).to_image(profile, width, height, true, meta),
_ => pixels.as_rgb_mut().to_image(profile, width, height, true, meta),
};
Ok(img.rotated(Rotate::from_exif_orientation(orientation)))
}
}
fn ycck_to_cmyk(y: u8, cb: u8, cr: u8, k: u8) -> CMYK {
let y = f32::from(y);
let cb = f32::from(cb) - 128.0;
let cr = f32::from(cr) - 128.0;
CMYK {
c: (y + 1.40200 * cr).round() as u8,
m: (y - 0.34414 * cb - 0.71414 * cr).round() as u8,
y: (y + 1.77200 * cb).round() as u8,
k: 255 - k,
}
}