use core::ops::{Index, IndexMut};
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub enum Lj92Error {
Corrupt = -1,
NoMemory = -2,
BadHandle = -3,
TooWide = -4,
Encoder = -5,
EndOfImage = -6,
}
#[derive(Debug)]
pub struct Lj92<'a, HuffLut> {
data: &'a [u8],
scanstart: usize,
ix: usize,
x: u32, y: u32, bitdepth: u8, components: u8,
hufflut: HuffLut,
huffbits: u32,
cnt: usize,
bits: i32,
}
#[cfg(feature = "std")]
impl<'a> Lj92<'a, Vec<u16>> {
#[inline]
pub fn open_vec(data: &'a [u8]) -> Result<Self, Lj92Error> {
let mut lj = Self::with_custom_lut(vec![0u16; 65536]);
lj.data = data;
let ret = lj.find_soi();
ret.map(|_| lj)
}
}
impl<'a> Lj92<'a, [u16; 16384]> {
#[inline]
pub fn open(data: &'a [u8]) -> Result<Self, Lj92Error> {
let mut lj = Self::with_custom_lut([0u16; 16384]);
lj.data = data;
let ret = lj.find_soi();
ret.map(|_| lj)
}
}
impl<'a, HuffLut> Lj92<'a, HuffLut>
where
HuffLut: Index<usize, Output=u16> + IndexMut<usize, Output=u16>
{
pub fn with_custom_lut(hufflut: HuffLut) -> Self {
Self {
data: Default::default(), scanstart: 0, ix: 0, x: 0, y: 0, bitdepth: 0,
components: 0, hufflut, huffbits: 0, cnt: 0, bits: 0,
}
}
pub fn width(&self) -> u32 { self.x }
pub fn height(&self) -> u32 { self.y }
pub fn bitdepth(&self) -> u8 { self.bitdepth }
pub fn components(&self) -> u8 { self.components }
#[inline(always)]
fn get_be_u16(&self, off: usize) -> u16 {
u16::from_be_bytes([self.data[self.ix+off], self.data[self.ix+off+1]])
}
#[inline]
pub fn decode(
&mut self,
out: &'a mut [u16],
skip_length: usize,
linearize: Option<&[u16]>
) -> Result<(), Lj92Error> {
self.ix = self.scanstart;
let compcount = self.data[self.ix+2];
let pred = self.data[self.ix+3+2*compcount as usize];
if pred > 7 { return Err(Lj92Error::Corrupt); }
self.ix += self.get_be_u16(0) as usize;
self.cnt = 0;
self.bits = 0;
let to_u16 = |x: i32| (x & 0xffff) as u16;
let mut diff;
let mut px;
let mut left = 0i32;
let row_out_len = (self.x * self.components as u32) as usize + skip_length;
for row in 0..(self.y as usize) {
let row_start = row * row_out_len;
let prev_row_start = row.saturating_sub(1) * row_out_len;
let lastrow = |data: &mut [u16], i: usize| -> u16 { data[prev_row_start + i] };
let thisrow = |data: &mut [u16], i: usize| -> u16 { data[row_start + i] };
for col in 0..(self.x as usize) {
let colx = col * self.components as usize;
for c in 0..(self.components as usize) {
px = match (row, col) {
(0, 0) => 1 << (self.bitdepth - 1),
(0, _) => thisrow(out, colx - self.components as usize + c),
(_, 0) => lastrow(out, c),
(_, _) => {
let prev_colx = colx - self.components as usize;
match pred {
0 => 0,
1 => thisrow(out, prev_colx + c),
2 => lastrow(out, colx + c),
3 => lastrow(out, prev_colx + c),
4 => to_u16(left + lastrow(out, colx + c) as i32 - lastrow(out, prev_colx + c) as i32),
5 => to_u16(left + ((lastrow(out, colx + c) as i32 - lastrow(out, prev_colx + c) as i32) >> 1)),
6 => to_u16(lastrow(out, colx + c) as i32 + ((left - lastrow(out, prev_colx + c) as i32) >> 1)),
7 => to_u16((left + lastrow(out, colx + c) as i32) >> 1),
_ => unreachable!("Invalid prediction mode")
}
}
};
diff = self.next_diff();
left = to_u16((px as i32) + diff) as i32;
let linear = if let Some(linearize) = linearize {
if left > linearize.len() as i32 { return Err(Lj92Error::Corrupt); }
linearize[left as usize]
} else { left as u16 };
if let Some(out) = out.get_mut(row_start + colx + c) {
*out = linear;
} else { return Ok(()); }
} } }
Ok(())
}
#[inline]
fn find_soi(&mut self) -> Result<(),Lj92Error> {
if self.find() == Ok(0xd8) {
self.parse_image()
} else { Err(Lj92Error::Corrupt) }
}
#[inline]
fn find(&mut self) -> Result<u8,Lj92Error> {
while self.data[self.ix] != 0xFF && self.ix < (self.data.len()-1) { self.ix += 1; }
self.ix += 2;
if self.ix >= self.data.len() { return Err(Lj92Error::EndOfImage); }
Ok(self.data[self.ix-1])
}
#[inline]
fn parse_image(&mut self) -> Result<(),Lj92Error> {
let mut ret = Ok(());
while let Ok(next_marker) = self.find() {
match next_marker {
0xC4 => ret = self.parse_huff(),
0xC3 => ret = self.parse_sof3(),
0xFE => ret = self.parse_block(),
0xD9 => {break},
0xDA => {
self.scanstart = self.ix;
ret = Ok(());
break;
},
_ => ret = self.parse_block(),
}
if ret != Ok(()) {break;}
}
return ret;
}
#[inline]
fn parse_block(&mut self) -> Result<(),Lj92Error> {
self.ix += self.get_be_u16(0) as usize;
if self.ix >= self.data.len() { return Err(Lj92Error::Corrupt); }
return Ok(());
}
#[inline]
fn parse_sof3(&mut self) -> Result<(),Lj92Error> {
if (self.ix + 6) >= self.data.len() { return Err(Lj92Error::Corrupt); }
self.y = self.get_be_u16(3) as u32;
self.x = self.get_be_u16(5) as u32;
self.bitdepth = self.data[self.ix+2];
self.components = self.data[self.ix+7];
self.ix += self.get_be_u16(0) as usize;
Ok(())
}
#[inline]
fn parse_huff(&mut self) -> Result<(),Lj92Error> {
let mut ret = Err(Lj92Error::Corrupt);
let huffhead = &self.data[self.ix..]; let bits = &huffhead[2..];
let hufflen = u16::from_be_bytes([huffhead[0], huffhead[1]]);
if (self.ix + hufflen as usize) >= self.data.len() { return ret; }
let huffvals = &self.data[(self.ix+19)..];
let mut maxbits = 16;
while maxbits > 0 {
if bits[maxbits] != 0 { break; }
maxbits -= 1;
}
self.huffbits = maxbits as u32;
let mut i = 0;
let mut hv = 0;
let mut rv = 0;
let mut vl = 0; let mut hcode;
let mut bitsused = 1;
while i < (1 << maxbits) {
if bitsused > maxbits {
break; }
if vl >= bits[bitsused] {
bitsused += 1;
vl = 0;
continue;
}
if rv == 1 << (maxbits-bitsused) {
rv = 0;
vl += 1;
hv += 1;
continue;
}
hcode = huffvals[hv];
self.hufflut[i] = ((hcode as u16) << 8) | bitsused as u16;
i += 1;
rv += 1;
}
ret = Ok(());
return ret;
}
#[inline]
fn next_diff(&mut self) -> i32 {
let mut bits = self.bits;
let mut cnt = self.cnt;
let huffbits = self.huffbits;
let mut ix = self.ix;
while cnt < huffbits as usize {
let one = self.data[ix] as i32;
let two = self.data[ix+1] as i32;
bits = (bits << 16) | (one << 8) | two;
cnt += 16;
ix += 2;
if one == 0xFF {
bits >>= 8;
cnt -= 8;
} else if two == 0xFF { ix += 1; };
}
let index = bits >> (cnt - huffbits as usize);
let ssssused: u16 = self.hufflut[index as usize];
let usedbits = ssssused & 0xFF;
let t = ssssused >> 8;
cnt -= usedbits as usize;
let mut keepbitsmask = (1 << cnt ) - 1;
bits &= keepbitsmask;
let mut diff;
if t == 16 {
diff = 1 << 15;
} else {
while cnt < t as usize {
let one = self.data[ix] as i32;
let two = self.data[ix+1] as i32;
bits = (bits << 16) | (one << 8) | two;
cnt += 16;
ix += 2;
if one == 0xFF {
bits >>= 8;
cnt -= 8;
} else if two == 0xFF { ix += 1; }
}
cnt -= t as usize;
diff = bits >> cnt;
let mut vt = 1 << (t - 1);
if diff < vt {
vt = (-1 << t) + 1;
diff += vt;
}
}
keepbitsmask = (1 << cnt)-1;
self.bits = bits & keepbitsmask;
self.cnt = cnt;
self.ix = ix;
return diff;
}
}