use super::{Decoder, create_rgba_image, validate_dimensions};
use crate::error::{BinaryError, Result};
use crate::texture::formats::TextureFormat;
use crate::texture::types::Texture2D;
use image::RgbaImage;
pub struct BasicDecoder;
impl BasicDecoder {
pub fn new() -> Self {
Self
}
fn decode_rgba32(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
validate_dimensions(width, height)?;
let expected_size = (width * height * 4) as usize;
if data.len() < expected_size {
return Err(BinaryError::invalid_data(format!(
"Insufficient data for RGBA32: expected {}, got {}",
expected_size,
data.len()
)));
}
create_rgba_image(data[..expected_size].to_vec(), width, height)
}
fn decode_rgb24(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
validate_dimensions(width, height)?;
let expected_size = (width * height * 3) as usize;
if data.len() < expected_size {
return Err(BinaryError::invalid_data(format!(
"Insufficient data for RGB24: expected {}, got {}",
expected_size,
data.len()
)));
}
let mut rgba_data = Vec::with_capacity((width * height * 4) as usize);
for chunk in data[..expected_size].chunks_exact(3) {
rgba_data.push(chunk[0]); rgba_data.push(chunk[1]); rgba_data.push(chunk[2]); rgba_data.push(255); }
create_rgba_image(rgba_data, width, height)
}
fn decode_argb32(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
validate_dimensions(width, height)?;
let expected_size = (width * height * 4) as usize;
if data.len() < expected_size {
return Err(BinaryError::invalid_data(format!(
"Insufficient data for ARGB32: expected {}, got {}",
expected_size,
data.len()
)));
}
let mut rgba_data = Vec::with_capacity(expected_size);
for chunk in data[..expected_size].chunks_exact(4) {
rgba_data.push(chunk[1]); rgba_data.push(chunk[2]); rgba_data.push(chunk[3]); rgba_data.push(chunk[0]); }
create_rgba_image(rgba_data, width, height)
}
fn decode_bgra32(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
validate_dimensions(width, height)?;
let expected_size = (width * height * 4) as usize;
if data.len() < expected_size {
return Err(BinaryError::invalid_data(format!(
"Insufficient data for BGRA32: expected {}, got {}",
expected_size,
data.len()
)));
}
let mut rgba_data = Vec::with_capacity(expected_size);
for chunk in data[..expected_size].chunks_exact(4) {
rgba_data.push(chunk[2]); rgba_data.push(chunk[1]); rgba_data.push(chunk[0]); rgba_data.push(chunk[3]); }
create_rgba_image(rgba_data, width, height)
}
fn decode_alpha8(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
validate_dimensions(width, height)?;
let expected_size = (width * height) as usize;
if data.len() < expected_size {
return Err(BinaryError::invalid_data(format!(
"Insufficient data for Alpha8: expected {}, got {}",
expected_size,
data.len()
)));
}
let mut rgba_data = Vec::with_capacity((width * height * 4) as usize);
for &alpha in &data[..expected_size] {
rgba_data.push(255); rgba_data.push(255); rgba_data.push(255); rgba_data.push(alpha); }
create_rgba_image(rgba_data, width, height)
}
fn decode_rgba4444(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
validate_dimensions(width, height)?;
let expected_size = (width * height * 2) as usize; if data.len() < expected_size {
return Err(BinaryError::invalid_data(format!(
"Insufficient data for RGBA4444: expected {}, got {}",
expected_size,
data.len()
)));
}
let mut rgba_data = Vec::with_capacity((width * height * 4) as usize);
for chunk in data[..expected_size].chunks_exact(2) {
let pixel = u16::from_le_bytes([chunk[0], chunk[1]]);
let r = ((pixel >> 12) & 0xF) as u8;
let g = ((pixel >> 8) & 0xF) as u8;
let b = ((pixel >> 4) & 0xF) as u8;
let a = (pixel & 0xF) as u8;
rgba_data.push(r << 4 | r);
rgba_data.push(g << 4 | g);
rgba_data.push(b << 4 | b);
rgba_data.push(a << 4 | a);
}
create_rgba_image(rgba_data, width, height)
}
fn decode_argb4444(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
validate_dimensions(width, height)?;
let expected_size = (width * height * 2) as usize; if data.len() < expected_size {
return Err(BinaryError::invalid_data(format!(
"Insufficient data for ARGB4444: expected {}, got {}",
expected_size,
data.len()
)));
}
let mut rgba_data = Vec::with_capacity((width * height * 4) as usize);
for chunk in data[..expected_size].chunks_exact(2) {
let pixel = u16::from_le_bytes([chunk[0], chunk[1]]);
let a = ((pixel >> 12) & 0xF) as u8;
let r = ((pixel >> 8) & 0xF) as u8;
let g = ((pixel >> 4) & 0xF) as u8;
let b = (pixel & 0xF) as u8;
rgba_data.push(r << 4 | r); rgba_data.push(g << 4 | g); rgba_data.push(b << 4 | b); rgba_data.push(a << 4 | a); }
create_rgba_image(rgba_data, width, height)
}
fn decode_rgb565(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
validate_dimensions(width, height)?;
let expected_size = (width * height * 2) as usize; if data.len() < expected_size {
return Err(BinaryError::invalid_data(format!(
"Insufficient data for RGB565: expected {}, got {}",
expected_size,
data.len()
)));
}
let mut rgba_data = Vec::with_capacity((width * height * 4) as usize);
for chunk in data[..expected_size].chunks_exact(2) {
let pixel = u16::from_le_bytes([chunk[0], chunk[1]]);
let r = ((pixel >> 11) & 0x1F) as u8;
let g = ((pixel >> 5) & 0x3F) as u8;
let b = (pixel & 0x1F) as u8;
rgba_data.push((r << 3) | (r >> 2)); rgba_data.push((g << 2) | (g >> 4)); rgba_data.push((b << 3) | (b >> 2)); rgba_data.push(255); }
create_rgba_image(rgba_data, width, height)
}
}
impl Decoder for BasicDecoder {
fn decode(&self, texture: &Texture2D) -> Result<RgbaImage> {
let width = texture.width as u32;
let height = texture.height as u32;
let data = &texture.image_data;
match texture.format {
TextureFormat::RGBA32 => self.decode_rgba32(data, width, height),
TextureFormat::RGB24 => self.decode_rgb24(data, width, height),
TextureFormat::ARGB32 => self.decode_argb32(data, width, height),
TextureFormat::BGRA32 => self.decode_bgra32(data, width, height),
TextureFormat::Alpha8 => self.decode_alpha8(data, width, height),
TextureFormat::RGBA4444 => self.decode_rgba4444(data, width, height),
TextureFormat::ARGB4444 => self.decode_argb4444(data, width, height),
TextureFormat::RGB565 => self.decode_rgb565(data, width, height),
_ => Err(BinaryError::unsupported(format!(
"Format {:?} is not a basic format",
texture.format
))),
}
}
fn can_decode(&self, format: TextureFormat) -> bool {
format.is_basic_format()
}
fn supported_formats(&self) -> Vec<TextureFormat> {
vec![
TextureFormat::Alpha8,
TextureFormat::RGB24,
TextureFormat::RGBA32,
TextureFormat::ARGB32,
TextureFormat::BGRA32,
TextureFormat::RGBA4444,
TextureFormat::ARGB4444,
TextureFormat::RGB565,
]
}
}
impl Default for BasicDecoder {
fn default() -> Self {
Self::new()
}
}