From 0ceee1cf3ae49f5bd0e3f2b346a4b34076e4523a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 4 Aug 2024 03:28:43 +0200 Subject: Implement image support for `canvas` widget --- graphics/Cargo.toml | 1 + graphics/src/geometry/frame.rs | 72 ++++++++++++++++++++++++++++++++++++++---- graphics/src/image.rs | 6 ++++ 3 files changed, 72 insertions(+), 7 deletions(-) (limited to 'graphics') diff --git a/graphics/Cargo.toml b/graphics/Cargo.toml index e8d27d07..7e2d767b 100644 --- a/graphics/Cargo.toml +++ b/graphics/Cargo.toml @@ -20,6 +20,7 @@ all-features = true [features] geometry = ["lyon_path"] image = ["dep:image", "kamadak-exif"] +svg = [] web-colors = [] fira-sans = [] diff --git a/graphics/src/geometry/frame.rs b/graphics/src/geometry/frame.rs index 377589d7..d53d1331 100644 --- a/graphics/src/geometry/frame.rs +++ b/graphics/src/geometry/frame.rs @@ -1,5 +1,7 @@ //! Draw and generate geometry. -use crate::core::{Point, Radians, Rectangle, Size, Vector}; +use crate::core::image; +use crate::core::svg; +use crate::core::{Color, Point, Radians, Rectangle, Size, Vector}; use crate::geometry::{self, Fill, Path, Stroke, Text}; /// The region of a surface that can be used to draw geometry. @@ -75,6 +77,25 @@ where self.raw.fill_text(text); } + /// Draws the given image on the [`Frame`] inside the given bounds. + #[cfg(feature = "image")] + pub fn draw_image( + &mut self, + handle: &image::Handle, + bounds: Rectangle, + filter_method: image::FilterMethod, + rotation: impl Into, + opacity: f32, + ) { + self.raw.draw_image( + handle, + bounds, + filter_method, + rotation.into(), + opacity, + ); + } + /// Stores the current transform of the [`Frame`] and executes the given /// drawing operations, restoring the transform afterwards. /// @@ -116,8 +137,7 @@ where let mut frame = self.draft(region); let result = f(&mut frame); - - self.paste(frame, Point::new(region.x, region.y)); + self.paste(frame); result } @@ -134,8 +154,8 @@ where } /// Draws the contents of the given [`Frame`] with origin at the given [`Point`]. - fn paste(&mut self, frame: Self, at: Point) { - self.raw.paste(frame.raw, at); + fn paste(&mut self, frame: Self) { + self.raw.paste(frame.raw); } /// Applies a translation to the current transform of the [`Frame`]. @@ -186,7 +206,7 @@ pub trait Backend: Sized { fn scale_nonuniform(&mut self, scale: impl Into); fn draft(&mut self, clip_bounds: Rectangle) -> Self; - fn paste(&mut self, frame: Self, at: Point); + fn paste(&mut self, frame: Self); fn stroke<'a>(&mut self, path: &Path, stroke: impl Into>); @@ -199,6 +219,24 @@ pub trait Backend: Sized { fill: impl Into, ); + fn draw_image( + &mut self, + handle: &image::Handle, + bounds: Rectangle, + filter_method: image::FilterMethod, + rotation: Radians, + opacity: f32, + ); + + fn draw_svg( + &mut self, + handle: &svg::Handle, + bounds: Rectangle, + color: Option, + rotation: Radians, + opacity: f32, + ); + fn into_geometry(self) -> Self::Geometry; } @@ -231,7 +269,7 @@ impl Backend for () { fn scale_nonuniform(&mut self, _scale: impl Into) {} fn draft(&mut self, _clip_bounds: Rectangle) -> Self {} - fn paste(&mut self, _frame: Self, _at: Point) {} + fn paste(&mut self, _frame: Self) {} fn stroke<'a>(&mut self, _path: &Path, _stroke: impl Into>) {} @@ -246,4 +284,24 @@ impl Backend for () { } fn into_geometry(self) -> Self::Geometry {} + + fn draw_image( + &mut self, + _handle: &image::Handle, + _bounds: Rectangle, + _filter_method: image::FilterMethod, + _rotation: Radians, + _opacity: f32, + ) { + } + + fn draw_svg( + &mut self, + _handle: &svg::Handle, + _bounds: Rectangle, + _color: Option, + _rotation: Radians, + _opacity: f32, + ) { + } } diff --git a/graphics/src/image.rs b/graphics/src/image.rs index 318592be..0e8f2fe3 100644 --- a/graphics/src/image.rs +++ b/graphics/src/image.rs @@ -23,6 +23,12 @@ pub enum Image { /// The opacity of the image. opacity: f32, + + /// If set to `true`, the image will be snapped to the pixel grid. + /// + /// This can avoid graphical glitches, specially when using a + /// [`image::FilterMethod::Nearest`]. + snap: bool, }, /// A vector image. Vector { -- cgit From 92bd3ecd6b4a6618f0fc725dea3694c3b40e5314 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 4 Aug 2024 04:30:12 +0200 Subject: Introduce `Image` struct in `core::image` --- graphics/src/geometry.rs | 1 + graphics/src/geometry/frame.rs | 39 +++++---------------------------------- graphics/src/image.rs | 28 +++------------------------- 3 files changed, 9 insertions(+), 59 deletions(-) (limited to 'graphics') diff --git a/graphics/src/geometry.rs b/graphics/src/geometry.rs index ab4a7a36..c7515e46 100644 --- a/graphics/src/geometry.rs +++ b/graphics/src/geometry.rs @@ -16,6 +16,7 @@ pub use stroke::{LineCap, LineDash, LineJoin, Stroke}; pub use style::Style; pub use text::Text; +pub use crate::core::Image; pub use crate::gradient::{self, Gradient}; use crate::cache::Cached; diff --git a/graphics/src/geometry/frame.rs b/graphics/src/geometry/frame.rs index d53d1331..1a7af8e6 100644 --- a/graphics/src/geometry/frame.rs +++ b/graphics/src/geometry/frame.rs @@ -1,8 +1,7 @@ //! Draw and generate geometry. -use crate::core::image; use crate::core::svg; use crate::core::{Color, Point, Radians, Rectangle, Size, Vector}; -use crate::geometry::{self, Fill, Path, Stroke, Text}; +use crate::geometry::{self, Fill, Image, Path, Stroke, Text}; /// The region of a surface that can be used to draw geometry. #[allow(missing_debug_implementations)] @@ -79,21 +78,8 @@ where /// Draws the given image on the [`Frame`] inside the given bounds. #[cfg(feature = "image")] - pub fn draw_image( - &mut self, - handle: &image::Handle, - bounds: Rectangle, - filter_method: image::FilterMethod, - rotation: impl Into, - opacity: f32, - ) { - self.raw.draw_image( - handle, - bounds, - filter_method, - rotation.into(), - opacity, - ); + pub fn draw_image(&mut self, bounds: Rectangle, image: impl Into) { + self.raw.draw_image(bounds, image); } /// Stores the current transform of the [`Frame`] and executes the given @@ -219,14 +205,7 @@ pub trait Backend: Sized { fill: impl Into, ); - fn draw_image( - &mut self, - handle: &image::Handle, - bounds: Rectangle, - filter_method: image::FilterMethod, - rotation: Radians, - opacity: f32, - ); + fn draw_image(&mut self, bounds: Rectangle, image: impl Into); fn draw_svg( &mut self, @@ -285,15 +264,7 @@ impl Backend for () { fn into_geometry(self) -> Self::Geometry {} - fn draw_image( - &mut self, - _handle: &image::Handle, - _bounds: Rectangle, - _filter_method: image::FilterMethod, - _rotation: Radians, - _opacity: f32, - ) { - } + fn draw_image(&mut self, _bounds: Rectangle, _image: impl Into) {} fn draw_svg( &mut self, diff --git a/graphics/src/image.rs b/graphics/src/image.rs index 0e8f2fe3..2e4f4b5a 100644 --- a/graphics/src/image.rs +++ b/graphics/src/image.rs @@ -8,28 +8,8 @@ use crate::core::{image, svg, Color, Radians, Rectangle}; #[derive(Debug, Clone, PartialEq)] pub enum Image { /// A raster image. - Raster { - /// The handle of a raster image. - handle: image::Handle, + Raster(image::Image, Rectangle), - /// The filter method of a raster image. - filter_method: image::FilterMethod, - - /// The bounds of the image. - bounds: Rectangle, - - /// The rotation of the image. - rotation: Radians, - - /// The opacity of the image. - opacity: f32, - - /// If set to `true`, the image will be snapped to the pixel grid. - /// - /// This can avoid graphical glitches, specially when using a - /// [`image::FilterMethod::Nearest`]. - snap: bool, - }, /// A vector image. Vector { /// The handle of a vector image. @@ -53,10 +33,8 @@ impl Image { /// Returns the bounds of the [`Image`]. pub fn bounds(&self) -> Rectangle { match self { - Image::Raster { - bounds, rotation, .. - } - | Image::Vector { + Image::Raster(image, bounds) => bounds.rotate(image.rotation), + Image::Vector { bounds, rotation, .. } => bounds.rotate(*rotation), } -- cgit From d4b08462e5a25929ec4df32f242898986902af56 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 4 Aug 2024 04:52:55 +0200 Subject: Introduce `Svg` struct in `core::svg` --- graphics/src/geometry.rs | 2 +- graphics/src/geometry/frame.rs | 28 +++++----------------------- graphics/src/image.rs | 25 +++++-------------------- 3 files changed, 11 insertions(+), 44 deletions(-) (limited to 'graphics') diff --git a/graphics/src/geometry.rs b/graphics/src/geometry.rs index c7515e46..2b4b45a6 100644 --- a/graphics/src/geometry.rs +++ b/graphics/src/geometry.rs @@ -16,7 +16,7 @@ pub use stroke::{LineCap, LineDash, LineJoin, Stroke}; pub use style::Style; pub use text::Text; -pub use crate::core::Image; +pub use crate::core::{Image, Svg}; pub use crate::gradient::{self, Gradient}; use crate::cache::Cached; diff --git a/graphics/src/geometry/frame.rs b/graphics/src/geometry/frame.rs index 1a7af8e6..f3c0817c 100644 --- a/graphics/src/geometry/frame.rs +++ b/graphics/src/geometry/frame.rs @@ -1,7 +1,6 @@ //! Draw and generate geometry. -use crate::core::svg; -use crate::core::{Color, Point, Radians, Rectangle, Size, Vector}; -use crate::geometry::{self, Fill, Image, Path, Stroke, Text}; +use crate::core::{Point, Radians, Rectangle, Size, Vector}; +use crate::geometry::{self, Fill, Image, Path, Stroke, Svg, Text}; /// The region of a surface that can be used to draw geometry. #[allow(missing_debug_implementations)] @@ -206,15 +205,7 @@ pub trait Backend: Sized { ); fn draw_image(&mut self, bounds: Rectangle, image: impl Into); - - fn draw_svg( - &mut self, - handle: &svg::Handle, - bounds: Rectangle, - color: Option, - rotation: Radians, - opacity: f32, - ); + fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into); fn into_geometry(self) -> Self::Geometry; } @@ -262,17 +253,8 @@ impl Backend for () { ) { } - fn into_geometry(self) -> Self::Geometry {} - fn draw_image(&mut self, _bounds: Rectangle, _image: impl Into) {} + fn draw_svg(&mut self, _bounds: Rectangle, _svg: impl Into) {} - fn draw_svg( - &mut self, - _handle: &svg::Handle, - _bounds: Rectangle, - _color: Option, - _rotation: Radians, - _opacity: f32, - ) { - } + fn into_geometry(self) -> Self::Geometry {} } diff --git a/graphics/src/image.rs b/graphics/src/image.rs index 2e4f4b5a..67a5e0cf 100644 --- a/graphics/src/image.rs +++ b/graphics/src/image.rs @@ -2,7 +2,9 @@ #[cfg(feature = "image")] pub use ::image as image_rs; -use crate::core::{image, svg, Color, Radians, Rectangle}; +use crate::core::image; +use crate::core::svg; +use crate::core::Rectangle; /// A raster or vector image. #[derive(Debug, Clone, PartialEq)] @@ -11,22 +13,7 @@ pub enum Image { Raster(image::Image, Rectangle), /// A vector image. - Vector { - /// The handle of a vector image. - handle: svg::Handle, - - /// The [`Color`] filter - color: Option, - - /// The bounds of the image. - bounds: Rectangle, - - /// The rotation of the image. - rotation: Radians, - - /// The opacity of the image. - opacity: f32, - }, + Vector(svg::Svg, Rectangle), } impl Image { @@ -34,9 +21,7 @@ impl Image { pub fn bounds(&self) -> Rectangle { match self { Image::Raster(image, bounds) => bounds.rotate(image.rotation), - Image::Vector { - bounds, rotation, .. - } => bounds.rotate(*rotation), + Image::Vector(svg, bounds) => bounds.rotate(svg.rotation), } } } -- cgit From 2b1b9c984ac1b290c351d0a9edc7bca69f8bd526 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 4 Aug 2024 05:03:48 +0200 Subject: Implement missing `draw_svg` in `Frame` wrapper --- graphics/src/geometry/frame.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'graphics') diff --git a/graphics/src/geometry/frame.rs b/graphics/src/geometry/frame.rs index f3c0817c..b5f2f139 100644 --- a/graphics/src/geometry/frame.rs +++ b/graphics/src/geometry/frame.rs @@ -75,12 +75,18 @@ where self.raw.fill_text(text); } - /// Draws the given image on the [`Frame`] inside the given bounds. + /// Draws the given [`Image`] on the [`Frame`] inside the given bounds. #[cfg(feature = "image")] pub fn draw_image(&mut self, bounds: Rectangle, image: impl Into) { self.raw.draw_image(bounds, image); } + /// Draws the given [`Svg`] on the [`Frame`] inside the given bounds. + #[cfg(feature = "svg")] + pub fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into) { + self.raw.draw_svg(bounds, svg); + } + /// Stores the current transform of the [`Frame`] and executes the given /// drawing operations, restoring the transform afterwards. /// -- cgit