rosetta_squint_decode/
decode.rs1use crate::bmp::decode_bmp;
2use crate::gif::decode_gif;
3use crate::heic::decode_heic;
4use crate::png::decode_png;
5use crate::tiff::decode_tiff;
6use crate::error::{DecodeError, DecodeErrorKind};
7use crate::types::{DecodedImage, Format};
8use crate::webp::decode_webp;
9
10pub fn decode(bytes: &[u8]) -> Result<DecodedImage, DecodeError> {
12 let fmt = detect_format(bytes).ok_or_else(|| {
13 DecodeError::new(DecodeErrorKind::UnsupportedFormat, None, "")
14 })?;
15 match fmt {
16 Format::Bmp => decode_bmp(bytes),
17 Format::Gif => decode_gif(bytes),
18 Format::Heic => decode_heic(bytes),
19 Format::Jpeg => crate::jpeg::decode_jpeg(bytes),
20 Format::Png => decode_png(bytes),
21 Format::Tiff => decode_tiff(bytes),
22 Format::Webp => decode_webp(bytes),
23 other => Err(DecodeError::new(DecodeErrorKind::UnsupportedFormat, Some(other), "")),
24 }
25}
26
27pub fn detect_format(bytes: &[u8]) -> Option<Format> {
29 if bytes.len() < 2 {
30 return None;
31 }
32 if bytes[0] == 0x42 && bytes[1] == 0x4D {
33 return Some(Format::Bmp);
34 }
35 if bytes.len() >= 8
36 && bytes[0] == 0x89
37 && bytes[1] == 0x50
38 && bytes[2] == 0x4E
39 && bytes[3] == 0x47
40 && bytes[4] == 0x0D
41 && bytes[5] == 0x0A
42 && bytes[6] == 0x1A
43 && bytes[7] == 0x0A
44 {
45 return Some(Format::Png);
46 }
47 if bytes.len() >= 6
49 && bytes[0] == b'G'
50 && bytes[1] == b'I'
51 && bytes[2] == b'F'
52 && bytes[3] == b'8'
53 && (bytes[4] == b'7' || bytes[4] == b'9')
54 && bytes[5] == b'a'
55 {
56 return Some(Format::Gif);
57 }
58 if bytes.len() >= 2
60 && bytes[0] == 0xFF
61 && bytes[1] == 0xD8
62 {
63 return Some(Format::Jpeg);
64 }
65 if bytes.len() >= 12
67 && bytes[0..4] == *b"RIFF"
68 && bytes[8..12] == *b"WEBP"
69 {
70 return Some(Format::Webp);
71 }
72 if bytes.len() >= 4
74 && ((bytes[0] == 0x49 && bytes[1] == 0x49 && bytes[2] == 0x2A && bytes[3] == 0x00)
75 || (bytes[0] == 0x4D && bytes[1] == 0x4D && bytes[2] == 0x00 && bytes[3] == 0x2A))
76 {
77 return Some(Format::Tiff);
78 }
79 if bytes.len() >= 12 && &bytes[4..8] == b"ftyp" {
82 let brand = &bytes[8..12];
83 match brand {
84 b"avif" | b"avis" => return None, b"heic" | b"heix" | b"mif1" | b"msf1" | b"hevc" | b"hevx" => {
86 return Some(Format::Heic)
87 }
88 _ => {} }
90 }
91 None
92}
93
94pub fn supported_formats() -> Vec<Format> {
96 vec![Format::Bmp, Format::Png, Format::Gif, Format::Jpeg, Format::Webp, Format::Tiff, Format::Heic]
97}