1use flashraw_core::par;
21use flashraw_core::{Error, Result};
22
23pub const BLOCK: usize = 0x4000;
25
26#[derive(Clone, Copy)]
29pub struct BlockedStream<'a> {
30 data: &'a [u8],
31 split: usize,
32}
33
34impl<'a> BlockedStream<'a> {
35 pub fn new(data: &'a [u8], split: usize) -> Result<Self> {
36 if split > BLOCK {
37 return Err(Error::corrupt("Panasonic block split beyond block size"));
38 }
39 Ok(BlockedStream { data, split })
40 }
41
42 pub fn len(&self) -> usize {
44 self.data.len()
45 }
46
47 pub fn is_empty(&self) -> bool {
48 self.data.is_empty()
49 }
50
51 #[inline(always)]
53 fn file_pos(&self, b: usize, i: usize) -> usize {
54 b * BLOCK + (i + BLOCK - self.split) % BLOCK
55 }
56
57 fn byte(&self, mut b: usize, i: usize) -> u8 {
60 loop {
61 if let Some(&v) = self.data.get(self.file_pos(b, i)) {
62 return v;
63 }
64 if b == 0 {
65 return 0;
66 }
67 b -= 1;
68 }
69 }
70
71 #[inline(always)]
73 pub fn packet(&self, p: usize) -> [u8; 16] {
74 let b = p * 16 / BLOCK;
75 let i = p * 16 % BLOCK;
76 let start = self.file_pos(b, i);
77 if (b + 1) * BLOCK <= self.data.len()
79 && start + 16 <= (b + 1) * BLOCK
80 && (i >= self.split || i + 16 <= self.split)
81 {
82 let mut out = [0u8; 16];
83 out.copy_from_slice(&self.data[start..start + 16]);
84 return out;
85 }
86 std::array::from_fn(|k| self.byte(b, i + k))
87 }
88
89 pub fn packets_available(&self) -> usize {
91 self.data.len().div_ceil(BLOCK) * BLOCK / 16
93 }
94}
95
96pub const V4_PIXELS: usize = 14;
101
102#[inline]
104pub fn v4_packet(packet: &[u8; 16], out: &mut [u16]) {
105 let mut v = u128::from_le_bytes(*packet);
107 let mut take = |n: u32| -> i32 {
108 let r = (v >> (128 - n)) as i32;
109 v <<= n;
110 r
111 };
112 let mut sh = 0i32;
113 let mut pred = [0i32; 2];
114 let mut nonz = [0i32; 2];
115 for (i, o) in out.iter_mut().enumerate().take(V4_PIXELS) {
116 let c = i & 1;
117 if i % 3 == 2 {
118 sh = 4 >> (3 - take(2));
119 }
120 if nonz[c] != 0 {
121 let j = take(8);
122 if j != 0 {
123 pred[c] -= 0x80 << sh;
124 if pred[c] < 0 || sh == 4 {
125 pred[c] &= !(-1i32 << sh);
126 }
127 pred[c] += j << sh;
128 }
129 } else {
130 nonz[c] = take(8);
131 if nonz[c] != 0 || i > 11 {
132 pred[c] = nonz[c] << 4 | take(4);
133 }
134 }
135 *o = pred[c] as u16;
136 }
137}
138
139pub fn decode_v4(s: &BlockedStream, width: usize, height: usize, out: &mut [u16], parallel: bool) -> Result<()> {
143 check_out(out, width, height)?;
144 if width % V4_PIXELS != 0 {
145 let needed = (width * height).div_ceil(V4_PIXELS);
146 if s.packets_available() < needed {
147 return Err(Error::corrupt("truncated Panasonic data"));
148 }
149 return decode_v4_sequential(s, width, height, out);
150 }
151 decode_v4_rows(s, width, height, 0, &mut out[..width * height], parallel)
152}
153
154pub fn decode_v4_rows(
157 s: &BlockedStream,
158 width: usize,
159 height: usize,
160 first_row: usize,
161 out: &mut [u16],
162 parallel: bool,
163) -> Result<()> {
164 let rows = out.len() / width.max(1);
165 if width == 0 || width % V4_PIXELS != 0 || first_row + rows > height {
166 return Err(Error::InvalidArgument("invalid Panasonic v4 row range".into()));
167 }
168 let needed = (width * height).div_ceil(V4_PIXELS);
169 if s.packets_available() < needed {
170 return Err(Error::corrupt(format!("truncated Panasonic data: {} of {needed} packets", s.packets_available())));
171 }
172 let per_row = width / V4_PIXELS;
173 par::for_each_row_chunk(&mut out[..width * rows], width, 16, parallel, |first, chunk| {
174 for (r, row) in chunk.chunks_exact_mut(width).enumerate() {
175 let base = (first_row + first + r) * per_row;
176 for (k, px) in row.chunks_exact_mut(V4_PIXELS).enumerate() {
177 v4_packet(&s.packet(base + k), px);
178 }
179 }
180 });
181 Ok(())
182}
183
184pub fn decode_v4_sequential(s: &BlockedStream, width: usize, height: usize, out: &mut [u16]) -> Result<()> {
186 check_out(out, width, height)?;
187 let mut buf = vec![0u8; BLOCK + 2];
188 let mut block = 0usize;
189 let mut vpos = 0u32;
190 let mut get = |nb: u32, buf: &mut Vec<u8>| -> i32 {
191 if vpos == 0 {
192 for (i, b) in buf.iter_mut().take(BLOCK).enumerate() {
193 if let Some(&v) = s.data.get(s.file_pos(block, i)) {
194 *b = v;
195 }
196 }
197 block += 1;
198 }
199 vpos = vpos.wrapping_sub(nb) & 0x1ffff;
200 let byte = (vpos >> 3 ^ 0x3ff0) as usize;
201 let w = buf[byte] as u32 | (buf[byte + 1] as u32) << 8;
202 (w >> (vpos & 7) & !(!0u32 << nb)) as i32
203 };
204 let (mut sh, mut pred, mut nonz) = (0i32, [0i32; 2], [0i32; 2]);
205 for row in 0..height {
206 for col in 0..width {
207 let i = col % V4_PIXELS;
208 if i == 0 {
209 pred = [0; 2];
210 nonz = [0; 2];
211 }
212 if i % 3 == 2 {
213 sh = 4 >> (3 - get(2, &mut buf));
214 }
215 let c = i & 1;
216 if nonz[c] != 0 {
217 let j = get(8, &mut buf);
218 if j != 0 {
219 pred[c] -= 0x80 << sh;
220 if pred[c] < 0 || sh == 4 {
221 pred[c] &= !(-1i32 << sh);
222 }
223 pred[c] += j << sh;
224 }
225 } else {
226 nonz[c] = get(8, &mut buf);
227 if nonz[c] != 0 || i > 11 {
228 pred[c] = nonz[c] << 4 | get(4, &mut buf);
229 }
230 }
231 out[row * width + col] = pred[col & 1] as u16;
232 }
233 }
234 Ok(())
235}
236
237fn check_out(out: &[u16], width: usize, height: usize) -> Result<()> {
238 if width == 0 || height == 0 || out.len() < width * height {
239 return Err(Error::InvalidArgument("Panasonic output buffer too small".into()));
240 }
241 Ok(())
242}
243
244pub fn packed_pixels(bits: u32) -> Option<usize> {
249 match bits {
250 12 => Some(10),
251 14 => Some(9),
252 _ => None,
253 }
254}
255
256#[inline]
257fn unpack_lsb(packet: &[u8; 16], bits: u32, out: &mut [u16]) {
258 let v = u128::from_le_bytes(*packet);
259 let mask = (1u128 << bits) - 1;
260 for (k, o) in out.iter_mut().enumerate() {
261 *o = ((v >> (bits as usize * k)) & mask) as u16;
262 }
263}
264
265pub fn decode_v5(
267 s: &BlockedStream,
268 bits: u32,
269 width: usize,
270 height: usize,
271 out: &mut [u16],
272 parallel: bool,
273) -> Result<()> {
274 check_out(out, width, height)?;
275 decode_v5_rows(s, bits, width, height, 0, &mut out[..width * height], parallel)
276}
277
278pub fn decode_v5_rows(
280 s: &BlockedStream,
281 bits: u32,
282 width: usize,
283 height: usize,
284 first_row: usize,
285 out: &mut [u16],
286 parallel: bool,
287) -> Result<()> {
288 let rows = out.len() / width.max(1);
289 if width == 0 || first_row + rows > height {
290 return Err(Error::InvalidArgument("invalid Panasonic v5 row range".into()));
291 }
292 let ppp = packed_pixels(bits).ok_or_else(|| Error::corrupt(format!("Panasonic v5 with {bits} bits")))?;
293 let per_row = width.div_ceil(ppp);
294 if s.packets_available() < per_row * height {
295 return Err(Error::corrupt("truncated Panasonic v5 data"));
296 }
297 par::for_each_row_chunk(&mut out[..width * rows], width, 16, parallel, |first, chunk| {
298 let mut tmp = [0u16; 10];
299 for (r, row) in chunk.chunks_exact_mut(width).enumerate() {
300 let base = (first_row + first + r) * per_row;
301 for (k, px) in row.chunks_mut(ppp).enumerate() {
302 unpack_lsb(&s.packet(base + k), bits, &mut tmp[..ppp]);
303 px.copy_from_slice(&tmp[..px.len()]);
304 }
305 }
306 });
307 Ok(())
308}
309
310pub fn decode_v7(data: &[u8], bits: u32, width: usize, height: usize, out: &mut [u16], parallel: bool) -> Result<()> {
314 check_out(out, width, height)?;
315 decode_v7_rows(data, bits, width, height, 0, &mut out[..width * height], parallel)
316}
317
318pub fn decode_v7_rows(
320 data: &[u8],
321 bits: u32,
322 width: usize,
323 height: usize,
324 first_row: usize,
325 out: &mut [u16],
326 parallel: bool,
327) -> Result<()> {
328 let nrows = out.len() / width.max(1);
329 if width == 0 || first_row + nrows > height {
330 return Err(Error::InvalidArgument("invalid Panasonic v7 row range".into()));
331 }
332 let ppp = packed_pixels(bits).ok_or_else(|| Error::corrupt(format!("Panasonic v7 with {bits} bits")))?;
333 let row_bytes = width / ppp * 16;
334 let rows = height / 16 * 16;
335 if row_bytes == 0 || data.len() < rows * row_bytes {
336 return Err(Error::corrupt("truncated Panasonic v7 data"));
337 }
338 par::for_each_row_chunk(&mut out[..width * nrows], width, 16, parallel, |first, chunk| {
339 for (r, row) in chunk.chunks_exact_mut(width).enumerate() {
340 let y = first_row + first + r;
341 if y >= rows {
342 row.fill(0);
343 continue;
344 }
345 let src = &data[y * row_bytes..(y + 1) * row_bytes];
346 for (p, px) in src.chunks_exact(16).zip(row.chunks_exact_mut(ppp)) {
347 unpack_lsb(p.try_into().unwrap_or(&[0; 16]), bits, px);
348 }
349 }
350 });
351 Ok(())
352}
353
354pub fn decode_v6(data: &[u8], bits: u32, width: usize, height: usize, out: &mut [u16], parallel: bool) -> Result<()> {
360 check_out(out, width, height)?;
361 decode_v6_rows(data, bits, width, height, 0, &mut out[..width * height], parallel)
362}
363
364pub fn decode_v6_rows(
366 data: &[u8],
367 bits: u32,
368 width: usize,
369 height: usize,
370 first_row: usize,
371 out: &mut [u16],
372 parallel: bool,
373) -> Result<()> {
374 let nrows = out.len() / width.max(1);
375 if width == 0 || first_row + nrows > height {
376 return Err(Error::InvalidArgument("invalid Panasonic v6 row range".into()));
377 }
378 let twelve = match bits {
379 12 => true,
380 14 => false,
381 _ => return Err(Error::corrupt(format!("Panasonic v6 with {bits} bits"))),
382 };
383 let ppb = if twelve { 14 } else { 11 };
384 let blocks = width / ppb;
385 let row_bytes = blocks * 16;
386 let rows = height / 16 * 16;
387 if row_bytes == 0 || data.len() < rows * row_bytes {
388 return Err(Error::corrupt("truncated Panasonic v6 data"));
389 }
390 par::for_each_row_chunk(&mut out[..width * nrows], width, 16, parallel, |first, chunk| {
391 for (r, row) in chunk.chunks_exact_mut(width).enumerate() {
392 let y = first_row + first + r;
393 if y >= rows {
394 row.fill(0);
395 continue;
396 }
397 let src = &data[y * row_bytes..(y + 1) * row_bytes];
398 for (p, px) in src.chunks_exact(16).zip(row.chunks_exact_mut(ppb)) {
399 v6_block(p.try_into().unwrap_or(&[0; 16]), twelve, px);
400 }
401 }
402 });
403 Ok(())
404}
405
406fn v6_fields(b: &[u8; 16], twelve: bool) -> ([u32; 18], usize) {
409 let w = |i: usize| b[15 - i] as u32;
411 let mut f = [0u32; 18];
412 if twelve {
413 f[0] = (w(0) << 4) | (w(1) >> 4);
414 f[1] = ((w(1) & 0xf) << 8 | w(2)) & 0xfff;
415 f[2] = (w(3) >> 6) & 0x3;
416 f[3] = ((w(3) & 0x3f) << 2) | (w(4) >> 6);
417 f[4] = ((w(4) & 0x3f) << 2) | (w(5) >> 6);
418 f[5] = ((w(5) & 0x3f) << 2) | (w(6) >> 6);
419 f[6] = (w(6) >> 4) & 0x3;
420 f[7] = ((w(6) & 0xf) << 4) | (w(7) >> 4);
421 f[8] = ((w(7) & 0xf) << 4) | (w(8) >> 4);
422 f[9] = ((w(8) & 0xf) << 4) | (w(9) >> 4);
423 f[10] = (w(9) >> 2) & 0x3;
424 f[11] = ((w(9) & 0x3) << 6) | (w(10) >> 2);
425 f[12] = ((w(10) & 0x3) << 6) | (w(11) >> 2);
426 f[13] = ((w(11) & 0x3) << 6) | (w(12) >> 2);
427 f[14] = w(12) & 0x3;
428 f[15] = w(13);
429 f[16] = w(14);
430 f[17] = w(15);
431 (f, 18)
432 } else {
433 f[0] = (w(0) << 6) | (w(1) >> 2);
434 f[1] = (((w(1) & 0x3) << 12) | (w(2) << 4) | (w(3) >> 4)) & 0x3fff;
435 f[2] = (w(3) >> 2) & 0x3;
436 f[3] = ((w(3) & 0x3) << 8) | w(4);
437 f[4] = (w(5) << 2) | (w(6) >> 6);
438 f[5] = ((w(6) & 0x3f) << 4) | (w(7) >> 4);
439 f[6] = (w(7) >> 2) & 0x3;
440 f[7] = ((w(7) & 0x3) << 8) | w(8);
441 f[8] = ((w(9) << 2) & 0x3fc) | (w(10) >> 6);
442 f[9] = ((w(10) << 4) | (w(11) >> 4)) & 0x3ff;
443 f[10] = (w(11) >> 2) & 0x3;
444 f[11] = ((w(11) & 0x3) << 8) | w(12);
445 f[12] = (((w(13) << 2) & 0x3fc) | w(14) >> 6) & 0x3ff;
446 f[13] = ((w(14) << 4) | (w(15) >> 4)) & 0x3ff;
447 (f, 14)
448 }
449}
450
451#[inline]
452fn v6_block(b: &[u8; 16], twelve: bool, out: &mut [u16]) {
453 let (f, nf) = v6_fields(b, twelve);
454 let mut next = 0usize;
455 let mut field = || {
456 let v = if next < nf { f[next] } else { 0 };
457 next += 1;
458 v
459 };
460 let (base0, base_cmp, spix_cmp, mask) =
461 if twelve { (0x80u32, 0x800u32, 0x3fffu32, 0xfffu32) } else { (0x200, 0x2000, 0xffff, 0x3fff) };
462 let mut oddeven = [0u32; 2];
463 let mut nonzero = [0u32; 2];
464 let (mut pmul, mut pixel_base) = (0u32, 0u32);
465 for (pix, o) in out.iter_mut().enumerate() {
466 if pix % 3 == 2 {
467 let mut base = field();
468 if base == 3 {
469 base = 4;
470 }
471 pixel_base = base0 << base;
472 pmul = 1 << base;
473 }
474 let mut epixel = field();
475 let c = pix % 2;
476 if oddeven[c] != 0 {
477 epixel = epixel.wrapping_mul(pmul);
478 if pixel_base < base_cmp && nonzero[c] > pixel_base {
479 epixel = epixel.wrapping_add(nonzero[c] - pixel_base);
480 }
481 nonzero[c] = epixel;
482 } else {
483 oddeven[c] = epixel;
484 if epixel != 0 {
485 nonzero[c] = epixel;
486 } else {
487 epixel = nonzero[c];
488 }
489 }
490 let spix = epixel.wrapping_sub(0xf);
491 *o = if spix <= spix_cmp {
492 (spix & spix_cmp) as u16
493 } else {
494 ((((epixel.wrapping_add(0x7fff_fff1)) as i32) >> 31) as u32 & mask) as u16
496 };
497 }
498}
499
500#[derive(Debug, Clone, Default)]
505pub struct V8Params {
506 pub gamma_points: [u32; 6],
508 pub gamma_slopes: [u32; 6],
509 pub clip: u32,
511 pub initial: [u16; 4],
513 pub codes: Vec<(u8, u16)>,
516 pub shift_down: Vec<u8>,
518}
519
520#[derive(Debug, Clone, Copy)]
522pub struct V8Strip<'a> {
523 pub data: &'a [u8],
524 pub bits: u64,
526 pub left: u32,
527 pub top: u32,
530 pub width: u32,
531 pub height: u32,
532}
533
534struct V8Lut {
536 entries: Vec<(u8, u8)>,
539 bits: u32,
540}
541
542impl V8Lut {
543 fn new(codes: &[(u8, u16)]) -> Result<Self> {
544 if codes.is_empty() || codes.len() > 17 {
545 return Err(Error::corrupt("invalid Panasonic v8 Huffman table size"));
546 }
547 let bits = codes.iter().map(|&(l, _)| l as u32).filter(|&l| l <= 16).max().unwrap_or(1).max(1);
548 let mut entries = vec![(0u8, 0u8); 1 << bits];
550 for (v, e) in entries.iter_mut().enumerate() {
551 for (sym, &(len, code)) in codes.iter().enumerate() {
552 if len == 0 || len as u32 > bits {
553 continue;
554 }
555 let shift = bits - len as u32;
556 if (v as u32 >> shift) == (code as u32 & ((1 << len) - 1)) {
557 *e = (len, sym as u8);
558 break;
559 }
560 }
561 }
562 Ok(V8Lut { entries, bits })
563 }
564}
565
566struct RevBits<'a> {
568 data: &'a [u8],
569 pos: usize,
570 cache: u64,
571 bits: u32,
572}
573
574impl<'a> RevBits<'a> {
575 fn new(data: &'a [u8]) -> Self {
576 RevBits { data, pos: 0, cache: 0, bits: 0 }
577 }
578 #[inline(always)]
579 fn fill(&mut self) {
580 if self.bits > 32 {
581 return;
582 }
583 let mut w = [0u8; 4];
585 if let Some(s) = self.data.get(self.pos..self.pos + 4) {
586 w.copy_from_slice(s);
587 } else {
588 for (k, b) in w.iter_mut().enumerate() {
589 *b = self.data.get(self.pos + k).copied().unwrap_or(0);
590 }
591 }
592 let v = u32::from_le_bytes(w).reverse_bits() as u64;
593 self.cache |= v << (32 - self.bits);
594 self.bits += 32;
595 self.pos += 4;
596 }
597 #[inline(always)]
598 fn skip(&mut self, n: u32) {
599 self.cache = if n >= 64 { 0 } else { self.cache << n };
600 self.bits -= n;
601 }
602 fn consumed(&self) -> u64 {
603 self.pos as u64 * 8 - self.bits as u64
604 }
605 fn at_bit(data: &'a [u8], bit: u64) -> Self {
607 let mut r = RevBits { data, pos: (bit / 32) as usize * 4, cache: 0, bits: 0 };
608 r.fill();
609 r.skip((bit % 32) as u32);
610 r
611 }
612}
613
614pub struct V8Decoder {
616 lut: V8Lut,
617 sym: [(u32, u32, i32, i32); 17],
620 clip: u32,
621 gamma: Option<Vec<u16>>,
622 initial: [u16; 4],
623}
624
625impl V8Decoder {
626 pub fn new(p: &V8Params) -> Result<Self> {
627 let lut = V8Lut::new(&p.codes)?;
628 let mut shift_down = [0u8; 17];
629 for (d, &s) in shift_down.iter_mut().zip(p.shift_down.iter()) {
630 *d = s.min(31);
631 }
632 let sym = std::array::from_fn(|i| {
633 let s = shift_down[i] as u32;
634 let d = (i as u32).saturating_sub(s);
635 let neg = if i > 0 { -(1i32 << i) + if s > 0 { 0 } else { 1 } } else { 0 };
636 let add = if s > 0 { 1i32 << (s - 1) } else { 0 };
637 (d, s, neg, add)
638 });
639 let curve: Vec<u16> = (0..0x10000u32).map(|i| gamma_curve(p, i)).collect();
641 let gamma = if curve.iter().enumerate().all(|(i, &v)| v as usize == i) { None } else { Some(curve) };
642 Ok(V8Decoder { lut, sym, clip: p.clip, gamma, initial: p.initial })
643 }
644
645 pub fn decode(
648 &self,
649 strips: &[V8Strip],
650 out: &mut [u16],
651 raw_width: usize,
652 raw_height: usize,
653 parallel: bool,
654 ) -> Result<()> {
655 if out.len() < raw_width * raw_height || raw_width == 0 || strips.is_empty() {
656 return Err(Error::InvalidArgument("Panasonic v8 output too small".into()));
657 }
658 let rect = |s: &V8Strip| (s.left as usize, s.top as usize, s.width as usize, s.height as usize);
660 let mut area = 0usize;
661 for (i, s) in strips.iter().enumerate() {
662 let (l, t, w, h) = rect(s);
663 if w < 2 || h < 2 || w % 2 != 0 || h % 2 != 0 || l + w > raw_width || t + h > raw_height {
664 return Err(Error::corrupt("invalid Panasonic v8 strip geometry"));
665 }
666 for o in &strips[..i] {
667 let (ol, ot, ow, oh) = rect(o);
668 if l < ol + ow && ol < l + w && t < ot + oh && ot < t + h {
669 return Err(Error::corrupt("overlapping Panasonic v8 strips"));
670 }
671 }
672 area += w * h;
673 }
674 if area != raw_width * raw_height {
675 return Err(Error::corrupt("Panasonic v8 strips do not cover the image"));
676 }
677 let mut order: Vec<usize> = (0..strips.len()).collect();
679 order.sort_by_key(|&i| (strips[i].top, strips[i].left));
680 let mut segments: Vec<Vec<&mut [u16]>> = strips.iter().map(|s| Vec::with_capacity(s.height as usize)).collect();
681 for (y, row) in out[..raw_width * raw_height].chunks_exact_mut(raw_width).enumerate() {
682 let mut rest = row;
683 let mut consumed = 0usize;
684 for &i in &order {
685 let (l, t, w, h) = rect(&strips[i]);
686 if y < t || y >= t + h {
687 continue;
688 }
689 let (_, tail) = std::mem::take(&mut rest).split_at_mut(l - consumed);
690 let (seg, tail) = tail.split_at_mut(w);
691 segments[i].push(seg);
692 rest = tail;
693 consumed = l + w;
694 }
695 }
696 let jobs: Vec<(usize, Vec<&mut [u16]>)> = segments.into_iter().enumerate().collect();
697 let results = par::map(jobs, parallel, |(i, rows)| self.decode_strip_with(&strips[i], rows, parallel));
698 results.into_iter().collect::<Result<Vec<()>>>().map(|_| ())
699 }
700
701 pub fn decode_strip(&self, s: &V8Strip, rows: Vec<&mut [u16]>) -> Result<()> {
703 self.decode_strip_with(s, rows, false)
704 }
705
706 fn decode_strip_with(&self, s: &V8Strip, rows: Vec<&mut [u16]>, parallel: bool) -> Result<()> {
707 let (w, h) = (s.width as usize, s.height as usize);
708 if w / 2 == 0 || h / 2 == 0 || rows.len() < h || rows.iter().any(|r| r.len() < w) {
709 return Err(Error::corrupt("invalid Panasonic v8 strip"));
710 }
711 if parallel && w * h >= crate::ljpeg_par::PARALLEL_MIN_SAMPLES / 4 {
712 if let Some(rows) = self.decode_strip_parallel(s, rows, None)? {
713 return self.decode_strip_seq(s, rows);
715 }
716 return Ok(());
717 }
718 self.decode_strip_seq(s, rows)
719 }
720
721 fn decode_strip_seq(&self, s: &V8Strip, mut rows: Vec<&mut [u16]>) -> Result<()> {
722 match &self.gamma {
723 Some(t) => self.decode_rows_seq::<true>(s, &mut rows, t),
724 None => self.decode_rows_seq::<false>(s, &mut rows, &[]),
725 }
726 }
727
728 fn decode_rows_seq<const GAMMA: bool>(&self, s: &V8Strip, rows: &mut [&mut [u16]], curve: &[u16]) -> Result<()> {
729 let (w, h) = (s.width as usize, s.height as usize);
730 let half_w = w / 2;
731 let budget = s.bits.div_ceil(64) * 64;
732 let mut bits = RevBits::new(s.data);
733 let clip = self.clip as i32;
734 let mut line_base = self.initial.map(|v| v as i32);
735 let mut err = false;
736 for pair in 0..h / 2 {
737 let mut base = line_base;
738 let (top, bottom) = rows[pair * 2..pair * 2 + 2].split_at_mut(1);
739 let (r0, r1) = (&mut *top[0], &mut *bottom[0]);
740 for bx in 0..half_w {
741 let mut blk = [0i32; 4];
742 for slot in [0usize, 2, 1, 3] {
744 let delta = self.diff(&mut bits, &mut err);
745 blk[slot] = (base[slot] + delta).clamp(0, clip);
746 }
747 base = blk;
748 if bx == 0 {
749 line_base = blk;
750 }
751 let g = |v: i32| if GAMMA { curve[v as usize & 0xffff] } else { v as u16 };
752 r0[2 * bx] = g(blk[0]);
753 r0[2 * bx + 1] = g(blk[1]);
754 r1[2 * bx] = g(blk[2]);
755 r1[2 * bx + 1] = g(blk[3]);
756 }
757 if err {
758 return Err(Error::corrupt("invalid Panasonic v8 Huffman code"));
759 }
760 if bits.consumed() > budget {
761 return Err(Error::corrupt("truncated Panasonic v8 strip"));
762 }
763 }
764 Ok(())
765 }
766
767 fn decode_strip_parallel<'r>(
772 &self,
773 s: &V8Strip,
774 rows: Vec<&'r mut [u16]>,
775 chunk: Option<usize>,
776 ) -> Result<Option<Vec<&'r mut [u16]>>> {
777 let (w, h) = (s.width as usize, s.height as usize);
778 let (half_w, pairs) = (w / 2, h / 2);
779 let budget = s.bits.div_ceil(64) * 64;
780 let scan = V8Scan { data: s.data, dec: self, budget };
781 let Some(chunk) = chunk.or_else(|| crate::par_entropy::default_chunk(s.data.len())) else {
782 return Ok(Some(rows));
783 };
784 let Some(values) = crate::par_entropy::decode(&scan, pairs * half_w * 4, chunk) else {
785 return Ok(Some(rows));
786 };
787 let delta = |k: usize| -> i32 { (values.get(2 * k) as u32 | (values.get(2 * k + 1) as u32) << 16) as i32 };
788 let clip = self.clip as i32;
789 let mut starts = Vec::with_capacity(pairs);
791 let mut line_base = self.initial.map(|v| v as i32);
792 for pair in 0..pairs {
793 starts.push(line_base);
794 let k0 = pair * half_w * 4;
795 let mut blk = [0i32; 4];
796 for (j, slot) in [0usize, 2, 1, 3].into_iter().enumerate() {
797 blk[slot] = (line_base[slot] + delta(k0 + j)).clamp(0, clip);
798 }
799 line_base = blk;
800 }
801 let mut it = rows.into_iter();
802 let jobs: Vec<(usize, &mut [u16], &mut [u16])> =
803 (0..pairs).filter_map(|p| Some((p, it.next()?, it.next()?))).collect();
804 par::map(jobs, true, |(pair, r0, r1)| {
805 let mut buf = vec![0u16; half_w * 8];
806 values.copy_to(pair * half_w * 8, &mut buf);
807 let mut base = starts[pair];
808 for (bx, d) in buf.chunks_exact(8).enumerate() {
809 let mut blk = [0i32; 4];
810 for (j, slot) in [0usize, 2, 1, 3].into_iter().enumerate() {
811 let delta = (d[2 * j] as u32 | (d[2 * j + 1] as u32) << 16) as i32;
812 blk[slot] = (base[slot] + delta).clamp(0, clip);
813 }
814 base = blk;
815 let g = |v: i32| match &self.gamma {
816 Some(t) => t[v as usize & 0xffff],
817 None => v as u16,
818 };
819 r0[2 * bx] = g(blk[0]);
820 r0[2 * bx + 1] = g(blk[1]);
821 r1[2 * bx] = g(blk[2]);
822 r1[2 * bx + 1] = g(blk[3]);
823 }
824 });
825 Ok(None)
826 }
827
828 #[inline(always)]
831 fn diff(&self, bits: &mut RevBits, err: &mut bool) -> i32 {
832 bits.fill();
834 let window = bits.cache;
835 let (len, sym) = self.lut.entries[(window >> (64 - self.lut.bits)) as usize];
836 if len == 0 {
837 *err = true;
838 bits.skip(1);
839 return 0;
840 }
841 let (d, s, neg, add) = self.sym[sym as usize];
842 let after = window << len;
843 bits.skip(len as u32 + d);
844 let positive = (after >> 63) == 1;
847 let raw = if d > 0 { (after >> (64 - d)) as i32 } else { 0 };
848 (raw << s) + if positive { 0 } else { neg } + add
849 }
850}
851
852struct V8Scan<'a> {
854 data: &'a [u8],
855 dec: &'a V8Decoder,
856 budget: u64,
857}
858
859impl crate::par_entropy::SymbolStream for V8Scan<'_> {
860 type Pump<'p>
861 = RevBits<'p>
862 where
863 Self: 'p;
864 const WIDTH: usize = 2;
865 fn cycle(&self) -> usize {
866 1
867 }
868 fn period(&self) -> usize {
869 1
870 }
871 fn total_bits(&self) -> u64 {
872 self.budget
873 }
874 fn end_check(&self, pos: u64) -> crate::par_entropy::EndCheck {
875 if pos <= self.budget { crate::par_entropy::EndCheck::Valid } else { crate::par_entropy::EndCheck::Invalid }
876 }
877 fn pump_at(&self, bit: u64) -> RevBits<'_> {
878 RevBits::at_bit(self.data, bit)
879 }
880 fn position(p: &RevBits<'_>) -> u64 {
881 p.consumed()
882 }
883 #[inline(always)]
884 fn decode(&self, p: &mut RevBits<'_>, _phase: usize, out: &mut [u16]) -> bool {
885 let mut err = false;
886 let d = self.dec.diff(p, &mut err);
887 out[0] = d as u32 as u16;
888 out[1] = (d as u32 >> 16) as u16;
889 !err
890 }
891}
892
893fn gamma_curve(p: &V8Params, idx: u32) -> u16 {
895 let t3a = &p.gamma_points;
896 let t39 = &p.gamma_slopes;
897 let v2 = if idx & 0x10000 == 0 { idx & 0x1ffff } else { idx | 0xffff_0000 };
898 let mut v4 = v2.min(0xffff);
899 if v4 & 0x8000_0000 != 0 {
900 v4 = 0;
901 }
902 let mut seg = 0usize;
903 if v4 >= (t3a[1] & 0xffff) {
904 seg = 1;
905 if v4 >= (t3a[2] & 0xffff) {
906 seg = 2;
907 if v4 >= (t3a[3] & 0xffff) {
908 seg = 3;
909 if v4 >= (t3a[4] & 0xffff) {
910 seg = (((v4 as u64 | 0x5_0000_0000) - (t3a[5] & 0xffff) as u64) >> 32) as usize;
911 }
912 }
913 }
914 }
915 let seg = seg.min(5);
916 let v6 = t3a[seg];
917 let v7 = t39[seg];
918 let mut v8 = v4.wrapping_sub(v6 & 0xffff);
919 let v9 = v7 & 0x1f;
920 let clip = p.clip;
921 let res: u64 = if v9 == 31 {
922 if seg == 5 { 0xffff } else { ((t3a[seg + 1] >> 16) & 0xffff) as u64 }
923 } else if v7 & 0x10 == 0 && v9 == 15 {
924 ((v6 >> 16) & 0xffff) as u64
925 } else {
926 if v7 & 0x10 == 0 {
927 if v9 != 0 {
928 v8 = (v8.wrapping_add(1 << (v9 - 1))) >> v9;
929 }
930 } else {
931 v8 = v8.wrapping_shl(v7 & 0xf);
932 }
933 v8 as u64 + ((v6 >> 16) & 0xffff) as u64
934 };
935 res.min(clip as u64) as u16
936}
937
938#[cfg(test)]
939mod tests {
940 use super::*;
941
942 fn pseudo(n: usize, seed: u64) -> Vec<u8> {
943 let mut x = seed;
944 (0..n)
945 .map(|_| {
946 x ^= x << 13;
947 x ^= x >> 7;
948 x ^= x << 17;
949 (x >> 24) as u8
950 })
951 .collect()
952 }
953
954 #[test]
955 fn blocked_stream_rotation() {
956 let data: Vec<u8> = (0..BLOCK).map(|i| (i % 251) as u8).collect();
958 let s = BlockedStream::new(&data, 0x2008).unwrap();
959 assert_eq!(s.packet(0)[0], data[BLOCK - 0x2008]);
960 assert_eq!(s.packet(0x2008 / 16 + 1)[0], data[8]);
961 let p = s.packet(0x2000 / 16);
963 for (k, &v) in p.iter().enumerate() {
964 let i = 0x2000 + k;
965 assert_eq!(v, data[(i + BLOCK - 0x2008) % BLOCK]);
966 }
967 }
968
969 #[test]
970 fn v4_parallel_matches_sequential_reference() {
971 for (w, h, extra) in [(28usize, 9usize, 0usize), (14 * 37, 31, 100), (14 * 5, 4, 0)] {
972 let packets = (w * h).div_ceil(14);
973 let mut data = pseudo(packets * 16 + extra, w as u64);
974 data.truncate(data.len() - extra.min(data.len() / 2));
976 let s = BlockedStream::new(&data, 0x2008).unwrap();
977 let mut a = vec![0u16; w * h];
978 let mut b = vec![0u16; w * h];
979 if decode_v4(&s, w, h, &mut a, true).is_ok() {
980 decode_v4_sequential(&s, w, h, &mut b).unwrap();
981 assert_eq!(a, b, "{w}x{h}");
982 }
983 }
984 let data = pseudo(4 * BLOCK, 7);
986 let s = BlockedStream::new(&data, 0x2008).unwrap();
987 let mut a = vec![0u16; 30 * 20];
988 decode_v4(&s, 30, 20, &mut a, true).unwrap();
989 }
990
991 #[test]
992 fn v4_packet_known_values() {
993 let mut out = [9u16; 14];
995 v4_packet(&[0; 16], &mut out);
996 assert_eq!(out, [0; 14]);
997 let mut v: u128 = 0x12 << 120 | 0x3 << 116;
999 v |= 0x01 << 108; let mut out = [0u16; 14];
1001 v4_packet(&v.to_le_bytes(), &mut out);
1002 assert_eq!(out[0], 0x123);
1003 assert_eq!(out[1], 0x010);
1004 }
1005
1006 #[test]
1007 fn v5_v7_unpack_roundtrip() {
1008 for bits in [12u32, 14] {
1009 let ppp = packed_pixels(bits).unwrap();
1010 let (w, h) = (ppp * 3, 16);
1011 let vals: Vec<u16> = (0..w * h).map(|i| ((i * 2654435761) >> 7) as u16 & ((1 << bits) - 1)).collect();
1012 let mut data = Vec::new();
1013 for row in vals.chunks(w) {
1014 for px in row.chunks(ppp) {
1015 let mut v: u128 = 0;
1016 for (k, &p) in px.iter().enumerate() {
1017 v |= (p as u128) << (bits as usize * k);
1018 }
1019 data.extend_from_slice(&v.to_le_bytes());
1020 }
1021 }
1022 let mut out = vec![0u16; w * h];
1023 decode_v7(&data, bits, w, h, &mut out, true).unwrap();
1024 assert_eq!(out, vals);
1025 let s = BlockedStream::new(&data, 0).unwrap();
1027 let mut out5 = vec![0u16; w * h];
1028 decode_v5(&s, bits, w, h, &mut out5, false).unwrap();
1029 assert_eq!(out5, vals);
1030 assert!(decode_v7(&data[..data.len() / 2], bits, w, h, &mut out, true).is_err());
1031 }
1032 }
1033
1034 #[test]
1035 fn v6_does_not_panic_and_rejects_truncation() {
1036 for bits in [12u32, 14] {
1037 let (w, h) = (154usize, 32usize);
1038 let ppb = if bits == 12 { 14 } else { 11 };
1039 let data = pseudo(w / ppb * 16 * h, bits as u64);
1040 let mut out = vec![0u16; w * h];
1041 decode_v6(&data, bits, w, h, &mut out, true).unwrap();
1042 assert!(out.iter().all(|&v| (v as u32) < if bits == 12 { 1 << 14 } else { 1 << 16 }));
1044 assert!(decode_v6(&data[..100], bits, w, h, &mut out, true).is_err());
1045 }
1046 }
1047
1048 fn v8_encode(vals: &[u16], w: usize, h: usize, codes: &[(u8, u16)], init: [u16; 4]) -> Vec<u8> {
1051 let mut bitsv: Vec<bool> = Vec::new();
1052 let put = |v: u32, n: u32, bitsv: &mut Vec<bool>| {
1053 for k in (0..n).rev() {
1054 bitsv.push(v >> k & 1 == 1);
1055 }
1056 };
1057 let mut line_base = init.map(|v| v as i32);
1058 for pair in 0..h / 2 {
1059 let mut base = line_base;
1060 for bx in 0..w / 2 {
1061 let blk = [
1062 vals[pair * 2 * w + 2 * bx] as i32,
1063 vals[pair * 2 * w + 2 * bx + 1] as i32,
1064 vals[(pair * 2 + 1) * w + 2 * bx] as i32,
1065 vals[(pair * 2 + 1) * w + 2 * bx + 1] as i32,
1066 ];
1067 for slot in [0usize, 2, 1, 3] {
1068 let d = blk[slot] - base[slot];
1069 let cat = if d == 0 { 0 } else { 32 - d.unsigned_abs().leading_zeros() };
1070 let (len, code) = codes[cat as usize];
1071 put(code as u32, len as u32, &mut bitsv);
1072 if cat > 0 {
1073 let m = if d > 0 { d as u32 } else { (d + (1 << cat) - 1) as u32 };
1074 put(m, cat, &mut bitsv);
1075 }
1076 }
1077 base = blk;
1078 if bx == 0 {
1079 line_base = blk;
1080 }
1081 }
1082 }
1083 let mut bytes = vec![0u8; bitsv.len().div_ceil(8) + 8];
1084 for (i, &b) in bitsv.iter().enumerate() {
1085 if b {
1086 bytes[i / 8] |= 1 << (i % 8);
1088 }
1089 }
1090 bytes
1091 }
1092
1093 #[test]
1094 fn v8_roundtrip() {
1095 let codes: Vec<(u8, u16)> = vec![
1097 (10, 1022),
1098 (11, 2046),
1099 (8, 254),
1100 (9, 510),
1101 (7, 126),
1102 (4, 14),
1103 (4, 12),
1104 (3, 4),
1105 (3, 2),
1106 (2, 0),
1107 (3, 3),
1108 (3, 5),
1109 (4, 13),
1110 (5, 30),
1111 (6, 62),
1112 (12, 4094),
1113 (12, 4095),
1114 ];
1115 let (w, h) = (24usize, 10usize);
1116 let vals: Vec<u16> = (0..w * h).map(|i| ((i * 7919) % 65536) as u16).collect();
1117 let data = v8_encode(&vals, w, h, &codes, [100, 200, 300, 400]);
1118 let p = V8Params {
1119 gamma_points: [0; 6],
1120 gamma_slopes: [65536; 6],
1121 clip: 65535,
1122 initial: [100, 200, 300, 400],
1123 codes: codes.clone(),
1124 shift_down: vec![0; 17],
1125 };
1126 let dec = V8Decoder::new(&p).unwrap();
1127 assert!(dec.gamma.is_none());
1128 let strip =
1129 V8Strip { data: &data, bits: (data.len() * 8) as u64, left: 0, top: 0, width: w as u32, height: h as u32 };
1130 let mut out = vec![0u16; w * h];
1131 dec.decode(&[strip], &mut out, w, h, true).unwrap();
1132 assert_eq!(out, vals);
1133 let short = V8Strip { data: &data[..data.len() / 3], bits: (data.len() / 3 * 8) as u64, ..strip };
1135 assert!(dec.decode(&[short], &mut out, w, h, true).is_err());
1136 for chunk in [3usize, 17, 64, 1 << 20] {
1138 let mut par = vec![0u16; w * h];
1139 let rows: Vec<&mut [u16]> = par.chunks_exact_mut(w).collect();
1140 assert!(dec.decode_strip_parallel(&strip, rows, Some(chunk)).unwrap().is_none(), "chunk {chunk}");
1141 assert_eq!(par, vals, "chunk {chunk}");
1142 }
1143 }
1144}