#[cfg(feature = "png")]
use png::BitDepth;
use crate::structs::*;
use crate::magic;
pub fn read(buf: &[u8]) -> Result<ImageInfo, ()> {
let file_type = magic::detect_file_type_with_magic_number(&buf).unwrap();
match file_type {
"png" => {
#[cfg(feature="png")]
return Ok(read_png(&buf));
#[cfg(not(feature="png"))]
return Err(());
}
"webp" => {
#[cfg(feature="webp")]
return Ok(read_webp(&buf));
#[cfg(not(feature="webp"))]
return Err(());
}
"jxl" => {
#[cfg(feature="jpegxl")]
return Ok(read_jpeg_xl(&buf));
#[cfg(not(feature="jpegxl"))]
return Err(());
}
_ => Err(()),
}
}
#[cfg(feature="webp")]
pub fn read_webp(buf: &[u8]) -> ImageInfo {
let decoder = webp::Decoder::new(&buf);
let webp_info = decoder.decode().unwrap();
let bit_per_pixel = match webp_info.is_alpha() {
true => 4, false => 3, };
let pixels_num = webp_info.width() as usize * webp_info.height() as usize;
let dots_num = pixels_num * bit_per_pixel;
let image = webp_info.to_image();
let mut pixels: Vec<u8> = vec![0; dots_num];
if webp_info.is_alpha() {
let image = image.as_rgba8().unwrap();
for x in 0..webp_info.width() {
for y in 0..webp_info.height() {
let pixel = image.get_pixel(x, y);
let i: usize = (y * webp_info.width() + x) as usize;
pixels[i * 4 + 0] = pixel[0];
pixels[i * 4 + 1] = pixel[1];
pixels[i * 4 + 2] = pixel[2];
pixels[i * 4 + 3] = pixel[3];
}
}
} else {
let image = image.as_rgb8().unwrap();
for x in 0..webp_info.width() {
for y in 0..webp_info.height() {
let pixel = image.get_pixel(x, y);
let i: usize = (y * webp_info.width() + x) as usize;
pixels[i * 3 + 0] = pixel[0];
pixels[i * 3 + 1] = pixel[1];
pixels[i * 3 + 2] = pixel[2];
}
}
}
let im_info = ImageInfo {
width: webp_info.width(),
height: webp_info.height(),
bit_depth: 8,
color_type: match webp_info.is_alpha() {
true => 6, false => 2, },
pixels: ImagePixels::U8(pixels),
};
im_info
}
#[cfg(feature="png")]
pub fn read_png(buf: &[u8]) -> ImageInfo {
let decoder = png::Decoder::new(buf);
let mut reader = decoder.read_info().unwrap();
let info = reader.info().to_owned();
let mut dot_per_pixel = match info.color_type {
png::ColorType::Grayscale => 1,
png::ColorType::Rgb => 3,
png::ColorType::Indexed => 1,
png::ColorType::GrayscaleAlpha => 2,
png::ColorType::Rgba => 4,
};
if info.bit_depth == BitDepth::Sixteen {
dot_per_pixel *= 2;
}
let mut pxls = vec![0; info.width as usize * info.height as usize * dot_per_pixel];
reader.next_frame(&mut pxls).unwrap();
let pixels: ImagePixels;
if info.bit_depth == BitDepth::Sixteen {
let mut pixels16 = vec![0; info.width as usize * info.height as usize * dot_per_pixel / 2];
for i in 0..pixels16.len() {
pixels16[i] = (pxls[i * 2] as u16) << 8 | pxls[i * 2 + 1] as u16;
}
pixels = ImagePixels::U16(pixels16);
} else {
let mut pixels8 = vec![0; info.width as usize * info.height as usize * dot_per_pixel];
for i in 0..pixels8.len() {
pixels8[i] = pxls[i];
}
pixels = ImagePixels::U8(pixels8);
}
let im_info = ImageInfo {
width: info.width,
height: info.height,
bit_depth: match info.bit_depth {
BitDepth::One => 1,
BitDepth::Two => 2,
BitDepth::Four => 4,
BitDepth::Eight => 8,
BitDepth::Sixteen => 16,
},
color_type: match info.color_type {
png::ColorType::Grayscale => 0,
png::ColorType::Rgb => 2,
png::ColorType::Indexed => 3,
png::ColorType::GrayscaleAlpha => 4,
png::ColorType::Rgba => 6,
},
pixels,
};
im_info
}
#[cfg(feature="jpegxl")]
pub fn read_jpeg_xl(buf: &[u8]) -> ImageInfo {
let mut decoder_builder = jpegxl_rs::decode::decoder_builder();
let mut decoder = decoder_builder.build().unwrap();
let data = decoder.decode(buf).unwrap();
let metadata = data.0;
let pixels = data.1;
let bit_depth = match pixels {
jpegxl_rs::decode::Pixels::Uint8(_) => 8,
jpegxl_rs::decode::Pixels::Uint16(_) => 16,
jpegxl_rs::decode::Pixels::Float16(_) => 16,
jpegxl_rs::decode::Pixels::Float(_) => 32,
};
let pixels = match pixels {
jpegxl_rs::decode::Pixels::Uint8(pixels) => {
ImagePixels::U8(pixels)
},
jpegxl_rs::decode::Pixels::Uint16(pixels) => {
ImagePixels::U16(pixels)
},
jpegxl_rs::decode::Pixels::Float16(pixels) => {
ImagePixels::F16(pixels)
},
jpegxl_rs::decode::Pixels::Float(pixels) => {
ImagePixels::F32(pixels)
},
};
let mut im_info = ImageInfo {
width: metadata.width,
height: metadata.height,
bit_depth,
color_type: (metadata.num_color_channels + (if metadata.has_alpha_channel { 1 } else { 0 })) as u8,
pixels,
};
im_info
}