use std::io::{BufRead, Seek, SeekFrom};
use crate::{
util::{read_u32, read_u64, Endian},
ImageResult, ImageSize,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PvrtcCompression {
Pvrtc2BppRgb,
Pvrtc2BppRgba,
Pvrtc4BppRgb,
Pvrtc4BppRgba,
Etc2Rgb,
Etc2Rgba,
Etc2RgbA1,
EacR11,
EacRg11,
Unknown,
}
pub fn size<R: BufRead + Seek>(reader: &mut R) -> ImageResult<ImageSize> {
reader.seek(SeekFrom::Start(0))?;
let mut magic = [0u8; 4];
reader.read_exact(&mut magic)?;
if &magic == b"PVR\x03" {
reader.seek(SeekFrom::Start(24))?;
let height = read_u32(reader, &Endian::Little)? as usize;
let width = read_u32(reader, &Endian::Little)? as usize;
Ok(ImageSize { width, height })
} else {
reader.seek(SeekFrom::Start(4))?;
let height = read_u32(reader, &Endian::Little)? as usize;
let width = read_u32(reader, &Endian::Little)? as usize;
Ok(ImageSize { width, height })
}
}
pub fn matches(header: &[u8]) -> bool {
if header.len() >= 4 {
let header_size = u32::from_le_bytes([header[0], header[1], header[2], header[3]]);
if header_size == 52 {
return true;
}
}
if header.len() >= 48 {
let pvr_magic = &header[44..48];
if pvr_magic == b"PVR!" {
return true;
}
}
if header.len() >= 4 && header.starts_with(b"PVR\x03") {
return true;
}
false
}
pub fn detect_compression<R: BufRead + Seek>(reader: &mut R) -> ImageResult<PvrtcCompression> {
reader.seek(SeekFrom::Start(0))?;
let mut magic = [0u8; 4];
reader.read_exact(&mut magic)?;
if &magic == b"PVR\x03" {
reader.seek(SeekFrom::Start(8))?;
let pixel_format = read_u64(reader, &Endian::Little)?;
let compression = match pixel_format {
0 => PvrtcCompression::Pvrtc2BppRgb, 1 => PvrtcCompression::Pvrtc2BppRgba, 2 => PvrtcCompression::Pvrtc4BppRgb, 3 => PvrtcCompression::Pvrtc4BppRgba, 22 => PvrtcCompression::Etc2Rgb, 23 => PvrtcCompression::Etc2Rgba, 24 => PvrtcCompression::Etc2RgbA1, 25 => PvrtcCompression::EacR11, 26 => PvrtcCompression::EacRg11, _ => PvrtcCompression::Unknown,
};
Ok(compression)
} else {
Ok(PvrtcCompression::Unknown)
}
}