use std::fmt::{Display, Formatter};
use crate::{
base::Dimension,
canvas::{Canvas, CanvasBackend},
device::{DeviceContext, DeviceContextBackend},
error::GraphicsError,
};
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum BitmapPixelFormat {
ARGB32 = 0,
BGRA32,
ABGR32,
RGBA32,
RGB24,
BGR24,
A8,
}
impl BitmapPixelFormat {
pub fn bits_per_pixel(&self) -> usize {
self.bytes_per_pixel() * 8
}
pub fn bytes_per_pixel(&self) -> usize {
match self {
Self::ARGB32 | Self::BGRA32 | Self::ABGR32 | Self::RGBA32 => 4,
Self::RGB24 | Self::BGR24 => 3,
Self::A8 => 1,
}
}
}
impl Display for BitmapPixelFormat {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
pub trait BitmapBackend: Dimension {
type DeviceContextType: DeviceContextBackend;
type CanvasType: CanvasBackend;
fn new(
context: Option<&Self::DeviceContextType>,
width: usize,
height: usize,
pixel_format: BitmapPixelFormat,
canvas: &Self::CanvasType,
) -> Result<Self, GraphicsError>
where
Self: Sized;
fn from_buffer(
context: Option<&Self::DeviceContextType>,
buffer: &[u8],
pitch: usize,
width: usize,
height: usize,
pixel_format: BitmapPixelFormat,
canvas: &Self::CanvasType,
) -> Result<Self, GraphicsError>
where
Self: Sized;
}
pub struct Bitmap<T: BitmapBackend> {
pub(crate) backend: T,
}
impl<T: BitmapBackend> Bitmap<T> {
pub fn new(
context: Option<&DeviceContext<T::DeviceContextType>>,
width: usize,
height: usize,
pixel_format: BitmapPixelFormat,
canvas: &Canvas<T::CanvasType>,
) -> Result<Self, GraphicsError> {
Ok(Self {
backend: T::new(context.map(|ctx| &ctx.backend), width, height, pixel_format, &canvas.backend)?,
})
}
pub fn from_buffer(
context: Option<&DeviceContext<T::DeviceContextType>>,
buffer: &[u8],
pitch: usize,
width: usize,
height: usize,
pixel_format: BitmapPixelFormat,
canvas: &Canvas<T::CanvasType>,
) -> Result<Self, GraphicsError> {
Ok(Self {
backend: T::from_buffer(context.map(|ctx| &ctx.backend), buffer, pitch, width, height, pixel_format, &canvas.backend)?,
})
}
}