Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ILDA file writer #1

Open
Boscop opened this issue Oct 7, 2024 · 0 comments
Open

Add ILDA file writer #1

Boscop opened this issue Oct 7, 2024 · 0 comments

Comments

@Boscop
Copy link

Boscop commented Oct 7, 2024

I wrote this ILDA writer based on your ILDA reader:

use byteorder::{BigEndian, WriteBytesExt};
use ilda_idtf::layout::{self, Header};
use std::io::{self, Write};

pub struct SectionWriter<W: Write> {
    writer: W,
}

impl<W: Write> SectionWriter<W> {
    pub fn new(writer: W) -> Self {
        SectionWriter { writer }
    }

    pub fn write_header(&mut self, header: &Header) -> io::Result<()> {
        self.writer.write_all(&header.ilda)?;
        self.writer.write_all(&header.reserved)?;
        self.writer.write_u8(header.format.0)?;
        self.writer.write_all(&header.data_name.0)?;
        self.writer.write_all(&header.company_name.0)?;
        self.writer
            .write_u16::<BigEndian>(header.num_records.get())?;
        self.writer
            .write_u16::<BigEndian>(header.data_number.get())?;
        self.writer
            .write_u16::<BigEndian>(header.color_or_total_frames.get())?;
        self.writer.write_u8(header.projector_number)?;
        self.writer.write_u8(header.reserved2)?;
        Ok(())
    }

    pub fn write_coords_3d_indexed_color(
        &mut self,
        point: &layout::Coords3dIndexedColor,
    ) -> io::Result<()> {
        self.writer.write_i16::<BigEndian>(point.coords.x.get())?;
        self.writer.write_i16::<BigEndian>(point.coords.y.get())?;
        self.writer.write_i16::<BigEndian>(point.coords.z.get())?;
        self.writer.write_u8(point.status.bits())?;
        self.writer.write_u8(point.color_index)?;
        Ok(())
    }

    pub fn write_coords_2d_indexed_color(
        &mut self,
        point: &layout::Coords2dIndexedColor,
    ) -> io::Result<()> {
        self.writer.write_i16::<BigEndian>(point.coords.x.get())?;
        self.writer.write_i16::<BigEndian>(point.coords.y.get())?;
        self.writer.write_u8(point.status.bits())?;
        self.writer.write_u8(point.color_index)?;
        Ok(())
    }

    pub fn write_color_palette(&mut self, color: &layout::ColorPalette) -> io::Result<()> {
        self.writer.write_u8(color.color.red)?;
        self.writer.write_u8(color.color.green)?;
        self.writer.write_u8(color.color.blue)?;
        Ok(())
    }

    pub fn write_coords_3d_true_color(
        &mut self,
        point: &layout::Coords3dTrueColor,
    ) -> io::Result<()> {
        self.writer.write_i16::<BigEndian>(point.coords.x.get())?;
        self.writer.write_i16::<BigEndian>(point.coords.y.get())?;
        self.writer.write_i16::<BigEndian>(point.coords.z.get())?;
        self.writer.write_u8(point.status.bits())?;
        self.writer.write_u8(point.color.red)?;
        self.writer.write_u8(point.color.green)?;
        self.writer.write_u8(point.color.blue)?;
        Ok(())
    }

    pub fn write_coords_2d_true_color(
        &mut self,
        point: &layout::Coords2dTrueColor,
    ) -> io::Result<()> {
        self.writer.write_i16::<BigEndian>(point.coords.x.get())?;
        self.writer.write_i16::<BigEndian>(point.coords.y.get())?;
        self.writer.write_u8(point.status.bits())?;
        self.writer.write_u8(point.color.red)?;
        self.writer.write_u8(point.color.green)?;
        self.writer.write_u8(point.color.blue)?;
        Ok(())
    }
}

pub fn create_buffered_writer<P: AsRef<std::path::Path>>(
    path: P,
) -> io::Result<SectionWriter<std::io::BufWriter<std::fs::File>>> {
    let file = std::fs::File::create(path)?;
    let buf_writer = std::io::BufWriter::new(file);
    Ok(SectionWriter::new(buf_writer))
}

This test checks if files are the same after reading & writing:

use ilda_opt::writer::SectionWriter;
use std::io::Cursor;
use std::io::Read;
use std::io::Write;

#[test]
fn test_read_write_compare() {
    let test_files_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("test_files");
    assert!(test_files_path.exists());
    assert!(test_files_path.is_dir());

    let mut total_files = 0;
    let mut unequal_files = 0;

    for entry in walkdir::WalkDir::new(test_files_path) {
        let entry = entry.unwrap();
        let path = entry.path();
        let ext = path.extension().and_then(|s| s.to_str());
        if ext != Some("ild") && ext != Some("ILD") {
            continue;
        }

        // Read the entire file into a buffer
        let mut in_file = std::fs::File::open(path).unwrap();
        let mut read_buffer = Vec::new();
        in_file.read_to_end(&mut read_buffer).unwrap();

        // Create a cursor for the buffer to use with SectionReader
        let cursor = Cursor::new(&read_buffer);
        let mut reader = ilda_idtf::SectionReader::new(cursor);

        /* println!(
            "Reading \"{}\"",
            path.file_stem().unwrap().to_str().unwrap()
        ); */

        // Create a new buffer for writing
        let mut write_buffer = Vec::new();
        let mut writer = SectionWriter::new(Cursor::new(&mut write_buffer));

        loop {
            let section = match reader.read_next() {
                Err(err) => panic!("  failed to read section header: {}", err),
                Ok(None) => break,
                Ok(Some(section)) => section,
            };

            // Write the header
            writer.write_header(section.header).unwrap();

            match section.reader {
                ilda_idtf::SubsectionReaderKind::Coords3dIndexedColor(mut r) => {
                    while let Some(t) = r.read_next().unwrap() {
                        writer.write_coords_3d_indexed_color(t).unwrap();
                    }
                }
                ilda_idtf::SubsectionReaderKind::Coords2dIndexedColor(mut r) => {
                    while let Some(t) = r.read_next().unwrap() {
                        writer.write_coords_2d_indexed_color(t).unwrap();
                    }
                }
                ilda_idtf::SubsectionReaderKind::ColorPalette(mut r) => {
                    while let Some(t) = r.read_next().unwrap() {
                        writer.write_color_palette(t).unwrap();
                    }
                }
                ilda_idtf::SubsectionReaderKind::Coords3dTrueColor(mut r) => {
                    while let Some(t) = r.read_next().unwrap() {
                        writer.write_coords_3d_true_color(t).unwrap();
                    }
                }
                ilda_idtf::SubsectionReaderKind::Coords2dTrueColor(mut r) => {
                    while let Some(t) = r.read_next().unwrap() {
                        writer.write_coords_2d_true_color(t).unwrap();
                    }
                }
            }
        }

        // Write to file <original_file_name>.out.ild
        let mut out_file = std::fs::File::create(path.with_extension("out.ild")).unwrap();
        out_file.write_all(&write_buffer).unwrap();

        total_files += 1;

        // Compare the original buffer with the written buffer
        /* assert_eq!(
            buffer, write_buffer,
            "Buffers do not match for file: {:?}",
            path
        ); */
        if read_buffer != write_buffer {
            println!("Buffers do not match for file: {:?}", path);
            unequal_files += 1;
        }
    }
    println!("Total files: {}", total_files);
    println!("Unequal files: {}", unequal_files);
    assert_eq!(unequal_files, 0);
}

I ran the test on all the test_files.
There are 86 files.
The test succeeds for all except 2:

running 1 test
Buffers do not match for file: "test_files\shownet\ILDA_Files_ShowNET_SD-Card_1_0\033.ild"
Buffers do not match for file: "test_files\shownet\ILDA_Files_ShowNET_SD-Card_1_0\059.ild"
Total files: 86
Unequal files: 2

Maybe it's worth investigating why those 2 files fail, but the writer is a direct "port" of the reader and seems to work for normal files :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant