diff options
Diffstat (limited to 'cairo-renderer/src/lib.rs')
-rw-r--r-- | cairo-renderer/src/lib.rs | 83 |
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 | ||
6 | use gdk::{gdk_pixbuf::Pixbuf, prelude::GdkContextExt}; | 6 | use gdk::{gdk_pixbuf::Pixbuf, prelude::GdkContextExt}; |
7 | use librsvg::SvgHandle; | ||
8 | use mime_guess::mime; | ||
7 | 9 | ||
8 | use diaphragm_core::{ | 10 | use 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 | ||
16 | enum Image { | ||
17 | Pixbuf(Pixbuf), | ||
18 | Svg(SvgHandle), | ||
19 | } | ||
20 | |||
21 | impl 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 | |||
14 | pub struct CairoRenderer { | 45 | pub 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 | ||
19 | impl CairoRenderer { | 50 | impl 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 | } |