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
use byteorder::{LittleEndian, WriteBytesExt};
use std::io::{self, Write};
use crate::color::ColorType;
use crate::error::ImageResult;
use crate::image::ImageEncoder;
use crate::png::PngEncoder;
const ICO_IMAGE_TYPE: u16 = 1;
const ICO_ICONDIR_SIZE: u32 = 6;
const ICO_DIRENTRY_SIZE: u32 = 16;
pub struct IcoEncoder<W: Write> {
    w: W,
}
#[allow(dead_code)]
#[deprecated(note = "Use `IcoEncoder` instead")]
pub type ICOEncoder<W> = IcoEncoder<W>;
impl<W: Write> IcoEncoder<W> {
    
    pub fn new(w: W) -> IcoEncoder<W> {
        IcoEncoder { w }
    }
    
    
    
    pub fn encode(
        mut self,
        data: &[u8],
        width: u32,
        height: u32,
        color: ColorType,
    ) -> ImageResult<()> {
        let mut image_data: Vec<u8> = Vec::new();
        PngEncoder::new(&mut image_data).encode(data, width, height, color)?;
        write_icondir(&mut self.w, 1)?;
        write_direntry(
            &mut self.w,
            width,
            height,
            color,
            ICO_ICONDIR_SIZE + ICO_DIRENTRY_SIZE,
            image_data.len() as u32,
        )?;
        self.w.write_all(&image_data)?;
        Ok(())
    }
}
impl<W: Write> ImageEncoder for IcoEncoder<W> {
    fn write_image(
        self,
        buf: &[u8],
        width: u32,
        height: u32,
        color_type: ColorType,
    ) -> ImageResult<()> {
        self.encode(buf, width, height, color_type)
    }
}
fn write_icondir<W: Write>(w: &mut W, num_images: u16) -> io::Result<()> {
    
    w.write_u16::<LittleEndian>(0)?;
    
    w.write_u16::<LittleEndian>(ICO_IMAGE_TYPE)?;
    
    w.write_u16::<LittleEndian>(num_images)?;
    Ok(())
}
fn write_direntry<W: Write>(
    w: &mut W,
    width: u32,
    height: u32,
    color: ColorType,
    data_start: u32,
    data_size: u32,
) -> io::Result<()> {
    
    write_width_or_height(w, width)?;
    write_width_or_height(w, height)?;
    
    w.write_u8(0)?;
    
    w.write_u8(0)?;
    
    w.write_u16::<LittleEndian>(0)?;
    
    w.write_u16::<LittleEndian>(color.bits_per_pixel())?;
    
    w.write_u32::<LittleEndian>(data_size)?;
    
    w.write_u32::<LittleEndian>(data_start)?;
    Ok(())
}
fn write_width_or_height<W: Write>(w: &mut W, value: u32) -> io::Result<()> {
    if value < 1 || value > 256 {
        
        
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            "Invalid ICO dimensions (width and \
             height must be between 1 and 256)",
        ));
    }
    w.write_u8(if value < 256 { value as u8 } else { 0 })
}