imagezero-sys 0.1.1

Rust wrapper for imagezero (losless image compression algorithm) used i.e. in robotics.
Documentation
// ------------------------------------------------------------------------------
// Copyright 2021 Uwe Arzt, mail@uwe-arzt.de
// SPDX-License-Identifier: Apache-2.0
// ------------------------------------------------------------------------------

#[macro_use]
extern crate clap;
use clap::Arg;

use std::convert::TryInto;

use std::fs::File;
use std::io::Read;
use std::io::Write;

fn main() {
    let matches = command!()
        .arg(
            arg!(<ACTION>)
                .help("compress/decompress")
                .value_parser(["c", "d"]),
        )
        .arg(Arg::new("INPUTFILE").required(true))
        .arg(Arg::new("OUTPUTFILE").required(true))
        .get_matches();

    let infile = matches.get_one::<String>("INPUTFILE").unwrap();
    let outfile = matches.get_one::<String>("OUTPUTFILE").unwrap();

    match matches.get_one::<String>("ACTION").unwrap().as_str() {
        "c" => {
            compress(infile, outfile);
        }
        "d" => {
            decompress(infile, outfile);
        }
        _ => unreachable!(),
    }

    fn compress(ppm: &str, iz: &str) {
        // println!("compress {} to {}", ppm, iz);

        // input image
        let img = image::open(ppm).unwrap();
        if img.color() != image::ColorType::Rgb8 {
            println!("Wrong image format");
        }
        let rgb = img.into_rgb8();
        let (width, height) = rgb.dimensions();

        // output buffer
        let memsize: usize = (height * width * 4 + 33).try_into().unwrap();
        let mut outbuf: Vec<u8> = Vec::with_capacity(memsize);

        unsafe {
            let p_in = imagezero_sys::IZ_Image {
                m_width: width as i32,
                m_height: height as i32,
                m_data: rgb.into_raw().as_mut_ptr(),
                m_spl: (width * 3) as isize,
            };
            let p_out = outbuf.as_mut_ptr();

            imagezero_sys::IZ_initEncodeTable();

            let p_end = imagezero_sys::IZ_encodeImage(&p_in, p_out);
            let retsize = p_end.offset_from(p_out);

            let mut iz = File::create(iz).unwrap();
            outbuf.set_len(retsize as usize);
            let _res = iz.write_all(outbuf.as_slice()).unwrap();
        }
    }

    fn decompress(iz: &str, ppm: &str) {
        // println!("decompress {} to {}", iz, ppm);

        // input image
        let mut iz = File::open(iz).unwrap();
        let mut buffer = Vec::new();
        iz.read_to_end(&mut buffer).unwrap();

        let p_buf = buffer.as_mut_ptr();

        let x: *mut u8 = &mut 0;
        // output image
        let mut img = imagezero_sys::IZ_Image {
            m_width: 0,
            m_height: 0,
            m_data: x,
            m_spl: 0,
        };

        unsafe {
            imagezero_sys::IZ_initDecodeTable();

            imagezero_sys::IZ_decodeImageSize(&mut img, p_buf);

            let datasize = img.m_width * img.m_height * 3;
            let mut outbuf: Vec<u8> = Vec::with_capacity(datasize as usize);
            img.m_data = outbuf.as_mut_ptr();
            imagezero_sys::IZ_decodeImage(&mut img, p_buf);
            outbuf.set_len(datasize as usize);

            let mut ppm = File::create(ppm).unwrap();
            // Write PPM header
            ppm.write(b"P6\n").unwrap();
            ppm.write(img.m_width.to_string().as_bytes()).unwrap();
            ppm.write(b" ").unwrap();
            ppm.write(img.m_height.to_string().as_bytes()).unwrap();
            ppm.write(b"\n").unwrap();
            ppm.write(b"255\n").unwrap();

            ppm.write_all(outbuf.as_slice()).unwrap();
        }
    }
}