1#[derive(Debug, Clone)]
29pub struct Image {
30 pub width: usize,
31 pub height: usize,
32 pub channels: usize,
33 pub data: Vec<u8>,
34 pub adobe_inverted: bool,
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
41pub enum Error {
42 Unsupported(&'static str),
43 Corrupt(&'static str),
44}
45
46#[derive(Debug, Clone, Copy)]
48pub struct Info {
49 pub width: usize,
50 pub height: usize,
51 pub components: usize,
52}
53
54const ZIGZAG: [usize; 64] = [
55 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20,
56 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59,
57 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
58];
59
60#[derive(Clone, Default)]
61struct Huffman {
62 maxcode: [i32; 18],
66 valptr: [i32; 17],
67 mincode: [i32; 17],
68 values: Vec<u8>,
69 present: bool,
70}
71
72impl Huffman {
73 fn build(bits: &[u8; 16], values: Vec<u8>) -> Result<Self, Error> {
74 let mut h = Huffman {
75 values,
76 present: true,
77 ..Default::default()
78 };
79 let mut code: i32 = 0;
80 let mut k: i32 = 0;
81 for l in 1..=16usize {
82 let n = i32::from(bits[l - 1]);
83 if n == 0 {
84 h.maxcode[l] = -1;
85 } else {
86 h.valptr[l] = k;
87 h.mincode[l] = code;
88 code += n;
89 k += n;
90 h.maxcode[l] = code - 1;
91 }
92 code <<= 1;
93 }
94 h.maxcode[17] = i32::MAX;
95 if k as usize != h.values.len() {
96 return Err(Error::Corrupt("DHT value count"));
97 }
98 Ok(h)
99 }
100}
101
102struct Reader<'a> {
103 data: &'a [u8],
104 pos: usize,
105 acc: u64,
106 nbits: u32,
107 marker: Option<u8>,
110}
111
112impl<'a> Reader<'a> {
113 fn new(data: &'a [u8], pos: usize) -> Self {
114 Reader {
115 data,
116 pos,
117 acc: 0,
118 nbits: 0,
119 marker: None,
120 }
121 }
122
123 fn fill(&mut self) {
124 while self.nbits <= 56 {
125 let byte = if self.marker.is_some() {
126 0
127 } else {
128 match self.data.get(self.pos) {
129 None => {
130 self.marker = Some(0xD9);
131 0
132 }
133 Some(&0xFF) => {
134 let next = self.data.get(self.pos + 1).copied().unwrap_or(0xD9);
135 if next == 0 {
136 self.pos += 2;
137 0xFF
138 } else if next == 0xFF {
139 self.pos += 1;
141 continue;
142 } else {
143 self.marker = Some(next);
144 0
145 }
146 }
147 Some(&b) => {
148 self.pos += 1;
149 b
150 }
151 }
152 };
153 self.acc |= u64::from(byte) << (56 - self.nbits);
154 self.nbits += 8;
155 }
156 }
157
158 fn bits(&mut self, n: u32) -> u32 {
159 if n == 0 {
160 return 0;
161 }
162 if self.nbits < n {
163 self.fill();
164 }
165 let v = (self.acc >> (64 - n)) as u32;
166 self.acc <<= n;
167 self.nbits -= n;
168 v
169 }
170
171 fn bit(&mut self) -> u32 {
172 self.bits(1)
173 }
174
175 fn receive_extend(&mut self, s: u32) -> i32 {
177 if s == 0 {
178 return 0;
179 }
180 let v = self.bits(s) as i32;
181 if v < (1 << (s - 1)) {
182 v - (1 << s) + 1
183 } else {
184 v
185 }
186 }
187
188 fn decode(&mut self, h: &Huffman) -> Result<u8, Error> {
189 if !h.present {
190 return Err(Error::Corrupt("missing Huffman table"));
191 }
192 let mut code = self.bit() as i32;
193 let mut l = 1usize;
194 while code > h.maxcode[l] {
195 code = (code << 1) | self.bit() as i32;
196 l += 1;
197 if l > 16 {
198 return Ok(0);
200 }
201 }
202 let idx = h.valptr[l] + code - h.mincode[l];
203 Ok(h.values.get(idx as usize).copied().unwrap_or(0))
204 }
205
206 fn reset(&mut self) {
208 self.acc = 0;
209 self.nbits = 0;
210 self.marker = None;
211 }
212
213 fn marker_position(&self) -> usize {
215 if self.marker.is_some() {
218 return self.pos;
219 }
220 let mut p = self.pos;
221 while p + 1 < self.data.len() {
222 if self.data[p] == 0xFF && self.data[p + 1] != 0 && self.data[p + 1] != 0xFF {
223 return p;
224 }
225 p += 1;
226 }
227 self.data.len()
228 }
229}
230
231struct Component {
232 id: u8,
233 h: usize,
234 v: usize,
235 tq: usize,
236 bw: usize,
238 bh: usize,
239 dw: usize,
242 dh: usize,
243 dct: usize,
247 coefs: Vec<i16>,
250 samples: Vec<u8>,
252 dc_tbl: usize,
253 ac_tbl: usize,
254 dc_pred: i32,
255}
256
257#[derive(Clone, Copy, PartialEq, Eq, Debug)]
258enum ColorSpace {
259 Gray,
260 YCbCr,
261 Rgb,
262}
263
264struct Decoder<'a> {
265 data: &'a [u8],
266 qt: [[u16; 64]; 4],
267 qt_present: [bool; 4],
268 dc: [Huffman; 4],
269 ac: [Huffman; 4],
270 comps: Vec<Component>,
271 width: usize,
272 height: usize,
273 hmax: usize,
274 vmax: usize,
275 mcux: usize,
276 mcuy: usize,
277 progressive: bool,
278 restart_interval: usize,
279 saw_jfif: bool,
280 adobe_transform: Option<u8>,
281 eobrun: u32,
282 min_dct: usize,
284}
285
286pub fn info(data: &[u8]) -> Result<Info, Error> {
288 let mut d = Decoder::new(data, 1)?;
289 d.run(true)?;
290 Ok(Info {
291 width: d.width,
292 height: d.height,
293 components: d.comps.len(),
294 })
295}
296
297pub fn decode(data: &[u8], color_transform: bool, scale_denom: u32) -> Result<Image, Error> {
305 let mut d = Decoder::new(data, scale_denom)?;
306 d.run(false)?;
307 d.finish(color_transform)
308}
309
310impl<'a> Decoder<'a> {
311 fn new(data: &'a [u8], scale_denom: u32) -> Result<Self, Error> {
312 let min_dct = match scale_denom {
314 1 => 8,
315 2 => 4,
316 4 => 2,
317 8 => 1,
318 _ => return Err(Error::Unsupported("DCT scale")),
319 };
320 Ok(Decoder {
321 data,
322 qt: [[0; 64]; 4],
323 qt_present: [false; 4],
324 dc: Default::default(),
325 ac: Default::default(),
326 comps: Vec::new(),
327 width: 0,
328 height: 0,
329 hmax: 1,
330 vmax: 1,
331 mcux: 0,
332 mcuy: 0,
333 progressive: false,
334 restart_interval: 0,
335 saw_jfif: false,
336 adobe_transform: None,
337 eobrun: 0,
338 min_dct,
339 })
340 }
341
342 fn u16_at(&self, p: usize) -> Result<usize, Error> {
343 match (self.data.get(p), self.data.get(p + 1)) {
344 (Some(&a), Some(&b)) => Ok(usize::from(a) << 8 | usize::from(b)),
345 _ => Err(Error::Corrupt("truncated")),
346 }
347 }
348
349 fn run(&mut self, header_only: bool) -> Result<(), Error> {
351 let mut p = 0usize;
352 while p + 1 < self.data.len() && !(self.data[p] == 0xFF && self.data[p + 1] == 0xD8) {
355 p += 1;
356 }
357 if p + 1 >= self.data.len() {
358 return Err(Error::Corrupt("no SOI"));
359 }
360 p += 2;
361 loop {
362 while p < self.data.len() && self.data[p] != 0xFF {
364 p += 1;
365 }
366 while p < self.data.len() && self.data[p] == 0xFF {
367 p += 1;
368 }
369 let Some(&marker) = self.data.get(p) else {
370 return if self.comps.is_empty() {
371 Err(Error::Corrupt("no frame"))
372 } else {
373 Ok(())
374 };
375 };
376 p += 1;
377 match marker {
378 0xD8 | 0x01 | 0xD0..=0xD7 => continue, 0xD9 => return Ok(()), _ => {}
381 }
382 let len = self.u16_at(p)?;
383 if len < 2 {
384 return Err(Error::Corrupt("segment length"));
385 }
386 let seg = self
387 .data
388 .get(p + 2..p + len)
389 .ok_or(Error::Corrupt("truncated segment"))?;
390 match marker {
391 0xC0..=0xC2 => {
392 self.progressive = marker == 0xC2;
393 self.frame(seg)?;
394 }
395 0xC3 | 0xC5..=0xC7 | 0xC9..=0xCB | 0xCD..=0xCF => {
396 return Err(Error::Unsupported(
397 "lossless, hierarchical or arithmetic JPEG",
398 ));
399 }
400 0xC4 => self.dht(seg)?,
401 0xDB => self.dqt(seg)?,
402 0xDD => {
403 if seg.len() < 2 {
404 return Err(Error::Corrupt("DRI"));
405 }
406 self.restart_interval = usize::from(seg[0]) << 8 | usize::from(seg[1]);
407 }
408 0xDC => return Err(Error::Unsupported("DNL")),
409 0xE0 => {
410 if seg.starts_with(b"JFIF\0") {
411 self.saw_jfif = true;
412 }
413 }
414 0xEE => {
415 if seg.starts_with(b"Adobe") && seg.len() >= 12 {
416 self.adobe_transform = Some(seg[11]);
417 }
418 }
419 0xDA => {
420 if header_only {
421 return if self.comps.is_empty() {
422 Err(Error::Corrupt("SOS before SOF"))
423 } else {
424 Ok(())
425 };
426 }
427 let end = self.scan(seg, p + len)?;
428 p = end;
429 continue;
430 }
431 _ => {}
432 }
433 p += len;
434 }
435 }
436
437 fn frame(&mut self, seg: &[u8]) -> Result<(), Error> {
438 if seg.len() < 6 {
439 return Err(Error::Corrupt("SOF"));
440 }
441 if seg[0] != 8 {
442 return Err(Error::Unsupported("sample precision other than 8"));
443 }
444 self.height = usize::from(seg[1]) << 8 | usize::from(seg[2]);
445 self.width = usize::from(seg[3]) << 8 | usize::from(seg[4]);
446 let n = usize::from(seg[5]);
447 if self.height == 0 {
448 return Err(Error::Unsupported("DNL-defined height"));
449 }
450 if self.width == 0 || !(n == 1 || n == 3 || n == 4) {
451 return Err(Error::Unsupported("component count"));
452 }
453 if seg.len() < 6 + 3 * n {
454 return Err(Error::Corrupt("SOF components"));
455 }
456 self.comps.clear();
457 for i in 0..n {
458 let c = &seg[6 + 3 * i..9 + 3 * i];
459 let (h, v) = (usize::from(c[1] >> 4), usize::from(c[1] & 15));
460 if !(1..=4).contains(&h) || !(1..=4).contains(&v) || c[2] > 3 {
461 return Err(Error::Corrupt("sampling factors"));
462 }
463 self.comps.push(Component {
464 id: c[0],
465 h,
466 v,
467 tq: usize::from(c[2]),
468 bw: 0,
469 bh: 0,
470 dw: 0,
471 dh: 0,
472 dct: 8,
473 coefs: Vec::new(),
474 samples: Vec::new(),
475 dc_tbl: 0,
476 ac_tbl: 0,
477 dc_pred: 0,
478 });
479 }
480 self.hmax = self.comps.iter().map(|c| c.h).max().unwrap_or(1);
481 self.vmax = self.comps.iter().map(|c| c.v).max().unwrap_or(1);
482 self.mcux = self.width.div_ceil(8 * self.hmax);
483 self.mcuy = self.height.div_ceil(8 * self.vmax);
484 let (w, h, hmax, vmax, mcux, mcuy, progressive, min_dct) = (
485 self.width,
486 self.height,
487 self.hmax,
488 self.vmax,
489 self.mcux,
490 self.mcuy,
491 self.progressive,
492 self.min_dct,
493 );
494 for c in &mut self.comps {
495 c.bw = mcux * c.h;
496 c.bh = mcuy * c.v;
497 let mut ssize = min_dct;
502 while ssize < 8
503 && (hmax * min_dct) % (c.h * ssize * 2) == 0
504 && (vmax * min_dct) % (c.v * ssize * 2) == 0
505 {
506 ssize *= 2;
507 }
508 c.dct = ssize;
509 c.dw = (w * c.h * c.dct).div_ceil(hmax * 8);
510 c.dh = (h * c.v * c.dct).div_ceil(vmax * 8);
511 let blocks = c.bw * c.bh;
512 if blocks > (1usize << 26) {
513 return Err(Error::Unsupported("image too large"));
514 }
515 if progressive {
516 c.coefs = vec![0; blocks * 64];
517 }
518 c.samples = vec![0; blocks * c.dct * c.dct];
519 }
520 Ok(())
521 }
522
523 fn dht(&mut self, mut seg: &[u8]) -> Result<(), Error> {
524 while !seg.is_empty() {
525 if seg.len() < 17 {
526 return Err(Error::Corrupt("DHT"));
527 }
528 let class = seg[0] >> 4;
529 let id = usize::from(seg[0] & 15);
530 if id > 3 || class > 1 {
531 return Err(Error::Corrupt("DHT id"));
532 }
533 let mut bits = [0u8; 16];
534 bits.copy_from_slice(&seg[1..17]);
535 let total: usize = bits.iter().map(|&b| usize::from(b)).sum();
536 if total > 256 || seg.len() < 17 + total {
537 return Err(Error::Corrupt("DHT counts"));
538 }
539 let table = Huffman::build(&bits, seg[17..17 + total].to_vec())?;
540 if class == 0 {
541 self.dc[id] = table;
542 } else {
543 self.ac[id] = table;
544 }
545 seg = &seg[17 + total..];
546 }
547 Ok(())
548 }
549
550 fn dqt(&mut self, mut seg: &[u8]) -> Result<(), Error> {
551 while !seg.is_empty() {
552 let pq = seg[0] >> 4;
553 let tq = usize::from(seg[0] & 15);
554 if tq > 3 || pq > 1 {
555 return Err(Error::Corrupt("DQT id"));
556 }
557 let n = if pq == 0 { 64 } else { 128 };
558 if seg.len() < 1 + n {
559 return Err(Error::Corrupt("DQT"));
560 }
561 for k in 0..64 {
562 let v = if pq == 0 {
563 u16::from(seg[1 + k])
564 } else {
565 u16::from(seg[1 + 2 * k]) << 8 | u16::from(seg[2 + 2 * k])
566 };
567 self.qt[tq][ZIGZAG[k]] = v;
568 }
569 self.qt_present[tq] = true;
570 seg = &seg[1 + n..];
571 }
572 Ok(())
573 }
574
575 fn scan(&mut self, seg: &[u8], start: usize) -> Result<usize, Error> {
578 if self.comps.is_empty() {
579 return Err(Error::Corrupt("SOS before SOF"));
580 }
581 let ns = usize::from(*seg.first().ok_or(Error::Corrupt("SOS"))?);
582 if ns == 0 || ns > 4 || seg.len() < 1 + 2 * ns + 3 {
583 return Err(Error::Corrupt("SOS"));
584 }
585 let mut in_scan = Vec::with_capacity(ns);
586 for i in 0..ns {
587 let cs = seg[1 + 2 * i];
588 let t = seg[2 + 2 * i];
589 let ci = self
590 .comps
591 .iter()
592 .position(|c| c.id == cs)
593 .ok_or(Error::Corrupt("SOS component"))?;
594 self.comps[ci].dc_tbl = usize::from(t >> 4).min(3);
595 self.comps[ci].ac_tbl = usize::from(t & 15).min(3);
596 in_scan.push(ci);
597 }
598 let ss = usize::from(seg[1 + 2 * ns]);
599 let se = usize::from(seg[2 + 2 * ns]);
600 let ah = u32::from(seg[3 + 2 * ns] >> 4);
601 let al = u32::from(seg[3 + 2 * ns] & 15);
602 if self.progressive {
603 if ss > se || se > 63 || (ss == 0 && se != 0) || (ss > 0 && ns != 1) || al > 13 {
604 return Err(Error::Corrupt("progressive scan parameters"));
605 }
606 } else if ss != 0 || se != 63 || ah != 0 || al != 0 {
607 return Err(Error::Corrupt("sequential scan parameters"));
608 }
609 for c in &mut self.comps {
610 c.dc_pred = 0;
611 }
612 self.eobrun = 0;
613 let mut rd = Reader::new(self.data, start);
614
615 let (mcus_x, mcus_y) = if ns == 1 {
622 let c = &self.comps[in_scan[0]];
623 (
624 (self.width * c.h).div_ceil(self.hmax * 8),
625 (self.height * c.v).div_ceil(self.vmax * 8),
626 )
627 } else {
628 (self.mcux, self.mcuy)
629 };
630 let total = mcus_x * mcus_y;
631 let mut count = 0usize;
632 for my in 0..mcus_y {
633 for mx in 0..mcus_x {
634 if self.restart_interval > 0 && count > 0 && count % self.restart_interval == 0 {
635 self.restart(&mut rd);
636 }
637 if ns == 1 {
638 let ci = in_scan[0];
639 self.block(&mut rd, ci, mx, my, ss, se, ah, al)?;
640 } else {
641 for &ci in &in_scan {
642 let (h, v) = (self.comps[ci].h, self.comps[ci].v);
643 for by in 0..v {
644 for bx in 0..h {
645 self.block(&mut rd, ci, mx * h + bx, my * v + by, ss, se, ah, al)?;
646 }
647 }
648 }
649 }
650 count += 1;
651 if count == total {
652 break;
653 }
654 }
655 }
656 Ok(rd.marker_position())
657 }
658
659 fn restart(&mut self, rd: &mut Reader<'_>) {
662 let mut p = rd.marker_position();
663 while p < self.data.len() && self.data[p] == 0xFF {
665 p += 1;
666 }
667 if p < self.data.len() && (0xD0..=0xD7).contains(&self.data[p]) {
668 p += 1;
669 }
670 rd.reset();
671 rd.pos = p;
672 for c in &mut self.comps {
673 c.dc_pred = 0;
674 }
675 self.eobrun = 0;
676 }
677
678 #[allow(clippy::too_many_arguments)]
679 fn block(
680 &mut self,
681 rd: &mut Reader<'_>,
682 ci: usize,
683 bx: usize,
684 by: usize,
685 ss: usize,
686 se: usize,
687 ah: u32,
688 al: u32,
689 ) -> Result<(), Error> {
690 let (bw, bh) = (self.comps[ci].bw, self.comps[ci].bh);
691 if bx >= bw || by >= bh {
692 return Err(Error::Corrupt("block outside the grid"));
693 }
694 let bi = by * bw + bx;
695 if !self.progressive {
696 let mut coef = [0i16; 64];
697 let dc = &self.dc[self.comps[ci].dc_tbl];
698 let ac = &self.ac[self.comps[ci].ac_tbl];
699 let t = rd.decode(dc)?;
700 let diff = rd.receive_extend(u32::from(t));
701 let c = &mut self.comps[ci];
702 c.dc_pred = c.dc_pred.wrapping_add(diff);
703 coef[0] = c.dc_pred as i16;
704 let mut k = 1usize;
705 while k < 64 {
706 let rs = rd.decode(ac)?;
707 let r = usize::from(rs >> 4);
708 let s = u32::from(rs & 15);
709 if s == 0 {
710 if r == 15 {
711 k += 16;
712 continue;
713 }
714 break;
715 }
716 k += r;
717 if k > 63 {
718 break;
719 }
720 coef[ZIGZAG[k]] = rd.receive_extend(s) as i16;
721 k += 1;
722 }
723 let q = &self.qt[self.comps[ci].tq.min(3)];
724 let c = &mut self.comps[ci];
725 idct(c.dct, &coef, q, &mut c.samples, bi, bw);
726 return Ok(());
727 }
728
729 let dc = &self.dc[self.comps[ci].dc_tbl];
731 let ac = &self.ac[self.comps[ci].ac_tbl];
732 let c = &mut self.comps[ci];
733 let coef = &mut c.coefs[bi * 64..bi * 64 + 64];
734 if ss == 0 {
735 if ah == 0 {
736 let t = rd.decode(dc)?;
738 let diff = rd.receive_extend(u32::from(t));
739 c.dc_pred = c.dc_pred.wrapping_add(diff);
740 coef[0] = (c.dc_pred << al) as i16;
741 } else if rd.bit() == 1 {
742 coef[0] |= (1i32 << al) as i16;
744 }
745 return Ok(());
746 }
747 if ah == 0 {
748 if self.eobrun > 0 {
750 self.eobrun -= 1;
751 return Ok(());
752 }
753 let mut k = ss;
754 while k <= se {
755 let rs = rd.decode(ac)?;
756 let r = u32::from(rs >> 4);
757 let s = u32::from(rs & 15);
758 if s != 0 {
759 k += r as usize;
760 if k > 63 {
761 break;
762 }
763 let v = rd.receive_extend(s);
764 coef[ZIGZAG[k]] = (v << al) as i16;
765 } else {
766 if r != 15 {
767 self.eobrun = 1 << r;
768 if r > 0 {
769 self.eobrun += rd.bits(r);
770 }
771 self.eobrun -= 1;
772 break;
773 }
774 k += 15;
775 }
776 k += 1;
777 }
778 return Ok(());
779 }
780 let p1: i16 = (1i32 << al) as i16;
782 let m1: i16 = (-1i32 << al) as i16;
783 let mut k = ss;
784 if self.eobrun == 0 {
785 while k <= se {
786 let rs = rd.decode(ac)?;
787 let mut r = i32::from(rs >> 4);
788 let mut s = i32::from(rs & 15);
789 if s != 0 {
790 s = if rd.bit() == 1 {
792 i32::from(p1)
793 } else {
794 i32::from(m1)
795 };
796 } else if r != 15 {
797 self.eobrun = 1 << r;
798 if r > 0 {
799 self.eobrun += rd.bits(r as u32);
800 }
801 break;
802 }
803 loop {
806 let pos = ZIGZAG[k];
807 if coef[pos] != 0 {
808 if rd.bit() == 1 && (coef[pos] & p1) == 0 {
809 coef[pos] = if coef[pos] >= 0 {
810 coef[pos].wrapping_add(p1)
811 } else {
812 coef[pos].wrapping_add(m1)
813 };
814 }
815 } else {
816 r -= 1;
817 if r < 0 {
818 break;
819 }
820 }
821 k += 1;
822 if k > se {
823 break;
824 }
825 }
826 if s != 0 && k <= se {
827 coef[ZIGZAG[k]] = s as i16;
828 }
829 k += 1;
830 }
831 }
832 if self.eobrun > 0 {
833 while k <= se {
834 let pos = ZIGZAG[k];
835 if coef[pos] != 0 && rd.bit() == 1 && (coef[pos] & p1) == 0 {
836 coef[pos] = if coef[pos] >= 0 {
837 coef[pos].wrapping_add(p1)
838 } else {
839 coef[pos].wrapping_add(m1)
840 };
841 }
842 k += 1;
843 }
844 self.eobrun -= 1;
845 }
846 Ok(())
847 }
848
849 fn finish(mut self, color_transform: bool) -> Result<Image, Error> {
851 if self.comps.is_empty() {
852 return Err(Error::Corrupt("no frame"));
853 }
854 for c in &self.comps {
855 if !self.qt_present[c.tq.min(3)] {
856 return Err(Error::Corrupt("missing quantization table"));
857 }
858 }
859 if self.progressive {
860 for ci in 0..self.comps.len() {
861 let q = self.qt[self.comps[ci].tq.min(3)];
862 let c = &mut self.comps[ci];
863 let bw = c.bw;
864 for bi in 0..c.bw * c.bh {
865 let mut coef = [0i16; 64];
866 coef.copy_from_slice(&c.coefs[bi * 64..bi * 64 + 64]);
867 idct(c.dct, &coef, &q, &mut c.samples, bi, bw);
868 }
869 c.coefs = Vec::new();
870 }
871 }
872 let (w, h) = (
874 (self.width * self.min_dct).div_ceil(8),
875 (self.height * self.min_dct).div_ceil(8),
876 );
877 let planes: Vec<Vec<u8>> = self.comps.iter().map(|c| self.upsample(c, w, h)).collect();
878 let n = self.comps.len();
879 let space = self.color_space();
880 let convert = n == 3
883 && space == ColorSpace::YCbCr
884 && (color_transform || self.adobe_transform.is_some());
885 let mut out = vec![0u8; w * h * n];
886 if n == 1 {
887 out.copy_from_slice(&planes[0][..w * h]);
888 } else if n == 4 {
889 let ycck = self.adobe_transform == Some(2);
892 let t = ycc_tables();
893 for i in 0..w * h {
894 if ycck {
895 let y = i32::from(planes[0][i]);
896 let cb = usize::from(planes[1][i]);
897 let cr = usize::from(planes[2][i]);
898 out[4 * i] = range_limit(255 - (y + t.cr_r[cr]));
899 out[4 * i + 1] = range_limit(255 - (y + ((t.cb_g[cb] + t.cr_g[cr]) >> 16)));
900 out[4 * i + 2] = range_limit(255 - (y + t.cb_b[cb]));
901 } else {
902 out[4 * i] = planes[0][i];
903 out[4 * i + 1] = planes[1][i];
904 out[4 * i + 2] = planes[2][i];
905 }
906 out[4 * i + 3] = planes[3][i];
907 }
908 } else if convert {
909 let t = ycc_tables();
910 for i in 0..w * h {
911 let y = i32::from(planes[0][i]);
912 let cb = usize::from(planes[1][i]);
913 let cr = usize::from(planes[2][i]);
914 out[3 * i] = range_limit(y + t.cr_r[cr]);
915 out[3 * i + 1] = range_limit(y + ((t.cb_g[cb] + t.cr_g[cr]) >> 16));
916 out[3 * i + 2] = range_limit(y + t.cb_b[cb]);
917 }
918 } else {
919 for i in 0..w * h {
920 out[3 * i] = planes[0][i];
921 out[3 * i + 1] = planes[1][i];
922 out[3 * i + 2] = planes[2][i];
923 }
924 }
925 Ok(Image {
926 width: w,
927 height: h,
928 channels: n,
929 data: out,
930 adobe_inverted: n == 4 && self.adobe_transform.is_some(),
931 })
932 }
933
934 fn color_space(&self) -> ColorSpace {
936 if self.comps.len() == 1 {
937 return ColorSpace::Gray;
938 }
939 if self.saw_jfif {
940 return ColorSpace::YCbCr;
941 }
942 if let Some(t) = self.adobe_transform {
943 return if t == 0 {
944 ColorSpace::Rgb
945 } else {
946 ColorSpace::YCbCr
947 };
948 }
949 let ids = [self.comps[0].id, self.comps[1].id, self.comps[2].id];
950 if ids == [b'R', b'G', b'B'] {
951 ColorSpace::Rgb
952 } else {
953 ColorSpace::YCbCr
954 }
955 }
956
957 fn upsample(&self, c: &Component, w: usize, h: usize) -> Vec<u8> {
965 let stride = c.bw * c.dct;
966 let (dw, dh) = (c.dw, c.dh);
967 let row = |r: usize| -> &[u8] {
968 let r = r.min(dh.saturating_sub(1));
969 &c.samples[r * stride..r * stride + dw]
970 };
971 let h_in = c.h * c.dct / self.min_dct;
972 let v_in = c.v * c.dct / self.min_dct;
973 let (h_out, v_out) = (self.hmax, self.vmax);
974 let do_fancy = self.min_dct > 1;
975 let mut out = vec![0u8; w * h];
976 let replicate = |out: &mut Vec<u8>, h_exp: usize, v_exp: usize| {
977 for y in 0..h {
978 let src = row(y / v_exp);
979 for x in 0..w {
980 out[y * w + x] = src[(x / h_exp).min(dw - 1)];
981 }
982 }
983 };
984 if h_in == h_out && v_in == v_out {
985 for y in 0..h {
986 out[y * w..y * w + w].copy_from_slice(&row(y)[..w]);
987 }
988 } else if h_in * 2 == h_out && v_in == v_out {
989 if do_fancy && dw > 2 {
990 let mut line = vec![0u8; dw * 2];
991 for y in 0..h {
992 h2v1_fancy(row(y), &mut line);
993 out[y * w..y * w + w].copy_from_slice(&line[..w]);
994 }
995 } else {
996 replicate(&mut out, 2, 1);
997 }
998 } else if h_in == h_out && v_in * 2 == v_out && do_fancy {
999 for r in 0..dh {
1000 for v in 0..2 {
1001 let y = 2 * r + v;
1002 if y >= h {
1003 break;
1004 }
1005 let near = row(r);
1006 let far = if v == 0 {
1007 row(r.saturating_sub(1))
1008 } else {
1009 row(r + 1)
1010 };
1011 let bias: u32 = if v == 0 { 1 } else { 2 };
1012 for x in 0..w {
1013 out[y * w + x] =
1014 ((3 * u32::from(near[x]) + u32::from(far[x]) + bias) >> 2) as u8;
1015 }
1016 }
1017 }
1018 } else if h_in * 2 == h_out && v_in * 2 == v_out {
1019 if do_fancy && dw > 2 {
1020 let mut line = vec![0u8; dw * 2];
1021 for r in 0..dh {
1022 for v in 0..2 {
1023 let y = 2 * r + v;
1024 if y >= h {
1025 break;
1026 }
1027 let near = row(r);
1028 let far = if v == 0 {
1029 row(r.saturating_sub(1))
1030 } else {
1031 row(r + 1)
1032 };
1033 h2v2_fancy(near, far, &mut line);
1034 out[y * w..y * w + w].copy_from_slice(&line[..w]);
1035 }
1036 }
1037 } else {
1038 replicate(&mut out, 2, 2);
1039 }
1040 } else if h_in > 0 && v_in > 0 && h_out % h_in == 0 && v_out % v_in == 0 {
1041 replicate(&mut out, h_out / h_in, v_out / v_in);
1043 } else {
1044 }
1047 out
1048 }
1049}
1050
1051fn h2v1_fancy(input: &[u8], out: &mut [u8]) {
1054 let n = input.len();
1055 let at = |i: usize| u32::from(input[i]);
1056 out[0] = input[0];
1057 out[1] = ((at(0) * 3 + at(1) + 2) >> 2) as u8;
1058 for i in 1..n - 1 {
1059 let v = at(i) * 3;
1060 out[2 * i] = ((v + at(i - 1) + 1) >> 2) as u8;
1061 out[2 * i + 1] = ((v + at(i + 1) + 2) >> 2) as u8;
1062 }
1063 out[2 * (n - 1)] = ((at(n - 1) * 3 + at(n - 2) + 1) >> 2) as u8;
1064 out[2 * (n - 1) + 1] = input[n - 1];
1065}
1066
1067fn h2v2_fancy(near: &[u8], far: &[u8], out: &mut [u8]) {
1070 let n = near.len();
1071 let colsum = |i: usize| u32::from(near[i]) * 3 + u32::from(far[i]);
1072 let mut this = colsum(0);
1073 let mut next = colsum(1);
1074 out[0] = ((this * 4 + 8) >> 4) as u8;
1075 out[1] = ((this * 3 + next + 7) >> 4) as u8;
1076 let mut last = this;
1077 this = next;
1078 for i in 1..n - 1 {
1079 next = colsum(i + 1);
1080 out[2 * i] = ((this * 3 + last + 8) >> 4) as u8;
1081 out[2 * i + 1] = ((this * 3 + next + 7) >> 4) as u8;
1082 last = this;
1083 this = next;
1084 }
1085 out[2 * (n - 1)] = ((this * 3 + last + 8) >> 4) as u8;
1086 out[2 * (n - 1) + 1] = ((this * 4 + 7) >> 4) as u8;
1087}
1088
1089struct YccTables {
1090 cr_r: [i32; 256],
1091 cb_b: [i32; 256],
1092 cr_g: [i32; 256],
1093 cb_g: [i32; 256],
1094}
1095
1096fn ycc_tables() -> YccTables {
1099 const SCALEBITS: i32 = 16;
1100 const ONE_HALF: i32 = 1 << (SCALEBITS - 1);
1101 let fix = |x: f64| (x * f64::from(1i32 << SCALEBITS) + 0.5) as i32;
1102 let mut t = YccTables {
1103 cr_r: [0; 256],
1104 cb_b: [0; 256],
1105 cr_g: [0; 256],
1106 cb_g: [0; 256],
1107 };
1108 for i in 0..256i32 {
1109 let x = i - 128;
1110 t.cr_r[i as usize] = (fix(1.402) * x + ONE_HALF) >> SCALEBITS;
1111 t.cb_b[i as usize] = (fix(1.772) * x + ONE_HALF) >> SCALEBITS;
1112 t.cr_g[i as usize] = -fix(0.71414) * x;
1113 t.cb_g[i as usize] = -fix(0.34414) * x + ONE_HALF;
1114 }
1115 t
1116}
1117
1118fn range_limit(v: i32) -> u8 {
1120 v.clamp(0, 255) as u8
1121}
1122
1123fn idct_range_limit(x: i32) -> u8 {
1127 let i = (x & 1023) as usize;
1128 match i {
1129 0..=127 => (128 + i) as u8,
1130 128..=511 => 255,
1131 512..=895 => 0,
1132 _ => (i - 896) as u8,
1133 }
1134}
1135
1136fn idct(dct: usize, coef: &[i16; 64], q: &[u16; 64], samples: &mut [u8], bi: usize, bw: usize) {
1141 match dct {
1142 8 => idct_islow(coef, q, samples, bi, bw),
1143 4 => idct_4x4(coef, q, samples, bi, bw),
1144 2 => idct_2x2(coef, q, samples, bi, bw),
1145 _ => idct_1x1(coef, q, samples, bi, bw),
1146 }
1147}
1148
1149const CONST_BITS: i32 = 13;
1150const PASS1_BITS: i32 = 2;
1151
1152#[inline(always)]
1153fn descale(x: i32, n: i32) -> i32 {
1154 x.wrapping_add(1 << (n - 1)) >> n
1155}
1156
1157#[inline(always)]
1158fn mul(a: i32, b: i32) -> i32 {
1159 a.wrapping_mul(b)
1160}
1161
1162fn idct_4x4(coef: &[i16; 64], q: &[u16; 64], samples: &mut [u8], bi: usize, bw: usize) {
1165 const FIX_0_211164243: i32 = 1730;
1166 const FIX_0_509795579: i32 = 4176;
1167 const FIX_0_601344887: i32 = 4926;
1168 const FIX_0_765366865: i32 = 6270;
1169 const FIX_0_899976223: i32 = 7373;
1170 const FIX_1_061594337: i32 = 8697;
1171 const FIX_1_451774981: i32 = 11893;
1172 const FIX_1_847759065: i32 = 15137;
1173 const FIX_2_172734803: i32 = 17799;
1174 const FIX_2_562915447: i32 = 20995;
1175 let dq = |k: usize| i32::from(coef[k]).wrapping_mul(i32::from(q[k]));
1176 let mut ws = [0i32; 32]; for col in 0..8 {
1178 if col == 4 {
1179 continue;
1180 }
1181 if [1, 2, 3, 5, 6, 7].iter().all(|&r| coef[r * 8 + col] == 0) {
1182 let dc = dq(col) << PASS1_BITS;
1183 for r in 0..4 {
1184 ws[r * 8 + col] = dc;
1185 }
1186 continue;
1187 }
1188 let tmp0 = dq(col) << (CONST_BITS + 1);
1189 let z2 = dq(2 * 8 + col);
1190 let z3 = dq(6 * 8 + col);
1191 let tmp2 = mul(z2, FIX_1_847759065).wrapping_add(mul(z3, -FIX_0_765366865));
1192 let tmp10 = tmp0.wrapping_add(tmp2);
1193 let tmp12 = tmp0.wrapping_sub(tmp2);
1194 let z1 = dq(7 * 8 + col);
1195 let z2 = dq(5 * 8 + col);
1196 let z3 = dq(3 * 8 + col);
1197 let z4 = dq(8 + col);
1198 let tmp0 = mul(z1, -FIX_0_211164243)
1199 .wrapping_add(mul(z2, FIX_1_451774981))
1200 .wrapping_add(mul(z3, -FIX_2_172734803))
1201 .wrapping_add(mul(z4, FIX_1_061594337));
1202 let tmp2 = mul(z1, -FIX_0_509795579)
1203 .wrapping_add(mul(z2, -FIX_0_601344887))
1204 .wrapping_add(mul(z3, FIX_0_899976223))
1205 .wrapping_add(mul(z4, FIX_2_562915447));
1206 let n = CONST_BITS - PASS1_BITS + 1;
1207 ws[col] = descale(tmp10.wrapping_add(tmp2), n);
1208 ws[3 * 8 + col] = descale(tmp10.wrapping_sub(tmp2), n);
1209 ws[8 + col] = descale(tmp12.wrapping_add(tmp0), n);
1210 ws[2 * 8 + col] = descale(tmp12.wrapping_sub(tmp0), n);
1211 }
1212 let stride = bw * 4;
1213 let (bx, by) = (bi % bw, bi / bw);
1214 for row in 0..4 {
1215 let w = &ws[row * 8..row * 8 + 8];
1216 let off = (by * 4 + row) * stride + bx * 4;
1217 let out = &mut samples[off..off + 4];
1218 if [1, 2, 3, 5, 6, 7].iter().all(|&k| w[k] == 0) {
1219 out.fill(idct_range_limit(descale(w[0], PASS1_BITS + 3)));
1220 continue;
1221 }
1222 let tmp0 = w[0] << (CONST_BITS + 1);
1223 let tmp2 = mul(w[2], FIX_1_847759065).wrapping_add(mul(w[6], -FIX_0_765366865));
1224 let tmp10 = tmp0.wrapping_add(tmp2);
1225 let tmp12 = tmp0.wrapping_sub(tmp2);
1226 let (z1, z2, z3, z4) = (w[7], w[5], w[3], w[1]);
1227 let tmp0 = mul(z1, -FIX_0_211164243)
1228 .wrapping_add(mul(z2, FIX_1_451774981))
1229 .wrapping_add(mul(z3, -FIX_2_172734803))
1230 .wrapping_add(mul(z4, FIX_1_061594337));
1231 let tmp2 = mul(z1, -FIX_0_509795579)
1232 .wrapping_add(mul(z2, -FIX_0_601344887))
1233 .wrapping_add(mul(z3, FIX_0_899976223))
1234 .wrapping_add(mul(z4, FIX_2_562915447));
1235 let n = CONST_BITS + PASS1_BITS + 3 + 1;
1236 out[0] = idct_range_limit(descale(tmp10.wrapping_add(tmp2), n));
1237 out[3] = idct_range_limit(descale(tmp10.wrapping_sub(tmp2), n));
1238 out[1] = idct_range_limit(descale(tmp12.wrapping_add(tmp0), n));
1239 out[2] = idct_range_limit(descale(tmp12.wrapping_sub(tmp0), n));
1240 }
1241}
1242
1243fn idct_2x2(coef: &[i16; 64], q: &[u16; 64], samples: &mut [u8], bi: usize, bw: usize) {
1245 const FIX_0_720959822: i32 = 5906;
1246 const FIX_0_850430095: i32 = 6967;
1247 const FIX_1_272758580: i32 = 10426;
1248 const FIX_3_624509785: i32 = 29692;
1249 let dq = |k: usize| i32::from(coef[k]).wrapping_mul(i32::from(q[k]));
1250 let mut ws = [0i32; 16]; for col in [0usize, 1, 3, 5, 7] {
1252 if [1, 3, 5, 7].iter().all(|&r| coef[r * 8 + col] == 0) {
1253 let dc = dq(col) << PASS1_BITS;
1254 ws[col] = dc;
1255 ws[8 + col] = dc;
1256 continue;
1257 }
1258 let tmp10 = dq(col) << (CONST_BITS + 2);
1259 let tmp0 = mul(dq(7 * 8 + col), -FIX_0_720959822)
1260 .wrapping_add(mul(dq(5 * 8 + col), FIX_0_850430095))
1261 .wrapping_add(mul(dq(3 * 8 + col), -FIX_1_272758580))
1262 .wrapping_add(mul(dq(8 + col), FIX_3_624509785));
1263 let n = CONST_BITS - PASS1_BITS + 2;
1264 ws[col] = descale(tmp10.wrapping_add(tmp0), n);
1265 ws[8 + col] = descale(tmp10.wrapping_sub(tmp0), n);
1266 }
1267 let stride = bw * 2;
1268 let (bx, by) = (bi % bw, bi / bw);
1269 for row in 0..2 {
1270 let w = &ws[row * 8..row * 8 + 8];
1271 let off = (by * 2 + row) * stride + bx * 2;
1272 let out = &mut samples[off..off + 2];
1273 if [1, 3, 5, 7].iter().all(|&k| w[k] == 0) {
1274 out.fill(idct_range_limit(descale(w[0], PASS1_BITS + 3)));
1275 continue;
1276 }
1277 let tmp10 = w[0] << (CONST_BITS + 2);
1278 let tmp0 = mul(w[7], -FIX_0_720959822)
1279 .wrapping_add(mul(w[5], FIX_0_850430095))
1280 .wrapping_add(mul(w[3], -FIX_1_272758580))
1281 .wrapping_add(mul(w[1], FIX_3_624509785));
1282 let n = CONST_BITS + PASS1_BITS + 3 + 2;
1283 out[0] = idct_range_limit(descale(tmp10.wrapping_add(tmp0), n));
1284 out[1] = idct_range_limit(descale(tmp10.wrapping_sub(tmp0), n));
1285 }
1286}
1287
1288fn idct_1x1(coef: &[i16; 64], q: &[u16; 64], samples: &mut [u8], bi: usize, bw: usize) {
1290 let dc = descale(i32::from(coef[0]).wrapping_mul(i32::from(q[0])), 3);
1291 let (bx, by) = (bi % bw, bi / bw);
1292 samples[by * bw + bx] = idct_range_limit(dc);
1293}
1294
1295fn idct_islow(coef: &[i16; 64], q: &[u16; 64], samples: &mut [u8], bi: usize, bw: usize) {
1299 const FIX_0_298631336: i32 = 2446;
1300 const FIX_0_390180644: i32 = 3196;
1301 const FIX_0_541196100: i32 = 4433;
1302 const FIX_0_765366865: i32 = 6270;
1303 const FIX_0_899976223: i32 = 7373;
1304 const FIX_1_175875602: i32 = 9633;
1305 const FIX_1_501321110: i32 = 12299;
1306 const FIX_1_847759065: i32 = 15137;
1307 const FIX_1_961570560: i32 = 16069;
1308 const FIX_2_053119869: i32 = 16819;
1309 const FIX_2_562915447: i32 = 20995;
1310 const FIX_3_072711026: i32 = 25172;
1311
1312 let dq = |k: usize| i32::from(coef[k]).wrapping_mul(i32::from(q[k]));
1313 let mut ws = [0i32; 64];
1314
1315 for col in 0..8 {
1317 if (1..8).all(|r| coef[r * 8 + col] == 0) {
1318 let dc = dq(col) << PASS1_BITS;
1319 for r in 0..8 {
1320 ws[r * 8 + col] = dc;
1321 }
1322 continue;
1323 }
1324 let z2 = dq(2 * 8 + col);
1325 let z3 = dq(6 * 8 + col);
1326 let z1 = mul(z2.wrapping_add(z3), FIX_0_541196100);
1327 let tmp2 = z1.wrapping_add(mul(z3, -FIX_1_847759065));
1328 let tmp3 = z1.wrapping_add(mul(z2, FIX_0_765366865));
1329 let z2 = dq(col);
1330 let z3 = dq(4 * 8 + col);
1331 let tmp0 = z2.wrapping_add(z3) << CONST_BITS;
1332 let tmp1 = z2.wrapping_sub(z3) << CONST_BITS;
1333 let tmp10 = tmp0.wrapping_add(tmp3);
1334 let tmp13 = tmp0.wrapping_sub(tmp3);
1335 let tmp11 = tmp1.wrapping_add(tmp2);
1336 let tmp12 = tmp1.wrapping_sub(tmp2);
1337
1338 let mut tmp0 = dq(7 * 8 + col);
1339 let mut tmp1 = dq(5 * 8 + col);
1340 let mut tmp2 = dq(3 * 8 + col);
1341 let mut tmp3 = dq(8 + col);
1342 let z1 = tmp0.wrapping_add(tmp3);
1343 let z2 = tmp1.wrapping_add(tmp2);
1344 let z3 = tmp0.wrapping_add(tmp2);
1345 let z4 = tmp1.wrapping_add(tmp3);
1346 let z5 = mul(z3.wrapping_add(z4), FIX_1_175875602);
1347 tmp0 = mul(tmp0, FIX_0_298631336);
1348 tmp1 = mul(tmp1, FIX_2_053119869);
1349 tmp2 = mul(tmp2, FIX_3_072711026);
1350 tmp3 = mul(tmp3, FIX_1_501321110);
1351 let z1 = mul(z1, -FIX_0_899976223);
1352 let z2 = mul(z2, -FIX_2_562915447);
1353 let z3 = mul(z3, -FIX_1_961570560).wrapping_add(z5);
1354 let z4 = mul(z4, -FIX_0_390180644).wrapping_add(z5);
1355 tmp0 = tmp0.wrapping_add(z1).wrapping_add(z3);
1356 tmp1 = tmp1.wrapping_add(z2).wrapping_add(z4);
1357 tmp2 = tmp2.wrapping_add(z2).wrapping_add(z3);
1358 tmp3 = tmp3.wrapping_add(z1).wrapping_add(z4);
1359
1360 let n = CONST_BITS - PASS1_BITS;
1361 ws[col] = descale(tmp10.wrapping_add(tmp3), n);
1362 ws[7 * 8 + col] = descale(tmp10.wrapping_sub(tmp3), n);
1363 ws[8 + col] = descale(tmp11.wrapping_add(tmp2), n);
1364 ws[6 * 8 + col] = descale(tmp11.wrapping_sub(tmp2), n);
1365 ws[2 * 8 + col] = descale(tmp12.wrapping_add(tmp1), n);
1366 ws[5 * 8 + col] = descale(tmp12.wrapping_sub(tmp1), n);
1367 ws[3 * 8 + col] = descale(tmp13.wrapping_add(tmp0), n);
1368 ws[4 * 8 + col] = descale(tmp13.wrapping_sub(tmp0), n);
1369 }
1370
1371 let stride = bw * 8;
1373 let (bx, by) = (bi % bw, bi / bw);
1374 for row in 0..8 {
1375 let w = &ws[row * 8..row * 8 + 8];
1376 let out_off = (by * 8 + row) * stride + bx * 8;
1377 let out = &mut samples[out_off..out_off + 8];
1378 let n = CONST_BITS + PASS1_BITS + 3;
1379 if w[1..].iter().all(|&v| v == 0) {
1380 let dc = idct_range_limit(descale(w[0], PASS1_BITS + 3));
1381 out.fill(dc);
1382 continue;
1383 }
1384 let z2 = w[2];
1385 let z3 = w[6];
1386 let z1 = mul(z2.wrapping_add(z3), FIX_0_541196100);
1387 let tmp2 = z1.wrapping_add(mul(z3, -FIX_1_847759065));
1388 let tmp3 = z1.wrapping_add(mul(z2, FIX_0_765366865));
1389 let tmp0 = w[0].wrapping_add(w[4]) << CONST_BITS;
1390 let tmp1 = w[0].wrapping_sub(w[4]) << CONST_BITS;
1391 let tmp10 = tmp0.wrapping_add(tmp3);
1392 let tmp13 = tmp0.wrapping_sub(tmp3);
1393 let tmp11 = tmp1.wrapping_add(tmp2);
1394 let tmp12 = tmp1.wrapping_sub(tmp2);
1395
1396 let mut tmp0 = w[7];
1397 let mut tmp1 = w[5];
1398 let mut tmp2 = w[3];
1399 let mut tmp3 = w[1];
1400 let z1 = tmp0.wrapping_add(tmp3);
1401 let z2 = tmp1.wrapping_add(tmp2);
1402 let z3 = tmp0.wrapping_add(tmp2);
1403 let z4 = tmp1.wrapping_add(tmp3);
1404 let z5 = mul(z3.wrapping_add(z4), FIX_1_175875602);
1405 tmp0 = mul(tmp0, FIX_0_298631336);
1406 tmp1 = mul(tmp1, FIX_2_053119869);
1407 tmp2 = mul(tmp2, FIX_3_072711026);
1408 tmp3 = mul(tmp3, FIX_1_501321110);
1409 let z1 = mul(z1, -FIX_0_899976223);
1410 let z2 = mul(z2, -FIX_2_562915447);
1411 let z3 = mul(z3, -FIX_1_961570560).wrapping_add(z5);
1412 let z4 = mul(z4, -FIX_0_390180644).wrapping_add(z5);
1413 tmp0 = tmp0.wrapping_add(z1).wrapping_add(z3);
1414 tmp1 = tmp1.wrapping_add(z2).wrapping_add(z4);
1415 tmp2 = tmp2.wrapping_add(z2).wrapping_add(z3);
1416 tmp3 = tmp3.wrapping_add(z1).wrapping_add(z4);
1417
1418 out[0] = idct_range_limit(descale(tmp10.wrapping_add(tmp3), n));
1419 out[7] = idct_range_limit(descale(tmp10.wrapping_sub(tmp3), n));
1420 out[1] = idct_range_limit(descale(tmp11.wrapping_add(tmp2), n));
1421 out[6] = idct_range_limit(descale(tmp11.wrapping_sub(tmp2), n));
1422 out[2] = idct_range_limit(descale(tmp12.wrapping_add(tmp1), n));
1423 out[5] = idct_range_limit(descale(tmp12.wrapping_sub(tmp1), n));
1424 out[3] = idct_range_limit(descale(tmp13.wrapping_add(tmp0), n));
1425 out[4] = idct_range_limit(descale(tmp13.wrapping_sub(tmp0), n));
1426 }
1427}
1428
1429#[cfg(test)]
1430mod tests {
1431 use super::*;
1432
1433 #[test]
1434 fn a_dc_only_block_is_flat() {
1435 let mut coef = [0i16; 64];
1436 coef[0] = 8; let q = [1u16; 64];
1438 let mut samples = vec![0u8; 64];
1439 idct_islow(&coef, &q, &mut samples, 0, 1);
1440 assert!(samples.iter().all(|&v| v == 129), "{samples:?}");
1441 }
1442
1443 #[test]
1444 fn colour_tables_match_libjpeg_constants() {
1445 let t = ycc_tables();
1446 assert_eq!(t.cr_r[255], 178);
1448 assert_eq!(t.cb_b[0], -227);
1449 assert_eq!(range_limit(300), 255);
1450 assert_eq!(idct_range_limit(-5), 123);
1451 assert_eq!(idct_range_limit(200), 255);
1452 assert_eq!(idct_range_limit(-300), 0);
1453 }
1454}