repo_description: A cross-platform GUI library for Rust, inspired by Elm
repo_topics: elm graphics gui interface renderer-agnostic rust toolkit user-interface widget widgets
code: //! Load and draw raster graphics.
  use crate::border;
  use crate::{Bytes, Radians, Rectangle, Size};
  
  use rustc_hash::FxHasher;
  
  use std::hash::{Hash, Hasher};
  use std::io;
  use std::path::{Path, PathBuf};
  use std::sync::{Arc, Weak};
  
  /// 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; on its center.
      pub rotation: Radians,
  
      /// The border radius of the [`Image`].
      ///
      /// Currently, this will only be applied to the `clip_bounds`.
      pub border_radius: border::Radius,
  
      /// The opacity of the image.
      ///
      /// 0 means transparent. 1 means opaque.
      pub opacity: f32,
  }
  
  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),
              border_radius: border::Radius::default(),
              opacity: 1.0,
          }
      }
  
      /// 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
      }
  }
  
  impl From<&Handle> for Image {
      fn from(handle: &Handle) -> Self {
          Image::new(handle.clone())
      }
  }
  
  /// A handle of some image data.
  #[derive(Clone, PartialEq, Eq)]
  pub enum Handle {
      /// A file handle. The image data will be read
      /// from the file path.
      ///
      /// Use [`from_path`] to create this variant.
      ///
      /// [`from_path`]: Self::from_path
      Path(Id, PathBuf),
  
      /// A handle pointing to some encoded image bytes in-memory.
      ///
      /// Use [`from_bytes`] to create this variant.
      ///
      /// [`from_bytes`]: Self::from_bytes
      Bytes(Id, Bytes),
  
      /// A handle pointing to decoded image pixels in RGBA format.
      ///
      /// Use [`from_rgba`] to create this variant.
      ///
      /// [`from_rgba`]: Self::from_rgba
      Rgba {
          /// The id of this handle.
          id: Id,
          /// The width of the image.
          width: u32,
          /// The height of the image.
          height: u32,
          /// The pixels.
          pixels: Bytes,
      },
  }
  
  impl Handle {
      /// Creates an image [`Handle`] pointing to the image of the given path.
      ///
      /// Makes an educated guess about the image format by examining the data in the file.
      pub fn from_path<T: Into<PathBuf>>(path: T) -> Handle {
          let path = path.into();
  
          Self::Path(Id::path(&path), path)
      }
  
      /// Creates an image [`Handle`] containing the encoded image data directly.
      ///
      /// Makes an educated guess about the image format by examining the given data.
      ///
      /// This is useful if you already have your image loaded in-memory, maybe
      /// because you downloaded or generated it procedurally.
      pub fn from_bytes(bytes: impl Into<Bytes>) -> Handle {
          Self::Bytes(Id::unique(), bytes.into())
      }
  
      /// Creates an image [`Handle`] containing the decoded image pixels directly.
      ///
      /// This function expects the pixel data to be provided as a collection of [`Bytes`]
      /// of RGBA pixels. Therefore, the length of the pixel data should always be
      /// `width * height * 4`.
      ///
      /// This is useful if you have already decoded your image.
      pub fn from_rgba(width: u32, height: u32, pixels: impl Into<Bytes>) -> Handle {
          Self::Rgba {
              id: Id::unique(),
              width,
              height,
              pixels: pixels.into(),
          }
      }
  
      /// Returns the unique identifier of the [`Handle`].
      pub fn id(&self) -> Id {
          match self {
              Handle::Path(id, _) | Handle::Bytes(id, _) | Handle::Rgba { id, .. } => *id,
          }
      }
  }
  
  impl<T> From<T> for Handle
  where
      T: Into<PathBuf>,
  {
      fn from(path: T) -> Handle {
          Handle::from_path(path.into())
      }
  }
  
  impl From<&Handle> for Handle {
      fn from(value: &Handle) -> Self {
          value.clone()
      }
  }
  
  impl std::fmt::Debug for Handle {
      fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
          match self {
              Self::Path(id, path) => write!(f, "Path({id:?}, {path:?})"),
              Self::Bytes(id, _) => write!(f, "Bytes({id:?}, ...)"),
              Self::Rgba {
                  id, width, height, ..
              } => {
                  write!(f, "Pixels({id:?}, {width} * {height})")
              }
          }
      }
  }
  
  /// The unique identifier of some [`Handle`] data.
  #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
  pub struct Id(_Id);
  
  #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
  enum _Id {
      Unique(u64),
      Hash(u64),
  }
  
  impl Id {
      fn unique() -> Self {
          use std::sync::atomic::{self, AtomicU64};
  
          static NEXT_ID: AtomicU64 = AtomicU64::new(0);
  
          Self(_Id::Unique(NEXT_ID.fetch_add(1, atomic::Ordering::Relaxed)))
      }
  
      fn path(path: impl AsRef<Path>) -> Self {
          let hash = {
              let mut hasher = FxHasher::default();
              path.as_ref().hash(&mut hasher);
  
              hasher.finish()
          };
  
          Self(_Id::Hash(hash))
      }
  }
  
  /// Image filtering strategy.
  #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
  pub enum FilterMethod {
      /// Bilinear interpolation.
      #[default]
      Linear,
      /// Nearest neighbor.
      Nearest,
  }
  
  /// A memory allocation of a [`Handle`], often in GPU memory.
  ///
  /// Renderers tend to decode and upload image data concurrently to
  /// avoid blocking the user interface. This means that when you use a
  /// [`Handle`] in a widget, there may be a slight frame delay until it
  /// is finally visible. If you are animating images, this can cause
  /// undesirable flicker.
  ///
  /// When you obtain an [`Allocation`] explicitly, you get the guarantee
  /// that using a [`Handle`] will draw the corresponding [`Image`]
  /// immediately in the next frame.
  ///
  /// This guarantee is valid as long as you hold an [`Allocation`].
  /// Only when you drop all its clones, the renderer may choose to free
  /// the memory of the [`Handle`]. Be careful!
  #[derive(Debug, Clone, PartialEq, Eq)]
  pub struct Allocation(Arc<Memory>);
  
  /// Some memory taken by an [`Allocation`].
  #[derive(Debug, Clone, PartialEq, Eq)]
  pub struct Memory {
      handle: Handle,
      size: Size<u32>,
  }
  
  impl Allocation {
      /// Returns a weak reference to the [`Memory`] of the [`Allocation`].
      pub fn downgrade(&self) -> Weak<Memory> {
          Arc::downgrade(&self.0)
      }
  
      /// Upgrades a [`Weak`] memory reference to an [`Allocation`].
      pub fn upgrade(weak: &Weak<Memory>) -> Option<Allocation> {
          Weak::upgrade(weak).map(Allocation)
      }
  
      /// Returns the [`Handle`] of this [`Allocation`].
      pub fn handle(&self) -> &Handle {
          &self.0.handle
      }
  
      /// Returns the [`Size`] of the image of this [`Allocation`].
      pub fn size(&self) -> Size<u32> {
          self.0.size
      }
  }
  
  /// Creates a new [`Allocation`] for the given handle.
  ///
  /// This should only be used internally by renderer implementations.
  ///
  /// # Safety
  /// Must only be created once the [`Handle`] is allocated in memory.
  #[allow(unsafe_code)]
  pub unsafe fn allocate(handle: &Handle, size: Size<u32>) -> Allocation {
      Allocation(Arc::new(Memory {
          handle: handle.clone(),
          size,
      }))
  }
  
  /// A [`Renderer`] that can render raster graphics.
  ///
  /// [renderer]: crate::renderer
  pub trait Renderer: crate::Renderer {
      /// The image Handle to be displayed. Iced exposes its own default implementation of a [`Handle`]
      ///
      /// [`Handle`]: Self::Handle
      type Handle: Clone;
  
      /// Loads an image and returns an explicit [`Allocation`] to it.
      ///
      /// If the image is not already loaded, this method will block! You should
      /// generally not use it in drawing logic if you want to avoid frame drops.
      fn load_image(&self, handle: &Self::Handle) -> Result<Allocation, Error>;
  
      /// Returns the dimensions of an image for the given [`Handle`].
      ///
      /// If the image is not already loaded, the [`Renderer`] may choose to return
      /// `None`, load the image in the background, and then trigger a relayout.
      ///
      /// If you need a measurement right away, consider using [`Renderer::load_image`].
      fn measure_image(&self, handle: &Self::Handle) -> Option<Size<u32>>;
  
      /// Draws an [`Image`] inside the provided `bounds`.
      ///
      /// If the image is not already loaded, the [`Renderer`] may choose to render
      /// nothing, load the image in the background, and then trigger a redraw.
      ///
      /// If you need to draw an image right away, consider using [`Renderer::load_image`]
      /// and hold on to an [`Allocation`] first.
      fn draw_image(&mut self, image: Image<Self::Handle>, bounds: Rectangle, clip_bounds: Rectangle);
  }
  
  /// An image loading error.
  #[derive(Debug, Clone, thiserror::Error)]
  pub enum Error {
      /// The image data was invalid or could not be decoded.
      #[error("the image data was invalid or could not be decoded: {0}")]
      Invalid(Arc<dyn std::error::Error + Send + Sync>),
      /// The image file was not found.
      #[error("the image file could not be opened: {0}")]
      Inaccessible(Arc<io::Error>),
      /// Loading images is unsupported.
      #[error("loading images is unsupported")]
      Unsupported,
      /// The image is empty.
      #[error("the image is empty")]
      Empty,
      /// Not enough memory to allocate the image.
      #[error("not enough memory to allocate the image")]
      OutOfMemory,
  }
  