rawloader/decoders/ljpeg/
huffman.rs

1use std::fmt;
2use crate::decoders::basics::*;
3
4const DECODE_CACHE_BITS: u32 = 13;
5
6pub struct HuffTable {
7  // These two fields directly represent the contents of a JPEG DHT marker
8  pub bits: [u32;17],
9  pub huffval: [u32;256],
10
11  // Represent the weird shifts that are needed for some NEF files
12  pub shiftval: [u32;256],
13
14  // Enable the workaround for 16 bit decodes in DNG that need to consume those
15  // bits instead of the value being implied
16  pub dng_bug: bool,
17
18  // In CRW we only use the len code so the cache is not needed
19  pub disable_cache: bool,
20
21  // The remaining fields are computed from the above to allow more
22  // efficient coding and decoding and thus private
23
24  // The max number of bits in a huffman code and the table that converts those
25  // bits into how many bits to consume and the decoded length and shift
26  nbits: u32,
27  hufftable: Vec<(u8,u8,u8)>,
28
29  // A pregenerated table that goes straight to decoding a diff without first
30  // finding a length, fetching bits, and sign extending them. The table is
31  // sized by DECODE_CACHE_BITS and can have 99%+ hit rate with 13 bits
32  decodecache: [Option<(u8,i16)>; 1<< DECODE_CACHE_BITS],
33
34  initialized: bool,
35}
36
37struct MockPump {
38  bits: u64,
39  nbits: u32,
40}
41
42impl MockPump {
43  pub fn empty() -> Self {
44    MockPump {
45      bits: 0,
46      nbits: 0,
47    }
48  }
49
50  pub fn set(&mut self, bits: u32, nbits: u32) {
51    self.bits = (bits as u64) << 32;
52    self.nbits = nbits + 32;
53  }
54
55  pub fn validbits(&self) -> i32 {
56    self.nbits as i32 - 32
57  }
58}
59
60impl BitPump for MockPump {
61  fn peek_bits(&mut self, num: u32) -> u32 {
62    (self.bits >> (self.nbits-num)) as u32
63  }
64
65  fn consume_bits(&mut self, num: u32) {
66    self.nbits -= num;
67    self.bits &= (1 << self.nbits) - 1;
68  }
69}
70
71impl HuffTable {
72  pub fn empty() -> HuffTable {
73    HuffTable {
74      bits: [0;17],
75      huffval: [0;256],
76      shiftval: [0;256],
77      dng_bug: false,
78      disable_cache: false,
79
80      nbits: 0,
81      hufftable: Vec::new(),
82      decodecache: [None; 1 << DECODE_CACHE_BITS],
83      initialized: false,
84    }
85  }
86
87  pub fn new(bits: [u32;17], huffval: [u32;256], dng_bug: bool) -> Result<HuffTable,String> {
88    let mut tbl = HuffTable {
89      bits: bits,
90      huffval: huffval,
91      shiftval: [0;256],
92      dng_bug: dng_bug,
93      disable_cache: false,
94
95      nbits: 0,
96      hufftable: Vec::new(),
97      decodecache: [None; 1 << DECODE_CACHE_BITS],
98      initialized: false,
99    };
100    tbl.initialize()?;
101    Ok(tbl)
102  }
103
104  pub fn initialize(&mut self) -> Result<(), String> {
105    // Find out the max code length and allocate a table with that size
106    self.nbits = 16;
107    for i in 0..16 {
108      if self.bits[16-i] != 0 {
109        break;
110      }
111      self.nbits -= 1;
112    }
113    self.hufftable = vec![(0,0,0); 1 << self.nbits];
114
115    // Fill in the table itself
116    let mut h = 0;
117    let mut pos = 0;
118    for len in 0..self.nbits {
119      for _ in 0..self.bits[len as usize + 1] {
120        for _ in 0..(1 << (self.nbits-len-1)) {
121          self.hufftable[h] = (len as u8 + 1, self.huffval[pos] as u8, self.shiftval[pos] as u8);
122          h += 1;
123        }
124        pos += 1;
125      }
126    }
127
128    // Create the decode cache by running the slow code over all the possible
129    // values DECODE_CACHE_BITS wide
130    if !self.disable_cache {
131      let mut pump = MockPump::empty();
132      let mut i = 0;
133      loop {
134        pump.set(i, DECODE_CACHE_BITS);
135        let (bits, decode) = self.huff_decode_slow(&mut pump);
136        if pump.validbits() >= 0 {
137          self.decodecache[i as usize] = Some((bits, decode as i16));
138        }
139        i += 1;
140        if i >= 1 << DECODE_CACHE_BITS {
141          break;
142        }
143      }
144    }
145
146    self.initialized = true;
147    Ok(())
148  }
149
150  #[inline(always)]
151  pub fn huff_decode(&self, pump: &mut dyn BitPump) -> Result<i32,String> {
152    let code = pump.peek_bits(DECODE_CACHE_BITS) as usize;
153    if let Some((bits,decode)) = self.decodecache[code] {
154      pump.consume_bits(bits as u32);
155      Ok(decode as i32)
156    } else {
157      let decode = self.huff_decode_slow(pump);
158      Ok(decode.1)
159    }
160  }
161
162  #[inline(always)]
163  pub fn huff_decode_slow(&self, pump: &mut dyn BitPump) -> (u8,i32) {
164    let len = self.huff_len(pump);
165    (len.0+len.1, self.huff_diff(pump, len))
166  }
167
168  #[inline(always)]
169  pub fn huff_len(&self, pump: &mut dyn BitPump) -> (u8,u8,u8) {
170    let code = pump.peek_bits(self.nbits) as usize;
171    let (bits, len, shift) = self.hufftable[code];
172    pump.consume_bits(bits as u32);
173    (bits, len, shift)
174  }
175
176  #[inline(always)]
177  pub fn huff_get_bits(&self, pump: &mut dyn BitPump) -> u32 {
178    let code = pump.peek_bits(self.nbits) as usize;
179    let (bits, len, _) = self.hufftable[code];
180    pump.consume_bits(bits as u32);
181    len as u32
182  }
183
184  #[inline(always)]
185  pub fn huff_diff(&self, pump: &mut dyn BitPump, input: (u8,u8,u8)) -> i32 {
186    let (_, len, shift) = input;
187
188    match len {
189      0 => 0,
190      16 => {
191        if self.dng_bug {
192          pump.get_bits(16); // consume can fail because we haven't peeked yet
193        }
194        -32768
195      },
196      len => {
197        // decode the difference and extend sign bit
198        let fulllen: i32 = len as i32 + shift as i32;
199        let shift: i32 = shift as i32;
200        let bits = pump.get_bits(len as u32) as i32;
201        let mut diff: i32 = ((bits << 1) + 1) << shift >> 1;
202        if (diff & (1 << (fulllen - 1))) == 0 {
203          diff -= (1 << fulllen) - ((shift == 0) as i32);
204        }
205        diff
206      },
207    }
208  }
209}
210
211impl fmt::Debug for HuffTable {
212  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
213    if self.initialized {
214      write!(f, "HuffTable {{ bits: {:?} huffval: {:?} }}", self.bits, &self.huffval[..])
215    } else {
216      write!(f, "HuffTable {{ uninitialized }}")
217    }
218  }
219}