use super::*;
use alloc::{boxed::Box, slice, string::ToString};
use core::ptr;
pub trait PixelsSource {
fn buffer(&self) -> &[u8];
}
pub struct FlashSource(pub &'static [u8]);
impl PixelsSource for FlashSource {
fn buffer(&self) -> &[u8] {
self.0
}
}
pub struct RamSource(pub Box<[u8]>);
impl PixelsSource for RamSource {
fn buffer(&self)-> &[u8] { &self.0 }
}
pub trait ImageFormat {
fn width(&self) -> u16;
fn height(&self) -> u16;
fn draw(&self, dest: Point);
}
pub enum Image {
Eif1Flash(Eif1<FlashSource>),
Eif1Ram(Eif1<RamSource>),
}
impl ImageFormat for Image {
fn width(&self) -> u16 {
match self {
Image::Eif1Flash(eif) => eif.width(),
Image::Eif1Ram(eif) => eif.width(),
}
}
fn height(&self) -> u16 {
match self {
Image::Eif1Flash(eif) => eif.height(),
Image::Eif1Ram(eif) => eif.height(),
}
}
fn draw(&self, dest: Point) {
match self {
Image::Eif1Flash(eif) => eif.draw(dest),
Image::Eif1Ram(eif) => eif.draw(dest),
}
}
}
pub struct ImageLoader;
impl ImageLoader {
pub fn from_flash(data: &'static [u8]) -> Result<Image, ImageError> {
if data.len() < 8 {
return Err(ImageError::CorruptedData { details: "Data too short to contain valid header".to_string() });
}
unsafe {
let magic = ptr::read_unaligned(data.as_ptr() as *const u32);
match magic {
EIF1_MAGIC_NUMBER => Ok( Image::Eif1Flash(Eif1::new(FlashSource(data))) ),
_ => Err(ImageError::UnsupportedFormat { magic_number: magic }),
}
}
}
pub fn from_ram(data: &[u8]) -> Result<Image, ImageError> {
if data.len() < 8 {
return Err(ImageError::CorruptedData { details: "Data too short to contain valid header".to_string() });
}
let buffer: Box<[u8]> = Box::from(data);
unsafe {
let magic = ptr::read_unaligned(buffer.as_ptr() as *const u32);
match magic {
EIF1_MAGIC_NUMBER => Ok( Image::Eif1Ram(Eif1::new(RamSource(buffer))) ),
_ => Err(ImageError::UnsupportedFormat { magic_number: magic }),
}
}
}
pub fn to_ram(data: &'static [u8]) -> Result<Image, ImageError> {
Self::from_ram(data)
}
}
pub struct Eif1<S: PixelsSource> {
pub width: u16,
pub height: u16,
pub source: S,
}
impl<S: PixelsSource> ImageFormat for Eif1<S> {
fn width(&self) -> u16 {
self.width
}
fn height(&self) -> u16 {
self.height
}
fn draw(&self, _dest: Point) {
let rect = Rect {
x: _dest.x,
y: _dest.y,
width: self.width,
height: self.height,
};
let raw_bytes = &self.source.buffer()[(4+2+2)..];
let pixels: &[Color] = unsafe {
slice::from_raw_parts(
raw_bytes.as_ptr() as *const Color,
raw_bytes.len() / 2
)
};
display::push_rect(rect, pixels);
}
}
impl<S: PixelsSource> Eif1<S> {
pub unsafe fn new(source: S)-> Self {
let buf = source.buffer();
Self {
width: u16::from_le_bytes([buf[4], buf[5]]),
height: u16::from_le_bytes([buf[6], buf[7]]),
source,
}
}
}