Introduce Image struct in core::image

This commit is contained in:
Héctor Ramón Jiménez 2024-08-04 04:30:12 +02:00
parent 974ae6d1e7
commit 92bd3ecd6b
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
19 changed files with 184 additions and 334 deletions

View file

@ -7,6 +7,73 @@ use rustc_hash::FxHasher;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
/// A raster image that can be drawn.
#[derive(Debug, Clone, PartialEq)]
pub struct Image<H = Handle> {
/// The handle of the image.
pub handle: H,
/// The filter method of the image.
pub filter_method: FilterMethod,
/// The rotation to be applied to the image, from its center.
pub rotation: Radians,
/// The opacity of the image.
///
/// 0 means transparent. 1 means opaque.
pub opacity: f32,
/// If set to `true`, the image will be snapped to the pixel grid.
///
/// This can avoid graphical glitches, specially when using a
/// [`FilterMethod::Nearest`].
pub snap: bool,
}
impl Image<Handle> {
/// Creates a new [`Image`] with the given handle.
pub fn new(handle: impl Into<Handle>) -> Self {
Self {
handle: handle.into(),
filter_method: FilterMethod::default(),
rotation: Radians(0.0),
opacity: 1.0,
snap: false,
}
}
/// Sets the filter method of the [`Image`].
pub fn filter_method(mut self, filter_method: FilterMethod) -> Self {
self.filter_method = filter_method;
self
}
/// Sets the rotation of the [`Image`].
pub fn rotation(mut self, rotation: impl Into<Radians>) -> Self {
self.rotation = rotation.into();
self
}
/// Sets the opacity of the [`Image`].
pub fn opacity(mut self, opacity: impl Into<f32>) -> Self {
self.opacity = opacity.into();
self
}
/// Sets whether the [`Image`] should be snapped to the pixel grid.
pub fn snap(mut self, snap: bool) -> Self {
self.snap = snap;
self
}
}
impl From<&Handle> for Image {
fn from(handle: &Handle) -> Self {
Image::new(handle.clone())
}
}
/// A handle of some image data. /// A handle of some image data.
#[derive(Clone, PartialEq, Eq)] #[derive(Clone, PartialEq, Eq)]
pub enum Handle { pub enum Handle {
@ -172,14 +239,6 @@ pub trait Renderer: crate::Renderer {
/// Returns the dimensions of an image for the given [`Handle`]. /// Returns the dimensions of an image for the given [`Handle`].
fn measure_image(&self, handle: &Self::Handle) -> Size<u32>; fn measure_image(&self, handle: &Self::Handle) -> Size<u32>;
/// Draws an image with the given [`Handle`] and inside the provided /// Draws an [`Image`] inside the provided `bounds`.
/// `bounds`. fn draw_image(&mut self, image: Image<Self::Handle>, bounds: Rectangle);
fn draw_image(
&mut self,
handle: Self::Handle,
filter_method: FilterMethod,
bounds: Rectangle,
rotation: Radians,
opacity: f32,
);
} }

View file

@ -57,6 +57,7 @@ pub use element::Element;
pub use event::Event; pub use event::Event;
pub use font::Font; pub use font::Font;
pub use gradient::Gradient; pub use gradient::Gradient;
pub use image::Image;
pub use layout::Layout; pub use layout::Layout;
pub use length::Length; pub use length::Length;
pub use overlay::Overlay; pub use overlay::Overlay;

View file

@ -1,5 +1,5 @@
use crate::alignment; use crate::alignment;
use crate::image; use crate::image::{self, Image};
use crate::renderer::{self, Renderer}; use crate::renderer::{self, Renderer};
use crate::svg; use crate::svg;
use crate::text::{self, Text}; use crate::text::{self, Text};
@ -178,20 +178,14 @@ impl text::Editor for () {
} }
impl image::Renderer for () { impl image::Renderer for () {
type Handle = (); type Handle = image::Handle;
fn measure_image(&self, _handle: &Self::Handle) -> Size<u32> { fn measure_image(&self, _handle: &Self::Handle) -> Size<u32> {
Size::default() Size::default()
} }
fn draw_image( fn draw_image(&mut self, _image: Image, _bounds: Rectangle) {
&mut self, todo!()
_handle: Self::Handle,
_filter_method: image::FilterMethod,
_bounds: Rectangle,
_rotation: Radians,
_opacity: f32,
) {
} }
} }

View file

@ -160,11 +160,8 @@ impl<Message> canvas::Program<Message> for State {
frame.translate(Vector::new(center.x, center.y)); frame.translate(Vector::new(center.x, center.y));
frame.draw_image( frame.draw_image(
&self.sun,
Rectangle::with_radius(Self::SUN_RADIUS), Rectangle::with_radius(Self::SUN_RADIUS),
image::FilterMethod::Linear, &self.sun,
0,
1.0,
); );
let orbit = Path::circle(Point::ORIGIN, Self::ORBIT_RADIUS); let orbit = Path::circle(Point::ORIGIN, Self::ORBIT_RADIUS);
@ -189,22 +186,16 @@ impl<Message> canvas::Program<Message> for State {
frame.translate(Vector::new(Self::ORBIT_RADIUS, 0.0)); frame.translate(Vector::new(Self::ORBIT_RADIUS, 0.0));
frame.draw_image( frame.draw_image(
&self.earth,
Rectangle::with_radius(Self::EARTH_RADIUS), Rectangle::with_radius(Self::EARTH_RADIUS),
image::FilterMethod::Linear, canvas::Image::new(&self.earth).rotation(rotation * 20.0),
rotation * 20.0,
1.0,
); );
frame.rotate(rotation * 10.0); frame.rotate(rotation * 10.0);
frame.translate(Vector::new(0.0, Self::MOON_DISTANCE)); frame.translate(Vector::new(0.0, Self::MOON_DISTANCE));
frame.draw_image( frame.draw_image(
&self.moon,
Rectangle::with_radius(Self::MOON_RADIUS), Rectangle::with_radius(Self::MOON_RADIUS),
image::FilterMethod::Linear, &self.moon,
0,
1.0,
); );
}); });

View file

@ -16,6 +16,7 @@ pub use stroke::{LineCap, LineDash, LineJoin, Stroke};
pub use style::Style; pub use style::Style;
pub use text::Text; pub use text::Text;
pub use crate::core::Image;
pub use crate::gradient::{self, Gradient}; pub use crate::gradient::{self, Gradient};
use crate::cache::Cached; use crate::cache::Cached;

View file

@ -1,8 +1,7 @@
//! Draw and generate geometry. //! Draw and generate geometry.
use crate::core::image;
use crate::core::svg; use crate::core::svg;
use crate::core::{Color, Point, Radians, Rectangle, Size, Vector}; 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. /// The region of a surface that can be used to draw geometry.
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
@ -79,21 +78,8 @@ where
/// 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")] #[cfg(feature = "image")]
pub fn draw_image( pub fn draw_image(&mut self, bounds: Rectangle, image: impl Into<Image>) {
&mut self, self.raw.draw_image(bounds, image);
handle: &image::Handle,
bounds: Rectangle,
filter_method: image::FilterMethod,
rotation: impl Into<Radians>,
opacity: f32,
) {
self.raw.draw_image(
handle,
bounds,
filter_method,
rotation.into(),
opacity,
);
} }
/// Stores the current transform of the [`Frame`] and executes the given /// Stores the current transform of the [`Frame`] and executes the given
@ -219,14 +205,7 @@ pub trait Backend: Sized {
fill: impl Into<Fill>, fill: impl Into<Fill>,
); );
fn draw_image( fn draw_image(&mut self, bounds: Rectangle, image: impl Into<Image>);
&mut self,
handle: &image::Handle,
bounds: Rectangle,
filter_method: image::FilterMethod,
rotation: Radians,
opacity: f32,
);
fn draw_svg( fn draw_svg(
&mut self, &mut self,
@ -285,15 +264,7 @@ impl Backend for () {
fn into_geometry(self) -> Self::Geometry {} fn into_geometry(self) -> Self::Geometry {}
fn draw_image( fn draw_image(&mut self, _bounds: Rectangle, _image: impl Into<Image>) {}
&mut self,
_handle: &image::Handle,
_bounds: Rectangle,
_filter_method: image::FilterMethod,
_rotation: Radians,
_opacity: f32,
) {
}
fn draw_svg( fn draw_svg(
&mut self, &mut self,

View file

@ -8,28 +8,8 @@ use crate::core::{image, svg, Color, Radians, Rectangle};
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Image { pub enum Image {
/// A raster image. /// A raster image.
Raster { Raster(image::Image, Rectangle),
/// The handle of a raster image.
handle: image::Handle,
/// 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. /// A vector image.
Vector { Vector {
/// The handle of a vector image. /// The handle of a vector image.
@ -53,10 +33,8 @@ impl Image {
/// Returns the bounds of the [`Image`]. /// Returns the bounds of the [`Image`].
pub fn bounds(&self) -> Rectangle { pub fn bounds(&self) -> Rectangle {
match self { match self {
Image::Raster { Image::Raster(image, bounds) => bounds.rotate(image.rotation),
bounds, rotation, .. Image::Vector {
}
| Image::Vector {
bounds, rotation, .. bounds, rotation, ..
} => bounds.rotate(*rotation), } => bounds.rotate(*rotation),
} }

View file

@ -3,7 +3,8 @@ use crate::core::image;
use crate::core::renderer; use crate::core::renderer;
use crate::core::svg; use crate::core::svg;
use crate::core::{ use crate::core::{
self, Background, Color, Point, Radians, Rectangle, Size, Transformation, self, Background, Color, Image, Point, Radians, Rectangle, Size,
Transformation,
}; };
use crate::graphics; use crate::graphics;
use crate::graphics::compositor; use crate::graphics::compositor;
@ -149,25 +150,8 @@ where
delegate!(self, renderer, renderer.measure_image(handle)) delegate!(self, renderer, renderer.measure_image(handle))
} }
fn draw_image( fn draw_image(&mut self, image: Image<A::Handle>, bounds: Rectangle) {
&mut self, delegate!(self, renderer, renderer.draw_image(image, bounds));
handle: Self::Handle,
filter_method: image::FilterMethod,
bounds: Rectangle,
rotation: Radians,
opacity: f32,
) {
delegate!(
self,
renderer,
renderer.draw_image(
handle,
filter_method,
bounds,
rotation,
opacity
)
);
} }
} }
@ -441,11 +425,10 @@ where
#[cfg(feature = "geometry")] #[cfg(feature = "geometry")]
mod geometry { mod geometry {
use super::Renderer; use super::Renderer;
use crate::core::image;
use crate::core::svg; use crate::core::svg;
use crate::core::{Color, Point, Radians, Rectangle, Size, Vector}; use crate::core::{Color, Point, Radians, Rectangle, Size, Vector};
use crate::graphics::cache::{self, Cached}; use crate::graphics::cache::{self, Cached};
use crate::graphics::geometry::{self, Fill, Path, Stroke, Text}; use crate::graphics::geometry::{self, Fill, Image, Path, Stroke, Text};
impl<A, B> geometry::Renderer for Renderer<A, B> impl<A, B> geometry::Renderer for Renderer<A, B>
where where
@ -574,25 +557,8 @@ mod geometry {
delegate!(self, frame, frame.fill_text(text)); delegate!(self, frame, frame.fill_text(text));
} }
fn draw_image( fn draw_image(&mut self, bounds: Rectangle, image: impl Into<Image>) {
&mut self, delegate!(self, frame, frame.draw_image(bounds, image));
handle: &image::Handle,
bounds: Rectangle,
filter_method: image::FilterMethod,
rotation: Radians,
opacity: f32,
) {
delegate!(
self,
frame,
frame.draw_image(
handle,
bounds,
filter_method,
rotation,
opacity
)
);
} }
fn draw_svg( fn draw_svg(

View file

@ -550,14 +550,7 @@ impl Engine {
) { ) {
match image { match image {
#[cfg(feature = "image")] #[cfg(feature = "image")]
Image::Raster { Image::Raster(raster, bounds) => {
handle,
filter_method,
bounds,
rotation,
opacity,
snap: _,
} => {
let physical_bounds = *bounds * _transformation; let physical_bounds = *bounds * _transformation;
if !_clip_bounds.intersects(&physical_bounds) { if !_clip_bounds.intersects(&physical_bounds) {
@ -568,7 +561,7 @@ impl Engine {
.then_some(_clip_mask as &_); .then_some(_clip_mask as &_);
let center = physical_bounds.center(); let center = physical_bounds.center();
let radians = f32::from(*rotation); let radians = f32::from(raster.rotation);
let transform = into_transform(_transformation).post_rotate_at( let transform = into_transform(_transformation).post_rotate_at(
radians.to_degrees(), radians.to_degrees(),
@ -577,10 +570,10 @@ impl Engine {
); );
self.raster_pipeline.draw( self.raster_pipeline.draw(
handle, &raster.handle,
*filter_method, raster.filter_method,
*bounds, *bounds,
*opacity, raster.opacity,
_pixels, _pixels,
transform, transform,
clip_mask, clip_mask,

View file

@ -1,12 +1,11 @@
use crate::core::image;
use crate::core::svg; use crate::core::svg;
use crate::core::text::LineHeight; use crate::core::text::LineHeight;
use crate::core::{Color, Pixels, Point, Radians, Rectangle, Size, Vector}; use crate::core::{Color, Pixels, Point, Radians, Rectangle, Size, Vector};
use crate::graphics::cache::{self, Cached}; use crate::graphics::cache::{self, Cached};
use crate::graphics::geometry::fill::{self, Fill}; use crate::graphics::geometry::fill::{self, Fill};
use crate::graphics::geometry::stroke::{self, Stroke}; use crate::graphics::geometry::stroke::{self, Stroke};
use crate::graphics::geometry::{self, Path, Style}; use crate::graphics::geometry::{self, Image, Path, Style};
use crate::graphics::{Gradient, Image, Text}; use crate::graphics::{self, Gradient, Text};
use crate::Primitive; use crate::Primitive;
use std::rc::Rc; use std::rc::Rc;
@ -15,7 +14,7 @@ use std::rc::Rc;
pub enum Geometry { pub enum Geometry {
Live { Live {
text: Vec<Text>, text: Vec<Text>,
images: Vec<Image>, images: Vec<graphics::Image>,
primitives: Vec<Primitive>, primitives: Vec<Primitive>,
clip_bounds: Rectangle, clip_bounds: Rectangle,
}, },
@ -25,7 +24,7 @@ pub enum Geometry {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Cache { pub struct Cache {
pub text: Rc<[Text]>, pub text: Rc<[Text]>,
pub images: Rc<[Image]>, pub images: Rc<[graphics::Image]>,
pub primitives: Rc<[Primitive]>, pub primitives: Rc<[Primitive]>,
pub clip_bounds: Rectangle, pub clip_bounds: Rectangle,
} }
@ -61,7 +60,7 @@ pub struct Frame {
transform: tiny_skia::Transform, transform: tiny_skia::Transform,
stack: Vec<tiny_skia::Transform>, stack: Vec<tiny_skia::Transform>,
primitives: Vec<Primitive>, primitives: Vec<Primitive>,
images: Vec<Image>, images: Vec<graphics::Image>,
text: Vec<Text>, text: Vec<Text>,
} }
@ -283,25 +282,15 @@ impl geometry::frame::Backend for Frame {
} }
} }
fn draw_image( fn draw_image(&mut self, bounds: Rectangle, image: impl Into<Image>) {
&mut self, let mut image = image.into();
handle: &image::Handle,
bounds: Rectangle,
filter_method: image::FilterMethod,
rotation: Radians,
opacity: f32,
) {
let (bounds, external_rotation) = let (bounds, external_rotation) =
transform_rectangle(bounds, self.transform); transform_rectangle(bounds, self.transform);
self.images.push(Image::Raster { image.rotation += external_rotation;
handle: handle.clone(),
filter_method, self.images.push(graphics::Image::Raster(image, bounds));
bounds,
rotation: rotation + external_rotation,
opacity,
snap: false,
});
} }
fn draw_svg( fn draw_svg(
@ -315,7 +304,7 @@ impl geometry::frame::Backend for Frame {
let (bounds, external_rotation) = let (bounds, external_rotation) =
transform_rectangle(bounds, self.transform); transform_rectangle(bounds, self.transform);
self.images.push(Image::Vector { self.images.push(graphics::Image::Vector {
handle: handle.clone(), handle: handle.clone(),
bounds, bounds,
color, color,

View file

@ -1,11 +1,12 @@
use crate::core::renderer::Quad;
use crate::core::svg;
use crate::core::{ use crate::core::{
image, renderer::Quad, svg, Background, Color, Point, Radians, Rectangle, Background, Color, Image, Point, Radians, Rectangle, Transformation,
Transformation,
}; };
use crate::graphics;
use crate::graphics::damage; use crate::graphics::damage;
use crate::graphics::layer; use crate::graphics::layer;
use crate::graphics::text::{Editor, Paragraph, Text}; use crate::graphics::text::{Editor, Paragraph, Text};
use crate::graphics::{self, Image};
use crate::Primitive; use crate::Primitive;
use std::rc::Rc; use std::rc::Rc;
@ -18,7 +19,7 @@ pub struct Layer {
pub quads: Vec<(Quad, Background)>, pub quads: Vec<(Quad, Background)>,
pub primitives: Vec<Item<Primitive>>, pub primitives: Vec<Item<Primitive>>,
pub text: Vec<Item<Text>>, pub text: Vec<Item<Text>>,
pub images: Vec<Image>, pub images: Vec<graphics::Image>,
} }
impl Layer { impl Layer {
@ -117,28 +118,14 @@ impl Layer {
pub fn draw_image( pub fn draw_image(
&mut self, &mut self,
image: &Image, image: graphics::Image,
transformation: Transformation, transformation: Transformation,
) { ) {
match image { match image {
Image::Raster { graphics::Image::Raster(raster, bounds) => {
handle, self.draw_raster(raster.clone(), bounds, transformation);
filter_method,
bounds,
rotation,
opacity,
snap: _,
} => {
self.draw_raster(
handle.clone(),
*filter_method,
*bounds,
transformation,
*rotation,
*opacity,
);
} }
Image::Vector { graphics::Image::Vector {
handle, handle,
color, color,
bounds, bounds,
@ -147,11 +134,11 @@ impl Layer {
} => { } => {
self.draw_svg( self.draw_svg(
handle.clone(), handle.clone(),
*color, color,
*bounds, bounds,
transformation, transformation,
*rotation, rotation,
*opacity, opacity,
); );
} }
} }
@ -159,21 +146,11 @@ impl Layer {
pub fn draw_raster( pub fn draw_raster(
&mut self, &mut self,
handle: image::Handle, image: Image,
filter_method: image::FilterMethod,
bounds: Rectangle, bounds: Rectangle,
transformation: Transformation, transformation: Transformation,
rotation: Radians,
opacity: f32,
) { ) {
let image = Image::Raster { let image = graphics::Image::Raster(image, bounds * transformation);
handle,
filter_method,
bounds: bounds * transformation,
rotation,
opacity,
snap: false,
};
self.images.push(image); self.images.push(image);
} }
@ -187,7 +164,7 @@ impl Layer {
rotation: Radians, rotation: Radians,
opacity: f32, opacity: f32,
) { ) {
let svg = Image::Vector { let svg = graphics::Image::Vector {
handle, handle,
color, color,
bounds: bounds * transformation, bounds: bounds * transformation,
@ -304,7 +281,7 @@ impl Layer {
&previous.images, &previous.images,
&current.images, &current.images,
|image| vec![image.bounds().expand(1.0)], |image| vec![image.bounds().expand(1.0)],
Image::eq, graphics::Image::eq,
); );
damage.extend(text); damage.extend(text);

View file

@ -341,7 +341,7 @@ impl graphics::geometry::Renderer for Renderer {
); );
for image in images { for image in images {
layer.draw_image(&image, transformation); layer.draw_image(image, transformation);
} }
layer.draw_text_group(text, clip_bounds, transformation); layer.draw_text_group(text, clip_bounds, transformation);
@ -354,7 +354,7 @@ impl graphics::geometry::Renderer for Renderer {
); );
for image in cache.images.iter() { for image in cache.images.iter() {
layer.draw_image(image, transformation); layer.draw_image(image.clone(), transformation);
} }
layer.draw_text_cache( layer.draw_text_cache(
@ -381,23 +381,9 @@ impl core::image::Renderer for Renderer {
self.engine.raster_pipeline.dimensions(handle) self.engine.raster_pipeline.dimensions(handle)
} }
fn draw_image( fn draw_image(&mut self, image: core::Image, bounds: Rectangle) {
&mut self,
handle: Self::Handle,
filter_method: core::image::FilterMethod,
bounds: Rectangle,
rotation: core::Radians,
opacity: f32,
) {
let (layer, transformation) = self.layers.current_mut(); let (layer, transformation) = self.layers.current_mut();
layer.draw_raster( layer.draw_raster(image, bounds, transformation);
handle,
filter_method,
bounds,
transformation,
rotation,
opacity,
);
} }
} }

View file

@ -1,5 +1,4 @@
//! Build and draw geometry. //! Build and draw geometry.
use crate::core::image;
use crate::core::svg; use crate::core::svg;
use crate::core::text::LineHeight; use crate::core::text::LineHeight;
use crate::core::{ use crate::core::{
@ -9,11 +8,11 @@ use crate::graphics::cache::{self, Cached};
use crate::graphics::color; use crate::graphics::color;
use crate::graphics::geometry::fill::{self, Fill}; use crate::graphics::geometry::fill::{self, Fill};
use crate::graphics::geometry::{ use crate::graphics::geometry::{
self, LineCap, LineDash, LineJoin, Path, Stroke, Style, self, Image, LineCap, LineDash, LineJoin, Path, Stroke, Style,
}; };
use crate::graphics::gradient::{self, Gradient}; use crate::graphics::gradient::{self, Gradient};
use crate::graphics::mesh::{self, Mesh}; use crate::graphics::mesh::{self, Mesh};
use crate::graphics::{self, Image, Text}; use crate::graphics::{self, Text};
use crate::text; use crate::text;
use crate::triangle; use crate::triangle;
@ -27,7 +26,7 @@ use std::sync::Arc;
pub enum Geometry { pub enum Geometry {
Live { Live {
meshes: Vec<Mesh>, meshes: Vec<Mesh>,
images: Vec<Image>, images: Vec<graphics::Image>,
text: Vec<Text>, text: Vec<Text>,
}, },
Cached(Cache), Cached(Cache),
@ -36,7 +35,7 @@ pub enum Geometry {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Cache { pub struct Cache {
pub meshes: Option<triangle::Cache>, pub meshes: Option<triangle::Cache>,
pub images: Option<Arc<[Image]>>, pub images: Option<Arc<[graphics::Image]>>,
pub text: Option<text::Cache>, pub text: Option<text::Cache>,
} }
@ -99,7 +98,7 @@ pub struct Frame {
clip_bounds: Rectangle, clip_bounds: Rectangle,
buffers: BufferStack, buffers: BufferStack,
meshes: Vec<Mesh>, meshes: Vec<Mesh>,
images: Vec<Image>, images: Vec<graphics::Image>,
text: Vec<Text>, text: Vec<Text>,
transforms: Transforms, transforms: Transforms,
fill_tessellator: tessellation::FillTessellator, fill_tessellator: tessellation::FillTessellator,
@ -377,25 +376,15 @@ impl geometry::frame::Backend for Frame {
} }
} }
fn draw_image( fn draw_image(&mut self, bounds: Rectangle, image: impl Into<Image>) {
&mut self, let mut image = image.into();
handle: &image::Handle,
bounds: Rectangle,
filter_method: image::FilterMethod,
rotation: Radians,
opacity: f32,
) {
let (bounds, external_rotation) = let (bounds, external_rotation) =
self.transforms.current.transform_rectangle(bounds); self.transforms.current.transform_rectangle(bounds);
self.images.push(Image::Raster { image.rotation += external_rotation;
handle: handle.clone(),
filter_method, self.images.push(graphics::Image::Raster(image, bounds));
bounds,
rotation: rotation + external_rotation,
opacity,
snap: false,
});
} }
fn draw_svg( fn draw_svg(
@ -409,7 +398,7 @@ impl geometry::frame::Backend for Frame {
let (bounds, external_rotation) = let (bounds, external_rotation) =
self.transforms.current.transform_rectangle(bounds); self.transforms.current.transform_rectangle(bounds);
self.images.push(Image::Vector { self.images.push(graphics::Image::Vector {
handle: handle.clone(), handle: handle.clone(),
color, color,
bounds, bounds,

View file

@ -220,25 +220,18 @@ impl Pipeline {
for image in images { for image in images {
match &image { match &image {
#[cfg(feature = "image")] #[cfg(feature = "image")]
Image::Raster { Image::Raster(image, bounds) => {
handle,
filter_method,
bounds,
rotation,
opacity,
snap,
} => {
if let Some(atlas_entry) = if let Some(atlas_entry) =
cache.upload_raster(device, encoder, handle) cache.upload_raster(device, encoder, &image.handle)
{ {
add_instances( add_instances(
[bounds.x, bounds.y], [bounds.x, bounds.y],
[bounds.width, bounds.height], [bounds.width, bounds.height],
f32::from(*rotation), f32::from(image.rotation),
*opacity, image.opacity,
*snap, image.snap,
atlas_entry, atlas_entry,
match filter_method { match image.filter_method {
crate::core::image::FilterMethod::Nearest => { crate::core::image::FilterMethod::Nearest => {
nearest_instances nearest_instances
} }

View file

@ -1,5 +1,6 @@
use crate::core::{ use crate::core::{
renderer, Background, Color, Point, Radians, Rectangle, Transformation, self, renderer, Background, Color, Point, Radians, Rectangle,
Transformation,
}; };
use crate::graphics; use crate::graphics;
use crate::graphics::color; use crate::graphics::color;
@ -112,29 +113,10 @@ impl Layer {
self.pending_text.push(text); self.pending_text.push(text);
} }
pub fn draw_image( pub fn draw_image(&mut self, image: Image, transformation: Transformation) {
&mut self,
image: &Image,
transformation: Transformation,
) {
match image { match image {
Image::Raster { Image::Raster(image, bounds) => {
handle, self.draw_raster(image, bounds, transformation);
filter_method,
bounds,
rotation,
opacity,
snap,
} => {
self.draw_raster(
handle.clone(),
*filter_method,
*bounds,
transformation,
*rotation,
*opacity,
*snap,
);
} }
Image::Vector { Image::Vector {
handle, handle,
@ -145,11 +127,11 @@ impl Layer {
} => { } => {
self.draw_svg( self.draw_svg(
handle.clone(), handle.clone(),
*color, color,
*bounds, bounds,
transformation, transformation,
*rotation, rotation,
*opacity, opacity,
); );
} }
} }
@ -157,22 +139,11 @@ impl Layer {
pub fn draw_raster( pub fn draw_raster(
&mut self, &mut self,
handle: crate::core::image::Handle, image: core::Image,
filter_method: crate::core::image::FilterMethod,
bounds: Rectangle, bounds: Rectangle,
transformation: Transformation, transformation: Transformation,
rotation: Radians,
opacity: f32,
snap: bool,
) { ) {
let image = Image::Raster { let image = Image::Raster(image, bounds * transformation);
handle,
filter_method,
bounds: bounds * transformation,
rotation,
opacity,
snap,
};
self.images.push(image); self.images.push(image);
} }

View file

@ -527,24 +527,9 @@ impl core::image::Renderer for Renderer {
self.image_cache.borrow_mut().measure_image(handle) self.image_cache.borrow_mut().measure_image(handle)
} }
fn draw_image( fn draw_image(&mut self, image: core::Image, bounds: Rectangle) {
&mut self,
handle: Self::Handle,
filter_method: core::image::FilterMethod,
bounds: Rectangle,
rotation: core::Radians,
opacity: f32,
) {
let (layer, transformation) = self.layers.current_mut(); let (layer, transformation) = self.layers.current_mut();
layer.draw_raster( layer.draw_raster(image, bounds, transformation);
handle,
filter_method,
bounds,
transformation,
rotation,
opacity,
true,
);
} }
} }
@ -602,7 +587,7 @@ impl graphics::geometry::Renderer for Renderer {
layer.draw_mesh_group(meshes, transformation); layer.draw_mesh_group(meshes, transformation);
for image in images { for image in images {
layer.draw_image(&image, transformation); layer.draw_image(image, transformation);
} }
layer.draw_text_group(text, transformation); layer.draw_text_group(text, transformation);
@ -613,7 +598,7 @@ impl graphics::geometry::Renderer for Renderer {
} }
if let Some(images) = cache.images { if let Some(images) = cache.images {
for image in images.iter() { for image in images.iter().cloned() {
layer.draw_image(image, transformation); layer.draw_image(image, transformation);
} }
} }

View file

@ -8,8 +8,8 @@ pub use program::Program;
pub use crate::graphics::cache::Group; pub use crate::graphics::cache::Group;
pub use crate::graphics::geometry::{ pub use crate::graphics::geometry::{
fill, gradient, path, stroke, Fill, Gradient, LineCap, LineDash, LineJoin, fill, gradient, path, stroke, Fill, Gradient, Image, LineCap, LineDash,
Path, Stroke, Style, Text, LineJoin, Path, Stroke, Style, Text,
}; };
use crate::core; use crate::core;

View file

@ -8,8 +8,8 @@ use crate::core::mouse;
use crate::core::renderer; use crate::core::renderer;
use crate::core::widget::Tree; use crate::core::widget::Tree;
use crate::core::{ use crate::core::{
ContentFit, Element, Layout, Length, Point, Rectangle, Rotation, Size, self, ContentFit, Element, Layout, Length, Point, Rectangle, Rotation,
Vector, Widget, Size, Vector, Widget,
}; };
pub use image::{FilterMethod, Handle}; pub use image::{FilterMethod, Handle};
@ -181,11 +181,14 @@ pub fn draw<Renderer, Handle>(
let render = |renderer: &mut Renderer| { let render = |renderer: &mut Renderer| {
renderer.draw_image( renderer.draw_image(
handle.clone(), core::Image {
filter_method, handle: handle.clone(),
filter_method,
rotation: rotation.radians(),
opacity,
snap: true,
},
drawing_bounds, drawing_bounds,
rotation.radians(),
opacity,
); );
}; };

View file

@ -6,8 +6,8 @@ use crate::core::mouse;
use crate::core::renderer; use crate::core::renderer;
use crate::core::widget::tree::{self, Tree}; use crate::core::widget::tree::{self, Tree};
use crate::core::{ use crate::core::{
Clipboard, ContentFit, Element, Layout, Length, Pixels, Point, Radians, Clipboard, ContentFit, Element, Image, Layout, Length, Pixels, Point,
Rectangle, Shell, Size, Vector, Widget, Radians, Rectangle, Shell, Size, Vector, Widget,
}; };
/// A frame that displays an image with the ability to zoom in/out and pan. /// A frame that displays an image with the ability to zoom in/out and pan.
@ -349,11 +349,14 @@ where
let render = |renderer: &mut Renderer| { let render = |renderer: &mut Renderer| {
renderer.with_translation(translation, |renderer| { renderer.with_translation(translation, |renderer| {
renderer.draw_image( renderer.draw_image(
self.handle.clone(), Image {
self.filter_method, handle: self.handle.clone(),
filter_method: self.filter_method,
rotation: Radians(0.0),
opacity: 1.0,
snap: true,
},
drawing_bounds, drawing_bounds,
Radians(0.0),
1.0,
); );
}); });
}; };