1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
use quick_xml::Reader; use quick_xml::events::Event; use std::{ fs::File, io, io::BufReader, io::prelude::*, path::Path }; pub trait IsImage { fn is_png(&self) -> Result<bool, io::Error>; fn is_jpg(&self) -> Result<bool, io::Error>; fn is_gif(&self) -> Result<bool, io::Error>; fn is_bmp(&self) -> Result<bool, io::Error>; fn is_tif(&self) -> Result<bool, io::Error>; fn is_xcf(&self) -> Result<bool, io::Error>; fn is_ppm(&self) -> Result<bool, io::Error>; fn is_pgm(&self) -> Result<bool, io::Error>; fn is_pbm(&self) -> Result<bool, io::Error>; fn is_svg(&self) -> Result<bool, quick_xml::Error>; } macro_rules! impl_isimage { ($head:ident) => { impl IsImage for $head { fn is_png(&self) -> Result<bool, io::Error> { let mut file = File::open(self)?; let mut bytes: [u8; 8] = [0; 8]; file.read_exact(&mut bytes)?; let header = vec![0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]; Ok(header == bytes) } fn is_jpg(&self) -> Result<bool, io::Error> { let mut file = File::open(self)?; let mut bytes: [u8; 11] = [0; 11]; file.read_exact(&mut bytes)?; let candidate = bytes.iter().enumerate().filter(|(i, _)| *i != 4 && *i != 5).map(|(_, b)| *b).collect::<Vec<u8>>(); let headerv1 = vec![0xFF, 0xD8, 0xFF, 0xE0, 0x4A, 0x46, 0x49, 0x46, 0x00]; let headerv2 = vec![0xFF, 0xD8, 0xFF, 0xFF, 0x4A, 0x46, 0x49, 0x46, 0x00]; Ok(headerv1 == candidate || headerv2 == candidate) } fn is_gif(&self) -> Result<bool, io::Error> { let mut file = File::open(self)?; let mut bytes: [u8; 6] = [0; 6]; file.read_exact(&mut bytes)?; let headerv89a = vec![0x47, 0x49, 0x46, 0x38, 0x39, 0x61]; let headerv87a = vec![0x47, 0x49, 0x46, 0x38, 0x37, 0x61]; Ok(headerv89a == bytes || headerv87a == bytes) } fn is_bmp(&self) -> Result<bool, io::Error> { let mut file = File::open(self)?; let mut bytes: [u8; 2] = [0; 2]; file.read_exact(&mut bytes)?; let header = vec![0x42, 0x4D]; Ok(header == bytes) } fn is_tif(&self) -> Result<bool, io::Error> { let mut file = File::open(self)?; let mut bytes: [u8; 3] = [0; 3]; file.read_exact(&mut bytes)?; let headerle = vec![0x49, 0x49, 0x2A]; let headerbe = vec![0x4D, 0x4D, 0x2A]; Ok(headerle == bytes || headerbe == bytes) } fn is_xcf(&self) -> Result<bool, io::Error> { let mut file = File::open(self)?; let mut bytes: [u8; 9] = [0; 9]; file.read_exact(&mut bytes)?; let header = vec![0x67, 0x69, 0x6D, 0x70, 0x20, 0x78, 0x63, 0x66, 0x20]; Ok(header == bytes) } fn is_ppm(&self) -> Result<bool, io::Error> { let mut file = File::open(self)?; let mut bytes: [u8; 2] = [0; 2]; file.read_exact(&mut bytes)?; let headerp3 = vec![0x50, 0x33]; let headerp6 = vec![0x50, 0x36]; Ok(headerp3 == bytes || headerp6 == bytes) } fn is_pgm(&self) -> Result<bool, io::Error> { let mut file = File::open(self)?; let mut bytes: [u8; 2] = [0; 2]; file.read_exact(&mut bytes)?; let headerp2 = vec![0x50, 0x32]; let headerp5 = vec![0x50, 0x35]; Ok(headerp2 == bytes || headerp5 == bytes) } fn is_pbm(&self) -> Result<bool, io::Error> { let mut file = File::open(self)?; let mut bytes: [u8; 2] = [0; 2]; file.read_exact(&mut bytes)?; let headerp1 = vec![0x50, 0x31]; Ok(headerp1 == bytes) } fn is_svg(&self) -> Result<bool, quick_xml::Error> { let mut reader: Reader<BufReader<File>>; reader = Reader::from_file(self)?; let mut buffer = Vec::new(); loop { match reader.read_event(&mut buffer) { Ok(Event::Start(ref e)) if e.name() == b"svg" => { return Ok(true); } Ok(Event::Eof) => break, Err(error) => return Err(error.into()), _ => () } } Ok(false) } } } } macro_rules! for_each_ident { ($callback:ident, $head:ident) => { $callback!($head); }; ($callback:ident, $head:ident, $($tail:ident),*) => { $callback!($head); for_each_ident!($callback, $($tail),*); } } for_each_ident!(impl_isimage, Path, String, str);