resource-fork-types 0.1.0

Support for reading common resource fork types in rust
Documentation
use binrw::{binread, BinRead, BinReaderExt};
use pict::{
    drawing_context::decode_pixmap,
    shared::{self, ColorTable},
};
use resource_fork::Resource;

#[derive(BinRead, Debug)]
#[br(big)]
pub struct Pat([u8; Self::DATA_LEN]);

impl Pat {
    pub const DATA_LEN: usize = Self::HEIGHT * Self::WIDTH / 8;
    pub const HEIGHT: usize = 8;
    pub const WIDTH: usize = 8;

    pub fn at(&self, x: usize, y: usize) -> bool {
        let bytes_per_row = self.width() / 8;
        let chosen_byte = y * bytes_per_row + x / 8;
        let bit = 7 - (x % 8);

        (self.0[chosen_byte] & (1 << bit)) != 0
    }

    pub fn into_data(self) -> [u8; Self::DATA_LEN] {
        self.0
    }

    pub const fn width(&self) -> usize {
        Self::WIDTH
    }

    pub const fn height(&self) -> usize {
        Self::HEIGHT
    }
}

#[binread]
#[derive(Debug, Resource)]
#[resource(code = "PAT#")]
#[br(big)]
pub struct Pattern {
    #[br(temp)]
    count: u16,
    #[br(count(count))]
    pub patterns: Vec<Pat>,
}

#[derive(Debug, Resource)]
#[resource(code = "ppat")]
pub struct PixelPattern {
    pub image: image::ImageBuffer<image::Rgba<u8>, Vec<u8>>,
}

impl BinRead for PixelPattern {
    type Args<'a> = ();

    fn read_options<R: std::io::Read + std::io::Seek>(
        reader: &mut R,
        _endian: binrw::Endian,
        _args: Self::Args<'_>,
    ) -> binrw::BinResult<Self> {
        let offset = reader.stream_position().unwrap();
        let header: PixelPatternHeader = reader.read_be()?;
        match header.pattern_type {
            PatternType::Monochrome => {
                todo!()
            }
            PatternType::Indexed => {
                reader.seek(std::io::SeekFrom::Start(
                    offset + header.pixel_map_offset as u64 + 4,
                ))?;

                let high_byte_and_row_flags: u8 = reader.read_be()?;
                let pix_map = reader.read_be_args::<shared::PixMap>((high_byte_and_row_flags,))?;

                reader.seek(std::io::SeekFrom::Start(offset + pix_map.pm_table as u64))?;
                let color_table = reader.read_be();
                let color_table: ColorTable = color_table?;
                reader.seek(std::io::SeekFrom::Start(
                    offset + header.pixel_data_offset as u64,
                ))?;
                let mut pixels =
                    vec![0u8; pix_map.bytes_per_row() as usize * pix_map.bounds.height() as usize];
                reader.read_exact(&mut pixels)?;

                let buffer = decode_pixmap(&pix_map, &color_table, &pixels);
                Ok(Self { image: buffer })
            }
            PatternType::Rgb => todo!(),
        }
    }
}

#[derive(Debug, BinRead)]
#[br(big, repr=u16)]
pub enum PatternType {
    Monochrome = 0,
    Indexed = 1,
    Rgb = 2,
}

#[derive(Debug, BinRead)]
#[br(big)]
pub struct PixelPatternHeader {
    pub pattern_type: PatternType,
    pub pixel_map_offset: u32,
    pub pixel_data_offset: u32,
    pub unused1: u32,
    pub unused2: u16,
    pub reserved: u32,
}