1pub fn render(
6 image: &usvg::Image,
7 transform: tiny_skia::Transform,
8 pixmap: &mut tiny_skia::PixmapMut,
9) {
10 if !image.is_visible() {
11 return;
12 }
13
14 render_inner(image.kind(), transform, image.rendering_mode(), pixmap);
15}
16
17pub fn render_inner(
18 image_kind: &usvg::ImageKind,
19 transform: tiny_skia::Transform,
20 #[allow(unused_variables)] rendering_mode: usvg::ImageRendering,
21 pixmap: &mut tiny_skia::PixmapMut,
22) {
23 match image_kind {
24 usvg::ImageKind::SVG(ref tree) => {
25 render_vector(tree, transform, pixmap);
26 }
27 #[cfg(feature = "raster-images")]
28 _ => {
29 raster_images::render_raster(image_kind, transform, rendering_mode, pixmap);
30 }
31 #[cfg(not(feature = "raster-images"))]
32 _ => {
33 log::warn!("Images decoding was disabled by a build feature.");
34 }
35 }
36}
37
38fn render_vector(
39 tree: &usvg::Tree,
40 transform: tiny_skia::Transform,
41 pixmap: &mut tiny_skia::PixmapMut,
42) -> Option<()> {
43 let mut sub_pixmap = tiny_skia::Pixmap::new(pixmap.width(), pixmap.height()).unwrap();
44 crate::render(tree, transform, &mut sub_pixmap.as_mut());
45 pixmap.draw_pixmap(
46 0,
47 0,
48 sub_pixmap.as_ref(),
49 &tiny_skia::PixmapPaint::default(),
50 tiny_skia::Transform::default(),
51 None,
52 );
53
54 Some(())
55}
56
57#[cfg(feature = "raster-images")]
58mod raster_images {
59 use crate::OptionLog;
60
61 fn decode_raster(image: &usvg::ImageKind) -> Option<tiny_skia::Pixmap> {
62 match image {
63 usvg::ImageKind::SVG(_) => None,
64 usvg::ImageKind::JPEG(ref data) => {
65 decode_jpeg(data).log_none(|| log::warn!("Failed to decode a JPEG image."))
66 }
67 usvg::ImageKind::PNG(ref data) => {
68 decode_png(data).log_none(|| log::warn!("Failed to decode a PNG image."))
69 }
70 usvg::ImageKind::GIF(ref data) => {
71 decode_gif(data).log_none(|| log::warn!("Failed to decode a GIF image."))
72 }
73 }
74 }
75
76 fn decode_png(data: &[u8]) -> Option<tiny_skia::Pixmap> {
77 tiny_skia::Pixmap::decode_png(data).ok()
78 }
79
80 fn decode_jpeg(data: &[u8]) -> Option<tiny_skia::Pixmap> {
81 let mut decoder = jpeg_decoder::Decoder::new(data);
82 let img_data = decoder.decode().ok()?;
83 let info = decoder.info()?;
84
85 let size = tiny_skia::IntSize::from_wh(info.width as u32, info.height as u32)?;
86
87 let data = match info.pixel_format {
88 jpeg_decoder::PixelFormat::RGB24 => img_data,
89 jpeg_decoder::PixelFormat::L8 => {
90 let mut rgb_data: Vec<u8> = Vec::with_capacity(img_data.len() * 3);
91 for gray in img_data {
92 rgb_data.push(gray);
93 rgb_data.push(gray);
94 rgb_data.push(gray);
95 }
96
97 rgb_data
98 }
99 _ => return None,
100 };
101
102 let (w, h) = size.dimensions();
103 let mut pixmap = tiny_skia::Pixmap::new(w, h)?;
104 rgb_to_pixmap(&data, &mut pixmap);
105 Some(pixmap)
106 }
107
108 fn decode_gif(data: &[u8]) -> Option<tiny_skia::Pixmap> {
109 let mut decoder = gif::DecodeOptions::new();
110 decoder.set_color_output(gif::ColorOutput::RGBA);
111 let mut decoder = decoder.read_info(data).ok()?;
112 let first_frame = decoder.read_next_frame().ok()??;
113
114 let size = tiny_skia::IntSize::from_wh(
115 u32::from(first_frame.width),
116 u32::from(first_frame.height),
117 )?;
118
119 let (w, h) = size.dimensions();
120 let mut pixmap = tiny_skia::Pixmap::new(w, h)?;
121 rgba_to_pixmap(&first_frame.buffer, &mut pixmap);
122 Some(pixmap)
123 }
124
125 fn rgb_to_pixmap(data: &[u8], pixmap: &mut tiny_skia::Pixmap) {
126 use rgb::FromSlice;
127
128 let mut i = 0;
129 let dst = pixmap.data_mut();
130 for p in data.as_rgb() {
131 dst[i + 0] = p.r;
132 dst[i + 1] = p.g;
133 dst[i + 2] = p.b;
134 dst[i + 3] = 255;
135
136 i += tiny_skia::BYTES_PER_PIXEL;
137 }
138 }
139
140 fn rgba_to_pixmap(data: &[u8], pixmap: &mut tiny_skia::Pixmap) {
141 use rgb::FromSlice;
142
143 let mut i = 0;
144 let dst = pixmap.data_mut();
145 for p in data.as_rgba() {
146 let a = p.a as f64 / 255.0;
147 dst[i + 0] = (p.r as f64 * a + 0.5) as u8;
148 dst[i + 1] = (p.g as f64 * a + 0.5) as u8;
149 dst[i + 2] = (p.b as f64 * a + 0.5) as u8;
150 dst[i + 3] = p.a;
151
152 i += tiny_skia::BYTES_PER_PIXEL;
153 }
154 }
155
156 pub(crate) fn render_raster(
157 image: &usvg::ImageKind,
158 transform: tiny_skia::Transform,
159 rendering_mode: usvg::ImageRendering,
160 pixmap: &mut tiny_skia::PixmapMut,
161 ) -> Option<()> {
162 let raster = decode_raster(image)?;
163
164 let rect = tiny_skia::Size::from_wh(raster.width() as f32, raster.height() as f32)?
165 .to_rect(0.0, 0.0)?;
166
167 let mut quality = tiny_skia::FilterQuality::Bicubic;
168 if rendering_mode == usvg::ImageRendering::OptimizeSpeed {
169 quality = tiny_skia::FilterQuality::Nearest;
170 }
171
172 let pattern = tiny_skia::Pattern::new(
173 raster.as_ref(),
174 tiny_skia::SpreadMode::Pad,
175 quality,
176 1.0,
177 tiny_skia::Transform::default(),
178 );
179 let mut paint = tiny_skia::Paint::default();
180 paint.shader = pattern;
181
182 pixmap.fill_rect(rect, &paint, transform, None);
183
184 Some(())
185 }
186}