use crate::bmp::decode_bmp;
use crate::gif::decode_gif;
use crate::heic::decode_heic;
use crate::png::decode_png;
use crate::tiff::decode_tiff;
use crate::error::{DecodeError, DecodeErrorKind};
use crate::types::{DecodedImage, Format};
use crate::webp::decode_webp;
pub fn decode(bytes: &[u8]) -> Result<DecodedImage, DecodeError> {
let fmt = detect_format(bytes).ok_or_else(|| {
DecodeError::new(DecodeErrorKind::UnsupportedFormat, None, "")
})?;
match fmt {
Format::Bmp => decode_bmp(bytes),
Format::Gif => decode_gif(bytes),
Format::Heic => decode_heic(bytes),
Format::Jpeg => crate::jpeg::decode_jpeg(bytes),
Format::Png => decode_png(bytes),
Format::Tiff => decode_tiff(bytes),
Format::Webp => decode_webp(bytes),
other => Err(DecodeError::new(DecodeErrorKind::UnsupportedFormat, Some(other), "")),
}
}
pub fn detect_format(bytes: &[u8]) -> Option<Format> {
if bytes.len() < 2 {
return None;
}
if bytes[0] == 0x42 && bytes[1] == 0x4D {
return Some(Format::Bmp);
}
if bytes.len() >= 8
&& bytes[0] == 0x89
&& bytes[1] == 0x50
&& bytes[2] == 0x4E
&& bytes[3] == 0x47
&& bytes[4] == 0x0D
&& bytes[5] == 0x0A
&& bytes[6] == 0x1A
&& bytes[7] == 0x0A
{
return Some(Format::Png);
}
if bytes.len() >= 6
&& bytes[0] == b'G'
&& bytes[1] == b'I'
&& bytes[2] == b'F'
&& bytes[3] == b'8'
&& (bytes[4] == b'7' || bytes[4] == b'9')
&& bytes[5] == b'a'
{
return Some(Format::Gif);
}
if bytes.len() >= 2
&& bytes[0] == 0xFF
&& bytes[1] == 0xD8
{
return Some(Format::Jpeg);
}
if bytes.len() >= 12
&& bytes[0..4] == [b'R', b'I', b'F', b'F']
&& bytes[8..12] == [b'W', b'E', b'B', b'P']
{
return Some(Format::Webp);
}
if bytes.len() >= 4
&& ((bytes[0] == 0x49 && bytes[1] == 0x49 && bytes[2] == 0x2A && bytes[3] == 0x00)
|| (bytes[0] == 0x4D && bytes[1] == 0x4D && bytes[2] == 0x00 && bytes[3] == 0x2A))
{
return Some(Format::Tiff);
}
if bytes.len() >= 12 && &bytes[4..8] == b"ftyp" {
let brand = &bytes[8..12];
match brand {
b"avif" | b"avis" => return None, b"heic" | b"heix" | b"mif1" | b"msf1" | b"hevc" | b"hevx" => {
return Some(Format::Heic)
}
_ => {} }
}
None
}
pub fn supported_formats() -> Vec<Format> {
vec![Format::Bmp, Format::Png, Format::Gif, Format::Jpeg, Format::Webp, Format::Tiff, Format::Heic]
}