ori_graphics/
image.rs

1use std::{
2    any::Any,
3    fmt::Debug,
4    io,
5    path::{Path, PathBuf},
6    sync::{Arc, Weak},
7};
8
9use glam::Vec2;
10
11#[macro_export]
12macro_rules! include_image {
13    ($($tt:tt)*) => {
14        $crate::ImageData::from_bytes(include_bytes!($($tt)*))
15    };
16}
17
18#[derive(Debug)]
19pub enum ImageLoadError {
20    Io(io::Error),
21    Image(image::ImageError),
22}
23
24impl From<io::Error> for ImageLoadError {
25    fn from(err: io::Error) -> Self {
26        Self::Io(err)
27    }
28}
29
30impl From<image::ImageError> for ImageLoadError {
31    fn from(err: image::ImageError) -> Self {
32        Self::Image(err)
33    }
34}
35
36#[derive(Clone, Debug, PartialEq, Eq, Hash)]
37pub enum ImageSource {
38    Path(PathBuf),
39    Data(ImageData),
40}
41
42impl Default for ImageSource {
43    fn default() -> Self {
44        Self::Data(ImageData::default())
45    }
46}
47
48impl From<PathBuf> for ImageSource {
49    fn from(path: PathBuf) -> Self {
50        Self::Path(path)
51    }
52}
53
54impl From<&Path> for ImageSource {
55    fn from(path: &Path) -> Self {
56        Self::Path(path.into())
57    }
58}
59
60impl From<String> for ImageSource {
61    fn from(path: String) -> Self {
62        Self::Path(path.into())
63    }
64}
65
66impl From<&str> for ImageSource {
67    fn from(path: &str) -> Self {
68        Self::Path(path.into())
69    }
70}
71
72impl From<ImageData> for ImageSource {
73    fn from(image: ImageData) -> Self {
74        Self::Data(image)
75    }
76}
77
78impl From<&[u8]> for ImageSource {
79    fn from(bytes: &[u8]) -> Self {
80        Self::Data(ImageData::from_bytes(bytes))
81    }
82}
83
84impl ImageSource {
85    pub fn try_load(&self) -> Result<ImageData, ImageLoadError> {
86        match self {
87            Self::Path(path) => Ok(ImageData::try_load(path)?),
88            Self::Data(image) => Ok(image.clone()),
89        }
90    }
91
92    pub fn load(&self) -> ImageData {
93        match self {
94            Self::Path(path) => ImageData::load(path),
95            Self::Data(image) => image.clone(),
96        }
97    }
98}
99
100#[derive(Clone, PartialEq, Eq, Hash)]
101pub struct ImageData {
102    width: u32,
103    height: u32,
104    pixels: Arc<[u8]>,
105}
106
107impl ImageData {
108    pub fn new(width: u32, height: u32, pixels: impl Into<Arc<[u8]>>) -> Self {
109        Self {
110            width,
111            height,
112            pixels: pixels.into(),
113        }
114    }
115
116    pub fn try_load(path: impl AsRef<Path>) -> image::ImageResult<Self> {
117        let image = image::open(path)?;
118        let width = image.width();
119        let height = image.height();
120        let pixels = image.into_rgba8().into_raw();
121
122        Ok(Self {
123            width,
124            height,
125            pixels: pixels.into(),
126        })
127    }
128
129    pub fn load(path: impl AsRef<Path>) -> Self {
130        match Self::try_load(path) {
131            Ok(image) => image,
132            Err(err) => {
133                tracing::error!("Failed to load image: {}", err);
134                Self::default()
135            }
136        }
137    }
138
139    pub fn try_from_bytes(bytes: &[u8]) -> image::ImageResult<Self> {
140        let image = image::load_from_memory(bytes)?;
141        let width = image.width();
142        let height = image.height();
143        let pixels = image.into_rgba8().into_raw();
144
145        Ok(Self {
146            width,
147            height,
148            pixels: pixels.into(),
149        })
150    }
151
152    pub fn from_bytes(bytes: &[u8]) -> Self {
153        match Self::try_from_bytes(bytes) {
154            Ok(image) => image,
155            Err(err) => {
156                tracing::error!("Failed to load image: {}", err);
157                Self::default()
158            }
159        }
160    }
161
162    pub fn width(&self) -> u32 {
163        self.width
164    }
165
166    pub fn height(&self) -> u32 {
167        self.height
168    }
169
170    pub fn size(&self) -> Vec2 {
171        Vec2::new(self.width as f32, self.height as f32)
172    }
173
174    pub fn pixels(&self) -> &[u8] {
175        &self.pixels
176    }
177}
178
179impl Default for ImageData {
180    fn default() -> Self {
181        Self {
182            width: 1,
183            height: 1,
184            pixels: vec![0, 0, 0, 0].into(),
185        }
186    }
187}
188
189impl Debug for ImageData {
190    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
191        f.debug_struct("ImageData")
192            .field("width", &self.width)
193            .field("height", &self.height)
194            .field("pixels", &Arc::as_ptr(&self.pixels))
195            .finish()
196    }
197}
198
199#[derive(Clone, Debug)]
200pub struct ImageHandle {
201    width: u32,
202    height: u32,
203    handle: Arc<dyn Any + Send + Sync>,
204}
205
206impl ImageHandle {
207    pub fn new<T: Any + Send + Sync>(handle: T, width: u32, height: u32) -> Self {
208        Self {
209            width,
210            height,
211            handle: Arc::new(handle),
212        }
213    }
214
215    pub fn downgrade(&self) -> WeakImageHandle {
216        WeakImageHandle {
217            width: self.width,
218            height: self.height,
219            handle: Arc::downgrade(&self.handle),
220        }
221    }
222
223    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
224        self.handle.downcast_ref()
225    }
226
227    pub fn downcast_arc<T: Any + Send + Sync>(self) -> Option<Arc<T>> {
228        Arc::downcast(self.handle).ok()
229    }
230
231    pub fn width(&self) -> u32 {
232        self.width
233    }
234
235    pub fn height(&self) -> u32 {
236        self.height
237    }
238
239    pub fn size(&self) -> Vec2 {
240        Vec2::new(self.width as f32, self.height as f32)
241    }
242}
243
244#[derive(Clone, Debug)]
245pub struct WeakImageHandle {
246    width: u32,
247    height: u32,
248    handle: Weak<dyn Any + Send + Sync>,
249}
250
251impl WeakImageHandle {
252    pub fn upgrade(&self) -> Option<ImageHandle> {
253        Some(ImageHandle {
254            width: self.width,
255            height: self.height,
256            handle: self.handle.upgrade()?,
257        })
258    }
259
260    pub fn is_alive(&self) -> bool {
261        self.handle.strong_count() > 0
262    }
263
264    pub fn width(&self) -> u32 {
265        self.width
266    }
267
268    pub fn height(&self) -> u32 {
269        self.height
270    }
271
272    pub fn size(&self) -> Vec2 {
273        Vec2::new(self.width as f32, self.height as f32)
274    }
275}