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(always)]
260fn unpack_packet<const B: usize, const P: usize>(p: &[u8; 16], out: &mut [u16]) {
261 let mask = (1u64 << B) - 1;
262 let lo = u64::from_le_bytes(p[..8].try_into().unwrap());
263 let hi = u64::from_le_bytes(p[8..].try_into().unwrap());
264 for (k, o) in out.iter_mut().enumerate().take(P) {
265 let s = B * k;
266 let v = if s + B <= 64 {
267 lo >> s
268 } else if s >= 64 {
269 hi >> (s - 64)
270 } else {
271 (lo >> s) | (hi << (64 - s))
272 };
273 *o = (v & mask) as u16;
274 }
275}
276
277#[inline]
279fn unpack_lsb_row<const B: usize, const P: usize>(src: &[u8], row: &mut [u16]) {
280 for (p, px) in src.chunks_exact(16).zip(row.chunks_exact_mut(P)) {
281 unpack_packet::<B, P>(p.try_into().unwrap(), px);
282 }
283}
284
285#[inline]
287fn unpack_lsb(packet: &[u8; 16], bits: u32, out: &mut [u16]) {
288 match bits {
289 14 => unpack_packet::<14, 9>(packet, out),
290 _ => unpack_packet::<12, 10>(packet, out),
291 }
292}
293
294pub fn decode_v5(
296 s: &BlockedStream,
297 bits: u32,
298 width: usize,
299 height: usize,
300 out: &mut [u16],
301 parallel: bool,
302) -> Result<()> {
303 check_out(out, width, height)?;
304 decode_v5_rows(s, bits, width, height, 0, &mut out[..width * height], parallel)
305}
306
307pub fn decode_v5_rows(
309 s: &BlockedStream,
310 bits: u32,
311 width: usize,
312 height: usize,
313 first_row: usize,
314 out: &mut [u16],
315 parallel: bool,
316) -> Result<()> {
317 let rows = out.len() / width.max(1);
318 if width == 0 || first_row + rows > height {
319 return Err(Error::InvalidArgument("invalid Panasonic v5 row range".into()));
320 }
321 let ppp = packed_pixels(bits).ok_or_else(|| Error::corrupt(format!("Panasonic v5 with {bits} bits")))?;
322 let per_row = width.div_ceil(ppp);
323 if s.packets_available() < per_row * height {
324 return Err(Error::corrupt("truncated Panasonic v5 data"));
325 }
326 par::for_each_row_chunk(&mut out[..width * rows], width, 16, parallel, |first, chunk| {
327 let mut tmp = [0u16; 10];
328 for (r, row) in chunk.chunks_exact_mut(width).enumerate() {
329 let base = (first_row + first + r) * per_row;
330 for (k, px) in row.chunks_mut(ppp).enumerate() {
331 unpack_lsb(&s.packet(base + k), bits, &mut tmp[..ppp]);
332 px.copy_from_slice(&tmp[..px.len()]);
333 }
334 }
335 });
336 Ok(())
337}
338
339pub fn decode_v7(data: &[u8], bits: u32, width: usize, height: usize, out: &mut [u16], parallel: bool) -> Result<()> {
343 check_out(out, width, height)?;
344 decode_v7_rows(data, bits, width, height, 0, &mut out[..width * height], parallel)
345}
346
347pub fn decode_v7_rows(
349 data: &[u8],
350 bits: u32,
351 width: usize,
352 height: usize,
353 first_row: usize,
354 out: &mut [u16],
355 parallel: bool,
356) -> Result<()> {
357 let nrows = out.len() / width.max(1);
358 if width == 0 || first_row + nrows > height {
359 return Err(Error::InvalidArgument("invalid Panasonic v7 row range".into()));
360 }
361 let ppp = packed_pixels(bits).ok_or_else(|| Error::corrupt(format!("Panasonic v7 with {bits} bits")))?;
362 let row_bytes = width / ppp * 16;
363 let rows = height / 16 * 16;
364 if row_bytes == 0 || data.len() < rows * row_bytes {
365 return Err(Error::corrupt("truncated Panasonic v7 data"));
366 }
367 par::for_each_row_chunk(&mut out[..width * nrows], width, 16, parallel, |first, chunk| {
368 for (r, row) in chunk.chunks_exact_mut(width).enumerate() {
369 let y = first_row + first + r;
370 if y >= rows {
371 row.fill(0);
372 continue;
373 }
374 let src = &data[y * row_bytes..(y + 1) * row_bytes];
375 match bits {
376 14 => unpack_lsb_row::<14, 9>(src, row),
377 _ => unpack_lsb_row::<12, 10>(src, row),
378 }
379 }
380 });
381 Ok(())
382}
383
384pub fn decode_v6(data: &[u8], bits: u32, width: usize, height: usize, out: &mut [u16], parallel: bool) -> Result<()> {
390 check_out(out, width, height)?;
391 decode_v6_rows(data, bits, width, height, 0, &mut out[..width * height], parallel)
392}
393
394pub fn decode_v6_rows(
396 data: &[u8],
397 bits: u32,
398 width: usize,
399 height: usize,
400 first_row: usize,
401 out: &mut [u16],
402 parallel: bool,
403) -> Result<()> {
404 let nrows = out.len() / width.max(1);
405 if width == 0 || first_row + nrows > height {
406 return Err(Error::InvalidArgument("invalid Panasonic v6 row range".into()));
407 }
408 let twelve = match bits {
409 12 => true,
410 14 => false,
411 _ => return Err(Error::corrupt(format!("Panasonic v6 with {bits} bits"))),
412 };
413 let ppb = if twelve { 14 } else { 11 };
414 let blocks = width / ppb;
415 let row_bytes = blocks * 16;
416 let rows = height / 16 * 16;
417 if row_bytes == 0 || data.len() < rows * row_bytes {
418 return Err(Error::corrupt("truncated Panasonic v6 data"));
419 }
420 par::for_each_row_chunk(&mut out[..width * nrows], width, 16, parallel, |first, chunk| {
421 for (r, row) in chunk.chunks_exact_mut(width).enumerate() {
422 let y = first_row + first + r;
423 if y >= rows {
424 row.fill(0);
425 continue;
426 }
427 let src = &data[y * row_bytes..(y + 1) * row_bytes];
428 for (p, px) in src.chunks_exact(16).zip(row.chunks_exact_mut(ppb)) {
429 v6_block(p.try_into().unwrap_or(&[0; 16]), twelve, px);
430 }
431 }
432 });
433 Ok(())
434}
435
436fn v6_fields(b: &[u8; 16], twelve: bool) -> ([u32; 18], usize) {
439 let w = |i: usize| b[15 - i] as u32;
441 let mut f = [0u32; 18];
442 if twelve {
443 f[0] = (w(0) << 4) | (w(1) >> 4);
444 f[1] = ((w(1) & 0xf) << 8 | w(2)) & 0xfff;
445 f[2] = (w(3) >> 6) & 0x3;
446 f[3] = ((w(3) & 0x3f) << 2) | (w(4) >> 6);
447 f[4] = ((w(4) & 0x3f) << 2) | (w(5) >> 6);
448 f[5] = ((w(5) & 0x3f) << 2) | (w(6) >> 6);
449 f[6] = (w(6) >> 4) & 0x3;
450 f[7] = ((w(6) & 0xf) << 4) | (w(7) >> 4);
451 f[8] = ((w(7) & 0xf) << 4) | (w(8) >> 4);
452 f[9] = ((w(8) & 0xf) << 4) | (w(9) >> 4);
453 f[10] = (w(9) >> 2) & 0x3;
454 f[11] = ((w(9) & 0x3) << 6) | (w(10) >> 2);
455 f[12] = ((w(10) & 0x3) << 6) | (w(11) >> 2);
456 f[13] = ((w(11) & 0x3) << 6) | (w(12) >> 2);
457 f[14] = w(12) & 0x3;
458 f[15] = w(13);
459 f[16] = w(14);
460 f[17] = w(15);
461 (f, 18)
462 } else {
463 f[0] = (w(0) << 6) | (w(1) >> 2);
464 f[1] = (((w(1) & 0x3) << 12) | (w(2) << 4) | (w(3) >> 4)) & 0x3fff;
465 f[2] = (w(3) >> 2) & 0x3;
466 f[3] = ((w(3) & 0x3) << 8) | w(4);
467 f[4] = (w(5) << 2) | (w(6) >> 6);
468 f[5] = ((w(6) & 0x3f) << 4) | (w(7) >> 4);
469 f[6] = (w(7) >> 2) & 0x3;
470 f[7] = ((w(7) & 0x3) << 8) | w(8);
471 f[8] = ((w(9) << 2) & 0x3fc) | (w(10) >> 6);
472 f[9] = ((w(10) << 4) | (w(11) >> 4)) & 0x3ff;
473 f[10] = (w(11) >> 2) & 0x3;
474 f[11] = ((w(11) & 0x3) << 8) | w(12);
475 f[12] = (((w(13) << 2) & 0x3fc) | w(14) >> 6) & 0x3ff;
476 f[13] = ((w(14) << 4) | (w(15) >> 4)) & 0x3ff;
477 (f, 14)
478 }
479}
480
481#[inline]
482fn v6_block(b: &[u8; 16], twelve: bool, out: &mut [u16]) {
483 let (f, nf) = v6_fields(b, twelve);
484 let mut next = 0usize;
485 let mut field = || {
486 let v = if next < nf { f[next] } else { 0 };
487 next += 1;
488 v
489 };
490 let (base0, base_cmp, spix_cmp, mask) =
491 if twelve { (0x80u32, 0x800u32, 0x3fffu32, 0xfffu32) } else { (0x200, 0x2000, 0xffff, 0x3fff) };
492 let mut oddeven = [0u32; 2];
493 let mut nonzero = [0u32; 2];
494 let (mut pmul, mut pixel_base) = (0u32, 0u32);
495 for (pix, o) in out.iter_mut().enumerate() {
496 if pix % 3 == 2 {
497 let mut base = field();
498 if base == 3 {
499 base = 4;
500 }
501 pixel_base = base0 << base;
502 pmul = 1 << base;
503 }
504 let mut epixel = field();
505 let c = pix % 2;
506 if oddeven[c] != 0 {
507 epixel = epixel.wrapping_mul(pmul);
508 if pixel_base < base_cmp && nonzero[c] > pixel_base {
509 epixel = epixel.wrapping_add(nonzero[c] - pixel_base);
510 }
511 nonzero[c] = epixel;
512 } else {
513 oddeven[c] = epixel;
514 if epixel != 0 {
515 nonzero[c] = epixel;
516 } else {
517 epixel = nonzero[c];
518 }
519 }
520 let spix = epixel.wrapping_sub(0xf);
521 *o = if spix <= spix_cmp {
522 (spix & spix_cmp) as u16
523 } else {
524 ((((epixel.wrapping_add(0x7fff_fff1)) as i32) >> 31) as u32 & mask) as u16
526 };
527 }
528}
529
530#[derive(Debug, Clone, Default)]
535pub struct V8Params {
536 pub gamma_points: [u32; 6],
538 pub gamma_slopes: [u32; 6],
539 pub clip: u32,
541 pub initial: [u16; 4],
543 pub codes: Vec<(u8, u16)>,
546 pub shift_down: Vec<u8>,
548}
549
550#[derive(Debug, Clone, Copy)]
552pub struct V8Strip<'a> {
553 pub data: &'a [u8],
554 pub bits: u64,
556 pub left: u32,
557 pub top: u32,
560 pub width: u32,
561 pub height: u32,
562}
563
564struct V8Lut {
566 entries: Vec<(u8, u8)>,
569 bits: u32,
570}
571
572impl V8Lut {
573 fn new(codes: &[(u8, u16)]) -> Result<Self> {
574 if codes.is_empty() || codes.len() > 17 {
575 return Err(Error::corrupt("invalid Panasonic v8 Huffman table size"));
576 }
577 let bits = codes.iter().map(|&(l, _)| l as u32).filter(|&l| l <= 16).max().unwrap_or(1).max(1);
578 let mut entries = vec![(0u8, 0u8); 1 << bits];
580 for (v, e) in entries.iter_mut().enumerate() {
581 for (sym, &(len, code)) in codes.iter().enumerate() {
582 if len == 0 || len as u32 > bits {
583 continue;
584 }
585 let shift = bits - len as u32;
586 if (v as u32 >> shift) == (code as u32 & ((1 << len) - 1)) {
587 *e = (len, sym as u8);
588 break;
589 }
590 }
591 }
592 Ok(V8Lut { entries, bits })
593 }
594}
595
596struct RevBits<'a> {
598 data: &'a [u8],
599 pos: usize,
600 cache: u64,
601 bits: u32,
602}
603
604impl<'a> RevBits<'a> {
605 fn new(data: &'a [u8]) -> Self {
606 RevBits { data, pos: 0, cache: 0, bits: 0 }
607 }
608 #[inline(always)]
609 fn fill(&mut self) {
610 if self.bits > 32 {
611 return;
612 }
613 let mut w = [0u8; 4];
615 if let Some(s) = self.data.get(self.pos..self.pos + 4) {
616 w.copy_from_slice(s);
617 } else {
618 for (k, b) in w.iter_mut().enumerate() {
619 *b = self.data.get(self.pos + k).copied().unwrap_or(0);
620 }
621 }
622 let v = u32::from_le_bytes(w).reverse_bits() as u64;
623 self.cache |= v << (32 - self.bits);
624 self.bits += 32;
625 self.pos += 4;
626 }
627 #[inline(always)]
628 fn skip(&mut self, n: u32) {
629 self.cache = if n >= 64 { 0 } else { self.cache << n };
630 self.bits -= n;
631 }
632 fn consumed(&self) -> u64 {
633 self.pos as u64 * 8 - self.bits as u64
634 }
635 fn at_bit(data: &'a [u8], bit: u64) -> Self {
637 let mut r = RevBits { data, pos: (bit / 32) as usize * 4, cache: 0, bits: 0 };
638 r.fill();
639 r.skip((bit % 32) as u32);
640 r
641 }
642}
643
644pub struct V8Decoder {
646 lut: V8Lut,
647 sym: [(u32, u32, i32, i32); 17],
650 clip: u32,
651 gamma: Option<Vec<u16>>,
652 initial: [u16; 4],
653}
654
655impl V8Decoder {
656 pub fn new(p: &V8Params) -> Result<Self> {
657 let lut = V8Lut::new(&p.codes)?;
658 let mut shift_down = [0u8; 17];
659 for (d, &s) in shift_down.iter_mut().zip(p.shift_down.iter()) {
660 *d = s.min(31);
661 }
662 let sym = std::array::from_fn(|i| {
663 let s = shift_down[i] as u32;
664 let d = (i as u32).saturating_sub(s);
665 let neg = if i > 0 { -(1i32 << i) + if s > 0 { 0 } else { 1 } } else { 0 };
666 let add = if s > 0 { 1i32 << (s - 1) } else { 0 };
667 (d, s, neg, add)
668 });
669 let curve: Vec<u16> = (0..0x10000u32).map(|i| gamma_curve(p, i)).collect();
671 let gamma = if curve.iter().enumerate().all(|(i, &v)| v as usize == i) { None } else { Some(curve) };
672 Ok(V8Decoder { lut, sym, clip: p.clip, gamma, initial: p.initial })
673 }
674
675 pub fn decode(
678 &self,
679 strips: &[V8Strip],
680 out: &mut [u16],
681 raw_width: usize,
682 raw_height: usize,
683 parallel: bool,
684 ) -> Result<()> {
685 if out.len() < raw_width * raw_height || raw_width == 0 || strips.is_empty() {
686 return Err(Error::InvalidArgument("Panasonic v8 output too small".into()));
687 }
688 let rect = |s: &V8Strip| (s.left as usize, s.top as usize, s.width as usize, s.height as usize);
690 let mut area = 0usize;
691 for (i, s) in strips.iter().enumerate() {
692 let (l, t, w, h) = rect(s);
693 if w < 2 || h < 2 || w % 2 != 0 || h % 2 != 0 || l + w > raw_width || t + h > raw_height {
694 return Err(Error::corrupt("invalid Panasonic v8 strip geometry"));
695 }
696 for o in &strips[..i] {
697 let (ol, ot, ow, oh) = rect(o);
698 if l < ol + ow && ol < l + w && t < ot + oh && ot < t + h {
699 return Err(Error::corrupt("overlapping Panasonic v8 strips"));
700 }
701 }
702 area += w * h;
703 }
704 if area != raw_width * raw_height {
705 return Err(Error::corrupt("Panasonic v8 strips do not cover the image"));
706 }
707 let mut order: Vec<usize> = (0..strips.len()).collect();
709 order.sort_by_key(|&i| (strips[i].top, strips[i].left));
710 let mut segments: Vec<Vec<&mut [u16]>> = strips.iter().map(|s| Vec::with_capacity(s.height as usize)).collect();
711 for (y, row) in out[..raw_width * raw_height].chunks_exact_mut(raw_width).enumerate() {
712 let mut rest = row;
713 let mut consumed = 0usize;
714 for &i in &order {
715 let (l, t, w, h) = rect(&strips[i]);
716 if y < t || y >= t + h {
717 continue;
718 }
719 let (_, tail) = std::mem::take(&mut rest).split_at_mut(l - consumed);
720 let (seg, tail) = tail.split_at_mut(w);
721 segments[i].push(seg);
722 rest = tail;
723 consumed = l + w;
724 }
725 }
726 let jobs: Vec<(usize, Vec<&mut [u16]>)> = segments.into_iter().enumerate().collect();
727 let results = par::map(jobs, parallel, |(i, rows)| self.decode_strip_with(&strips[i], rows, parallel));
728 results.into_iter().collect::<Result<Vec<()>>>().map(|_| ())
729 }
730
731 pub fn decode_strip(&self, s: &V8Strip, rows: Vec<&mut [u16]>) -> Result<()> {
733 self.decode_strip_with(s, rows, false)
734 }
735
736 fn decode_strip_with(&self, s: &V8Strip, rows: Vec<&mut [u16]>, parallel: bool) -> Result<()> {
737 let (w, h) = (s.width as usize, s.height as usize);
738 if w / 2 == 0 || h / 2 == 0 || rows.len() < h || rows.iter().any(|r| r.len() < w) {
739 return Err(Error::corrupt("invalid Panasonic v8 strip"));
740 }
741 if parallel && w * h >= crate::ljpeg_par::PARALLEL_MIN_SAMPLES / 4 {
742 if let Some(rows) = self.decode_strip_parallel(s, rows, None)? {
743 return self.decode_strip_seq(s, rows);
745 }
746 return Ok(());
747 }
748 self.decode_strip_seq(s, rows)
749 }
750
751 fn decode_strip_seq(&self, s: &V8Strip, mut rows: Vec<&mut [u16]>) -> Result<()> {
752 match &self.gamma {
753 Some(t) => self.decode_rows_seq::<true>(s, &mut rows, t),
754 None => self.decode_rows_seq::<false>(s, &mut rows, &[]),
755 }
756 }
757
758 fn decode_rows_seq<const GAMMA: bool>(&self, s: &V8Strip, rows: &mut [&mut [u16]], curve: &[u16]) -> Result<()> {
759 let (w, h) = (s.width as usize, s.height as usize);
760 let half_w = w / 2;
761 let budget = s.bits.div_ceil(64) * 64;
762 let mut bits = RevBits::new(s.data);
763 let clip = self.clip as i32;
764 let mut line_base = self.initial.map(|v| v as i32);
765 let mut err = false;
766 for pair in 0..h / 2 {
767 let mut base = line_base;
768 let (top, bottom) = rows[pair * 2..pair * 2 + 2].split_at_mut(1);
769 let (r0, r1) = (&mut *top[0], &mut *bottom[0]);
770 for bx in 0..half_w {
771 let mut blk = [0i32; 4];
772 for slot in [0usize, 2, 1, 3] {
774 let delta = self.diff(&mut bits, &mut err);
775 blk[slot] = (base[slot] + delta).clamp(0, clip);
776 }
777 base = blk;
778 if bx == 0 {
779 line_base = blk;
780 }
781 let g = |v: i32| if GAMMA { curve[v as usize & 0xffff] } else { v as u16 };
782 r0[2 * bx] = g(blk[0]);
783 r0[2 * bx + 1] = g(blk[1]);
784 r1[2 * bx] = g(blk[2]);
785 r1[2 * bx + 1] = g(blk[3]);
786 }
787 if err {
788 return Err(Error::corrupt("invalid Panasonic v8 Huffman code"));
789 }
790 if bits.consumed() > budget {
791 return Err(Error::corrupt("truncated Panasonic v8 strip"));
792 }
793 }
794 Ok(())
795 }
796
797 fn decode_strip_parallel<'r>(
802 &self,
803 s: &V8Strip,
804 rows: Vec<&'r mut [u16]>,
805 chunk: Option<usize>,
806 ) -> Result<Option<Vec<&'r mut [u16]>>> {
807 let (w, h) = (s.width as usize, s.height as usize);
808 let (half_w, pairs) = (w / 2, h / 2);
809 let budget = s.bits.div_ceil(64) * 64;
810 let scan = V8Scan { data: s.data, dec: self, budget };
811 let Some(chunk) = chunk.or_else(|| crate::par_entropy::default_chunk(s.data.len())) else {
812 return Ok(Some(rows));
813 };
814 let Some(values) = crate::par_entropy::decode(&scan, pairs * half_w * 4, chunk) else {
815 return Ok(Some(rows));
816 };
817 let delta = |k: usize| -> i32 { (values.get(2 * k) as u32 | (values.get(2 * k + 1) as u32) << 16) as i32 };
818 let clip = self.clip as i32;
819 let mut starts = Vec::with_capacity(pairs);
821 let mut line_base = self.initial.map(|v| v as i32);
822 for pair in 0..pairs {
823 starts.push(line_base);
824 let k0 = pair * half_w * 4;
825 let mut blk = [0i32; 4];
826 for (j, slot) in [0usize, 2, 1, 3].into_iter().enumerate() {
827 blk[slot] = (line_base[slot] + delta(k0 + j)).clamp(0, clip);
828 }
829 line_base = blk;
830 }
831 let mut it = rows.into_iter();
832 let jobs: Vec<(usize, &mut [u16], &mut [u16])> =
833 (0..pairs).filter_map(|p| Some((p, it.next()?, it.next()?))).collect();
834 par::map(jobs, true, |(pair, r0, r1)| {
835 let mut buf = vec![0u16; half_w * 8];
836 values.copy_to(pair * half_w * 8, &mut buf);
837 let mut base = starts[pair];
838 for (bx, d) in buf.chunks_exact(8).enumerate() {
839 let mut blk = [0i32; 4];
840 for (j, slot) in [0usize, 2, 1, 3].into_iter().enumerate() {
841 let delta = (d[2 * j] as u32 | (d[2 * j + 1] as u32) << 16) as i32;
842 blk[slot] = (base[slot] + delta).clamp(0, clip);
843 }
844 base = blk;
845 let g = |v: i32| match &self.gamma {
846 Some(t) => t[v as usize & 0xffff],
847 None => v as u16,
848 };
849 r0[2 * bx] = g(blk[0]);
850 r0[2 * bx + 1] = g(blk[1]);
851 r1[2 * bx] = g(blk[2]);
852 r1[2 * bx + 1] = g(blk[3]);
853 }
854 });
855 Ok(None)
856 }
857
858 #[inline(always)]
861 fn diff(&self, bits: &mut RevBits, err: &mut bool) -> i32 {
862 bits.fill();
864 let window = bits.cache;
865 let (len, sym) = self.lut.entries[(window >> (64 - self.lut.bits)) as usize];
866 if len == 0 {
867 *err = true;
868 bits.skip(1);
869 return 0;
870 }
871 let (d, s, neg, add) = self.sym[sym as usize];
872 let after = window << len;
873 bits.skip(len as u32 + d);
874 let positive = (after >> 63) == 1;
877 let raw = if d > 0 { (after >> (64 - d)) as i32 } else { 0 };
878 (raw << s) + if positive { 0 } else { neg } + add
879 }
880}
881
882struct V8Scan<'a> {
884 data: &'a [u8],
885 dec: &'a V8Decoder,
886 budget: u64,
887}
888
889impl crate::par_entropy::SymbolStream for V8Scan<'_> {
890 type Pump<'p>
891 = RevBits<'p>
892 where
893 Self: 'p;
894 const WIDTH: usize = 2;
895 fn cycle(&self) -> usize {
896 1
897 }
898 fn period(&self) -> usize {
899 1
900 }
901 fn total_bits(&self) -> u64 {
902 self.budget
903 }
904 fn end_check(&self, pos: u64) -> crate::par_entropy::EndCheck {
905 if pos <= self.budget { crate::par_entropy::EndCheck::Valid } else { crate::par_entropy::EndCheck::Invalid }
906 }
907 fn pump_at(&self, bit: u64) -> RevBits<'_> {
908 RevBits::at_bit(self.data, bit)
909 }
910 fn position(p: &RevBits<'_>) -> u64 {
911 p.consumed()
912 }
913 #[inline(always)]
914 fn decode(&self, p: &mut RevBits<'_>, _phase: usize, out: &mut [u16]) -> bool {
915 let mut err = false;
916 let d = self.dec.diff(p, &mut err);
917 out[0] = d as u32 as u16;
918 out[1] = (d as u32 >> 16) as u16;
919 !err
920 }
921}
922
923fn gamma_curve(p: &V8Params, idx: u32) -> u16 {
925 let t3a = &p.gamma_points;
926 let t39 = &p.gamma_slopes;
927 let v2 = if idx & 0x10000 == 0 { idx & 0x1ffff } else { idx | 0xffff_0000 };
928 let mut v4 = v2.min(0xffff);
929 if v4 & 0x8000_0000 != 0 {
930 v4 = 0;
931 }
932 let mut seg = 0usize;
933 if v4 >= (t3a[1] & 0xffff) {
934 seg = 1;
935 if v4 >= (t3a[2] & 0xffff) {
936 seg = 2;
937 if v4 >= (t3a[3] & 0xffff) {
938 seg = 3;
939 if v4 >= (t3a[4] & 0xffff) {
940 seg = (((v4 as u64 | 0x5_0000_0000) - (t3a[5] & 0xffff) as u64) >> 32) as usize;
941 }
942 }
943 }
944 }
945 let seg = seg.min(5);
946 let v6 = t3a[seg];
947 let v7 = t39[seg];
948 let mut v8 = v4.wrapping_sub(v6 & 0xffff);
949 let v9 = v7 & 0x1f;
950 let clip = p.clip;
951 let res: u64 = if v9 == 31 {
952 if seg == 5 { 0xffff } else { ((t3a[seg + 1] >> 16) & 0xffff) as u64 }
953 } else if v7 & 0x10 == 0 && v9 == 15 {
954 ((v6 >> 16) & 0xffff) as u64
955 } else {
956 if v7 & 0x10 == 0 {
957 if v9 != 0 {
958 v8 = (v8.wrapping_add(1 << (v9 - 1))) >> v9;
959 }
960 } else {
961 v8 = v8.wrapping_shl(v7 & 0xf);
962 }
963 v8 as u64 + ((v6 >> 16) & 0xffff) as u64
964 };
965 res.min(clip as u64) as u16
966}
967
968#[cfg(test)]
969mod tests {
970 use super::*;
971
972 fn pseudo(n: usize, seed: u64) -> Vec<u8> {
973 let mut x = seed;
974 (0..n)
975 .map(|_| {
976 x ^= x << 13;
977 x ^= x >> 7;
978 x ^= x << 17;
979 (x >> 24) as u8
980 })
981 .collect()
982 }
983
984 #[test]
985 fn blocked_stream_rotation() {
986 let data: Vec<u8> = (0..BLOCK).map(|i| (i % 251) as u8).collect();
988 let s = BlockedStream::new(&data, 0x2008).unwrap();
989 assert_eq!(s.packet(0)[0], data[BLOCK - 0x2008]);
990 assert_eq!(s.packet(0x2008 / 16 + 1)[0], data[8]);
991 let p = s.packet(0x2000 / 16);
993 for (k, &v) in p.iter().enumerate() {
994 let i = 0x2000 + k;
995 assert_eq!(v, data[(i + BLOCK - 0x2008) % BLOCK]);
996 }
997 }
998
999 #[test]
1000 fn v4_parallel_matches_sequential_reference() {
1001 for (w, h, extra) in [(28usize, 9usize, 0usize), (14 * 37, 31, 100), (14 * 5, 4, 0)] {
1002 let packets = (w * h).div_ceil(14);
1003 let mut data = pseudo(packets * 16 + extra, w as u64);
1004 data.truncate(data.len() - extra.min(data.len() / 2));
1006 let s = BlockedStream::new(&data, 0x2008).unwrap();
1007 let mut a = vec![0u16; w * h];
1008 let mut b = vec![0u16; w * h];
1009 if decode_v4(&s, w, h, &mut a, true).is_ok() {
1010 decode_v4_sequential(&s, w, h, &mut b).unwrap();
1011 assert_eq!(a, b, "{w}x{h}");
1012 }
1013 }
1014 let data = pseudo(4 * BLOCK, 7);
1016 let s = BlockedStream::new(&data, 0x2008).unwrap();
1017 let mut a = vec![0u16; 30 * 20];
1018 decode_v4(&s, 30, 20, &mut a, true).unwrap();
1019 }
1020
1021 #[test]
1022 fn v4_packet_known_values() {
1023 let mut out = [9u16; 14];
1025 v4_packet(&[0; 16], &mut out);
1026 assert_eq!(out, [0; 14]);
1027 let mut v: u128 = 0x12 << 120 | 0x3 << 116;
1029 v |= 0x01 << 108; let mut out = [0u16; 14];
1031 v4_packet(&v.to_le_bytes(), &mut out);
1032 assert_eq!(out[0], 0x123);
1033 assert_eq!(out[1], 0x010);
1034 }
1035
1036 #[test]
1037 fn v5_v7_unpack_roundtrip() {
1038 for bits in [12u32, 14] {
1039 let ppp = packed_pixels(bits).unwrap();
1040 let (w, h) = (ppp * 3, 16);
1041 let vals: Vec<u16> = (0..w * h).map(|i| ((i * 2654435761) >> 7) as u16 & ((1 << bits) - 1)).collect();
1042 let mut data = Vec::new();
1043 for row in vals.chunks(w) {
1044 for px in row.chunks(ppp) {
1045 let mut v: u128 = 0;
1046 for (k, &p) in px.iter().enumerate() {
1047 v |= (p as u128) << (bits as usize * k);
1048 }
1049 data.extend_from_slice(&v.to_le_bytes());
1050 }
1051 }
1052 let mut out = vec![0u16; w * h];
1053 decode_v7(&data, bits, w, h, &mut out, true).unwrap();
1054 assert_eq!(out, vals);
1055 let s = BlockedStream::new(&data, 0).unwrap();
1057 let mut out5 = vec![0u16; w * h];
1058 decode_v5(&s, bits, w, h, &mut out5, false).unwrap();
1059 assert_eq!(out5, vals);
1060 assert!(decode_v7(&data[..data.len() / 2], bits, w, h, &mut out, true).is_err());
1061 }
1062 }
1063
1064 #[test]
1065 fn v6_does_not_panic_and_rejects_truncation() {
1066 for bits in [12u32, 14] {
1067 let (w, h) = (154usize, 32usize);
1068 let ppb = if bits == 12 { 14 } else { 11 };
1069 let data = pseudo(w / ppb * 16 * h, bits as u64);
1070 let mut out = vec![0u16; w * h];
1071 decode_v6(&data, bits, w, h, &mut out, true).unwrap();
1072 assert!(out.iter().all(|&v| (v as u32) < if bits == 12 { 1 << 14 } else { 1 << 16 }));
1074 assert!(decode_v6(&data[..100], bits, w, h, &mut out, true).is_err());
1075 }
1076 }
1077
1078 fn v8_encode(vals: &[u16], w: usize, h: usize, codes: &[(u8, u16)], init: [u16; 4]) -> Vec<u8> {
1081 let mut bitsv: Vec<bool> = Vec::new();
1082 let put = |v: u32, n: u32, bitsv: &mut Vec<bool>| {
1083 for k in (0..n).rev() {
1084 bitsv.push(v >> k & 1 == 1);
1085 }
1086 };
1087 let mut line_base = init.map(|v| v as i32);
1088 for pair in 0..h / 2 {
1089 let mut base = line_base;
1090 for bx in 0..w / 2 {
1091 let blk = [
1092 vals[pair * 2 * w + 2 * bx] as i32,
1093 vals[pair * 2 * w + 2 * bx + 1] as i32,
1094 vals[(pair * 2 + 1) * w + 2 * bx] as i32,
1095 vals[(pair * 2 + 1) * w + 2 * bx + 1] as i32,
1096 ];
1097 for slot in [0usize, 2, 1, 3] {
1098 let d = blk[slot] - base[slot];
1099 let cat = if d == 0 { 0 } else { 32 - d.unsigned_abs().leading_zeros() };
1100 let (len, code) = codes[cat as usize];
1101 put(code as u32, len as u32, &mut bitsv);
1102 if cat > 0 {
1103 let m = if d > 0 { d as u32 } else { (d + (1 << cat) - 1) as u32 };
1104 put(m, cat, &mut bitsv);
1105 }
1106 }
1107 base = blk;
1108 if bx == 0 {
1109 line_base = blk;
1110 }
1111 }
1112 }
1113 let mut bytes = vec![0u8; bitsv.len().div_ceil(8) + 8];
1114 for (i, &b) in bitsv.iter().enumerate() {
1115 if b {
1116 bytes[i / 8] |= 1 << (i % 8);
1118 }
1119 }
1120 bytes
1121 }
1122
1123 #[test]
1124 fn v8_roundtrip() {
1125 let codes: Vec<(u8, u16)> = vec![
1127 (10, 1022),
1128 (11, 2046),
1129 (8, 254),
1130 (9, 510),
1131 (7, 126),
1132 (4, 14),
1133 (4, 12),
1134 (3, 4),
1135 (3, 2),
1136 (2, 0),
1137 (3, 3),
1138 (3, 5),
1139 (4, 13),
1140 (5, 30),
1141 (6, 62),
1142 (12, 4094),
1143 (12, 4095),
1144 ];
1145 let (w, h) = (24usize, 10usize);
1146 let vals: Vec<u16> = (0..w * h).map(|i| ((i * 7919) % 65536) as u16).collect();
1147 let data = v8_encode(&vals, w, h, &codes, [100, 200, 300, 400]);
1148 let p = V8Params {
1149 gamma_points: [0; 6],
1150 gamma_slopes: [65536; 6],
1151 clip: 65535,
1152 initial: [100, 200, 300, 400],
1153 codes: codes.clone(),
1154 shift_down: vec![0; 17],
1155 };
1156 let dec = V8Decoder::new(&p).unwrap();
1157 assert!(dec.gamma.is_none());
1158 let strip =
1159 V8Strip { data: &data, bits: (data.len() * 8) as u64, left: 0, top: 0, width: w as u32, height: h as u32 };
1160 let mut out = vec![0u16; w * h];
1161 dec.decode(&[strip], &mut out, w, h, true).unwrap();
1162 assert_eq!(out, vals);
1163 let short = V8Strip { data: &data[..data.len() / 3], bits: (data.len() / 3 * 8) as u64, ..strip };
1165 assert!(dec.decode(&[short], &mut out, w, h, true).is_err());
1166 for chunk in [3usize, 17, 64, 1 << 20] {
1168 let mut par = vec![0u16; w * h];
1169 let rows: Vec<&mut [u16]> = par.chunks_exact_mut(w).collect();
1170 assert!(dec.decode_strip_parallel(&strip, rows, Some(chunk)).unwrap().is_none(), "chunk {chunk}");
1171 assert_eq!(par, vals, "chunk {chunk}");
1172 }
1173 }
1174}