feim 0.25.1

Modular crate for working with images in Rust
Documentation
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,
}