summaryrefslogtreecommitdiffstats
path: root/cairo-renderer/src/lib.rs
diff options
context:
space:
mode:
authorMinijackson <minijackson@riseup.net>2023-03-03 09:03:12 +0100
committerMinijackson <minijackson@riseup.net>2023-03-03 09:03:12 +0100
commitf0db30c92348b0a71633c25d25569c925d0c77b7 (patch)
treedd26413cda95d1ed441f41aab921855c79f30f85 /cairo-renderer/src/lib.rs
parent1535dea8ab8e0a5a9d00664de3509db84c1908a9 (diff)
downloaddiaphragm-f0db30c92348b0a71633c25d25569c925d0c77b7.tar.gz
diaphragm-f0db30c92348b0a71633c25d25569c925d0c77b7.zip
cairo-renderer: add support for SVG images
Diffstat (limited to 'cairo-renderer/src/lib.rs')
-rw-r--r--cairo-renderer/src/lib.rs83
1 files changed, 70 insertions, 13 deletions
diff --git a/cairo-renderer/src/lib.rs b/cairo-renderer/src/lib.rs
index 01eb7ef..d49e5ce 100644
--- a/cairo-renderer/src/lib.rs
+++ b/cairo-renderer/src/lib.rs
@@ -4,6 +4,8 @@ use std::{
4}; 4};
5 5
6use gdk::{gdk_pixbuf::Pixbuf, prelude::GdkContextExt}; 6use gdk::{gdk_pixbuf::Pixbuf, prelude::GdkContextExt};
7use librsvg::SvgHandle;
8use mime_guess::mime;
7 9
8use diaphragm_core::{ 10use diaphragm_core::{
9 styles::{DefinedDashStyle, Pattern}, 11 styles::{DefinedDashStyle, Pattern},
@@ -11,9 +13,38 @@ use diaphragm_core::{
11 Renderer, 13 Renderer,
12}; 14};
13 15
16enum Image {
17 Pixbuf(Pixbuf),
18 Svg(SvgHandle),
19}
20
21impl Image {
22 fn width(&self) -> f64 {
23 match self {
24 Image::Pixbuf(pixbuf) => pixbuf.width() as f64,
25 Image::Svg(handle) => {
26 let dimensions = librsvg::CairoRenderer::new(handle).intrinsic_dimensions();
27 // TODO: this doesn't check if the SVG has different unit for width of height
28 dimensions.width.length
29 }
30 }
31 }
32
33 fn height(&self) -> f64 {
34 match self {
35 Image::Pixbuf(pixbuf) => pixbuf.height() as f64,
36 Image::Svg(handle) => {
37 let dimensions = librsvg::CairoRenderer::new(handle).intrinsic_dimensions();
38 // TODO: this doesn't check if the SVG has different unit for width of height
39 dimensions.height.length
40 }
41 }
42 }
43}
44
14pub struct CairoRenderer { 45pub struct CairoRenderer {
15 ctx: cairo::Context, 46 ctx: cairo::Context,
16 loaded_images: HashMap<PathBuf, Pixbuf>, 47 loaded_images: HashMap<PathBuf, Image>,
17} 48}
18 49
19impl CairoRenderer { 50impl CairoRenderer {
@@ -29,11 +60,24 @@ impl CairoRenderer {
29 } 60 }
30 } 61 }
31 62
32 fn get_image(&mut self, path: &Path) -> &Pixbuf { 63 fn load_image(&mut self, path: &Path) {
33 let path = path.to_owned(); 64 if self.loaded_images.contains_key(path) {
34 self.loaded_images 65 return;
35 .entry(path.clone()) 66 }
36 .or_insert_with(|| Pixbuf::from_file(path).unwrap()) 67
68 let mime_type = mime_guess::from_path(&path).first().unwrap();
69 assert_eq!(mime_type.type_(), "image", "File is not an image");
70 let image = match mime_type.subtype() {
71 mime::SVG => Image::Svg(librsvg::Loader::new().read_path(path).unwrap()),
72 // TODO: use Pixbuf::formats() to check for supported formats
73 mime::PNG | mime::GIF | mime::JPEG => Image::Pixbuf(Pixbuf::from_file(path).unwrap()),
74 other => panic!("Unsupported image type: {}", other),
75 };
76 self.loaded_images.insert(path.to_owned(), image);
77 }
78
79 fn get_image(&self, path: &Path) -> &Image {
80 self.loaded_images.get(path).unwrap()
37 } 81 }
38} 82}
39 83
@@ -134,23 +178,36 @@ impl Renderer for CairoRenderer {
134 } 178 }
135 179
136 fn show_image(&mut self, path: &Path, x: f64, y: f64, width: f64, height: f64) { 180 fn show_image(&mut self, path: &Path, x: f64, y: f64, width: f64, height: f64) {
137 let image = self.get_image(path).clone(); 181 self.load_image(path);
182 let image = self.get_image(path);
138 183
139 self.ctx.save().unwrap(); 184 self.ctx.save().unwrap();
140 185
141 let scale_x = width / image.width() as f64; 186 match image {
142 let scale_y = height / image.height() as f64; 187 Image::Pixbuf(pixbuf) => {
188 let scale_x = width / image.width();
189 let scale_y = height / image.height();
143 190
144 self.ctx.scale(scale_x, scale_y); 191 self.ctx.scale(scale_x, scale_y);
145 192
146 self.ctx.set_source_pixbuf(&image, x / scale_x, y / scale_y); 193 self.ctx.set_source_pixbuf(pixbuf, x / scale_x, y / scale_y);
147 self.ctx.paint().unwrap(); 194 self.ctx.paint().unwrap();
195 }
196 Image::Svg(handle) => {
197 // TODO: if aspect ratio is not kept, the image is not "scaled", only margins are
198 // added
199 librsvg::CairoRenderer::new(handle)
200 .render_document(&self.ctx, &cairo::Rectangle::new(x, y, width, height))
201 .unwrap();
202 }
203 }
148 204
149 self.ctx.restore().unwrap(); 205 self.ctx.restore().unwrap();
150 } 206 }
151 207
152 fn geometry_for_image(&mut self, path: &Path) -> (f64, f64) { 208 fn geometry_for_image(&mut self, path: &Path) -> (f64, f64) {
209 self.load_image(path);
153 let image = self.get_image(path); 210 let image = self.get_image(path);
154 (image.width() as f64, image.height() as f64) 211 (image.width(), image.height())
155 } 212 }
156} 213}