use std::io::{self, Read, Write};
use super::{Dimensions, Format, Image};
use crate::buffer::RawPixBuf;
use crate::color::convert::ConvertInto;
use crate::color::{BigEndian, NativeEndian, Nrgba64};
use crate::impl_format;
use crate::serialize::{Decode, DecodeOptions, Encode, EncodeOptions};
use crate::specialized;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct FarbfeldDecodeOptions {
pub check_header: bool,
}
impl Default for FarbfeldDecodeOptions {
fn default() -> Self {
Self { check_header: true }
}
}
pub struct Farbfeld;
impl_format! {
name: Farbfeld,
id: "feim:ff",
magic: b"farbfeld????????",
}
impl EncodeOptions for Farbfeld {
type Options = ();
}
impl DecodeOptions for Farbfeld {
type Options = FarbfeldDecodeOptions;
}
impl Encode<RawPixBuf<Nrgba64<BigEndian>>> for Farbfeld {
type Error = io::Error;
fn encode<W: Write>(
mut w: W,
_opts: (),
buf: &RawPixBuf<Nrgba64<BigEndian>>,
) -> io::Result<()> {
let width = (buf.width() as u32).to_be_bytes();
let height = (buf.height() as u32).to_be_bytes();
let magic = Farbfeld.magic();
w.write_all(&magic[..8])?;
w.write_all(&width[..])?;
w.write_all(&height[..])?;
w.write_all(buf.as_ref())?;
Ok(())
}
}
pub struct FarbfeldEncodeBuffer<'pixels> {
width: u32,
height: u32,
inner: &'pixels [u8],
}
impl<'pixels> FarbfeldEncodeBuffer<'pixels> {
pub fn new(width: u32, height: u32, pixel_data: &'pixels [u8]) -> Option<Self> {
let expected_length = pixel_data.len() as u32;
let acquired_length = width * height * const { 4 * 2 };
if expected_length == acquired_length {
Some(Self {
width,
height,
inner: pixel_data,
})
} else {
None
}
}
}
impl Encode<FarbfeldEncodeBuffer<'_>> for Farbfeld {
type Error = io::Error;
fn encode<W: Write>(mut w: W, _opts: (), buffer: &FarbfeldEncodeBuffer<'_>) -> io::Result<()> {
let width = buffer.width.to_be_bytes();
let height = buffer.height.to_be_bytes();
let magic = Farbfeld.magic();
w.write_all(&magic[..8])?;
w.write_all(&width[..])?;
w.write_all(&height[..])?;
w.write_all(buffer.inner)?;
Ok(())
}
}
impl<I: Image + Dimensions> Encode<I, specialized::No> for Farbfeld {
type Error = io::Error;
fn encode<W: Write>(mut w: W, _opts: (), buf: &I) -> io::Result<()> {
let (width, height) = buf.dimensions();
{
let width_ = (width as u32).to_be_bytes();
let height_ = (height as u32).to_be_bytes();
let magic = Farbfeld.magic();
w.write_all(&magic[..8])?;
w.write_all(&width_[..])?;
w.write_all(&height_[..])?;
}
for y in 0..height {
for x in 0..width {
let c = buf.color_get(x, y);
let c: Nrgba64<BigEndian> = c.convert_into();
let c: Nrgba64<NativeEndian> = c.cast();
let c: u64 = c.into();
let c = c.to_ne_bytes();
w.write_all(&c[..])?;
}
}
Ok(())
}
}
impl Decode<RawPixBuf<Nrgba64<BigEndian>>> for Farbfeld {
type Error = io::Error;
fn decode<R: Read>(mut r: R, opt: Self::Options) -> io::Result<RawPixBuf<Nrgba64<BigEndian>>> {
let FarbfeldHeader { width, height } = Self::decode_header(&mut r, opt)?;
let mut buf = RawPixBuf::new(width as usize, height as usize);
r.read_exact(buf.as_mut())?;
Ok(buf)
}
}
impl Farbfeld {
pub fn decode_header<R: Read>(
mut r: R,
opt: FarbfeldDecodeOptions,
) -> io::Result<FarbfeldHeader> {
let mut m: [u8; 16] = [0; 16];
r.read_exact(&mut m[..])?;
if opt.check_header && !Farbfeld.is_valid_magic(&m[..]) {
return Err(std::io::Error::other("Invalid farbfeld magic"));
}
let width = u32::from_be_bytes([m[8], m[9], m[10], m[11]]);
let height = u32::from_be_bytes([m[12], m[13], m[14], m[15]]);
Ok(FarbfeldHeader { width, height })
}
}
pub struct FarbfeldHeader {
pub width: u32,
pub height: u32,
}