mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-25 02:30:15 -06:00
Decoders (JPEG via zune-jpeg + jpeg-decoder for DCT scaling/CMYK, PNG, TIFF, WebP, GIF, BMP, PSD composite, JPEG XL via jxl-oxide) produce linear Rgb32f in source primaries with SourceSpace; ICC matrix/TRC applied exactly, LUT/CMYK profiles through moxcms; to_working() to linear Rec.2020 D65. Encoders: JPEG, PNG 8/16, TIFF 8/16/32f, lossless WebP, AVIF (native). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
39 lines
1.9 KiB
Rust
39 lines
1.9 KiB
Rust
//! GIF (first frame) and BMP via the `image` crate's pure-Rust decoders.
|
|
|
|
use crate::convert::{Buf, Meta, Model, Raw, check_size, finish};
|
|
use crate::{DecodeOptions, Decoded, Error, Format, Result};
|
|
use image::{DynamicImage, ImageDecoder};
|
|
|
|
pub(crate) fn decode(bytes: &[u8], format: Format, opts: &DecodeOptions) -> Result<Decoded> {
|
|
let err = |e: image::ImageError| Error::Malformed(format, e.to_string());
|
|
let cursor = std::io::Cursor::new(bytes);
|
|
let (img, icc) = match format {
|
|
Format::Gif => {
|
|
let mut d = image::codecs::gif::GifDecoder::new(cursor).map_err(err)?;
|
|
let (w, h) = d.dimensions();
|
|
check_size(format, w as u64, h as u64, opts)?;
|
|
let icc = d.icc_profile().ok().flatten();
|
|
(DynamicImage::from_decoder(d).map_err(err)?, icc)
|
|
}
|
|
Format::Bmp => {
|
|
let mut d = image::codecs::bmp::BmpDecoder::new(cursor).map_err(err)?;
|
|
let (w, h) = d.dimensions();
|
|
check_size(format, w as u64, h as u64, opts)?;
|
|
let icc = d.icc_profile().ok().flatten();
|
|
(DynamicImage::from_decoder(d).map_err(err)?, icc)
|
|
}
|
|
_ => return Err(Error::Unsupported(format, "not handled by this decoder")),
|
|
};
|
|
let (w, h) = (img.width(), img.height());
|
|
let alpha = img.color().has_alpha();
|
|
let gray = !img.color().has_color();
|
|
let (model, alpha, buf) = match (gray, alpha) {
|
|
(true, false) => (Model::Gray, false, img.into_luma8().into_raw()),
|
|
(true, true) => (Model::Gray, true, img.into_luma_alpha8().into_raw()),
|
|
(false, false) => (Model::Rgb, false, img.into_rgb8().into_raw()),
|
|
(false, true) => (Model::Rgb, true, img.into_rgba8().into_raw()),
|
|
};
|
|
let raw = Raw { width: w as usize, height: h as usize, model, alpha, premultiplied: false, buf: Buf::U8(buf), bit_depth: 8 };
|
|
finish(format, raw, Meta { icc, ..Default::default() }, (w, h), opts)
|
|
}
|