use super::errors::FxError; use std::{io::Read, path::Path}; const HEADER_JPG1: [u8; 4] = [0xff, 0xd8, 0xff, 0xdb]; const HEADER_JPG2: [u8; 4] = [0xff, 0xd8, 0xff, 0xe0]; const HEADER_JPG3: [u8; 4] = [0xff, 0xd8, 0xff, 0xee]; const HEADER_JPG_EXIF: [u8; 4] = [0xff, 0xd8, 0xff, 0xe1]; const HEADER_JPG_EXIF_AFTER: [u8; 6] = [0x45, 0x78, 0x69, 0x66, 0x00, 0x00]; const HEADER_PNG: [u8; 8] = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]; const HEADER_GIF1: [u8; 6] = [0x47, 0x49, 0x46, 0x38, 0x37, 0x61]; const HEADER_GIF2: [u8; 6] = [0x47, 0x49, 0x46, 0x38, 0x39, 0x61]; const HEADER_WEBP: [u8; 4] = [0x52, 0x49, 0x46, 0x46]; const HEADER_WEBP_AFTER: [u8; 4] = [0x57, 0x45, 0x42, 0x50]; const HEADER_TIF_LITTLE: [u8; 4] = [0x49, 0x49, 0x2A, 0x00]; const HEADER_TIF_BIG: [u8; 4] = [0x4D, 0x4D, 0x00, 0x2A]; const HEADER_BMP: [u8; 2] = [0x42, 0x4D]; const HEADER_ICO: [u8; 4] = [0x00, 0x00, 0x01, 0x00]; const HEADER_HDR: [u8; 11] = [ 0x23, 0x3f, 0x52, 0x41, 0x44, 0x49, 0x41, 0x4e, 0x43, 0x45, 0x0a, ]; const HEADER_EXR: [u8; 4] = [0x76, 0x2F, 0x31, 0x01]; const HEADER_PBM1: [u8; 3] = [0x50, 0x31, 0x0A]; const HEADER_PBM2: [u8; 3] = [0x50, 0x34, 0x0A]; const HEADER_PGM1: [u8; 3] = [0x50, 0x32, 0x0A]; const HEADER_PGM2: [u8; 3] = [0x50, 0x35, 0x0A]; const HEADER_PPM1: [u8; 3] = [0x50, 0x33, 0x0A]; const HEADER_PPM2: [u8; 3] = [0x50, 0x36, 0x0A]; #[derive(Debug, PartialEq, Eq)] enum ImageSignature { Jpg, Png, Gif, Webp, Tif, Bmp, Ico, Hdr, Exr, Pbm, Pgm, Ppm, NotSupported, } fn inspect_image(p: &Path) -> Result { let mut file = std::fs::File::open(p)?; let mut buffer = [0; 12]; file.read_exact(&mut buffer)?; let sign = if buffer[..4] == HEADER_JPG1 || buffer[..4] == HEADER_JPG2 || buffer[..4] == HEADER_JPG3 || (buffer[..4] == HEADER_JPG_EXIF && buffer[6..] == HEADER_JPG_EXIF_AFTER) { ImageSignature::Jpg } else if buffer[..8] == HEADER_PNG { ImageSignature::Png } else if buffer[..6] == HEADER_GIF1 || buffer[..6] == HEADER_GIF2 { ImageSignature::Gif } else if buffer[..4] == HEADER_WEBP || buffer[8..] == HEADER_WEBP_AFTER { ImageSignature::Webp } else if buffer[..4] == HEADER_TIF_LITTLE || buffer[..4] == HEADER_TIF_BIG { ImageSignature::Tif } else if buffer[..2] == HEADER_BMP { ImageSignature::Bmp } else if buffer[..4] == HEADER_ICO { ImageSignature::Ico } else if buffer[..11] == HEADER_HDR { ImageSignature::Hdr } else if buffer[..4] == HEADER_EXR { ImageSignature::Exr } else if buffer[..3] == HEADER_PBM1 || buffer[..3] == HEADER_PBM2 { ImageSignature::Pbm } else if buffer[..3] == HEADER_PGM1 || buffer[..3] == HEADER_PGM2 { ImageSignature::Pgm } else if buffer[..3] == HEADER_PPM1 || buffer[..3] == HEADER_PPM2 { ImageSignature::Ppm } else { ImageSignature::NotSupported }; Ok(sign) } pub fn is_supported_image_type(p: &Path) -> bool { if let Ok(sign) = inspect_image(p) { !matches!(sign, ImageSignature::NotSupported) } else { false } } #[cfg(test)] mod tests { use super::*; use std::path::PathBuf; #[test] /// Supported: /// jpg, png, gif, webp, tif, bmp, ico, hdr, exr, pbm, pgm, ppm fn test_inspect_image() { let p = PathBuf::from("testfiles/images/sample.jpg"); assert_eq!(ImageSignature::Jpg, inspect_image(&p).unwrap()); let p = PathBuf::from("testfiles/images/sample.png"); assert_eq!(ImageSignature::Png, inspect_image(&p).unwrap()); let p = PathBuf::from("testfiles/images/sample.gif"); assert_eq!(ImageSignature::Gif, inspect_image(&p).unwrap()); let p = PathBuf::from("testfiles/images/sample.webp"); assert_eq!(ImageSignature::Webp, inspect_image(&p).unwrap()); let p = PathBuf::from("testfiles/images/sample.tiff"); assert_eq!(ImageSignature::Tif, inspect_image(&p).unwrap()); let p = PathBuf::from("testfiles/images/sample.bmp"); assert_eq!(ImageSignature::Bmp, inspect_image(&p).unwrap()); let p = PathBuf::from("testfiles/images/sample.ico"); assert_eq!(ImageSignature::Ico, inspect_image(&p).unwrap()); let p = PathBuf::from("testfiles/images/sample.hdr"); assert_eq!(ImageSignature::Hdr, inspect_image(&p).unwrap()); let p = PathBuf::from("testfiles/images/sample.exr"); assert_eq!(ImageSignature::Exr, inspect_image(&p).unwrap()); let p = PathBuf::from("testfiles/images/sample.pbm"); assert_eq!(ImageSignature::Pbm, inspect_image(&p).unwrap()); let p = PathBuf::from("testfiles/images/sample.pgm"); assert_eq!(ImageSignature::Pgm, inspect_image(&p).unwrap()); let p = PathBuf::from("testfiles/images/sample.ppm"); assert_eq!(ImageSignature::Ppm, inspect_image(&p).unwrap()); } }