use alloc::vec::Vec;
use crate::widget::{Color, Rect};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PixelFormat {
Rgb565,
Argb8888,
L8,
}
impl PixelFormat {
pub const fn bytes_per_pixel(self) -> u32 {
match self {
PixelFormat::Rgb565 => 2,
PixelFormat::Argb8888 => 4,
PixelFormat::L8 => 1,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum ImageData<'a> {
Borrowed(&'a [u8]),
BorrowedColors(&'a [Color]),
Owned(Vec<u8>),
#[cfg(feature = "fs")]
Asset(crate::asset::AssetHandle),
}
impl<'a> ImageData<'a> {
pub fn byte_len(&self) -> usize {
match self {
ImageData::Borrowed(bytes) => bytes.len(),
ImageData::BorrowedColors(colors) => {
colors.len() * PixelFormat::Argb8888.bytes_per_pixel() as usize
}
ImageData::Owned(bytes) => bytes.len(),
#[cfg(feature = "fs")]
ImageData::Asset(_) => 0,
#[allow(unreachable_patterns)]
_ => 0,
}
}
pub fn is_empty(&self) -> bool {
self.byte_len() == 0
}
pub fn as_bytes(&self) -> Option<&[u8]> {
match self {
ImageData::Borrowed(bytes) => Some(bytes),
ImageData::Owned(bytes) => Some(bytes),
ImageData::BorrowedColors(_) => None,
#[cfg(feature = "fs")]
ImageData::Asset(_) => None,
#[allow(unreachable_patterns)]
_ => None,
}
}
pub fn as_color_slice(&self) -> Option<&[Color]> {
match self {
ImageData::BorrowedColors(colors) => Some(colors),
ImageData::Borrowed(_) | ImageData::Owned(_) => None,
#[cfg(feature = "fs")]
ImageData::Asset(_) => None,
#[allow(unreachable_patterns)]
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImageDescriptor<'a> {
pub format: PixelFormat,
pub width: u16,
pub height: u16,
pub data: ImageData<'a>,
pub stride: Option<u32>,
}
impl<'a> ImageDescriptor<'a> {
pub const fn new(
format: PixelFormat,
width: u16,
height: u16,
data: ImageData<'a>,
stride: Option<u32>,
) -> Self {
Self {
format,
width,
height,
data,
stride,
}
}
pub const fn borrowed(format: PixelFormat, width: u16, height: u16, data: &'a [u8]) -> Self {
Self::new(format, width, height, ImageData::Borrowed(data), None)
}
pub fn owned(format: PixelFormat, width: u16, height: u16, data: Vec<u8>) -> Self {
Self::new(format, width, height, ImageData::Owned(data), None)
}
pub const fn from_color_slice(pixels: &'a [Color], width: u16, height: u16) -> Self {
Self::new(
PixelFormat::Argb8888,
width,
height,
ImageData::BorrowedColors(pixels),
None,
)
}
pub const fn dimensions(&self) -> (u16, u16) {
(self.width, self.height)
}
pub const fn tightly_packed_stride(&self) -> u32 {
self.width as u32 * self.format.bytes_per_pixel()
}
pub fn stride_bytes(&self) -> u32 {
match self.stride {
Some(stride) => stride,
None => self.tightly_packed_stride(),
}
}
pub fn is_tightly_packed(&self) -> bool {
match self.stride {
Some(stride) => stride == self.tightly_packed_stride(),
None => true,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BlitOpts {
pub recolor: Option<Color>,
pub recolor_alpha: u8,
pub scale_x: u16,
pub scale_y: u16,
pub rotation_deg: i16,
pub pivot: (i16, i16),
pub clip: Option<Rect>,
}
impl Default for BlitOpts {
fn default() -> Self {
Self {
recolor: None,
recolor_alpha: 0,
scale_x: 256,
scale_y: 256,
rotation_deg: 0,
pivot: (0, 0),
clip: None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CacheHandle(u32);
impl CacheHandle {
pub const fn new(raw: u32) -> Self {
Self(raw)
}
pub const fn as_u32(self) -> u32 {
self.0
}
}
pub trait ImageCache<'a> {
fn get(&self, handle: CacheHandle) -> Option<&ImageDescriptor<'a>>;
fn put(&mut self, descriptor: ImageDescriptor<'a>) -> CacheHandle;
}