jabcode 1.1.0

Bindings for the JAB code reference implementation
Documentation
use crate::jabcode;

mod error;

pub use error::ReadError;

const RGBA_CHANNELS: i32 = 4;

pub fn read_jabcode(image: &image::RgbaImage) -> Result<Vec<u8>, ReadError> {
    let image_buf = image.as_raw();
    let bits_per_pixel = 8 * image_buf.len() as i32 / (image.width() * image.height()) as i32;

    let layout = std::alloc::Layout::from_size_align(
        5 * std::mem::size_of::<jabcode::jab_int32>()
            + image_buf.len() * std::mem::size_of::<jabcode::jab_byte>(),
        std::cmp::max(
            std::mem::align_of::<jabcode::jab_int32>(),
            std::mem::align_of::<jabcode::jab_byte>(),
        ),
    )
    .unwrap();
    let bitmap = unsafe { std::alloc::alloc(layout) as *mut jabcode::jab_bitmap };
    unsafe {
        (*bitmap).width = image.width() as i32;
        (*bitmap).height = image.height() as i32;
        (*bitmap).bits_per_pixel = bits_per_pixel;
        (*bitmap).bits_per_channel = bits_per_pixel / RGBA_CHANNELS;
        (*bitmap).channel_count = RGBA_CHANNELS;
    }
    for (i, b) in image_buf.iter().enumerate() {
        unsafe {
            *(*bitmap).pixel.as_mut_ptr().offset(i as isize) = std::mem::transmute_copy(b);
        }
    }

    let mut decode_status: i32 = 0;

    let decoded = unsafe {
        jabcode::decodeJABCode(bitmap, jabcode::NORMAL_DECODE as i32, &mut decode_status)
    };

    unsafe {
        std::alloc::dealloc(bitmap as *mut u8, layout);
    }

    if decoded.is_null() {
        return Err(ReadError::Jab);
    };

    if decode_status == 2 {
        eprintln!("The code is only partly decoded. Some slave symbols have not been decoded and are ignored.");
    }

    let buf = unsafe {
        let data_bytes = std::mem::transmute::<
            &jabcode::__IncompleteArrayField<i8>,
            &jabcode::__IncompleteArrayField<u8>,
        >(&(*decoded).data);
        data_bytes.as_slice((*decoded).length as usize)
    };
    let mut res = vec![0; buf.len()];
    res.copy_from_slice(buf);

    unsafe {
        libc::free(decoded as *mut libc::c_void);
    }

    Ok(res)
}