Skip to main content

mlv/
lj92.rs

1/*
2lj92.rs
3(c) Andrew Baldwin 2014
4(c) Ilia Sibiryakov 2024 (translated to Rust)
5
6Permission is hereby granted, free of charge, to any person obtaining a copy of
7this software and associated documentation files (the "Software"), to deal in
8the Software without restriction, including without limitation the rights to
9use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10of the Software, and to permit persons to whom the Software is furnished to do
11so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25use core::ops::{Index, IndexMut};
26
27#[derive(Debug,Copy,Clone,PartialEq,Eq)]
28pub enum Lj92Error {
29    Corrupt = -1,
30    NoMemory = -2,
31    BadHandle = -3,
32    TooWide = -4,
33    Encoder = -5,
34    EndOfImage = -6, /* ilia3101 */
35}
36
37#[derive(Debug)]
38pub struct Lj92<'a, HuffLut> {
39    data: &'a [u8],
40
41    scanstart: usize,
42    ix: usize, /* Position in data */
43    x: u32, // Width
44    y: u32, // Height
45    bitdepth: u8, // Bit depth
46    components: u8,  // Components(Nf)
47    // sssshist: [u32; 16],
48
49    // Huffman table - only one supported, and probably needed
50    hufflut: HuffLut,
51    huffbits: u32,
52
53    // Parse state
54    cnt: usize,
55    bits: i32, /* Current bits */
56}
57
58#[cfg(feature = "std")]
59impl<'a> Lj92<'a, Vec<u16>> {
60    #[inline]
61    pub fn open_vec(data: &'a [u8]) -> Result<Self, Lj92Error> {
62        let mut lj = Self::with_custom_lut(vec![0u16; 65536]);
63        lj.data = data;
64        let ret = lj.find_soi();
65        ret.map(|_| lj)
66    }
67}
68
69impl<'a> Lj92<'a, [u16; 16384]> {
70    #[inline]
71    pub fn open(data: &'a [u8]) -> Result<Self, Lj92Error> {
72        let mut lj = Self::with_custom_lut([0u16; 16384]);
73        lj.data = data;
74        let ret = lj.find_soi();
75        ret.map(|_| lj)
76    }
77}
78
79impl<'a, HuffLut> Lj92<'a, HuffLut>
80where
81    HuffLut: Index<usize, Output=u16> + IndexMut<usize, Output=u16>
82{
83    pub fn with_custom_lut(hufflut: HuffLut) -> Self {
84        Self {
85            data: Default::default(), scanstart: 0, ix: 0, x: 0, y: 0, bitdepth: 0,
86            components: 0, hufflut, huffbits: 0, cnt: 0, bits: 0,
87        }
88    }
89
90    /* Getters */
91    pub fn width(&self) -> u32 { self.x }
92    pub fn height(&self) -> u32 { self.y }
93    pub fn bitdepth(&self) -> u8 { self.bitdepth }
94    pub fn components(&self) -> u8 { self.components }
95
96    /* This does what the 'BEH' macro did in the original -
97     * getting a Big Endian Half from the input data, with given offset */
98    #[inline(always)]
99    fn get_be_u16(&self, off: usize) -> u16 {
100        u16::from_be_bytes([self.data[self.ix+off], self.data[self.ix+off+1]])
101    }
102
103    /* I have merged lj92_decode and parse_scan into one function,
104     * skipping the saving of parameters into the struct */
105    #[inline]
106    pub fn decode(
107        &mut self,
108        out: &'a mut [u16],
109        skip_length: usize,
110        linearize: Option<&[u16]>
111    ) -> Result<(), Lj92Error> {
112        // self.sssshist = [0; 16];
113        self.ix = self.scanstart;
114        let compcount = self.data[self.ix+2];
115        let pred = self.data[self.ix+3+2*compcount as usize];
116        if pred > 7 { return Err(Lj92Error::Corrupt); }
117        // if (pred==6) { return parsePred6(self); } /* Fast path, TODO: translate it to rust as well? */
118        self.ix += self.get_be_u16(0) as usize;
119        self.cnt = 0;
120        self.bits = 0;
121
122        /* To convert to u16 while overflowing */
123        let to_u16 = |x: i32| (x & 0xffff) as u16;
124
125        // First pixel predicted from base value
126        let mut diff;
127        let mut px;
128        let mut left = 0i32;
129        let row_out_len = (self.x * self.components as u32) as usize + skip_length;
130
131        for row in 0..(self.y as usize) {
132            let row_start = row * row_out_len;
133            let prev_row_start = row.saturating_sub(1) * row_out_len;
134            let lastrow = |data: &mut [u16], i: usize| -> u16 { data[prev_row_start + i] };
135            let thisrow = |data: &mut [u16], i: usize| -> u16 { data[row_start + i] };
136            for col in 0..(self.x as usize) {
137                let colx = col * self.components as usize;
138                for c in 0..(self.components as usize) {
139                    px = match (row, col) {
140                        (0, 0) => 1 << (self.bitdepth - 1),
141                        (0, _) => thisrow(out, colx - self.components as usize + c),
142                        (_, 0) => lastrow(out, c),
143                        (_, _) => {
144                            let prev_colx = colx - self.components as usize;
145                            match pred {
146                                0 => 0,
147                                1 => thisrow(out, prev_colx + c),
148                                2 => lastrow(out, colx + c),
149                                3 => lastrow(out, prev_colx + c),
150                                4 => to_u16(left + lastrow(out, colx + c) as i32 - lastrow(out, prev_colx + c) as i32),
151                                5 => to_u16(left + ((lastrow(out, colx + c) as i32 - lastrow(out, prev_colx + c) as i32) >> 1)),
152                                6 => to_u16(lastrow(out, colx + c) as i32 + ((left - lastrow(out, prev_colx + c) as i32) >> 1)),
153                                7 => to_u16((left + lastrow(out, colx + c) as i32) >> 1),
154                                _ => unreachable!("Invalid prediction mode")
155                            }
156                        }
157                    };
158
159                    diff = self.next_diff();
160                    left = to_u16((px as i32) + diff) as i32;
161
162                    let linear = if let Some(linearize) = linearize {
163                            /* ilia3101: Is this bounds checking really necessary? */
164                            if left > linearize.len() as i32 { return Err(Lj92Error::Corrupt); }
165                            linearize[left as usize]
166                        } else { left as u16 };
167
168                    /* Weird- adding this checked version made it a tiny bit faster than normal indexing??? */
169                    if let Some(out) = out.get_mut(row_start + colx + c) {
170                        *out = linear;
171                    } else { return Ok(()); } /* Todo: return ok... or error? */
172                } // c
173            } // col
174        } // row
175
176        Ok(())
177    }
178
179    #[inline]
180    fn find_soi(&mut self) -> Result<(),Lj92Error> {
181        if self.find() == Ok(0xd8) {
182            self.parse_image()
183        } else { Err(Lj92Error::Corrupt) }
184    }
185
186    #[inline]
187    fn find(&mut self) -> Result<u8,Lj92Error> {
188        while self.data[self.ix] != 0xFF && self.ix < (self.data.len()-1) { self.ix += 1; }
189        self.ix += 2;
190        if self.ix >= self.data.len() { return Err(Lj92Error::EndOfImage); }
191        Ok(self.data[self.ix-1])
192    }
193
194    #[inline]
195    fn parse_image(&mut self) -> Result<(),Lj92Error> {
196        let mut ret = Ok(());
197        while let Ok(next_marker) = self.find() {
198            match next_marker {
199                0xC4 => ret = self.parse_huff(),
200                0xC3 => ret = self.parse_sof3(),
201                0xFE => ret = self.parse_block(),
202                0xD9 => {break},
203                0xDA => {
204                    self.scanstart = self.ix;
205                    ret = Ok(());
206                    break;
207                },
208                _ => ret = self.parse_block(),
209            }
210
211            if ret != Ok(()) {break;}
212        }
213        return ret;
214    }
215
216    #[inline]
217    fn parse_block(&mut self) -> Result<(),Lj92Error> {
218        self.ix += self.get_be_u16(0) as usize;
219        if self.ix >= self.data.len() { return Err(Lj92Error::Corrupt); }
220        return Ok(());
221    }
222
223    #[inline]
224    fn parse_sof3(&mut self) -> Result<(),Lj92Error> {
225        if (self.ix + 6) >= self.data.len() { return Err(Lj92Error::Corrupt); }
226        self.y = self.get_be_u16(3) as u32;
227        self.x = self.get_be_u16(5) as u32;
228        self.bitdepth = self.data[self.ix+2];
229        self.components = self.data[self.ix+7];
230        self.ix += self.get_be_u16(0) as usize;
231        Ok(())
232    }
233
234    #[inline]
235    fn parse_huff(&mut self) -> Result<(),Lj92Error> {
236        let mut ret = Err(Lj92Error::Corrupt);
237        let huffhead = &self.data[self.ix..]; // xstruct.unpack('>HB16B',self.data[self.ix:self.ix+19])
238        let bits = &huffhead[2..];
239        /* TODO: why is this weird mutation of the input data here (commenting it out didnt' break anything) */
240        // bits[0] = 0; // Because table starts from 1
241        let hufflen = u16::from_be_bytes([huffhead[0], huffhead[1]]);
242        if (self.ix + hufflen as usize) >= self.data.len() { return ret; }
243
244        /* Calculate huffman direct lut */
245        // How many bits in the table - find highest entry
246        let huffvals = &self.data[(self.ix+19)..];
247        let mut maxbits = 16;
248        while maxbits > 0 {
249            if bits[maxbits] != 0 { break; }
250            maxbits -= 1;
251        }
252        self.huffbits = maxbits as u32;
253        /* Now fill the lut */
254        // self.hufflut = vec![0u16; 1 << maxbits];
255        let mut i = 0;
256        let mut hv = 0;
257        let mut rv = 0;
258        let mut vl = 0; // i
259        let mut hcode;
260        let mut bitsused = 1;
261
262        while i < (1 << maxbits) {
263            if bitsused > maxbits {
264                break; // Done. Should never get here!
265            }
266            if vl >= bits[bitsused] {
267                bitsused += 1;
268                vl = 0;
269                continue;
270            }
271            if rv == 1 << (maxbits-bitsused) {
272                rv = 0;
273                vl += 1;
274                hv += 1;
275                continue;
276            }
277            hcode = huffvals[hv];
278            self.hufflut[i] = ((hcode as u16) << 8) | bitsused as u16;
279            i += 1;
280            rv += 1;
281        }
282        ret = Ok(());
283        return ret;
284    }
285
286    #[inline]
287    fn next_diff(&mut self) -> i32 {
288        let mut bits = self.bits;
289        let mut cnt = self.cnt;
290        let huffbits = self.huffbits;
291        let mut ix = self.ix;
292        while cnt < huffbits as usize {
293            /* ilia3101: I have modified this line to be more endianness independent */
294            let one = self.data[ix] as i32;
295            let two = self.data[ix+1] as i32;
296            bits = (bits << 16) | (one << 8) | two;
297            cnt += 16;
298            ix += 2;
299            if one == 0xFF {
300                bits >>= 8;
301                cnt -= 8;
302            } else if two == 0xFF { ix += 1; };
303        }
304        let index = bits >> (cnt - huffbits as usize);
305        let ssssused: u16 = self.hufflut[index as usize];
306        let usedbits = ssssused & 0xFF;
307        let t = ssssused >> 8;
308        // self.sssshist[t as usize] += 1;
309        cnt -= usedbits as usize;
310        let mut keepbitsmask = (1 << cnt ) - 1;
311        bits &= keepbitsmask;
312        let mut diff;
313        if t == 16 {
314            diff = 1 << 15;
315        } else {
316            while cnt < t as usize {
317                /* ilia3101: I have modified this line to be more endianness independent */
318                let one = self.data[ix] as i32;
319                let two = self.data[ix+1] as i32;
320                bits = (bits << 16) | (one << 8) | two;
321                cnt += 16;
322                ix += 2;
323                /* Skip the 0 byte after each FF byte */
324                if one == 0xFF {
325                    bits >>= 8;
326                    cnt -= 8;
327                } else if two == 0xFF { ix += 1; }
328            }
329            cnt -= t as usize;
330            diff = bits >> cnt;
331            let mut vt = 1 << (t - 1);
332            if diff < vt {
333                vt = (-1 << t) + 1;
334                diff += vt;
335            }
336        }
337        keepbitsmask = (1 << cnt)-1;
338        self.bits = bits & keepbitsmask;
339        self.cnt = cnt;
340        self.ix = ix;
341
342        return diff;
343    }
344}