This repository has no description
1use super::renderable::SVGRenderable;
2use crate::{
3 graphics::canvas::Canvas,
4 rendering::{
5 rasterization::{
6 create_pixmap, pixmap_to_png_data, svg_to_usvg_tree,
7 usvg_tree_to_pixmap, write_png_data,
8 },
9 svg,
10 },
11};
12use measure_time::debug_time;
13
14impl SVGRenderable for Canvas {
15 fn render_to_svg(
16 &self,
17 colormap: crate::ColorMapping,
18 cell_size: usize,
19 object_sizes: crate::graphics::objects::ObjectSizes,
20 _id: &str,
21 ) -> anyhow::Result<svg::Node> {
22 debug_time!("render_to_svg/canvas");
23 let background_color = self.background.unwrap_or_default();
24 let mut svg = svg::tag("svg").attr("xmlns", "http://www.w3.org/2000/svg");
25
26 svg.add(
27 svg::tag("rect")
28 .attr("x", -(self.canvas_outer_padding as i32))
29 .attr("y", -(self.canvas_outer_padding as i32))
30 .attr("width", self.width())
31 .attr("height", self.height())
32 .attr("fill", background_color.render(&self.colormap)),
33 );
34
35 for layer in self.layers.iter().filter(|layer| !layer.hidden).rev() {
36 svg.add(layer.render_to_svg(
37 colormap.clone(),
38 cell_size,
39 layer.object_sizes,
40 layer.name.as_str(),
41 )?);
42 }
43
44 let mut defs = svg::tag("defs");
45 for filter in self.unique_filters() {
46 defs.add(filter.render_to_svg(
47 colormap.clone(),
48 cell_size,
49 object_sizes,
50 "",
51 )?);
52 }
53
54 for pattern_fill in self.unique_pattern_fills() {
55 if let Some(patterndef) =
56 pattern_fill.pattern_definition(&self.colormap)
57 {
58 defs.add(patterndef);
59 }
60 }
61
62 svg.add(defs);
63
64 Ok(svg
65 .attr(
66 "viewBox",
67 format!(
68 "{0} {0} {1} {2}",
69 -(self.canvas_outer_padding as i32),
70 self.width(),
71 self.height()
72 ),
73 )
74 .attr("width", self.width())
75 .attr("height", self.height())
76 .into())
77 }
78}
79
80impl Canvas {
81 pub fn svg_to_pixmap(
82 &self,
83 width: u32,
84 height: u32,
85 contents: &str,
86 ) -> anyhow::Result<tiny_skia::Pixmap> {
87 let mut pixmap = create_pixmap(width, height);
88
89 let parsed_svg = &svg_to_usvg_tree(contents, &self.fontdb)?;
90
91 usvg_tree_to_pixmap(self.dimensions(), pixmap.as_mut(), parsed_svg);
92
93 Ok(pixmap)
94 }
95
96 pub fn render_to_pixmap(
97 &mut self,
98 width: u32,
99 height: u32,
100 ) -> anyhow::Result<tiny_skia::Pixmap> {
101 let svg_contents = self
102 .render_to_svg(
103 self.colormap.clone(),
104 self.cell_size,
105 self.object_sizes,
106 "",
107 )?
108 .to_string();
109 self.svg_to_pixmap(width, height, &svg_contents)
110 }
111
112 // previous_frame_at gives path to the previously rendered frame, which allows to copy on cache hits instead of having to re-write bytes again
113 pub fn render_to_png(
114 &mut self,
115 at: &str,
116 resolution: u32,
117 ) -> anyhow::Result<()> {
118 debug_time!("render_to_png");
119 let (width, height) = self.resolution_to_size(resolution);
120
121 self.render_to_pixmap(width, height).and_then(|pixmap| {
122 pixmap_to_png_data(pixmap).and_then(|data| write_png_data(data, at))
123 })
124 }
125
126 pub fn render_to_svg_string(&mut self) -> anyhow::Result<String> {
127 debug_time!("render_to_svg_string");
128
129 let rendered = self.render_to_svg(
130 self.colormap.clone(),
131 self.cell_size,
132 self.object_sizes,
133 "",
134 )?;
135
136 Ok(rendered.to_string())
137 }
138
139 pub fn render_to_svg_file(&mut self, at: &str) -> anyhow::Result<()> {
140 debug_time!("render_to_svg_file");
141
142 std::fs::write(at, self.render_to_svg_string()?)?;
143
144 Ok(())
145 }
146}