assets.rs

 1use crate::{size, DevicePixels, Result, SharedString, Size};
 2use anyhow::anyhow;
 3use image::{Bgra, ImageBuffer};
 4use std::{
 5    borrow::Cow,
 6    fmt,
 7    hash::Hash,
 8    sync::atomic::{AtomicUsize, Ordering::SeqCst},
 9};
10
11/// A source of assets for this app to use.
12pub trait AssetSource: 'static + Send + Sync {
13    /// Load the given asset from the source path.
14    fn load(&self, path: &str) -> Result<Cow<'static, [u8]>>;
15
16    /// List the assets at the given path.
17    fn list(&self, path: &str) -> Result<Vec<SharedString>>;
18}
19
20impl AssetSource for () {
21    fn load(&self, path: &str) -> Result<Cow<'static, [u8]>> {
22        Err(anyhow!(
23            "get called on empty asset provider with \"{}\"",
24            path
25        ))
26    }
27
28    fn list(&self, _path: &str) -> Result<Vec<SharedString>> {
29        Ok(vec![])
30    }
31}
32
33/// A unique identifier for the image cache
34#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
35pub struct ImageId(usize);
36
37#[derive(PartialEq, Eq, Hash, Clone)]
38pub(crate) struct RenderImageParams {
39    pub(crate) image_id: ImageId,
40}
41
42/// A cached and processed image.
43pub struct ImageData {
44    /// The ID associated with this image
45    pub id: ImageId,
46    data: ImageBuffer<Bgra<u8>, Vec<u8>>,
47}
48
49impl ImageData {
50    /// Create a new image from the given data.
51    pub fn new(data: ImageBuffer<Bgra<u8>, Vec<u8>>) -> Self {
52        static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
53
54        Self {
55            id: ImageId(NEXT_ID.fetch_add(1, SeqCst)),
56            data,
57        }
58    }
59
60    /// Convert this image into a byte slice.
61    pub fn as_bytes(&self) -> &[u8] {
62        &self.data
63    }
64
65    /// Get the size of this image, in pixels
66    pub fn size(&self) -> Size<DevicePixels> {
67        let (width, height) = self.data.dimensions();
68        size(width.into(), height.into())
69    }
70}
71
72impl fmt::Debug for ImageData {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        f.debug_struct("ImageData")
75            .field("id", &self.id)
76            .field("size", &self.data.dimensions())
77            .finish()
78    }
79}