use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Bitmap {
color: BitmapColor,
fmt: BitmapFormat,
mip_levels: u32,
#[serde(with = "serde_bytes")]
pixels: Vec<u8>,
width: u32,
}
impl Bitmap {
pub fn new(
color: BitmapColor,
fmt: BitmapFormat,
width: u32,
mip_levels: u32,
pixels: impl Into<Vec<u8>>,
) -> Self {
let pixels = pixels.into();
Self {
color,
fmt,
mip_levels,
pixels,
width,
}
}
pub fn color(&self) -> BitmapColor {
self.color
}
pub fn extent(&self) -> (u32, u32) {
(self.width(), self.height())
}
pub fn format(&self) -> BitmapFormat {
self.fmt
}
pub fn height(&self) -> u32 {
let len = self.pixels.len() as u32;
let byte_height = len / self.width;
match self.fmt {
BitmapFormat::R => byte_height,
BitmapFormat::Rg => byte_height / 2,
BitmapFormat::Rgb => byte_height / 3,
BitmapFormat::Rgba => byte_height >> 2,
}
}
pub fn mip_levels(&self) -> u32 {
self.mip_levels
}
pub fn pixel(&self, x: u32, y: u32) -> &[u8] {
let offset = y as usize * self.stride() + x as usize * self.fmt.byte_len();
&self.pixels[offset..offset + self.fmt.byte_len()]
}
pub fn pixels(&self) -> &[u8] {
&self.pixels
}
pub fn pixels_as_format(&self, dst_fmt: BitmapFormat) -> impl Iterator<Item = u8> + '_ {
let stride = self.fmt.byte_len().min(dst_fmt.byte_len());
self.pixels
.chunks(self.fmt.byte_len())
.flat_map(move |src| {
let mut dst = [0; 4];
dst[0..stride].copy_from_slice(&src[0..stride]);
dst.into_iter()
})
}
pub fn stride(&self) -> usize {
self.width as usize * self.fmt.byte_len()
}
pub fn width(&self) -> u32 {
self.width
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum BitmapFormat {
#[serde(rename = "r")]
R,
#[serde(rename = "rg")]
Rg,
#[serde(rename = "rgb")]
Rgb,
#[serde(rename = "rgba")]
Rgba,
}
impl BitmapFormat {
#[inline]
pub const fn byte_len(self) -> usize {
match self {
Self::R => 1,
Self::Rg => 2,
Self::Rgb => 3,
Self::Rgba => 4,
}
}
pub const fn has_alpha(self) -> bool {
matches!(self, Self::Rgba)
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum BitmapColor {
#[serde(rename = "linear")]
Linear,
#[serde(rename = "srgb")]
Srgb,
}