iced_core/image.rs
1//! Load and draw raster graphics.
2pub use bytes::Bytes;
3
4use crate::{Radians, Rectangle, Size};
5
6use rustc_hash::FxHasher;
7use std::hash::{Hash, Hasher};
8use std::path::{Path, PathBuf};
9
10/// A raster image that can be drawn.
11#[derive(Debug, Clone, PartialEq)]
12pub struct Image<H = Handle> {
13 /// The handle of the image.
14 pub handle: H,
15
16 /// The filter method of the image.
17 pub filter_method: FilterMethod,
18
19 /// The rotation to be applied to the image; on its center.
20 pub rotation: Radians,
21
22 /// The opacity of the image.
23 ///
24 /// 0 means transparent. 1 means opaque.
25 pub opacity: f32,
26
27 /// If set to `true`, the image will be snapped to the pixel grid.
28 ///
29 /// This can avoid graphical glitches, specially when using
30 /// [`FilterMethod::Nearest`].
31 pub snap: bool,
32}
33
34impl Image<Handle> {
35 /// Creates a new [`Image`] with the given handle.
36 pub fn new(handle: impl Into<Handle>) -> Self {
37 Self {
38 handle: handle.into(),
39 filter_method: FilterMethod::default(),
40 rotation: Radians(0.0),
41 opacity: 1.0,
42 snap: false,
43 }
44 }
45
46 /// Sets the filter method of the [`Image`].
47 pub fn filter_method(mut self, filter_method: FilterMethod) -> Self {
48 self.filter_method = filter_method;
49 self
50 }
51
52 /// Sets the rotation of the [`Image`].
53 pub fn rotation(mut self, rotation: impl Into<Radians>) -> Self {
54 self.rotation = rotation.into();
55 self
56 }
57
58 /// Sets the opacity of the [`Image`].
59 pub fn opacity(mut self, opacity: impl Into<f32>) -> Self {
60 self.opacity = opacity.into();
61 self
62 }
63
64 /// Sets whether the [`Image`] should be snapped to the pixel grid.
65 pub fn snap(mut self, snap: bool) -> Self {
66 self.snap = snap;
67 self
68 }
69}
70
71impl From<&Handle> for Image {
72 fn from(handle: &Handle) -> Self {
73 Image::new(handle.clone())
74 }
75}
76
77/// A handle of some image data.
78#[derive(Clone, PartialEq, Eq)]
79pub enum Handle {
80 /// A file handle. The image data will be read
81 /// from the file path.
82 ///
83 /// Use [`from_path`] to create this variant.
84 ///
85 /// [`from_path`]: Self::from_path
86 Path(Id, PathBuf),
87
88 /// A handle pointing to some encoded image bytes in-memory.
89 ///
90 /// Use [`from_bytes`] to create this variant.
91 ///
92 /// [`from_bytes`]: Self::from_bytes
93 Bytes(Id, Bytes),
94
95 /// A handle pointing to decoded image pixels in RGBA format.
96 ///
97 /// Use [`from_rgba`] to create this variant.
98 ///
99 /// [`from_rgba`]: Self::from_rgba
100 Rgba {
101 /// The id of this handle.
102 id: Id,
103 /// The width of the image.
104 width: u32,
105 /// The height of the image.
106 height: u32,
107 /// The pixels.
108 pixels: Bytes,
109 },
110}
111
112impl Handle {
113 /// Creates an image [`Handle`] pointing to the image of the given path.
114 ///
115 /// Makes an educated guess about the image format by examining the data in the file.
116 pub fn from_path<T: Into<PathBuf>>(path: T) -> Handle {
117 let path = path.into();
118
119 Self::Path(Id::path(&path), path)
120 }
121
122 /// Creates an image [`Handle`] containing the encoded image data directly.
123 ///
124 /// Makes an educated guess about the image format by examining the given data.
125 ///
126 /// This is useful if you already have your image loaded in-memory, maybe
127 /// because you downloaded or generated it procedurally.
128 pub fn from_bytes(bytes: impl Into<Bytes>) -> Handle {
129 Self::Bytes(Id::unique(), bytes.into())
130 }
131
132 /// Creates an image [`Handle`] containing the decoded image pixels directly.
133 ///
134 /// This function expects the pixel data to be provided as a collection of [`Bytes`]
135 /// of RGBA pixels. Therefore, the length of the pixel data should always be
136 /// `width * height * 4`.
137 ///
138 /// This is useful if you have already decoded your image.
139 pub fn from_rgba(
140 width: u32,
141 height: u32,
142 pixels: impl Into<Bytes>,
143 ) -> Handle {
144 Self::Rgba {
145 id: Id::unique(),
146 width,
147 height,
148 pixels: pixels.into(),
149 }
150 }
151
152 /// Returns the unique identifier of the [`Handle`].
153 pub fn id(&self) -> Id {
154 match self {
155 Handle::Path(id, _)
156 | Handle::Bytes(id, _)
157 | Handle::Rgba { id, .. } => *id,
158 }
159 }
160}
161
162impl<T> From<T> for Handle
163where
164 T: Into<PathBuf>,
165{
166 fn from(path: T) -> Handle {
167 Handle::from_path(path.into())
168 }
169}
170
171impl From<&Handle> for Handle {
172 fn from(value: &Handle) -> Self {
173 value.clone()
174 }
175}
176
177impl std::fmt::Debug for Handle {
178 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
179 match self {
180 Self::Path(_, path) => write!(f, "Path({path:?})"),
181 Self::Bytes(_, _) => write!(f, "Bytes(...)"),
182 Self::Rgba { width, height, .. } => {
183 write!(f, "Pixels({width} * {height})")
184 }
185 }
186 }
187}
188
189/// The unique identifier of some [`Handle`] data.
190#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
191pub struct Id(_Id);
192
193#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
194enum _Id {
195 Unique(u64),
196 Hash(u64),
197}
198
199impl Id {
200 fn unique() -> Self {
201 use std::sync::atomic::{self, AtomicU64};
202
203 static NEXT_ID: AtomicU64 = AtomicU64::new(0);
204
205 Self(_Id::Unique(NEXT_ID.fetch_add(1, atomic::Ordering::Relaxed)))
206 }
207
208 fn path(path: impl AsRef<Path>) -> Self {
209 let hash = {
210 let mut hasher = FxHasher::default();
211 path.as_ref().hash(&mut hasher);
212
213 hasher.finish()
214 };
215
216 Self(_Id::Hash(hash))
217 }
218}
219
220/// Image filtering strategy.
221#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
222pub enum FilterMethod {
223 /// Bilinear interpolation.
224 #[default]
225 Linear,
226 /// Nearest neighbor.
227 Nearest,
228}
229
230/// A [`Renderer`] that can render raster graphics.
231///
232/// [renderer]: crate::renderer
233pub trait Renderer: crate::Renderer {
234 /// The image Handle to be displayed. Iced exposes its own default implementation of a [`Handle`]
235 ///
236 /// [`Handle`]: Self::Handle
237 type Handle: Clone;
238
239 /// Returns the dimensions of an image for the given [`Handle`].
240 fn measure_image(&self, handle: &Self::Handle) -> Size<u32>;
241
242 /// Draws an [`Image`] inside the provided `bounds`.
243 fn draw_image(&mut self, image: Image<Self::Handle>, bounds: Rectangle);
244}