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
use std::io;
use image::{imageops, DynamicImage, ImageBuffer, GenericImageView, FilterType, Bgra};
use resvg::{usvg::{self, Tree}, raqote::DrawTarget , FitTo};
pub use error::ResampleError;
mod error;
pub fn linear(source: &DynamicImage, size: u32) -> io::Result<DynamicImage> {
overfit(&scale(source, size, FilterType::Triangle)?, size)
}
pub fn cubic(source: &DynamicImage, size: u32) -> io::Result<DynamicImage> {
overfit(&scale(source, size, FilterType::Lanczos3)?, size)
}
pub fn nearest(source: &DynamicImage, size: u32) -> io::Result<DynamicImage> {
let scaled = if source.width() < size && source.height() < size {
nearest_upscale_integer(source, size)?
} else {
scale(source, size, FilterType::Nearest)?
};
overfit(&scaled, size)
}
pub fn apply<F: FnMut(&DynamicImage, u32) -> io::Result<DynamicImage>>(
mut filter: F,
source: &DynamicImage,
size: u32
) -> Result<DynamicImage, ResampleError> {
let icon = filter(source, size)?;
let dims = icon.dimensions();
if dims != (size, size) {
Err(ResampleError::MismatchedDimensions(size, dims))
} else {
Ok(icon)
}
}
fn nearest_upscale_integer(source: &DynamicImage, size: u32) -> io::Result<DynamicImage> {
let (w , h) = source.dimensions();
let scale = if w > h { size / w } else { size / h };
let (nw, nh) = (w * scale, h * scale);
Ok(DynamicImage::ImageRgba8(imageops::resize(source, nw, nh, FilterType::Nearest)))
}
fn scale(source: &DynamicImage, size: u32, filter: FilterType) -> io::Result<DynamicImage> {
let (w , h) = source.dimensions();
let (nw, nh) = if w > h { (size, (size * h) / w) } else { ((size * w) / h, size) };
Ok(DynamicImage::ImageRgba8(imageops::resize(source, nw, nh, filter)))
}
fn overfit(source: &DynamicImage, size: u32) -> io::Result<DynamicImage> {
let mut output = DynamicImage::new_rgba8(size, size);
let dx = (output.width() - source.width() ) / 2;
let dy = (output.height() - source.height()) / 2;
imageops::overlay(&mut output, source, dx, dy);
Ok(output)
}
pub(crate) fn svg(source: &Tree, size: u32) -> Result<DynamicImage, ResampleError> {
let rect = source.svg_node().view_box.rect;
let (w, h) = (rect.width(), rect.height());
let fit_to = if w > h { FitTo::Width(size) } else { FitTo::Height(size) };
let opts = resvg::Options {
usvg: usvg::Options::default(),
fit_to,
background: None
};
let draw_target = resvg::backend_raqote::render_to_image(source, &opts)
.expect("Could not render svg tree to image buffer");
Ok(draw_target_to_rgba(draw_target, size)?)
}
#[inline]
fn draw_target_to_rgba(mut surface: DrawTarget, size: u32) -> io::Result<DynamicImage> {
let (w, h) = (surface.width() as u32, surface.height() as u32);
let data = surface.get_data_u8_mut().to_vec();
match ImageBuffer::<Bgra<u8>, Vec<u8>>::from_vec(w, h, data) {
Some(buf) => overfit(&DynamicImage::ImageBgra8(buf), size),
None => panic!("Buffer in not big enought")
}
}