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 | |