x_graphics/
bitmap.rs

1use std::fmt::{Display, Formatter};
2
3use crate::{
4    base::Dimension,
5    canvas::{Canvas, CanvasBackend},
6    device::{DeviceContext, DeviceContextBackend},
7    error::GraphicsError,
8};
9
10#[derive(Clone, Copy, Debug, PartialEq)]
11pub enum BitmapPixelFormat {
12    ARGB32 = 0,
13    BGRA32,
14    ABGR32,
15    RGBA32,
16    RGB24,
17    BGR24,
18    A8,
19}
20
21impl BitmapPixelFormat {
22    pub fn bits_per_pixel(&self) -> usize {
23        self.bytes_per_pixel() * 8
24    }
25
26    pub fn bytes_per_pixel(&self) -> usize {
27        match self {
28            Self::ARGB32 | Self::BGRA32 | Self::ABGR32 | Self::RGBA32 => 4,
29            Self::RGB24 | Self::BGR24 => 3,
30            Self::A8 => 1,
31        }
32    }
33}
34
35impl Display for BitmapPixelFormat {
36    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
37        write!(f, "{:?}", self)
38    }
39}
40
41pub trait BitmapBackend: Dimension {
42    type DeviceContextType: DeviceContextBackend;
43    type CanvasType: CanvasBackend;
44
45    fn new(
46        context: Option<&Self::DeviceContextType>,
47        width: usize,
48        height: usize,
49        pixel_format: BitmapPixelFormat,
50        canvas: &Self::CanvasType,
51    ) -> Result<Self, GraphicsError>
52    where
53        Self: Sized;
54
55    fn from_buffer(
56        context: Option<&Self::DeviceContextType>,
57        buffer: &[u8],
58        pitch: usize,
59        width: usize,
60        height: usize,
61        pixel_format: BitmapPixelFormat,
62        canvas: &Self::CanvasType,
63    ) -> Result<Self, GraphicsError>
64    where
65        Self: Sized;
66}
67
68pub struct Bitmap<T: BitmapBackend> {
69    pub(crate) backend: T,
70}
71
72impl<T: BitmapBackend> Bitmap<T> {
73    pub fn new(
74        context: Option<&DeviceContext<T::DeviceContextType>>,
75        width: usize,
76        height: usize,
77        pixel_format: BitmapPixelFormat,
78        canvas: &Canvas<T::CanvasType>,
79    ) -> Result<Self, GraphicsError> {
80        Ok(Self {
81            backend: T::new(context.map(|ctx| &ctx.backend), width, height, pixel_format, &canvas.backend)?,
82        })
83    }
84
85    pub fn from_buffer(
86        context: Option<&DeviceContext<T::DeviceContextType>>,
87        buffer: &[u8],
88        pitch: usize,
89        width: usize,
90        height: usize,
91        pixel_format: BitmapPixelFormat,
92        canvas: &Canvas<T::CanvasType>,
93    ) -> Result<Self, GraphicsError> {
94        Ok(Self {
95            backend: T::from_buffer(context.map(|ctx| &ctx.backend), buffer, pitch, width, height, pixel_format, &canvas.backend)?,
96        })
97    }
98}