use crate::common::error::{Error, Result};
pub fn unpack_bits(compressed: &[u8], expected_size: usize) -> Result<Vec<u8>> {
let mut output = Vec::with_capacity(expected_size);
let mut input_pos = 0;
let mut bytes_done = 0;
while bytes_done < expected_size && input_pos < compressed.len() {
let code = compressed[input_pos] as i8;
input_pos += 1;
if code == -128 {
continue;
} else if code < 0 {
let run_length = (1i32 - code as i32) as usize;
if input_pos >= compressed.len() {
return Err(Error::ParseError("Invalid PackBits data: unexpected end of input".into()));
}
let byte = compressed[input_pos];
input_pos += 1;
if bytes_done + run_length > expected_size {
return Err(Error::ParseError("PackBits decompression exceeded expected size".into()));
}
output.extend(std::iter::repeat_n(byte, run_length));
bytes_done += run_length;
} else {
let literal_count = (code as usize) + 1;
if input_pos + literal_count > compressed.len() {
return Err(Error::ParseError("Invalid PackBits data: not enough literal bytes".into()));
}
if bytes_done + literal_count > expected_size {
return Err(Error::ParseError("PackBits decompression exceeded expected size".into()));
}
output.extend_from_slice(&compressed[input_pos..input_pos + literal_count]);
input_pos += literal_count;
bytes_done += literal_count;
}
}
if bytes_done != expected_size {
return Err(Error::ParseError(format!(
"PackBits decompression size mismatch: expected {}, got {}",
expected_size, bytes_done
)));
}
Ok(output)
}
#[inline(always)]
pub fn get_bitmap_pixel(bitmap: &[u8], bounds: &super::types::PictRect, x: i32, y: i32) -> u32 {
let width = bounds.right - bounds.left;
let height = bounds.bottom - bounds.top;
if x < 0 || y < 0 || x >= width as i32 || y >= height as i32 {
return 0xFFFFFFFF; }
let stride = width as i32;
let bit_offset = 7 - (x % 8);
let byte_pos = (y * stride / 8) + (x / 8);
if byte_pos >= bitmap.len() as i32 {
return 0xFFFFFFFF; }
let byte = bitmap[byte_pos as usize];
let bit_set = (byte & (1 << bit_offset)) != 0;
if bit_set {
0xFF000000 } else {
0xFFFFFFFF }
}
#[inline(always)]
pub fn stretch_coordinates(
dst_rect: &super::types::PictRect,
src_rect: &super::types::PictRect,
dst_x: i32,
dst_y: i32,
src_x: &mut i32,
src_y: &mut i32,
) {
let dst_width = dst_rect.right - dst_rect.left;
let dst_height = dst_rect.bottom - dst_rect.top;
let src_width = src_rect.right - src_rect.left;
let src_height = src_rect.bottom - src_rect.top;
if dst_width == 0 || dst_height == 0 || src_width == 0 || src_height == 0 {
*src_x = 0;
*src_y = 0;
return;
}
let x_rel = dst_x - dst_rect.left as i32;
let y_rel = dst_y - dst_rect.top as i32;
let x_ratio = src_width as f64 / dst_width as f64;
let y_ratio = src_height as f64 / dst_height as f64;
let x_scaled = x_rel as f64 * x_ratio;
let y_scaled = y_rel as f64 * y_ratio;
*src_x = src_rect.left as i32 + x_scaled as i32;
*src_y = src_rect.top as i32 + y_scaled as i32;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_unpack_bits_literal() {
let compressed = vec![2, 0xAA, 0xBB, 0xCC];
let result = unpack_bits(&compressed, 3).unwrap();
assert_eq!(result, vec![0xAA, 0xBB, 0xCC]);
}
#[test]
fn test_unpack_bits_run() {
let compressed = vec![0xFE, 0xDD]; let result = unpack_bits(&compressed, 3).unwrap();
assert_eq!(result, vec![0xDD, 0xDD, 0xDD]);
}
#[test]
fn test_unpack_bits_noop() {
let compressed = vec![0x80, 1, 0xEE]; let result = unpack_bits(&compressed, 1).unwrap();
assert_eq!(result, vec![0xEE]);
}
#[test]
fn test_unpack_bits_mixed() {
let compressed = vec![1, 0x11, 0x22, 0xFD, 0x33]; let result = unpack_bits(&compressed, 5).unwrap();
assert_eq!(result, vec![0x11, 0x22, 0x33, 0x33, 0x33]);
}
#[test]
fn test_unpack_bits_error() {
let compressed = vec![2, 0xAA]; assert!(unpack_bits(&compressed, 3).is_err());
}
}