#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum PixelFormat {
Rgba8,
Bgra8,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Rect {
pub x: usize,
pub y: usize,
pub width: usize,
pub height: usize,
}
impl Rect {
pub const fn new(x: usize, y: usize, width: usize, height: usize) -> Self {
Rect {
x,
y,
width,
height,
}
}
}
impl From<(usize, usize, usize, usize)> for Rect {
fn from(v: (usize, usize, usize, usize)) -> Self {
Rect::new(v.0, v.1, v.2, v.3)
}
}
#[derive(Clone, Debug)]
pub struct Frame {
pub pixels: Vec<u8>,
pub width: usize,
pub height: usize,
pub format: PixelFormat,
}
impl Frame {
pub fn rgba8(width: usize, height: usize, pixels: Vec<u8>) -> Self {
Frame {
width,
height,
pixels,
format: PixelFormat::Rgba8,
}
}
pub fn bgra8(width: usize, height: usize, pixels: Vec<u8>) -> Self {
Frame {
width,
height,
pixels,
format: PixelFormat::Bgra8,
}
}
pub fn prepare_bgra(&mut self, width: usize, height: usize) {
self.width = width;
self.height = height;
self.format = PixelFormat::Bgra8;
self.pixels.clear();
self.pixels.resize(width * height * 4, 0);
}
pub fn prepare_rgba(&mut self, width: usize, height: usize) {
self.width = width;
self.height = height;
self.format = PixelFormat::Rgba8;
self.pixels.clear();
self.pixels.resize(width * height * 4, 0);
}
pub fn full_rect(&self) -> Rect {
Rect::new(0, 0, self.width, self.height)
}
#[inline]
pub fn stride(&self) -> usize {
self.width * 4
}
#[inline]
pub fn rgb_offsets(&self) -> (usize, usize, usize) {
match self.format {
PixelFormat::Rgba8 => (0, 1, 2),
PixelFormat::Bgra8 => (2, 1, 0),
}
}
pub fn clamp(&self, r: Rect) -> Rect {
let x = r.x.min(self.width);
let y = r.y.min(self.height);
let width = r.width.min(self.width - x);
let height = r.height.min(self.height - y);
Rect {
x,
y,
width,
height,
}
}
pub fn crop(&self, r: Rect) -> Frame {
let r = self.clamp(r);
let row = r.width * 4;
let mut out = Vec::with_capacity(r.width * r.height * 4);
for y in 0..r.height {
let src = ((r.y + y) * self.width + r.x) * 4;
out.extend_from_slice(&self.pixels[src..src + row]);
}
Frame {
pixels: out,
width: r.width,
height: r.height,
format: self.format,
}
}
pub fn to_gray(&self) -> Vec<u8> {
let mut v = Vec::with_capacity(self.width * self.height);
self.to_gray_into(&mut v);
v
}
pub fn to_gray_into(&self, out: &mut Vec<u8>) {
let (ro, go, bo) = self.rgb_offsets();
out.clear();
out.reserve(self.width * self.height);
for px in self.pixels.chunks_exact(4) {
let r = px[ro] as u32;
let g = px[go] as u32;
let bl = px[bo] as u32;
out.push(((r * 299 + g * 587 + bl * 114) / 1000) as u8);
}
}
}