use std::fs::File;
use std::io::{BufReader, Read};
use std::path::Path;
const SUPPORTED_IMAGE_MIMES: &[&str] = &["image/jpeg", "image/png", "image/gif", "image/webp"];
const FILE_TYPE_SNIFF_BYTES: usize = 4100;
pub fn detect_supported_image_mime_type_from_file(file_path: &Path) -> Option<String> {
let file = File::open(file_path).ok()?;
let mut reader = BufReader::new(file);
let mut buffer = vec![0u8; FILE_TYPE_SNIFF_BYTES];
let bytes_read = reader.read(&mut buffer).ok()?;
if bytes_read == 0 {
return None;
}
let buffer = &buffer[..bytes_read];
let mime_type = detect_mime_from_bytes(buffer)?;
if SUPPORTED_IMAGE_MIMES.contains(&mime_type.as_str()) {
Some(mime_type)
} else {
None
}
}
fn detect_mime_from_bytes(bytes: &[u8]) -> Option<String> {
if bytes.len() < 4 {
return None;
}
if bytes.starts_with(&[0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]) {
return Some("image/png".to_string());
}
if bytes.starts_with(&[0xFF, 0xD8, 0xFF]) {
return Some("image/jpeg".to_string());
}
if bytes.starts_with(b"GIF87a") {
return Some("image/gif".to_string());
}
if bytes.starts_with(b"GIF89a") {
return Some("image/gif".to_string());
}
if bytes.len() >= 12 && bytes.starts_with(b"RIFF") && &bytes[8..12] == b"WEBP" {
return Some("image/webp".to_string());
}
if bytes.starts_with(b"BM") {
return Some("image/bmp".to_string());
}
None
}
pub fn is_supported_image_mime(mime_type: &str) -> bool {
SUPPORTED_IMAGE_MIMES.contains(&mime_type)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_supported_image_mime() {
assert!(is_supported_image_mime("image/png"));
assert!(is_supported_image_mime("image/jpeg"));
assert!(is_supported_image_mime("image/gif"));
assert!(is_supported_image_mime("image/webp"));
assert!(!is_supported_image_mime("image/bmp"));
assert!(!is_supported_image_mime("text/plain"));
}
#[test]
fn test_detect_mime_from_bytes() {
let png_bytes = [
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,
];
assert_eq!(detect_mime_from_bytes(&png_bytes), Some("image/png".to_string()));
let jpeg_bytes = [0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46];
assert_eq!(detect_mime_from_bytes(&jpeg_bytes), Some("image/jpeg".to_string()));
let gif_bytes = b"GIF87a\x00\x01\x00\x01\x00";
assert_eq!(detect_mime_from_bytes(gif_bytes), Some("image/gif".to_string()));
let gif_bytes = b"GIF89a\x00\x01\x00\x01\x00";
assert_eq!(detect_mime_from_bytes(gif_bytes), Some("image/gif".to_string()));
let webp_bytes = b"RIFF\x00\x00\x00\x00WEBP";
assert_eq!(detect_mime_from_bytes(webp_bytes), Some("image/webp".to_string()));
let bmp_bytes = b"BM\x00\x00\x00\x00\x00\x00\x00";
assert_eq!(detect_mime_from_bytes(bmp_bytes), Some("image/bmp".to_string()));
let unknown_bytes = b"hello world";
assert_eq!(detect_mime_from_bytes(unknown_bytes), None);
let short_bytes = [0x89, 0x50];
assert_eq!(detect_mime_from_bytes(&short_bytes), None);
}
}