1 use byteorder::{LittleEndian, ReadBytesExt};
2 use std::io::{Read, Seek, SeekFrom};
3 
4 use color::ColorType;
5 use image::{DecodingResult, ImageDecoder, ImageError, ImageResult};
6 
7 use self::InnerDecoder::*;
8 use bmp::BMPDecoder;
9 use png::PNGDecoder;
10 
11 // http://www.w3.org/TR/PNG-Structure.html
12 // The first eight bytes of a PNG file always contain the following (decimal) values:
13 const PNG_SIGNATURE: [u8; 8] = [137, 80, 78, 71, 13, 10, 26, 10];
14 
15 /// An ico decoder
16 pub struct ICODecoder<R: Read> {
17     selected_entry: DirEntry,
18     inner_decoder: InnerDecoder<R>,
19 }
20 
21 enum InnerDecoder<R: Read> {
22     BMP(BMPDecoder<R>),
23     PNG(PNGDecoder<R>),
24 }
25 
26 #[derive(Clone, Copy, Default)]
27 struct DirEntry {
28     width: u8,
29     height: u8,
30     color_count: u8,
31     reserved: u8,
32 
33     num_color_planes: u16,
34     bits_per_pixel: u16,
35 
36     image_length: u32,
37     image_offset: u32,
38 }
39 
40 impl<R: Read + Seek> ICODecoder<R> {
41     /// Create a new decoder that decodes from the stream ```r```
new(mut r: R) -> ImageResult<ICODecoder<R>>42     pub fn new(mut r: R) -> ImageResult<ICODecoder<R>> {
43         let entries = try!(read_entries(&mut r));
44         let entry = try!(best_entry(entries));
45         let decoder = try!(entry.decoder(r));
46 
47         Ok(ICODecoder {
48             selected_entry: entry,
49             inner_decoder: decoder,
50         })
51     }
52 }
53 
read_entries<R: Read>(r: &mut R) -> ImageResult<Vec<DirEntry>>54 fn read_entries<R: Read>(r: &mut R) -> ImageResult<Vec<DirEntry>> {
55     let _reserved = try!(r.read_u16::<LittleEndian>());
56     let _type = try!(r.read_u16::<LittleEndian>());
57     let count = try!(r.read_u16::<LittleEndian>());
58     (0..count).map(|_| read_entry(r)).collect()
59 }
60 
read_entry<R: Read>(r: &mut R) -> ImageResult<DirEntry>61 fn read_entry<R: Read>(r: &mut R) -> ImageResult<DirEntry> {
62     let mut entry = DirEntry::default();
63 
64     entry.width = try!(r.read_u8());
65     entry.height = try!(r.read_u8());
66     entry.color_count = try!(r.read_u8());
67     // Reserved value (not used)
68     entry.reserved = try!(r.read_u8());
69 
70     // This may be either the number of color planes (0 or 1), or the horizontal coordinate
71     // of the hotspot for CUR files.
72     entry.num_color_planes = try!(r.read_u16::<LittleEndian>());
73     if entry.num_color_planes > 256 {
74         return Err(ImageError::FormatError(
75             "ICO image entry has a too large color planes/hotspot value".to_string(),
76         ));
77     }
78 
79     // This may be either the bit depth (may be 0 meaning unspecified),
80     // or the vertical coordinate of the hotspot for CUR files.
81     entry.bits_per_pixel = try!(r.read_u16::<LittleEndian>());
82     if entry.bits_per_pixel > 256 {
83         return Err(ImageError::FormatError(
84             "ICO image entry has a too large bits per pixel/hotspot value".to_string(),
85         ));
86     }
87 
88     entry.image_length = try!(r.read_u32::<LittleEndian>());
89     entry.image_offset = try!(r.read_u32::<LittleEndian>());
90 
91     Ok(entry)
92 }
93 
94 /// Find the entry with the highest (color depth, size).
best_entry(mut entries: Vec<DirEntry>) -> ImageResult<DirEntry>95 fn best_entry(mut entries: Vec<DirEntry>) -> ImageResult<DirEntry> {
96     let mut best = try!(entries.pop().ok_or(ImageError::ImageEnd));
97     let mut best_score = (
98         best.bits_per_pixel,
99         u32::from(best.real_width()) * u32::from(best.real_height()),
100     );
101 
102     for entry in entries {
103         let score = (
104             entry.bits_per_pixel,
105             u32::from(entry.real_width()) * u32::from(entry.real_height()),
106         );
107         if score > best_score {
108             best = entry;
109             best_score = score;
110         }
111     }
112     Ok(best)
113 }
114 
115 impl DirEntry {
real_width(&self) -> u16116     fn real_width(&self) -> u16 {
117         match self.width {
118             0 => 256,
119             w => u16::from(w),
120         }
121     }
122 
real_height(&self) -> u16123     fn real_height(&self) -> u16 {
124         match self.height {
125             0 => 256,
126             h => u16::from(h),
127         }
128     }
129 
matches_dimensions(&self, width: u32, height: u32) -> bool130     fn matches_dimensions(&self, width: u32, height: u32) -> bool {
131         u32::from(self.real_width()) == width && u32::from(self.real_height()) == height
132     }
133 
seek_to_start<R: Read + Seek>(&self, r: &mut R) -> ImageResult<()>134     fn seek_to_start<R: Read + Seek>(&self, r: &mut R) -> ImageResult<()> {
135         try!(r.seek(SeekFrom::Start(u64::from(self.image_offset))));
136         Ok(())
137     }
138 
is_png<R: Read + Seek>(&self, r: &mut R) -> ImageResult<bool>139     fn is_png<R: Read + Seek>(&self, r: &mut R) -> ImageResult<bool> {
140         try!(self.seek_to_start(r));
141 
142         // Read the first 8 bytes to sniff the image.
143         let mut signature = [0u8; 8];
144         try!(r.read_exact(&mut signature));
145 
146         Ok(signature == PNG_SIGNATURE)
147     }
148 
decoder<R: Read + Seek>(&self, mut r: R) -> ImageResult<InnerDecoder<R>>149     fn decoder<R: Read + Seek>(&self, mut r: R) -> ImageResult<InnerDecoder<R>> {
150         let is_png = try!(self.is_png(&mut r));
151         try!(self.seek_to_start(&mut r));
152 
153         if is_png {
154             Ok(PNG(PNGDecoder::new(r)))
155         } else {
156             let mut decoder = BMPDecoder::new(r);
157             try!(decoder.read_metadata_in_ico_format());
158             Ok(BMP(decoder))
159         }
160     }
161 }
162 
163 impl<R: Read + Seek> ImageDecoder for ICODecoder<R> {
dimensions(&mut self) -> ImageResult<(u32, u32)>164     fn dimensions(&mut self) -> ImageResult<(u32, u32)> {
165         match self.inner_decoder {
166             BMP(ref mut decoder) => decoder.dimensions(),
167             PNG(ref mut decoder) => decoder.dimensions(),
168         }
169     }
170 
colortype(&mut self) -> ImageResult<ColorType>171     fn colortype(&mut self) -> ImageResult<ColorType> {
172         match self.inner_decoder {
173             BMP(ref mut decoder) => decoder.colortype(),
174             PNG(ref mut decoder) => decoder.colortype(),
175         }
176     }
177 
row_len(&mut self) -> ImageResult<usize>178     fn row_len(&mut self) -> ImageResult<usize> {
179         match self.inner_decoder {
180             BMP(ref mut decoder) => decoder.row_len(),
181             PNG(ref mut decoder) => decoder.row_len(),
182         }
183     }
184 
read_scanline(&mut self, buf: &mut [u8]) -> ImageResult<u32>185     fn read_scanline(&mut self, buf: &mut [u8]) -> ImageResult<u32> {
186         match self.inner_decoder {
187             BMP(ref mut decoder) => decoder.read_scanline(buf),
188             PNG(ref mut decoder) => decoder.read_scanline(buf),
189         }
190     }
191 
read_image(&mut self) -> ImageResult<DecodingResult>192     fn read_image(&mut self) -> ImageResult<DecodingResult> {
193         match self.inner_decoder {
194             PNG(ref mut decoder) => {
195                 if self.selected_entry.image_length < PNG_SIGNATURE.len() as u32 {
196                     return Err(ImageError::FormatError(
197                         "Entry specified a length that is shorter than PNG header!".to_string(),
198                     ));
199                 }
200 
201                 // Check if the image dimensions match the ones in the image data.
202                 let (width, height) = try!(decoder.dimensions());
203                 if !self.selected_entry.matches_dimensions(width, height) {
204                     return Err(ImageError::FormatError(
205                         "Entry and PNG dimensions do not match!".to_string(),
206                     ));
207                 }
208 
209                 // Embedded PNG images can only be of the 32BPP RGBA format.
210                 // https://blogs.msdn.microsoft.com/oldnewthing/20101022-00/?p=12473/
211                 let color_type = try!(decoder.colortype());
212                 if let ColorType::RGBA(8) = color_type {
213                 } else {
214                     return Err(ImageError::FormatError(
215                         "The PNG is not in RGBA format!".to_string(),
216                     ));
217                 }
218 
219                 decoder.read_image()
220             }
221             BMP(ref mut decoder) => {
222                 let (width, height) = try!(decoder.dimensions());
223                 if !self.selected_entry.matches_dimensions(width, height) {
224                     return Err(ImageError::FormatError(
225                         "Entry({:?}) and BMP({:?}) dimensions do not match!".to_string(),
226                     ));
227                 }
228 
229                 // The ICO decoder needs an alpha channel to apply the AND mask.
230                 if try!(decoder.colortype()) != ColorType::RGBA(8) {
231                     return Err(ImageError::UnsupportedError(
232                         "Unsupported color type".to_string(),
233                     ));
234                 }
235 
236                 let mut pixel_data = match try!(decoder.read_image()) {
237                     DecodingResult::U8(v) => v,
238                     _ => unreachable!(),
239                 };
240 
241                 // If there's an AND mask following the image, read and apply it.
242                 let r = decoder.reader();
243                 let mask_start = try!(r.seek(SeekFrom::Current(0)));
244                 let mask_end =
245                     u64::from(self.selected_entry.image_offset + self.selected_entry.image_length);
246                 let mask_length = mask_end - mask_start;
247 
248                 if mask_length > 0 {
249                     // A mask row contains 1 bit per pixel, padded to 4 bytes.
250                     let mask_row_bytes = ((width + 31) / 32) * 4;
251                     let expected_length = u64::from(mask_row_bytes * height);
252                     if mask_length < expected_length {
253                         return Err(ImageError::ImageEnd);
254                     }
255 
256                     for y in 0..height {
257                         let mut x = 0;
258                         for _ in 0..mask_row_bytes {
259                             // Apply the bits of each byte until we reach the end of the row.
260                             let mask_byte = try!(r.read_u8());
261                             for bit in (0..8).rev() {
262                                 if x >= width {
263                                     break;
264                                 }
265                                 if mask_byte & (1 << bit) != 0 {
266                                     // Set alpha channel to transparent.
267                                     pixel_data[((height - y - 1) * width + x) as usize * 4 + 3] = 0;
268                                 }
269                                 x += 1;
270                             }
271                         }
272                     }
273                 }
274                 Ok(DecodingResult::U8(pixel_data))
275             }
276         }
277     }
278 }
279