#[inline]
pub fn decode_rle_to_indexed(data: &[u8], target: &mut [u8]) -> usize {
let mut idx = 0;
let mut pos = 0;
let len = data.len();
let target_len = target.len();
while pos < len && idx < target_len {
let byte1 = data[pos];
pos += 1;
if byte1 != 0 {
target[idx] = byte1;
idx += 1;
continue;
}
if pos >= len {
break;
}
let byte2 = data[pos];
pos += 1;
if byte2 == 0 {
continue;
}
let (count, value) = if byte2 & 0xC0 == 0xC0 {
let high = (byte2 & 0x3F) as usize;
let low = data.get(pos).copied().unwrap_or(0) as usize;
pos += 1;
let color = data.get(pos).copied().unwrap_or(0);
pos += 1;
((high << 8) | low, color)
} else if byte2 & 0x80 != 0 {
let count = (byte2 & 0x3F) as usize;
let color = data.get(pos).copied().unwrap_or(0);
pos += 1;
(count, color)
} else if byte2 & 0x40 != 0 {
let high = (byte2 & 0x3F) as usize;
let low = data.get(pos).copied().unwrap_or(0) as usize;
pos += 1;
((high << 8) | low, 0)
} else {
((byte2 & 0x3F) as usize, 0)
};
let end = (idx + count).min(target_len);
if count > 8 {
target[idx..end].fill(value);
} else {
while idx < end {
target[idx] = value;
idx += 1;
}
}
idx = end;
}
idx
}
#[inline]
pub fn decode_rle_to_rgba(data: &[u8], palette: &[u32], target: &mut [u32]) -> usize {
let mut idx = 0;
let mut pos = 0;
let len = data.len();
let target_len = target.len();
let palette_len = palette.len();
let transparent = if palette_len > 0 { palette[0] } else { 0 };
while pos < len && idx < target_len {
let byte1 = data[pos];
pos += 1;
if byte1 != 0 {
let color = if (byte1 as usize) < palette_len {
palette[byte1 as usize]
} else {
0
};
target[idx] = color;
idx += 1;
continue;
}
if pos >= len {
break;
}
let byte2 = data[pos];
pos += 1;
if byte2 == 0 {
continue;
}
let (count, color) = if byte2 & 0xC0 == 0xC0 {
let high = (byte2 & 0x3F) as usize;
let low = data.get(pos).copied().unwrap_or(0) as usize;
pos += 1;
let color_idx = data.get(pos).copied().unwrap_or(0) as usize;
pos += 1;
let color = if color_idx < palette_len {
palette[color_idx]
} else {
0
};
((high << 8) | low, color)
} else if byte2 & 0x80 != 0 {
let count = (byte2 & 0x3F) as usize;
let color_idx = data.get(pos).copied().unwrap_or(0) as usize;
pos += 1;
let color = if color_idx < palette_len {
palette[color_idx]
} else {
0
};
(count, color)
} else if byte2 & 0x40 != 0 {
let high = (byte2 & 0x3F) as usize;
let low = data.get(pos).copied().unwrap_or(0) as usize;
pos += 1;
((high << 8) | low, transparent)
} else {
((byte2 & 0x3F) as usize, transparent)
};
let end = (idx + count).min(target_len);
if count > 8 {
target[idx..end].fill(color);
} else {
while idx < end {
target[idx] = color;
idx += 1;
}
}
idx = end;
}
idx
}
#[inline]
pub fn apply_palette(indexed: &[u8], palette: &[u32], target: &mut [u32]) {
let len = indexed.len().min(target.len());
if palette.len() >= 256 {
let chunks = len / 8;
let remainder = len % 8;
for chunk in 0..chunks {
let base = chunk * 8;
target[base] = palette[indexed[base] as usize];
target[base + 1] = palette[indexed[base + 1] as usize];
target[base + 2] = palette[indexed[base + 2] as usize];
target[base + 3] = palette[indexed[base + 3] as usize];
target[base + 4] = palette[indexed[base + 4] as usize];
target[base + 5] = palette[indexed[base + 5] as usize];
target[base + 6] = palette[indexed[base + 6] as usize];
target[base + 7] = palette[indexed[base + 7] as usize];
}
let base = chunks * 8;
for i in 0..remainder {
target[base + i] = palette[indexed[base + i] as usize];
}
} else {
let palette_len = palette.len();
for i in 0..len {
let idx = indexed[i] as usize;
target[i] = if idx < palette_len { palette[idx] } else { 0 };
}
}
}
#[inline]
pub fn apply_palette_rgba_bytes(indexed: &[u8], palette: &[u32], target: &mut [u8]) {
let len = indexed.len().min(target.len() / 4);
if palette.len() >= 256 {
for (pixel_index, &palette_index) in indexed.iter().take(len).enumerate() {
let start = pixel_index * 4;
target[start..start + 4]
.copy_from_slice(&palette[palette_index as usize].to_le_bytes());
}
} else {
let palette_len = palette.len();
for (pixel_index, &palette_index) in indexed.iter().take(len).enumerate() {
let start = pixel_index * 4;
let rgba = if (palette_index as usize) < palette_len {
palette[palette_index as usize]
} else {
0
};
target[start..start + 4].copy_from_slice(&rgba.to_le_bytes());
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_decode_literal() {
let data = [1, 2, 3, 4, 5];
let mut target = vec![0u8; 10];
let count = decode_rle_to_indexed(&data, &mut target);
assert_eq!(count, 5);
assert_eq!(&target[..5], &[1, 2, 3, 4, 5]);
}
#[test]
fn test_decode_short_run_transparent() {
let data = [0x00, 0x05];
let mut target = vec![0xFFu8; 10];
let count = decode_rle_to_indexed(&data, &mut target);
assert_eq!(count, 5);
assert_eq!(&target[..5], &[0, 0, 0, 0, 0]);
}
#[test]
fn test_decode_short_run_color() {
let data = [0x00, 0x85, 0x07];
let mut target = vec![0u8; 10];
let count = decode_rle_to_indexed(&data, &mut target);
assert_eq!(count, 5);
assert_eq!(&target[..5], &[7, 7, 7, 7, 7]);
}
#[test]
fn test_decode_end_of_line() {
let data = [0x01, 0x00, 0x00, 0x02];
let mut target = vec![0u8; 10];
let count = decode_rle_to_indexed(&data, &mut target);
assert_eq!(count, 2);
assert_eq!(&target[..2], &[1, 2]);
}
}