This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

1use super::renderable::SVGRenderable; 2use crate::{graphics::canvas::Canvas, rendering::svg}; 3use measure_time::debug_time; 4use resvg::usvg; 5use std::sync::Arc; 6 7impl SVGRenderable for Canvas { 8 fn render_to_svg( 9 &self, 10 colormap: crate::ColorMapping, 11 cell_size: usize, 12 object_sizes: crate::graphics::objects::ObjectSizes, 13 _id: &str, 14 ) -> anyhow::Result<svg::Node> { 15 debug_time!("render_to_svg/canvas"); 16 let background_color = self.background.unwrap_or_default(); 17 let mut svg = svg::tag("svg").attr("xmlns", "http://www.w3.org/2000/svg"); 18 19 svg.add( 20 svg::tag("rect") 21 .attr("x", -(self.canvas_outer_padding as i32)) 22 .attr("y", -(self.canvas_outer_padding as i32)) 23 .attr("width", self.width()) 24 .attr("height", self.height()) 25 .attr("fill", background_color.render(&self.colormap)), 26 ); 27 28 for layer in self.layers.iter().filter(|layer| !layer.hidden).rev() { 29 svg.add(layer.render_to_svg( 30 colormap.clone(), 31 cell_size, 32 layer.object_sizes, 33 layer.name.as_str(), 34 )?); 35 } 36 37 let mut defs = svg::tag("defs"); 38 for filter in self.unique_filters() { 39 defs.add(filter.render_to_svg( 40 colormap.clone(), 41 cell_size, 42 object_sizes, 43 "", 44 )?); 45 } 46 47 for pattern_fill in self.unique_pattern_fills() { 48 if let Some(patterndef) = 49 pattern_fill.pattern_definition(&self.colormap) 50 { 51 defs.add(patterndef); 52 } 53 } 54 55 svg.add(defs); 56 57 Ok(svg 58 .attr( 59 "viewBox", 60 format!( 61 "{0} {0} {1} {2}", 62 -(self.canvas_outer_padding as i32), 63 self.width(), 64 self.height() 65 ), 66 ) 67 .attr("width", self.width()) 68 .attr("height", self.height()) 69 .into()) 70 } 71} 72 73impl Canvas { 74 pub fn svg_to_pixmap( 75 &self, 76 width: u32, 77 height: u32, 78 contents: &str, 79 ) -> anyhow::Result<tiny_skia::Pixmap> { 80 let mut pixmap = self.create_pixmap(width, height); 81 82 let parsed_svg = &svg_to_usvg_tree(contents, &self.fontdb)?; 83 84 self.usvg_tree_to_pixmap(width, height, pixmap.as_mut(), parsed_svg); 85 86 Ok(pixmap) 87 } 88 89 pub fn render_to_pixmap( 90 &mut self, 91 width: u32, 92 height: u32, 93 ) -> anyhow::Result<tiny_skia::Pixmap> { 94 let svg_contents = self 95 .render_to_svg( 96 self.colormap.clone(), 97 self.cell_size, 98 self.object_sizes, 99 "", 100 )? 101 .to_string(); 102 self.svg_to_pixmap(width, height, &svg_contents) 103 } 104 105 fn usvg_tree_to_pixmap( 106 &self, 107 width: u32, 108 height: u32, 109 mut pixmap_mut: tiny_skia::PixmapMut<'_>, 110 parsed_svg: &resvg::usvg::Tree, 111 ) { 112 debug_time!("usvg_tree_to_pixmap"); 113 resvg::render( 114 parsed_svg, 115 tiny_skia::Transform::from_scale( 116 width as f32 / self.width() as f32, 117 height as f32 / self.height() as f32, 118 ), 119 &mut pixmap_mut, 120 ); 121 } 122 123 fn create_pixmap(&self, width: u32, height: u32) -> tiny_skia::Pixmap { 124 debug_time!("create_pixmap"); 125 tiny_skia::Pixmap::new(width, height).expect("Failed to create pixmap") 126 } 127 128 // 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 129 pub fn render_to_png( 130 &mut self, 131 at: &str, 132 resolution: u32, 133 ) -> anyhow::Result<()> { 134 debug_time!("render_to_png"); 135 let (width, height) = self.resolution_to_size(resolution); 136 137 self.render_to_pixmap(width, height).and_then(|pixmap| { 138 pixmap_to_png_data(pixmap).and_then(|data| write_png_data(data, at)) 139 }) 140 } 141 142 pub fn render_to_svg_string(&mut self) -> anyhow::Result<String> { 143 debug_time!("render_to_svg_string"); 144 145 let rendered = self.render_to_svg( 146 self.colormap.clone(), 147 self.cell_size, 148 self.object_sizes, 149 "", 150 )?; 151 152 Ok(rendered.to_string()) 153 } 154 155 pub fn render_to_svg_file(&mut self, at: &str) -> anyhow::Result<()> { 156 debug_time!("render_to_svg_file"); 157 158 std::fs::write(at, self.render_to_svg_string()?)?; 159 160 Ok(()) 161 } 162} 163 164fn svg_to_usvg_tree( 165 svg: &str, 166 fontdb: &Option<Arc<usvg::fontdb::Database>>, 167) -> anyhow::Result<resvg::usvg::Tree> { 168 debug_time!("svg_to_usvg_tree"); 169 Ok(resvg::usvg::Tree::from_str( 170 svg, 171 &match fontdb { 172 Some(fontdb) => resvg::usvg::Options { 173 fontdb: fontdb.clone(), 174 ..Default::default() 175 }, 176 None => resvg::usvg::Options::default(), 177 }, 178 )?) 179} 180 181fn pixmap_to_png_data(pixmap: tiny_skia::Pixmap) -> anyhow::Result<Vec<u8>> { 182 debug_time!("pixmap_to_png_data"); 183 Ok(pixmap.encode_png()?) 184} 185 186fn write_png_data(data: Vec<u8>, at: &str) -> anyhow::Result<()> { 187 debug_time!("write_png_data"); 188 std::fs::write(at, data)?; 189 Ok(()) 190}