/rust/registry/src/index.crates.io-6f17d22bba15001f/zune-jpeg-0.4.18/src/mcu.rs
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2023. |
3 | | * |
4 | | * This software is free software; |
5 | | * |
6 | | * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license |
7 | | */ |
8 | | |
9 | | use alloc::{format, vec}; |
10 | | use core::cmp::min; |
11 | | use zune_core::bytestream::ZReaderTrait; |
12 | | use zune_core::colorspace::ColorSpace; |
13 | | use zune_core::colorspace::ColorSpace::Luma; |
14 | | use zune_core::log::{error, trace, warn}; |
15 | | |
16 | | use crate::bitstream::BitStream; |
17 | | use crate::components::SampleRatios; |
18 | | use crate::decoder::MAX_COMPONENTS; |
19 | | use crate::errors::DecodeErrors; |
20 | | use crate::marker::Marker; |
21 | | use crate::mcu_prog::get_marker; |
22 | | use crate::misc::{calculate_padded_width, setup_component_params}; |
23 | | use crate::worker::{color_convert, upsample}; |
24 | | use crate::JpegDecoder; |
25 | | |
26 | | /// The size of a DC block for a MCU. |
27 | | |
28 | | pub const DCT_BLOCK: usize = 64; |
29 | | |
30 | | impl<T: ZReaderTrait> JpegDecoder<T> { |
31 | | /// Check for existence of DC and AC Huffman Tables |
32 | 0 | pub(crate) fn check_tables(&self) -> Result<(), DecodeErrors> { |
33 | | // check that dc and AC tables exist outside the hot path |
34 | 0 | for component in &self.components { |
35 | 0 | let _ = &self |
36 | 0 | .dc_huffman_tables |
37 | 0 | .get(component.dc_huff_table) |
38 | 0 | .as_ref() |
39 | 0 | .ok_or_else(|| { |
40 | 0 | DecodeErrors::HuffmanDecode(format!( |
41 | 0 | "No Huffman DC table for component {:?} ", |
42 | 0 | component.component_id |
43 | 0 | )) |
44 | 0 | })? Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0} |
45 | 0 | .as_ref() |
46 | 0 | .ok_or_else(|| { |
47 | 0 | DecodeErrors::HuffmanDecode(format!( |
48 | 0 | "No DC table for component {:?}", |
49 | 0 | component.component_id |
50 | 0 | )) |
51 | 0 | })?; Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1} |
52 | | |
53 | 0 | let _ = &self |
54 | 0 | .ac_huffman_tables |
55 | 0 | .get(component.ac_huff_table) |
56 | 0 | .as_ref() |
57 | 0 | .ok_or_else(|| { |
58 | 0 | DecodeErrors::HuffmanDecode(format!( |
59 | 0 | "No Huffman AC table for component {:?} ", |
60 | 0 | component.component_id |
61 | 0 | )) |
62 | 0 | })? Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2} |
63 | 0 | .as_ref() |
64 | 0 | .ok_or_else(|| { |
65 | 0 | DecodeErrors::HuffmanDecode(format!( |
66 | 0 | "No AC table for component {:?}", |
67 | 0 | component.component_id |
68 | 0 | )) |
69 | 0 | })?; Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3} |
70 | | } |
71 | 0 | Ok(()) |
72 | 0 | } Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables |
73 | | |
74 | | /// Decode MCUs and carry out post processing. |
75 | | /// |
76 | | /// This is the main decoder loop for the library, the hot path. |
77 | | /// |
78 | | /// Because of this, we pull in some very crazy optimization tricks hence readability is a pinch |
79 | | /// here. |
80 | | #[allow( |
81 | | clippy::similar_names, |
82 | | clippy::too_many_lines, |
83 | | clippy::cast_possible_truncation |
84 | | )] |
85 | | #[inline(never)] |
86 | 0 | pub(crate) fn decode_mcu_ycbcr_baseline( |
87 | 0 | &mut self, pixels: &mut [u8] |
88 | 0 | ) -> Result<(), DecodeErrors> { |
89 | 0 | setup_component_params(self)?; |
90 | | |
91 | | // check dc and AC tables |
92 | 0 | self.check_tables()?; |
93 | | |
94 | | let (mut mcu_width, mut mcu_height); |
95 | | |
96 | 0 | if self.is_interleaved { |
97 | | // set upsampling functions |
98 | 0 | self.set_upsampling()?; |
99 | | |
100 | 0 | mcu_width = self.mcu_x; |
101 | 0 | mcu_height = self.mcu_y; |
102 | 0 | } else { |
103 | 0 | // For non-interleaved images( (1*1) subsampling) |
104 | 0 | // number of MCU's are the widths (+7 to account for paddings) divided bu 8. |
105 | 0 | mcu_width = ((self.info.width + 7) / 8) as usize; |
106 | 0 | mcu_height = ((self.info.height + 7) / 8) as usize; |
107 | 0 | } |
108 | 0 | if self.is_interleaved |
109 | 0 | && self.input_colorspace.num_components() > 1 |
110 | 0 | && self.options.jpeg_get_out_colorspace().num_components() == 1 |
111 | 0 | && (self.sub_sample_ratio == SampleRatios::V |
112 | 0 | || self.sub_sample_ratio == SampleRatios::HV) |
113 | 0 | { |
114 | 0 | // For a specific set of images, e.g interleaved, |
115 | 0 | // when converting from YcbCr to grayscale, we need to |
116 | 0 | // take into account mcu height since the MCU decoding needs to take |
117 | 0 | // it into account for padding purposes and the post processor |
118 | 0 | // parses two rows per mcu width. |
119 | 0 | // |
120 | 0 | // set coeff to be 2 to ensure that we increment two rows |
121 | 0 | // for every mcu processed also |
122 | 0 | mcu_height *= self.v_max; |
123 | 0 | mcu_height /= self.h_max; |
124 | 0 | self.coeff = 2; |
125 | 0 | } |
126 | | |
127 | 0 | if self.input_colorspace == ColorSpace::Luma && self.is_interleaved { |
128 | 0 | warn!("Grayscale image with down-sampled component, resetting component details"); |
129 | 0 |
|
130 | 0 | self.reset_params(); |
131 | 0 |
|
132 | 0 | mcu_width = ((self.info.width + 7) / 8) as usize; |
133 | 0 | mcu_height = ((self.info.height + 7) / 8) as usize; |
134 | 0 | } |
135 | 0 | let width = usize::from(self.info.width); |
136 | 0 |
|
137 | 0 | let padded_width = calculate_padded_width(width, self.sub_sample_ratio); |
138 | 0 |
|
139 | 0 | let mut stream = BitStream::new(); |
140 | 0 | let mut tmp = [0_i32; DCT_BLOCK]; |
141 | 0 |
|
142 | 0 | let comp_len = self.components.len(); |
143 | | |
144 | 0 | for (pos, comp) in self.components.iter_mut().enumerate() { |
145 | | // Allocate only needed components. |
146 | | // |
147 | | // For special colorspaces i.e YCCK and CMYK, just allocate all of the needed |
148 | | // components. |
149 | 0 | if min( |
150 | 0 | self.options.jpeg_get_out_colorspace().num_components() - 1, |
151 | 0 | pos |
152 | 0 | ) == pos |
153 | 0 | || comp_len == 4 |
154 | | // Special colorspace |
155 | 0 | { |
156 | 0 | // allocate enough space to hold a whole MCU width |
157 | 0 | // this means we should take into account sampling ratios |
158 | 0 | // `*8` is because each MCU spans 8 widths. |
159 | 0 | let len = comp.width_stride * comp.vertical_sample * 8; |
160 | 0 |
|
161 | 0 | comp.needed = true; |
162 | 0 | comp.raw_coeff = vec![0; len]; |
163 | 0 | } else { |
164 | 0 | comp.needed = false; |
165 | 0 | } |
166 | | } |
167 | | |
168 | 0 | let mut pixels_written = 0; |
169 | 0 |
|
170 | 0 | let is_hv = usize::from(self.is_interleaved); |
171 | 0 | let upsampler_scratch_size = is_hv * self.components[0].width_stride; |
172 | 0 | let mut upsampler_scratch_space = vec![0; upsampler_scratch_size]; |
173 | | |
174 | 0 | for i in 0..mcu_height { |
175 | | // Report if we have no more bytes |
176 | | // This may generate false negatives since we over-read bytes |
177 | | // hence that why 37 is chosen(we assume if we over-read more than 37 bytes, we have a problem) |
178 | 0 | if stream.overread_by > 37 |
179 | | // favourite number :) |
180 | | { |
181 | 0 | if self.options.get_strict_mode() { |
182 | 0 | return Err(DecodeErrors::FormatStatic("Premature end of buffer")); |
183 | 0 | }; |
184 | 0 |
|
185 | 0 | error!("Premature end of buffer"); |
186 | 0 | break; |
187 | 0 | } |
188 | | |
189 | | // decode a whole MCU width, |
190 | | // this takes into account interleaved components. |
191 | 0 | let terminate = self.decode_mcu_width(mcu_width, &mut tmp, &mut stream)?; |
192 | | // if i >=7{ |
193 | | // panic!() |
194 | | // } |
195 | | // process that width up until it's impossible |
196 | | |
197 | 0 | self.post_process( |
198 | 0 | pixels, |
199 | 0 | i, |
200 | 0 | mcu_height, |
201 | 0 | width, |
202 | 0 | padded_width, |
203 | 0 | &mut pixels_written, |
204 | 0 | &mut upsampler_scratch_space |
205 | 0 | )?; |
206 | 0 | if terminate { |
207 | 0 | warn!("Got terminate signal, will not process further"); |
208 | 0 | return Ok(()); |
209 | 0 | } |
210 | | } |
211 | | // it may happen that some images don't have the whole buffer |
212 | | // so we can't panic in case of that |
213 | | // assert_eq!(pixels_written, pixels.len()); |
214 | | |
215 | | // For UHD usecases that tie two images separating them with EOI and |
216 | | // SOI markers, it may happen that we do not reach this image end of image |
217 | | // So this ensures we reach it |
218 | | // Ensure we read EOI |
219 | 0 | if !stream.seen_eoi { |
220 | 0 | let marker = get_marker(&mut self.stream, &mut stream); |
221 | 0 | match marker { |
222 | 0 | Ok(_m) => { |
223 | 0 | trace!("Found marker {:?}", _m); |
224 | 0 | } |
225 | 0 | Err(_) => { |
226 | 0 | // ignore error |
227 | 0 | } |
228 | | } |
229 | 0 | } |
230 | | |
231 | | trace!("Finished decoding image"); |
232 | | |
233 | 0 | Ok(()) |
234 | 0 | } Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline |
235 | 0 | fn decode_mcu_width( |
236 | 0 | &mut self, mcu_width: usize, tmp: &mut [i32; 64], stream: &mut BitStream |
237 | 0 | ) -> Result<bool, DecodeErrors> { |
238 | 0 | for j in 0..mcu_width { |
239 | | // iterate over components |
240 | 0 | for component in &mut self.components { |
241 | 0 | let dc_table = self.dc_huffman_tables[component.dc_huff_table % MAX_COMPONENTS] |
242 | 0 | .as_ref() |
243 | 0 | .unwrap(); |
244 | 0 |
|
245 | 0 | let ac_table = self.ac_huffman_tables[component.ac_huff_table % MAX_COMPONENTS] |
246 | 0 | .as_ref() |
247 | 0 | .unwrap(); |
248 | 0 |
|
249 | 0 | let qt_table = &component.quantization_table; |
250 | 0 | let channel = &mut component.raw_coeff; |
251 | | |
252 | | // If image is interleaved iterate over scan components, |
253 | | // otherwise if it-s non-interleaved, these routines iterate in |
254 | | // trivial scanline order(Y,Cb,Cr) |
255 | 0 | for v_samp in 0..component.vertical_sample { |
256 | 0 | for h_samp in 0..component.horizontal_sample { |
257 | | // Fill the array with zeroes, decode_mcu_block expects |
258 | | // a zero based array. |
259 | 0 | tmp.fill(0); |
260 | 0 |
|
261 | 0 | stream.decode_mcu_block( |
262 | 0 | &mut self.stream, |
263 | 0 | dc_table, |
264 | 0 | ac_table, |
265 | 0 | qt_table, |
266 | 0 | tmp, |
267 | 0 | &mut component.dc_pred |
268 | 0 | )?; |
269 | | |
270 | 0 | if component.needed { |
271 | 0 | let idct_position = { |
272 | 0 | // derived from stb and rewritten for my tastes |
273 | 0 | let c2 = v_samp * 8; |
274 | 0 | let c3 = ((j * component.horizontal_sample) + h_samp) * 8; |
275 | 0 |
|
276 | 0 | component.width_stride * c2 + c3 |
277 | 0 | }; |
278 | 0 |
|
279 | 0 | let idct_pos = channel.get_mut(idct_position..).unwrap(); |
280 | 0 | // call idct. |
281 | 0 | (self.idct_func)(tmp, idct_pos, component.width_stride); |
282 | 0 | } |
283 | | } |
284 | | } |
285 | | } |
286 | 0 | self.todo = self.todo.wrapping_sub(1); |
287 | 0 |
|
288 | 0 | if self.todo == 0 { |
289 | 0 | self.handle_rst_main(stream)?; |
290 | 0 | } |
291 | | |
292 | | // After all interleaved components, that's an MCU |
293 | | // handle stream markers |
294 | | // |
295 | | // In some corrupt images, it may occur that header markers occur in the stream. |
296 | | // The spec EXPLICITLY FORBIDS this, specifically, in |
297 | | // routine F.2.2.5 it says |
298 | | // `The only valid marker which may occur within the Huffman coded data is the RSTm marker.` |
299 | | // |
300 | | // But libjpeg-turbo allows it because of some weird reason. so I'll also |
301 | | // allow it because of some weird reason. |
302 | 0 | if let Some(m) = stream.marker { |
303 | 0 | if m == Marker::EOI { |
304 | 0 | // acknowledge and ignore EOI marker. |
305 | 0 | stream.marker.take(); |
306 | 0 | trace!("Found EOI marker"); |
307 | 0 | // Google Introduced the Ultra-HD image format which is basically |
308 | 0 | // stitching two images into one container. |
309 | 0 | // They basically separate two images via a EOI and SOI marker |
310 | 0 | // so let's just ensure if we ever see EOI, we never read past that |
311 | 0 | // ever. |
312 | 0 | // https://github.com/google/libultrahdr |
313 | 0 | stream.seen_eoi = true; |
314 | 0 | } else if let Marker::RST(_) = m { |
315 | | //debug_assert_eq!(self.todo, 0); |
316 | 0 | if self.todo == 0 { |
317 | 0 | self.handle_rst(stream)?; |
318 | 0 | } |
319 | | } else { |
320 | 0 | if self.options.get_strict_mode() { |
321 | 0 | return Err(DecodeErrors::Format(format!( |
322 | 0 | "Marker {m:?} found where not expected" |
323 | 0 | ))); |
324 | 0 | } |
325 | 0 | error!( |
326 | 0 | "Marker `{:?}` Found within Huffman Stream, possibly corrupt jpeg", |
327 | 0 | m |
328 | 0 | ); |
329 | 0 | self.parse_marker_inner(m)?; |
330 | 0 | if m == Marker::SOS { |
331 | 0 | return Ok(true); |
332 | 0 | } |
333 | | } |
334 | 0 | } |
335 | | } |
336 | 0 | Ok(false) |
337 | 0 | } Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width |
338 | | // handle RST markers. |
339 | | // No-op if not using restarts |
340 | | // this routine is shared with mcu_prog |
341 | | #[cold] |
342 | 0 | pub(crate) fn handle_rst(&mut self, stream: &mut BitStream) -> Result<(), DecodeErrors> { |
343 | 0 | self.todo = self.restart_interval; |
344 | | |
345 | 0 | if let Some(marker) = stream.marker { |
346 | | // Found a marker |
347 | | // Read stream and see what marker is stored there |
348 | 0 | match marker { |
349 | 0 | Marker::RST(_) => { |
350 | 0 | // reset stream |
351 | 0 | stream.reset(); |
352 | 0 | // Initialize dc predictions to zero for all components |
353 | 0 | self.components.iter_mut().for_each(|x| x.dc_pred = 0); Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0} |
354 | 0 | // Start iterating again. from position. |
355 | 0 | } |
356 | 0 | Marker::EOI => { |
357 | 0 | // silent pass |
358 | 0 | } |
359 | | _ => { |
360 | 0 | return Err(DecodeErrors::MCUError(format!( |
361 | 0 | "Marker {marker:?} found in bitstream, possibly corrupt jpeg" |
362 | 0 | ))); |
363 | | } |
364 | | } |
365 | 0 | } |
366 | 0 | Ok(()) |
367 | 0 | } Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst |
368 | | #[allow(clippy::too_many_lines, clippy::too_many_arguments)] |
369 | 0 | pub(crate) fn post_process( |
370 | 0 | &mut self, pixels: &mut [u8], i: usize, mcu_height: usize, width: usize, |
371 | 0 | padded_width: usize, pixels_written: &mut usize, upsampler_scratch_space: &mut [i16] |
372 | 0 | ) -> Result<(), DecodeErrors> { |
373 | 0 | let out_colorspace_components = self.options.jpeg_get_out_colorspace().num_components(); |
374 | 0 |
|
375 | 0 | let mut px = *pixels_written; |
376 | 0 | // indicates whether image is vertically up-sampled |
377 | 0 | let is_vertically_sampled = self |
378 | 0 | .components |
379 | 0 | .iter() |
380 | 0 | .any(|c| c.sample_ratio == SampleRatios::HV || c.sample_ratio == SampleRatios::V); Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0} |
381 | 0 |
|
382 | 0 | let mut comp_len = self.components.len(); |
383 | 0 |
|
384 | 0 | // If we are moving from YCbCr-> Luma, we do not allocate storage for other components, so we |
385 | 0 | // will panic when we are trying to read samples, so for that case, |
386 | 0 | // hardcode it so that we don't panic when doing |
387 | 0 | // *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width] |
388 | 0 | if out_colorspace_components < comp_len && self.options.jpeg_get_out_colorspace() == Luma { |
389 | 0 | comp_len = out_colorspace_components; |
390 | 0 | } |
391 | 0 | let mut color_conv_function = |
392 | 0 | |num_iters: usize, samples: [&[i16]; 4]| -> Result<(), DecodeErrors> { |
393 | 0 | for (pos, output) in pixels[px..] |
394 | 0 | .chunks_exact_mut(width * out_colorspace_components) |
395 | 0 | .take(num_iters) |
396 | 0 | .enumerate() |
397 | | { |
398 | 0 | let mut raw_samples: [&[i16]; 4] = [&[], &[], &[], &[]]; |
399 | | |
400 | | // iterate over each line, since color-convert needs only |
401 | | // one line |
402 | 0 | for (j, samp) in raw_samples.iter_mut().enumerate().take(comp_len) { |
403 | 0 | *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width]; |
404 | 0 | } |
405 | 0 | color_convert( |
406 | 0 | &raw_samples, |
407 | 0 | self.color_convert_16, |
408 | 0 | self.input_colorspace, |
409 | 0 | self.options.jpeg_get_out_colorspace(), |
410 | 0 | output, |
411 | 0 | width, |
412 | 0 | padded_width |
413 | 0 | )?; |
414 | 0 | px += width * out_colorspace_components; |
415 | | } |
416 | 0 | Ok(()) |
417 | 0 | }; Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1} |
418 | | |
419 | 0 | let comps = &mut self.components[..]; |
420 | 0 |
|
421 | 0 | if self.is_interleaved && self.options.jpeg_get_out_colorspace() != ColorSpace::Luma { |
422 | | { |
423 | | // duplicated so that we can check that samples match |
424 | | // Fixes bug https://github.com/etemesi254/zune-image/issues/151 |
425 | 0 | let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]]; |
426 | | |
427 | 0 | for (samp, component) in samples.iter_mut().zip(comps.iter()) { |
428 | 0 | *samp = if component.sample_ratio == SampleRatios::None { |
429 | 0 | &component.raw_coeff |
430 | | } else { |
431 | 0 | &component.upsample_dest |
432 | | }; |
433 | | } |
434 | | } |
435 | 0 | for comp in comps.iter_mut() { |
436 | 0 | upsample( |
437 | 0 | comp, |
438 | 0 | mcu_height, |
439 | 0 | i, |
440 | 0 | upsampler_scratch_space, |
441 | 0 | is_vertically_sampled |
442 | 0 | ); |
443 | 0 | } |
444 | | |
445 | 0 | if is_vertically_sampled { |
446 | 0 | if i > 0 { |
447 | | // write the last line, it wasn't up-sampled as we didn't have row_down |
448 | | // yet |
449 | 0 | let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]]; |
450 | | |
451 | 0 | for (samp, component) in samples.iter_mut().zip(comps.iter()) { |
452 | 0 | *samp = &component.first_row_upsample_dest; |
453 | 0 | } |
454 | | |
455 | | // ensure length matches for all samples |
456 | 0 | let _first_len = samples[0].len(); |
457 | 0 |
|
458 | 0 | // This was a good check, but can be caused to panic, esp on invalid/corrupt images. |
459 | 0 | // See one in issue https://github.com/etemesi254/zune-image/issues/262, so for now |
460 | 0 | // we just ignore and generate invalid images at the end. |
461 | 0 |
|
462 | 0 | // |
463 | 0 | // |
464 | 0 | // for samp in samples.iter().take(comp_len) { |
465 | 0 | // assert_eq!(first_len, samp.len()); |
466 | 0 | // } |
467 | 0 | let num_iters = self.coeff * self.v_max; |
468 | 0 |
|
469 | 0 | color_conv_function(num_iters, samples)?; |
470 | 0 | } |
471 | | |
472 | | // After up-sampling the last row, save any row that can be used for |
473 | | // a later up-sampling, |
474 | | // |
475 | | // E.g the Y sample is not sampled but we haven't finished upsampling the last row of |
476 | | // the previous mcu, since we don't have the down row, so save it |
477 | 0 | for component in comps.iter_mut() { |
478 | 0 | if component.sample_ratio != SampleRatios::H { |
479 | 0 | // We don't care about H sampling factors, since it's copied in the workers function |
480 | 0 |
|
481 | 0 | // copy last row to be used for the next color conversion |
482 | 0 | let size = component.vertical_sample |
483 | 0 | * component.width_stride |
484 | 0 | * component.sample_ratio.sample(); |
485 | 0 |
|
486 | 0 | let last_bytes = |
487 | 0 | component.raw_coeff.rchunks_exact_mut(size).next().unwrap(); |
488 | 0 |
|
489 | 0 | component |
490 | 0 | .first_row_upsample_dest |
491 | 0 | .copy_from_slice(last_bytes); |
492 | 0 | } |
493 | | } |
494 | 0 | } |
495 | | |
496 | 0 | let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]]; |
497 | | |
498 | 0 | for (samp, component) in samples.iter_mut().zip(comps.iter()) { |
499 | 0 | *samp = if component.sample_ratio == SampleRatios::None { |
500 | 0 | &component.raw_coeff |
501 | | } else { |
502 | 0 | &component.upsample_dest |
503 | | }; |
504 | | } |
505 | | |
506 | | // we either do 7 or 8 MCU's depending on the state, this only applies to |
507 | | // vertically sampled images |
508 | | // |
509 | | // for rows up until the last MCU, we do not upsample the last stride of the MCU |
510 | | // which means that the number of iterations should take that into account is one less the |
511 | | // up-sampled size |
512 | | // |
513 | | // For the last MCU, we upsample the last stride, meaning that if we hit the last MCU, we |
514 | | // should sample full raw coeffs |
515 | 0 | let is_last_considered = is_vertically_sampled && (i != mcu_height.saturating_sub(1)); |
516 | | |
517 | 0 | let num_iters = (8 - usize::from(is_last_considered)) * self.coeff * self.v_max; |
518 | 0 |
|
519 | 0 | color_conv_function(num_iters, samples)?; |
520 | | } else { |
521 | 0 | let mut channels_ref: [&[i16]; MAX_COMPONENTS] = [&[]; MAX_COMPONENTS]; |
522 | 0 |
|
523 | 0 | self.components |
524 | 0 | .iter() |
525 | 0 | .enumerate() |
526 | 0 | .for_each(|(pos, x)| channels_ref[pos] = &x.raw_coeff); Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2} Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2} |
527 | 0 |
|
528 | 0 | color_conv_function(8 * self.coeff, channels_ref)?; |
529 | | } |
530 | | |
531 | 0 | *pixels_written = px; |
532 | 0 | Ok(()) |
533 | 0 | } Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process |
534 | | } |