This repository has no description
0

Configure Feed

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

at main 4.9 kB View raw
1use super::renderable::SVGRenderable; 2use crate::{ 3 Object, 4 graphics::canvas::Canvas, 5 rendering::{ 6 rasterization::{ 7 create_pixmap, pixmap_to_png_data, svg_to_usvg_tree, 8 usvg_tree_to_pixmap, write_png_data, 9 }, 10 svg, 11 }, 12}; 13use measure_time::debug_time; 14use std::path::PathBuf; 15 16impl SVGRenderable for Canvas { 17 fn render_to_svg( 18 &self, 19 colormap: crate::ColorMapping, 20 cell_size: usize, 21 object_sizes: crate::graphics::objects::ObjectSizes, 22 _id: &str, 23 ) -> anyhow::Result<svg::Node> { 24 debug_time!("render_to_svg/canvas"); 25 let background_color = self.background.unwrap_or_default(); 26 let mut svg = svg::tag("svg").attr("xmlns", "http://www.w3.org/2000/svg"); 27 28 svg.add( 29 svg::tag("rect") 30 .attr("x", -(self.outer_padding as i32)) 31 .attr("y", -(self.outer_padding as i32)) 32 .attr("width", self.width()) 33 .attr("height", self.height()) 34 .attr("fill", background_color.render(&self.colormap)), 35 ); 36 37 for layer in self.layers.iter().filter(|layer| !layer.hidden).rev() { 38 svg.add(layer.render_to_svg( 39 colormap.clone(), 40 cell_size, 41 layer.object_sizes, 42 layer.name.as_str(), 43 )?); 44 } 45 46 let mut defs = svg::tag("defs"); 47 for filter in self.unique_filters() { 48 defs.add(filter.render_to_svg( 49 colormap.clone(), 50 cell_size, 51 object_sizes, 52 "", 53 )?); 54 } 55 56 for pattern_fill in self.unique_pattern_fills() { 57 if let Some(patterndef) = 58 pattern_fill.pattern_definition(&self.colormap) 59 { 60 defs.add(patterndef); 61 } 62 } 63 64 for layer in self.layers.iter() { 65 for Object { clip_to, .. } in layer.objects.values() { 66 if let Some(region) = clip_to { 67 defs.add( 68 svg::tag("clipPath") 69 .attr("id", region.clip_path_id()) 70 .child( 71 svg::tag("rect") 72 .position(region.start, cell_size) 73 .size(*region, cell_size) 74 .node(), 75 ), 76 ); 77 } 78 } 79 } 80 81 svg.add(defs); 82 83 Ok(svg 84 .attr( 85 "viewBox", 86 format!( 87 "{0} {0} {1} {2}", 88 -(self.outer_padding as i32), 89 self.width(), 90 self.height() 91 ), 92 ) 93 .attr("width", self.width()) 94 .attr("height", self.height()) 95 .into()) 96 } 97} 98 99impl Canvas { 100 pub fn svg_to_pixmap( 101 &self, 102 width: u32, 103 height: u32, 104 contents: &str, 105 ) -> anyhow::Result<tiny_skia::Pixmap> { 106 let mut pixmap = create_pixmap(width, height); 107 108 let parsed_svg = &svg_to_usvg_tree(contents, &self.fontdb)?; 109 110 usvg_tree_to_pixmap(self.dimensions(), pixmap.as_mut(), parsed_svg); 111 112 Ok(pixmap) 113 } 114 115 pub fn render_to_pixmap( 116 &mut self, 117 width: u32, 118 height: u32, 119 ) -> anyhow::Result<tiny_skia::Pixmap> { 120 let svg_contents = self 121 .render_to_svg( 122 self.colormap.clone(), 123 self.cell_size, 124 self.object_sizes, 125 "", 126 )? 127 .to_string(); 128 self.svg_to_pixmap(width, height, &svg_contents) 129 } 130 131 // 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 132 pub fn render_to_png( 133 &mut self, 134 at: &str, 135 resolution: u32, 136 ) -> anyhow::Result<()> { 137 debug_time!("render_to_png"); 138 let (width, height) = self.resolution_to_size(resolution); 139 140 self.render_to_pixmap(width, height).and_then(|pixmap| { 141 pixmap_to_png_data(pixmap).and_then(|data| write_png_data(data, at)) 142 }) 143 } 144 145 pub fn render_to_svg_string(&mut self) -> anyhow::Result<String> { 146 debug_time!("render_to_svg_string"); 147 148 let rendered = self.render_to_svg( 149 self.colormap.clone(), 150 self.cell_size, 151 self.object_sizes, 152 "", 153 )?; 154 155 Ok(rendered.to_string()) 156 } 157 158 pub fn render_to_svg_file( 159 &mut self, 160 at: impl Into<PathBuf>, 161 ) -> anyhow::Result<()> { 162 debug_time!("render_to_svg_file"); 163 164 std::fs::write(at.into(), self.render_to_svg_string()?)?; 165 166 Ok(()) 167 } 168}