lerc-reader 0.5.0

Pure-Rust decoder for the LERC raster compression format
Documentation
#![allow(dead_code)]

use lerc_core::fletcher32;

pub struct HeaderV2 {
    pub width: u32,
    pub height: u32,
    pub valid_pixel_count: u32,
    pub image_type: i32,
    pub max_z_error: f64,
    pub z_min: f64,
    pub z_max: f64,
    pub payload_len: usize,
}

pub struct HeaderV6 {
    pub width: u32,
    pub height: u32,
    pub depth: u32,
    pub valid_pixel_count: u32,
    pub image_type: i32,
    pub max_z_error: f64,
    pub z_min: f64,
    pub z_max: f64,
    pub internal_no_data_value: f64,
    pub original_no_data_value: f64,
    pub payload_len: usize,
}

pub fn build_header_v2(header: HeaderV2) -> Vec<u8> {
    let blob_size = 58 + 4 + header.payload_len;
    let mut bytes = Vec::with_capacity(blob_size);
    bytes.extend_from_slice(b"Lerc2 ");
    bytes.extend_from_slice(&2i32.to_le_bytes());
    bytes.extend_from_slice(&header.height.to_le_bytes());
    bytes.extend_from_slice(&header.width.to_le_bytes());
    bytes.extend_from_slice(&header.valid_pixel_count.to_le_bytes());
    bytes.extend_from_slice(&8i32.to_le_bytes());
    bytes.extend_from_slice(&(blob_size as i32).to_le_bytes());
    bytes.extend_from_slice(&header.image_type.to_le_bytes());
    bytes.extend_from_slice(&header.max_z_error.to_le_bytes());
    bytes.extend_from_slice(&header.z_min.to_le_bytes());
    bytes.extend_from_slice(&header.z_max.to_le_bytes());
    bytes
}

pub fn build_header_v6(header: HeaderV6) -> Vec<u8> {
    let blob_size = 90 + 4 + header.payload_len;
    let mut bytes = Vec::with_capacity(blob_size);
    bytes.extend_from_slice(b"Lerc2 ");
    bytes.extend_from_slice(&6i32.to_le_bytes());
    bytes.extend_from_slice(&0u32.to_le_bytes());
    bytes.extend_from_slice(&header.height.to_le_bytes());
    bytes.extend_from_slice(&header.width.to_le_bytes());
    bytes.extend_from_slice(&header.depth.to_le_bytes());
    bytes.extend_from_slice(&header.valid_pixel_count.to_le_bytes());
    bytes.extend_from_slice(&8i32.to_le_bytes());
    bytes.extend_from_slice(&(blob_size as i32).to_le_bytes());
    bytes.extend_from_slice(&header.image_type.to_le_bytes());
    bytes.extend_from_slice(&0i32.to_le_bytes());
    bytes.push(1);
    bytes.push(0);
    bytes.push(0);
    bytes.push(0);
    bytes.extend_from_slice(&header.max_z_error.to_le_bytes());
    bytes.extend_from_slice(&header.z_min.to_le_bytes());
    bytes.extend_from_slice(&header.z_max.to_le_bytes());
    bytes.extend_from_slice(&header.internal_no_data_value.to_le_bytes());
    bytes.extend_from_slice(&header.original_no_data_value.to_le_bytes());
    bytes
}

pub fn finalize_lerc2_with_checksum(mut bytes: Vec<u8>) -> Vec<u8> {
    let blob_size = bytes.len() as i32;
    bytes[34..38].copy_from_slice(&blob_size.to_le_bytes());
    let checksum = fletcher32(&bytes[14..blob_size as usize]);
    bytes[10..14].copy_from_slice(&checksum.to_le_bytes());
    bytes
}

pub fn encode_mask_rle(mask: &[u8]) -> Vec<u8> {
    let bitset_len = mask.len().div_ceil(8);
    let mut bitset = vec![0u8; bitset_len];
    for (index, &value) in mask.iter().enumerate() {
        if value != 0 {
            bitset[index >> 3] |= 1 << (7 - (index & 7));
        }
    }

    let mut encoded = Vec::with_capacity(bitset_len + 4);
    encoded.extend_from_slice(&(bitset_len as i16).to_le_bytes());
    encoded.extend_from_slice(&bitset);
    encoded.extend_from_slice(&i16::MIN.to_le_bytes());
    encoded
}

pub fn pack_msb_bits(values: &[u32], bits_per_pixel: u8) -> Vec<u8> {
    let total_bits = values.len() * usize::from(bits_per_pixel);
    let mut bytes = vec![0u8; total_bits.div_ceil(8)];
    let mut bit_offset = 0usize;
    for &value in values {
        for bit in (0..bits_per_pixel).rev() {
            if ((value >> bit) & 1) != 0 {
                let byte_index = bit_offset / 8;
                let bit_index = 7 - (bit_offset % 8);
                bytes[byte_index] |= 1 << bit_index;
            }
            bit_offset += 1;
        }
    }
    bytes
}