use anyhow::Result;
use aom_decode::{
avif::{Avif, Image},
Config,
};
pub use image;
use image::{DynamicImage, ImageBuffer, ImageFormat};
pub fn load_avif(bin: &[u8]) -> Result<DynamicImage> {
let avif = Avif::decode(bin, &Config { threads: 1 })?.convert()?;
match avif {
Image::RGB8(avif) => {
let width = avif.width() as u32;
let height = avif.height() as u32;
let pxli = avif.pixels();
let mut li = Vec::with_capacity(pxli.len() * 3);
for px in pxli {
li.push(px.r);
li.push(px.g);
li.push(px.b);
}
let img = ImageBuffer::<image::Rgb<u8>, Vec<u8>>::from_raw(width, height, li).unwrap();
Ok(img.into())
}
Image::RGB16(avif) => {
let width = avif.width() as u32;
let height = avif.height() as u32;
let pxli = avif.pixels();
let mut li = Vec::with_capacity(pxli.len() * 3);
for px in pxli {
li.push((px.r >> 8) as u8);
li.push((px.g >> 8) as u8);
li.push((px.b >> 8) as u8);
}
let img = ImageBuffer::<image::Rgb<u8>, Vec<u8>>::from_raw(width, height, li).unwrap();
Ok(img.into())
}
Image::RGBA8(avif) => {
let width = avif.width() as u32;
let height = avif.height() as u32;
let pxli = avif.pixels();
let mut li = Vec::with_capacity(pxli.len() * 3);
for px in pxli {
if px.a == 0 {
li.push(255);
li.push(255);
li.push(255);
} else if px.a == 255 {
li.push(px.r);
li.push(px.g);
li.push(px.b);
} else {
let a = (px.a as f64) / 255.0;
let bg = (1.0 - a) * 255.0;
let r = px.r as f64;
let g = px.g as f64;
let b = px.b as f64;
li.push((r * a + bg) as u8);
li.push((g * a + bg) as u8);
li.push((b * a + bg) as u8);
}
}
let img = ImageBuffer::<image::Rgb<u8>, Vec<u8>>::from_raw(width, height, li).unwrap();
Ok(img.into())
}
Image::RGBA16(avif) => {
let width = avif.width() as u32;
let height = avif.height() as u32;
let pxli = avif.pixels();
let mut li = Vec::with_capacity(pxli.len() * 3);
const BG: u16 = 65535;
const BG64: f64 = BG as f64;
for px in pxli {
if px.a == 0 {
li.push(255);
li.push(255);
li.push(255);
} else if px.a == BG {
li.push((px.r >> 8) as u8);
li.push((px.g >> 8) as u8);
li.push((px.b >> 8) as u8);
} else {
let a = (px.a as f64) / BG64;
let pxbg = (1.0 - a) * BG64;
let r = px.r as f64;
let g = px.g as f64;
let b = px.b as f64;
li.push(((r * a + pxbg) as u16 >> 8) as u8);
li.push(((g * a + pxbg) as u16 >> 8) as u8);
li.push(((b * a + pxbg) as u16 >> 8) as u8);
}
}
let img = ImageBuffer::<image::Rgb<u8>, Vec<u8>>::from_raw(width, height, li).unwrap();
Ok(img.into())
}
_ => {
todo!();
}
}
}
pub fn load_image(ext: Option<&str>, bin: &[u8]) -> Result<DynamicImage> {
let mut not_avifed = true;
if let Some(ext) = ext {
if ext == "avif" {
if let Ok(r) = load_avif(bin) {
return Ok(r);
}
not_avifed = false;
}
if let Some(format) = ImageFormat::from_extension(ext) {
if format != ImageFormat::Avif {
if let Ok(r) = image::load_from_memory_with_format(bin, format) {
return Ok(r);
}
}
}
}
let format = image::guess_format(bin)?;
if format == ImageFormat::Avif && not_avifed {
if let Ok(r) = load_avif(bin) {
return Ok(r);
}
}
Ok(image::load_from_memory_with_format(bin, format)?)
}