1use crate::x3f::PrefixCode;
19use flashraw_core::bits::{BitPumpMsb, BitRead};
20use flashraw_core::{Error, Result};
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum CfaPhase {
25 Rggb,
26 Grbg,
27 Gbrg,
28 Bggr,
29}
30
31impl CfaPhase {
32 pub fn from_pattern(p: &flashraw_core::CfaPattern) -> Option<Self> {
34 use flashraw_core::CfaColor::{Blue, Green, Red};
35 if !p.is_bayer() {
36 return None;
37 }
38 Some(match (p.color_at(0, 0), p.color_at(1, 0)) {
39 (Red, Green) => CfaPhase::Rggb,
40 (Green, Red) => CfaPhase::Grbg,
41 (Green, Blue) => CfaPhase::Gbrg,
42 (Blue, Green) => CfaPhase::Bggr,
43 _ => return None,
44 })
45 }
46}
47
48const NUM_CHANNELS: usize = 4;
49const NUM_LEVELS: usize = 3;
50const NUM_SUBBANDS: usize = 1 + 3 * NUM_LEVELS;
51const RUN_BITS: u32 = 9;
52const LOG_TABLE_BITS: u32 = 12;
53const MARKER_BAND_END: i16 = 1;
54
55#[rustfmt::skip]
57const TABLE17: [(u8, u32, u16, u16); 264] = [
58 (1, 0x0, 1, 0), (2, 0x2, 1, 1), (3, 0x7, 1, 2), (5, 0x19, 1, 3), (6, 0x30, 1, 4), (6, 0x36, 1, 5),
59 (7, 0x6F, 1, 8), (7, 0x63, 1, 6), (7, 0x69, 12, 0), (7, 0x6B, 1, 7), (8, 0xD1, 20, 0), (8, 0xD4, 1, 9),
60 (8, 0xDC, 1, 10), (9, 0x189, 1, 11), (9, 0x18A, 32, 0), (9, 0x1A0, 1, 12), (9, 0x1AB, 1, 13), (10, 0x377, 1, 18),
61 (10, 0x310, 1, 14), (10, 0x316, 1, 15), (10, 0x343, 60, 0), (10, 0x354, 1, 16), (10, 0x375, 1, 17),
62 (11, 0x623, 1, 19), (11, 0x684, 1, 20), (11, 0x685, 100, 0), (11, 0x6AB, 1, 21), (11, 0x6EC, 1, 22),
63 (12, 0xDDB, 1, 29), (12, 0xC5C, 1, 24), (12, 0xC5E, 1, 25), (12, 0xC44, 1, 23), (12, 0xD55, 1, 26),
64 (12, 0xDD1, 1, 27), (12, 0xDD3, 1, 28), (13, 0x1BB5, 1, 35), (13, 0x188B, 1, 30), (13, 0x18BB, 1, 31),
65 (13, 0x18BF, 180, 0), (13, 0x1AA8, 1, 32), (13, 0x1BA0, 1, 33), (13, 0x1BA5, 320, 0), (13, 0x1BA4, 1, 34),
66 (14, 0x3115, 1, 36), (14, 0x3175, 1, 37), (14, 0x317D, 1, 38), (14, 0x3553, 1, 39), (14, 0x3768, 1, 40),
67 (15, 0x6E87, 1, 46), (15, 0x6ED3, 1, 47), (15, 0x62E8, 1, 42), (15, 0x62F8, 1, 43), (15, 0x6228, 1, 41),
68 (15, 0x6AA4, 1, 44), (15, 0x6E85, 1, 45), (16, 0xC453, 1, 48), (16, 0xC5D3, 1, 49), (16, 0xC5F3, 1, 50),
69 (16, 0xDDA4, 1, 53), (16, 0xDD08, 1, 51), (16, 0xDD0C, 1, 52), (17, 0x1BB4B, 1, 61), (17, 0x1BB4A, 1, 60),
70 (17, 0x18BA5, 1, 55), (17, 0x18BE5, 1, 56), (17, 0x1AA95, 1, 57), (17, 0x1AA97, 1, 58), (17, 0x188A4, 1, 54),
71 (17, 0x1BA13, 1, 59), (18, 0x31748, 1, 62), (18, 0x317C8, 1, 63), (18, 0x35528, 1, 64), (18, 0x3552C, 1, 65),
72 (18, 0x37424, 1, 66), (18, 0x37434, 1, 67), (18, 0x37436, 1, 68), (19, 0x62294, 1, 69), (19, 0x62E92, 1, 70),
73 (19, 0x62F92, 1, 71), (19, 0x6AA52, 1, 72), (19, 0x6AA5A, 1, 73), (19, 0x6E86A, 1, 75), (19, 0x6E86E, 1, 76),
74 (19, 0x6E84A, 1, 74), (20, 0xC452A, 1, 77), (20, 0xC5D27, 1, 78), (20, 0xC5F26, 1, 79), (20, 0xD54A6, 1, 80),
75 (20, 0xD54B6, 1, 81), (20, 0xDD096, 1, 82), (20, 0xDD0D6, 1, 83), (20, 0xDD0DE, 1, 84), (21, 0x188A56, 1, 85),
76 (21, 0x18BA4D, 1, 86), (21, 0x18BE4E, 1, 87), (21, 0x18BE4F, 1, 88), (21, 0x1AA96E, 1, 89),
77 (21, 0x1BA12E, 1, 90), (21, 0x1BA12F, 1, 91), (21, 0x1BA1AF, 1, 92), (21, 0x1BA1BF, 1, 93),
78 (22, 0x37435D, 1, 99), (22, 0x37437D, 1, 100), (22, 0x317498, 1, 94), (22, 0x35529C, 1, 95),
79 (22, 0x35529D, 1, 96), (22, 0x3552DE, 1, 97), (22, 0x3552DF, 1, 98), (23, 0x62E933, 1, 102),
80 (23, 0x62295D, 1, 101), (23, 0x6AA53D, 1, 103), (23, 0x6AA53F, 1, 105), (23, 0x6AA53E, 1, 104),
81 (23, 0x6E86B9, 1, 106), (23, 0x6E86F8, 1, 107), (24, 0xD54A79, 1, 111), (24, 0xC5D265, 1, 109),
82 (24, 0xC452B8, 1, 108), (24, 0xDD0D71, 1, 113), (24, 0xD54A78, 1, 110), (24, 0xDD0D70, 1, 112),
83 (24, 0xDD0DF2, 1, 114), (24, 0xDD0DF3, 1, 115), (25, 0x188A5F6, 1, 225), (25, 0x188A5F5, 1, 189),
84 (25, 0x188A5F4, 1, 188), (25, 0x188A5F3, 1, 203), (25, 0x188A5F2, 1, 202), (25, 0x188A5F1, 1, 197),
85 (25, 0x188A5F0, 1, 207), (25, 0x188A5EF, 1, 169), (25, 0x188A5EE, 1, 223), (25, 0x188A5ED, 1, 159),
86 (25, 0x188A5AA, 1, 235), (25, 0x188A5E3, 1, 152), (25, 0x188A5DF, 1, 192), (25, 0x188A589, 1, 179),
87 (25, 0x188A5DD, 1, 201), (25, 0x188A578, 1, 172), (25, 0x188A5E0, 1, 149), (25, 0x188A588, 1, 178),
88 (25, 0x188A5D6, 1, 120), (25, 0x188A5DB, 1, 219), (25, 0x188A5E1, 1, 150), (25, 0x188A587, 1, 127),
89 (25, 0x188A59A, 1, 211), (25, 0x188A5C4, 1, 125), (25, 0x188A5EC, 1, 158), (25, 0x188A586, 1, 247),
90 (25, 0x188A573, 1, 238), (25, 0x188A59C, 1, 163), (25, 0x188A5C8, 1, 228), (25, 0x188A5FB, 1, 183),
91 (25, 0x188A5A1, 1, 217), (25, 0x188A5EB, 1, 168), (25, 0x188A5A8, 1, 122), (25, 0x188A584, 1, 128),
92 (25, 0x188A5D2, 1, 249), (25, 0x188A599, 1, 187), (25, 0x188A598, 1, 186), (25, 0x188A583, 1, 136),
93 (25, 0x18BA4C9, 1, 181), (25, 0x188A5D0, 1, 255), (25, 0x188A594, 1, 230), (25, 0x188A582, 1, 135),
94 (25, 0x188A5CB, 1, 233), (25, 0x188A5D8, 1, 222), (25, 0x188A5E7, 1, 145), (25, 0x188A581, 1, 134),
95 (25, 0x188A5EA, 1, 167), (25, 0x188A5A9, 1, 248), (25, 0x188A5A6, 1, 209), (25, 0x188A580, 1, 243),
96 (25, 0x188A5A0, 1, 216), (25, 0x188A59D, 1, 164), (25, 0x188A5C3, 1, 140), (25, 0x188A57F, 1, 157),
97 (25, 0x188A5C0, 1, 239), (25, 0x188A5DE, 1, 191), (25, 0x188A5D4, 1, 251), (25, 0x188A57E, 1, 156),
98 (25, 0x188A5C2, 1, 139), (25, 0x188A592, 1, 242), (25, 0x188A5CD, 1, 133), (25, 0x188A57D, 1, 162),
99 (25, 0x188A5A3, 1, 213), (25, 0x188A5E8, 1, 165), (25, 0x188A5A2, 1, 212), (25, 0x188A57C, 1, 227),
100 (25, 0x188A58E, 1, 198), (25, 0x188A5B3, 1, 236), (25, 0x188A5B2, 1, 234), (25, 0x188A5B1, 1, 117),
101 (25, 0x188A5B0, 1, 215), (25, 0x188A5AF, 1, 124), (25, 0x188A5AE, 1, 123), (25, 0x188A5AD, 1, 254),
102 (25, 0x188A5AC, 1, 253), (25, 0x188A5AB, 1, 148), (25, 0x188A5DA, 1, 218), (25, 0x188A5E4, 1, 146),
103 (25, 0x188A5E5, 1, 147), (25, 0x188A5D9, 1, 224), (25, 0x188A5B5, 1, 143), (25, 0x188A5BC, 1, 184),
104 (25, 0x188A5BD, 1, 185), (25, 0x188A5E9, 1, 166), (25, 0x188A5CC, 1, 132), (25, 0x188A585, 1, 129),
105 (25, 0x188A5D3, 1, 250), (25, 0x188A5E2, 1, 151), (25, 0x188A595, 1, 119), (25, 0x188A596, 1, 193),
106 (25, 0x188A5B8, 1, 176), (25, 0x188A590, 1, 245), (25, 0x188A5C9, 1, 229), (25, 0x188A5A4, 1, 206),
107 (25, 0x188A5E6, 1, 144), (25, 0x188A5A5, 1, 208), (25, 0x188A5CE, 1, 137), (25, 0x188A5BF, 1, 241),
108 (25, 0x188A572, 1, 237), (25, 0x188A59B, 1, 190), (25, 0x188A5BE, 1, 240), (25, 0x188A5C7, 1, 131),
109 (25, 0x188A5CA, 1, 232), (25, 0x188A5D5, 1, 252), (25, 0x188A57B, 1, 171), (25, 0x188A58D, 1, 205),
110 (25, 0x188A58C, 1, 204), (25, 0x188A58B, 1, 118), (25, 0x188A58A, 1, 214), (25, 0x18BA4C8, 1, 180),
111 (25, 0x188A5C5, 1, 126), (25, 0x188A5FA, 1, 182), (25, 0x188A5BB, 1, 175), (25, 0x188A5C1, 1, 141),
112 (25, 0x188A5CF, 1, 138), (25, 0x188A5B9, 1, 177), (25, 0x188A5B6, 1, 153), (25, 0x188A597, 1, 194),
113 (25, 0x188A5FE, 1, 160), (25, 0x188A5D7, 1, 121), (25, 0x188A5BA, 1, 174), (25, 0x188A591, 1, 246),
114 (25, 0x188A5C6, 1, 130), (25, 0x188A5DC, 1, 200), (25, 0x188A57A, 1, 170), (25, 0x188A59F, 1, 221),
115 (25, 0x188A5F9, 1, 196), (25, 0x188A5B4, 1, 142), (25, 0x188A5A7, 1, 210), (25, 0x188A58F, 1, 199),
116 (25, 0x188A5FD, 1, 155), (25, 0x188A5B7, 1, 154), (25, 0x188A593, 1, 244), (25, 0x188A59E, 1, 220),
117 (25, 0x188A5F8, 1, 195), (25, 0x188A5FF, 1, 161), (25, 0x188A5FC, 1, 231), (25, 0x188A579, 1, 173),
118 (25, 0x188A5F7, 1, 226), (26, 0x3114BA2, 1, 116), (26, 0x3114BA3, 0, 1),
119];
120
121fn decompand(v: i16) -> i16 {
123 let c = v as f64;
124 let c = c + (c * c * c * 768.0) / (255.0 * 255.0 * 255.0);
125 c.clamp(i16::MIN as f64, i16::MAX as f64) as i16
126}
127
128fn code_book() -> Result<PrefixCode> {
130 let codes: Vec<(u32, u32, u32)> = TABLE17
131 .iter()
132 .map(|&(len, bits, count, value)| {
133 let v = ((decompand(value as i16) as u16 as u32) << RUN_BITS) | count as u32;
134 (bits, len as u32, v)
135 })
136 .collect();
137 PrefixCode::new(&codes)
138}
139
140fn log_table(output_bits: u32) -> Vec<u16> {
142 let n = 1usize << LOG_TABLE_BITS;
143 (0..n)
144 .map(|i| {
145 let x = i as f64 / (n as f64 - 1.0);
146 let y = (113f64.powf(x) - 1.0) / 112.0;
147 let y = (u16::MAX as f64 * y) as u32;
148 (y >> (16 - output_bits)) as u16
149 })
150 .collect()
151}
152
153struct Band {
155 width: usize,
156 height: usize,
157 stride: usize,
158 data: Vec<i16>,
159}
160
161impl Band {
162 fn new(width: usize, height: usize) -> Result<Self> {
163 let n = width.checked_mul(height).ok_or_else(|| Error::corrupt("VC-5 band size overflow"))?;
164 Ok(Band { width, height, stride: width, data: vec![0; n] })
165 }
166 #[inline(always)]
167 fn at(&self, row: usize, col: usize) -> i32 {
168 self.data[row * self.stride + col] as i32
169 }
170}
171
172#[derive(Clone, Copy)]
173enum Coded<'a> {
174 Lowpass { precision: u32, data: &'a [u8] },
175 Highpass { quant: i16, data: &'a [u8] },
176}
177
178struct Stream<'a> {
180 bands: [[[Option<Coded<'a>>; 4]; NUM_LEVELS]; NUM_CHANNELS],
181 prescale: [[u16; NUM_LEVELS]; NUM_CHANNELS],
182}
183
184fn level_dims(width: usize, height: usize) -> [(usize, usize); NUM_LEVELS + 1] {
186 let mut d = [(0, 0); NUM_LEVELS + 1];
187 let (mut w, mut h) = (width, height);
188 for e in d.iter_mut() {
189 w = w.div_ceil(2);
190 h = h.div_ceil(2);
191 *e = (w, h);
192 }
193 d
194}
195
196fn parse(data: &[u8], width: usize, height: usize) -> Result<Stream<'_>> {
197 if data.get(..4) != Some(b"VC-5") {
198 return Err(Error::corrupt("missing VC-5 signature"));
199 }
200 let mut st = Stream { bands: Default::default(), prescale: [[0; NUM_LEVELS]; NUM_CHANNELS] };
201 let dims = level_dims(width, height);
202 let mut pos = 4usize;
203 let mut channel = 0usize;
204 let mut subband: Option<usize> = None;
205 let mut precision: Option<u32> = None;
206 let mut quant: Option<i16> = None;
207 let mut complete = [false; NUM_CHANNELS];
208 while !complete.iter().all(|&c| c) {
209 let b = data.get(pos..pos + 4).ok_or_else(|| Error::corrupt("truncated VC-5 bitstream"))?;
210 pos += 4;
211 let mut tag = i16::from_be_bytes([b[0], b[1]]);
212 let val = u16::from_be_bytes([b[2], b[3]]);
213 let mut optional = tag < 0;
214 if optional {
215 tag = tag.wrapping_neg();
216 }
217 let expect = |ok: bool, what: &str| {
218 if ok { Ok(()) } else { Err(Error::corrupt(format!("VC-5: unexpected {what} {val}"))) }
219 };
220 match tag {
221 0x000c => expect(val as usize == NUM_CHANNELS, "channel count")?,
222 0x0014 => expect(val as usize == width, "image width")?,
223 0x0015 => expect(val as usize == height, "image height")?,
224 0x000e => expect(val as usize == NUM_SUBBANDS, "subband count")?,
225 0x0054 => expect(val == 4, "image format")?,
226 0x0066 => expect(val as u32 == LOG_TABLE_BITS, "bits per component")?,
227 0x006a | 0x006b => expect(val == 2, "pattern size")?,
228 0x006c => expect(val == 1, "components per sample")?,
229 0x0023 => {
230 expect((8..=16).contains(&val), "lowpass precision")?;
231 precision = Some(val as u32);
232 }
233 0x003e => {
234 expect((val as usize) < NUM_CHANNELS, "channel number")?;
235 channel = val as usize;
236 }
237 0x0030 => {
238 expect((val as usize) < NUM_SUBBANDS, "subband number")?;
239 subband = Some(val as usize);
240 }
241 0x0035 => quant = Some(val as i16),
242 0x006d => {
243 for (i, p) in st.prescale[channel].iter_mut().enumerate() {
245 *p = (val >> (14 - 2 * i as u32)) & 3;
246 }
247 }
248 _ => {
249 let t = tag as u16;
250 let mut size = 0usize;
251 if t & 0x2000 != 0 {
252 size = (((t & 0xFF) as usize) << 16) | val as usize;
253 } else if t & 0x4000 != 0 {
254 size = val as usize;
255 }
256 if t & 0x6000 == 0x6000 {
257 let len = size * 4;
258 let chunk = data
259 .get(pos..pos.saturating_add(len))
260 .ok_or_else(|| Error::corrupt("truncated VC-5 codeblock"))?;
261 pos += len;
262 let sb = subband.take().ok_or_else(|| Error::corrupt("VC-5 codeblock without subband"))?;
263 let (level, band) =
266 if sb == 0 { (NUM_LEVELS - 1, 0) } else { (NUM_LEVELS - 1 - (sb - 1) / 3, 1 + (sb - 1) % 3) };
267 let slot = &mut st.bands[channel][level][band];
268 if slot.is_some() {
269 return Err(Error::corrupt("VC-5 band specified twice"));
270 }
271 *slot = Some(if sb == 0 {
272 let p = precision.take().ok_or_else(|| Error::corrupt("VC-5 lowpass without precision"))?;
273 let (w, h) = dims[NUM_LEVELS];
274 let bytes = ((w * h) as u64 * p as u64).div_ceil(64) as usize * 8;
275 let d = chunk.get(..bytes).ok_or_else(|| Error::corrupt("truncated VC-5 lowpass band"))?;
276 Coded::Lowpass { precision: p, data: d }
277 } else {
278 let q = quant.take().ok_or_else(|| Error::corrupt("VC-5 highpass without quantisation"))?;
279 Coded::Highpass { quant: q, data: chunk }
280 });
281 let bands = &st.bands[channel];
282 complete[channel] =
283 bands[NUM_LEVELS - 1][0].is_some() && bands.iter().all(|l| l[1..].iter().all(|b| b.is_some()));
284 continue;
285 }
286 if t & 0x2000 != 0 {
287 optional = true;
289 size = 0;
290 }
291 if !optional {
292 return Err(Error::corrupt(format!("VC-5: unknown required tag 0x{t:04x}")));
293 }
294 pos = pos.saturating_add(size * 4);
295 }
296 }
297 }
298 Ok(st)
299}
300
301fn decode_lowpass(data: &[u8], precision: u32, w: usize, h: usize) -> Result<Band> {
302 let mut band = Band::new(w, h)?;
303 let mut bits = BitPumpMsb::new(data);
304 for v in band.data.iter_mut() {
305 *v = bits.get(precision) as i16;
306 }
307 Ok(band)
308}
309
310#[inline(always)]
311fn read_rlv(code: &PrefixCode, bits: &mut BitPumpMsb) -> Result<(i16, usize)> {
312 let v = code.decode(bits)?;
313 let count = (v & ((1 << RUN_BITS) - 1)) as usize;
314 let mut value = (v >> RUN_BITS) as u16 as i16;
315 if value != 0 && bits.get(1) != 0 {
316 value = -value;
317 }
318 Ok((value, count))
319}
320
321fn decode_highpass(code: &PrefixCode, data: &[u8], quant: i16, w: usize, h: usize) -> Result<Band> {
322 let mut band = Band::new(w, h)?;
323 let mut bits = BitPumpMsb::new(data);
324 let out = &mut band.data[..];
325 let mut i = 0usize;
326 while i < out.len() {
327 let (value, count) = read_rlv(code, &mut bits)?;
328 if count == 0 {
329 return Err(Error::corrupt("VC-5 end-of-band marker inside band"));
330 }
331 let value = value.checked_mul(quant).ok_or_else(|| Error::corrupt("VC-5 dequantisation overflow"))?;
332 let end =
333 i.checked_add(count).filter(|&e| e <= out.len()).ok_or_else(|| Error::corrupt("VC-5 run past band end"))?;
334 out[i..end].fill(value);
335 i = end;
336 if bits.exhausted() {
337 return Err(Error::corrupt("truncated VC-5 highpass band"));
338 }
339 }
340 let (value, count) = read_rlv(code, &mut bits)?;
341 if value != MARKER_BAND_END || count != 0 {
342 return Err(Error::corrupt("missing VC-5 end-of-band marker"));
343 }
344 Ok(band)
345}
346
347type Taps = ([i32; 4], [i32; 4], isize);
350const FIRST: Taps = ([1, 11, -4, 1], [-1, 5, 4, -1], 0);
351const MIDDLE: Taps = ([1, 1, 8, -1], [-1, -1, 8, 1], -1);
352const LAST: Taps = ([1, -1, 4, 5], [-1, 1, -4, 11], -2);
353
354#[inline(always)]
355fn taps_for(i: usize, n: usize) -> Taps {
356 if i == 0 {
357 FIRST
358 } else if i + 1 < n {
359 MIDDLE
360 } else {
361 LAST
362 }
363}
364
365#[inline(always)]
366fn tap(m: &[i32; 4], high: i32, l: [i32; 3], descale: u32) -> i32 {
367 let lows = (m[1] * l[0] + m[2] * l[1] + m[3] * l[2] + 4) >> 3;
368 ((m[0] * high + lows) << descale) >> 1
369}
370
371fn check_pair(high: &Band, low: &Band) -> Result<()> {
372 if high.width < 3 || high.height < 3 || low.width < high.width || low.height < high.height {
373 return Err(Error::corrupt("VC-5 band geometry too small"));
374 }
375 Ok(())
376}
377
378fn vertical(high: &Band, low: &Band) -> Result<Band> {
380 check_pair(high, low)?;
381 let (w, h) = (high.width, high.height);
382 let mut out = Band::new(w, 2 * h)?;
383 for row in 0..h {
384 let (even, odd, shift) = taps_for(row, h);
385 let base = (row as isize + shift) as usize;
386 let (top, bottom) = out.data[2 * row * w..(2 * row + 2) * w].split_at_mut(w);
387 for col in 0..w {
388 let l = [low.at(base, col), low.at(base + 1, col), low.at(base + 2, col)];
389 let hv = high.at(row, col);
390 top[col] = tap(&even, hv, l, 0) as i16;
391 bottom[col] = tap(&odd, hv, l, 0) as i16;
392 }
393 }
394 Ok(out)
395}
396
397fn horizontal(low: &Band, high: &Band, descale: u32, clamp: bool) -> Result<Band> {
399 check_pair(high, low)?;
400 let (w, h) = (high.width, high.height);
401 let mut out = Band::new(2 * w, h)?;
402 let fin = |v: i32| if clamp { v.clamp(0, (1 << 14) - 1) as i16 } else { v as i16 };
403 for row in 0..h {
404 let o = &mut out.data[row * 2 * w..(row + 1) * 2 * w];
405 for col in 0..w {
406 let (even, odd, shift) = taps_for(col, w);
407 let base = (col as isize + shift) as usize;
408 let l = [low.at(row, base), low.at(row, base + 1), low.at(row, base + 2)];
409 let hv = high.at(row, col);
410 o[2 * col] = fin(tap(&even, hv, l, descale));
411 o[2 * col + 1] = fin(tap(&odd, hv, l, descale));
412 }
413 }
414 Ok(out)
415}
416
417pub fn decode(
421 data: &[u8],
422 width: usize,
423 height: usize,
424 white_level: u32,
425 phase: CfaPhase,
426 out: &mut [u16],
427 parallel: bool,
428) -> Result<()> {
429 if width == 0 || height == 0 || width % 2 != 0 || height % 2 != 0 || width > 65535 || height > 65535 {
430 return Err(Error::corrupt(format!("invalid VC-5 image size {width}x{height}")));
431 }
432 if out.len() < width * height {
433 return Err(Error::InvalidArgument("VC-5: output buffer too small".into()));
434 }
435 if white_level == 0 || white_level > 0xFFFF {
436 return Err(Error::corrupt(format!("invalid VC-5 white level {white_level}")));
437 }
438 let output_bits = 32 - white_level.leading_zeros();
439 let st = parse(data, width, height)?;
440 let code = code_book()?;
441 let dims = level_dims(width, height);
442
443 let coded: Vec<(usize, Coded)> = (0..NUM_CHANNELS * NUM_LEVELS * 4)
445 .filter_map(|i| st.bands[i / (NUM_LEVELS * 4)][(i / 4) % NUM_LEVELS][i % 4].map(|c| (i, c)))
446 .collect();
447 let decoded = flashraw_core::par::map(coded, parallel, |(i, cb)| -> Result<(usize, Band)> {
448 let (w, h) = dims[(i / 4) % NUM_LEVELS + 1];
449 Ok((
450 i,
451 match cb {
452 Coded::Lowpass { precision, data } => decode_lowpass(data, precision, w, h)?,
453 Coded::Highpass { quant, data } => decode_highpass(&code, data, quant, w, h)?,
454 },
455 ))
456 });
457 let mut bands: Vec<Option<Band>> = (0..NUM_CHANNELS * NUM_LEVELS * 4).map(|_| None).collect();
458 for r in decoded {
459 let (i, b) = r?;
460 bands[i] = Some(b);
461 }
462
463 let mut per_channel: Vec<(usize, Vec<Option<Band>>)> = Vec::with_capacity(NUM_CHANNELS);
465 let mut it = bands.into_iter();
466 for c in 0..NUM_CHANNELS {
467 per_channel.push((c, it.by_ref().take(NUM_LEVELS * 4).collect()));
468 }
469 let prescale = st.prescale;
470 let finals = flashraw_core::par::map(per_channel, parallel, |(c, mut v)| -> Result<Band> {
471 let mut low = v[(NUM_LEVELS - 1) * 4].take().ok_or_else(|| Error::corrupt("missing VC-5 lowpass band"))?;
472 for level in (0..NUM_LEVELS).rev() {
473 let mut take = |b: usize| v[level * 4 + b].take().ok_or_else(|| Error::corrupt("missing VC-5 band"));
474 let (lh, hl, hh) = (take(1)?, take(2)?, take(3)?);
475 let lowpass = vertical(&hl, &low)?;
476 let highpass = vertical(&hh, &lh)?;
477 let descale = if prescale[c][level] == 2 { 2 } else { 0 };
478 low = horizontal(&lowpass, &highpass, descale, level == 0)?;
479 }
480 Ok(low)
481 });
482 let mut ch = Vec::with_capacity(NUM_CHANNELS);
483 for f in finals {
484 ch.push(f?);
485 }
486 let (hw, hh) = (width / 2, height / 2);
487 if ch.iter().any(|b| b.width < hw || b.height < hh) {
488 return Err(Error::corrupt("VC-5 reconstructed channel too small"));
489 }
490
491 let lut = log_table(output_bits);
493 let curve = |v: i32| lut[v.clamp(0, (1 << LOG_TABLE_BITS) - 1) as usize];
494 flashraw_core::par::for_each_row_chunk(&mut out[..width * height], width * 2, 16, parallel, |first, chunk| {
495 for (i, rows) in chunk.chunks_exact_mut(width * 2).enumerate() {
496 let row = first + i;
497 let (r0, r1) = rows.split_at_mut(width);
498 for col in 0..hw {
499 let gs = ch[0].at(row, col);
500 let rg = ch[1].at(row, col) - 2048;
501 let bg = ch[2].at(row, col) - 2048;
502 let gd = ch[3].at(row, col) - 2048;
503 let (r, b, g1, g2) = (curve(gs + 2 * rg), curve(gs + 2 * bg), curve(gs + gd), curve(gs - gd));
504 let q = match phase {
506 CfaPhase::Rggb => [r, g1, g2, b],
507 CfaPhase::Grbg => [g1, r, b, g2],
508 CfaPhase::Gbrg => [g1, b, r, g2],
509 CfaPhase::Bggr => [b, g1, g2, r],
510 };
511 r0[2 * col] = q[0];
512 r0[2 * col + 1] = q[1];
513 r1[2 * col] = q[2];
514 r1[2 * col + 1] = q[3];
515 }
516 }
517 });
518 Ok(())
519}
520
521#[cfg(test)]
522mod tests {
523 use super::*;
524
525 #[test]
526 fn decompand_is_odd_and_monotonic() {
527 let mut prev = i16::MIN;
528 for v in 0..=255i16 {
529 assert_eq!(decompand(-v), -decompand(v));
530 assert!(decompand(v) >= prev);
531 prev = decompand(v);
532 }
533 assert_eq!(decompand(1), 1);
534 assert_eq!(decompand(255), 1023);
535 }
536
537 #[test]
538 fn code_book_round_trips() {
539 let code = code_book().unwrap();
540 for &(len, bits, count, value) in TABLE17.iter() {
541 let buf = ((bits as u64) << (64 - len as u32)).to_be_bytes();
542 let mut b = BitPumpMsb::new(&buf);
543 let got = code.decode(&mut b).unwrap();
544 assert_eq!(got & 0x1FF, count as u32);
545 assert_eq!((got >> 9) as u16 as i16, decompand(value as i16));
546 }
547 }
548
549 #[test]
550 fn log_curve_endpoints() {
551 let t = log_table(12);
552 assert_eq!(t[0], 0);
553 assert_eq!(t[4095], 4095);
554 assert!(t.windows(2).all(|w| w[0] <= w[1]));
555 assert_eq!(log_table(14)[4095], 16383);
556 }
557
558 #[test]
559 fn inverse_transform_of_flat_lowpass_is_flat() {
560 let mut low = Band::new(4, 4).unwrap();
561 low.data.fill(100);
562 let zero = Band::new(4, 4).unwrap();
563 let v = vertical(&zero, &low).unwrap();
564 assert!(v.data.iter().all(|&x| x == 50));
565 let lp = Band { width: 4, height: 8, stride: 4, data: vec![100; 32] };
566 let hz = Band::new(4, 8).unwrap();
567 let h = horizontal(&lp, &hz, 0, true).unwrap();
568 assert_eq!((h.width, h.height), (8, 8));
569 assert!(h.data.iter().all(|&x| x == 50));
570 }
571
572 #[test]
573 fn malformed_streams_error() {
574 let mut out = vec![0u16; 64 * 64];
575 assert!(decode(b"nope", 64, 64, 4095, CfaPhase::Rggb, &mut out, false).is_err());
576 assert!(decode(b"VC-5", 64, 64, 4095, CfaPhase::Rggb, &mut out, false).is_err());
577 let mut s = b"VC-5".to_vec();
578 s.extend_from_slice(&[0x00, 0x0c, 0x00, 0x04, 0x00, 0x14, 0x00, 0x40, 0x00, 0x15, 0x00, 0x41]);
579 assert!(decode(&s, 64, 64, 4095, CfaPhase::Rggb, &mut out, false).is_err());
580 let mut s = b"VC-5".to_vec();
581 s.extend_from_slice(&[0x00, 0x77, 0x00, 0x00]);
582 assert!(decode(&s, 64, 64, 4095, CfaPhase::Rggb, &mut out, false).is_err());
583 assert!(decode(b"VC-5", 63, 64, 4095, CfaPhase::Rggb, &mut out, false).is_err());
584 assert!(decode(b"VC-5", 64, 64, 0, CfaPhase::Rggb, &mut out, false).is_err());
585 }
586}