1use crate::util::*;
2use crate::{ImageError, ImageResult, ImageSize};
3
4use std::io::{BufRead, Seek, SeekFrom};
5
6pub 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
25pub 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
30fn 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