| 1 | use crate::util::*; |
| 2 | use crate::{ImageError, ImageResult, ImageSize}; |
| 3 | |
| 4 | use std::io::{BufRead, Seek, SeekFrom}; |
| 5 | |
| 6 | pub fn size<R: BufRead + Seek>(reader: &mut R) -> ImageResult<ImageSize> { |
| 7 | reader.seek(pos:SeekFrom::Start(4))?; |
| 8 | let img_count: u16 = read_u16(reader, &Endian::Little)?; |
| 9 | let mut sizes: Vec = Vec::with_capacity(img_count as usize); |
| 10 | |
| 11 | for _ in 0..img_count { |
| 12 | if let Ok(size: ImageSize) = ico_image_size(reader) { |
| 13 | sizes.push(size) |
| 14 | } else { |
| 15 | // if we don't have all the bytes of the headers, just |
| 16 | // return the largest one found so far |
| 17 | break; |
| 18 | } |
| 19 | // each ICONDIRENTRY (image header) is 16 bytes, skip the last 14 |
| 20 | reader.seek(pos:SeekFrom::Current(14))?; |
| 21 | } |
| 22 | sizes.into_iter().max().ok_or(err:ImageError::CorruptedImage) |
| 23 | } |
| 24 | |
| 25 | pub fn matches(header: &[u8]) -> bool { |
| 26 | header.starts_with(&[0, 0, 1, 0]) |
| 27 | } |
| 28 | |
| 29 | /// Reads two bytes to determine an individual image's size within an ICO |
| 30 | fn ico_image_size<R: BufRead + Seek>(reader: &mut R) -> ImageResult<ImageSize> { |
| 31 | // ICO dimensions are 1-256 pixels, with a byte value of 0 representing 256 |
| 32 | Ok(ImageSize { |
| 33 | width: read_u8(reader)?.wrapping_sub(1) as usize + 1, |
| 34 | height: read_u8(reader)?.wrapping_sub(1) as usize + 1, |
| 35 | }) |
| 36 | } |
| 37 | |