use std::io::{BufRead, Seek, SeekFrom};
use crate::{
util::{read_u16, read_u32, Endian},
ImageResult, ImageSize,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum AtcCompression {
Rgb,
RgbaExplicit,
RgbaInterpolated,
Unknown,
}
pub fn size<R: BufRead + Seek>(reader: &mut R) -> ImageResult<ImageSize> {
let mut header = [0u8; 4];
reader.read_exact(&mut header)?;
if header == *b"DDS " {
reader.seek(SeekFrom::Start(12))?;
let height = read_u32(reader, &Endian::Little)? as usize;
let width = read_u32(reader, &Endian::Little)? as usize;
return Ok(ImageSize { width, height });
}
reader.seek(SeekFrom::Start(0))?;
let mut pkm_header = [0u8; 8];
reader.read_exact(&mut pkm_header)?;
if pkm_header.starts_with(b"PKM ")
&& (pkm_header[4..6] == [b'1', b'0'] || pkm_header[4..6] == [b'2', b'0'])
{
let data_type = u16::from_be_bytes([pkm_header[6], pkm_header[7]]);
if matches!(data_type, 0x8C92 | 0x8C93 | 0x87EE) {
reader.seek(SeekFrom::Start(8))?; let _extended_width = read_u16(reader, &Endian::Big)?;
let _extended_height = read_u16(reader, &Endian::Big)?;
let width = read_u16(reader, &Endian::Big)? as usize;
let height = read_u16(reader, &Endian::Big)? as usize;
return Ok(ImageSize { width, height });
}
}
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() >= 8
&& header.starts_with(b"PKM ")
&& (header[4..6] == [b'1', b'0'] || header[4..6] == [b'2', b'0'])
{
let data_type = u16::from_be_bytes([header[6], header[7]]);
return matches!(data_type, 0x8C92 | 0x8C93 | 0x87EE);
}
false
}
pub fn detect_compression<R: BufRead + Seek>(reader: &mut R) -> ImageResult<AtcCompression> {
let mut header = [0u8; 8];
reader.seek(SeekFrom::Start(0))?;
reader.read_exact(&mut header)?;
if header.starts_with(b"PKM ") && (header[4..6] == [b'1', b'0'] || header[4..6] == [b'2', b'0'])
{
let data_type = u16::from_be_bytes([header[6], header[7]]);
let compression = match data_type {
0x8C92 => AtcCompression::Rgb, 0x8C93 => AtcCompression::RgbaExplicit, 0x87EE => AtcCompression::RgbaInterpolated, _ => AtcCompression::Unknown,
};
return Ok(compression);
}
if header[0..4] == *b"DDS " {
return Ok(AtcCompression::Unknown); }
Ok(AtcCompression::Unknown)
}