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
extern crate ico;
use crate::{AsSize, IconError, Icon, Image};
use image::DynamicImage;
use std::{
convert::TryFrom,
fmt::{self, Debug, Formatter},
io::{self, Write},
result,
};
#[derive(Clone)]
pub struct Ico {
icon_dir: ico::IconDir,
keys: Vec<u32>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Key(pub u8);
impl Icon for Ico {
type Key = Key;
fn with_capacity(capacity: usize) -> Self {
Ico {
icon_dir: ico::IconDir::new(ico::ResourceType::Icon),
keys: Vec::with_capacity(capacity),
}
}
fn len(&self) -> usize {
self.icon_dir.entries().len()
}
fn add_entry<F: FnMut(&DynamicImage, u32) -> io::Result<DynamicImage>>(
&mut self,
filter: F,
source: &Image,
key: Self::Key,
) -> Result<(), IconError<Self::Key>> {
let size = key.as_size();
if self.keys.contains(&size) {
return Err(IconError::AlreadyIncluded(key));
}
let icon = source.rasterize(filter, size)?;
let data = icon.to_rgba().into_vec();
let image = ico::IconImage::from_rgba_data(size, size, data);
let entry = ico::IconDirEntry::encode(&image)?;
self.icon_dir.add_entry(entry);
Ok(())
}
fn write<W: Write>(&mut self, w: &mut W) -> io::Result<()> {
self.icon_dir.write(w)
}
}
impl Debug for Ico {
fn fmt(&self, f: &mut Formatter) -> result::Result<(), fmt::Error> {
let n_entries = self.icon_dir.entries().len();
let mut entries_str = String::with_capacity(42 * n_entries);
for _ in 0..n_entries {
entries_str.push_str("ico::IconDirEntry {{ /* fields omitted */ }}, ");
}
let icon_dir = format!(
"ico::IconDir {{ restype: ico::ResourceType::Icon, entries: [{:?}] }}",
entries_str
);
write!(f, "iconwriter::Ico {{ icon_dir: {} }} ", icon_dir)
}
}
impl AsSize for Key {
fn as_size(&self) -> u32 {
if self.0 == 0 {
256
} else {
self.0 as u32
}
}
}
impl TryFrom<u32> for Key {
type Error = io::Error;
fn try_from(val: u32) -> io::Result<Self> {
match val {
256 => Ok(Key(0)),
0 => Err(io::Error::from(io::ErrorKind::InvalidInput)),
n if n < 256 => Ok(Key(n as u8)),
_ => Err(io::Error::from(io::ErrorKind::InvalidInput))
}
}
}