/rust/registry/src/index.crates.io-1949cf8c6b5b557f/zune-jpeg-0.4.21/src/mcu_prog.rs
Line | Count | Source |
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 | | //!Routines for progressive decoding |
10 | | /* |
11 | | This file is needlessly complicated, |
12 | | |
13 | | It is that way to ensure we don't burn memory anyhow |
14 | | |
15 | | Memory is a scarce resource in some environments, I would like this to be viable |
16 | | in such environments |
17 | | |
18 | | Half of the complexity comes from the jpeg spec, because progressive decoding, |
19 | | is one hell of a ride. |
20 | | |
21 | | */ |
22 | | use alloc::string::ToString; |
23 | | use alloc::vec::Vec; |
24 | | use alloc::{format, vec}; |
25 | | use core::cmp::min; |
26 | | use zune_core::bytestream::{ZByteReader, ZReaderTrait}; |
27 | | use zune_core::colorspace::ColorSpace; |
28 | | use zune_core::log::{debug, error, warn}; |
29 | | |
30 | | use crate::bitstream::BitStream; |
31 | | use crate::components::{ComponentID, SampleRatios}; |
32 | | use crate::decoder::{JpegDecoder, MAX_COMPONENTS}; |
33 | | use crate::errors::DecodeErrors; |
34 | | use crate::headers::{parse_sos}; |
35 | | use crate::marker::Marker; |
36 | | use crate::mcu::DCT_BLOCK; |
37 | | use crate::misc::{calculate_padded_width, setup_component_params}; |
38 | | |
39 | | impl<T: ZReaderTrait> JpegDecoder<T> { |
40 | | /// Decode a progressive image |
41 | | /// |
42 | | /// This routine decodes a progressive image, stopping if it finds any error. |
43 | | #[allow( |
44 | | clippy::needless_range_loop, |
45 | | clippy::cast_sign_loss, |
46 | | clippy::redundant_else, |
47 | | clippy::too_many_lines |
48 | | )] |
49 | | #[inline(never)] |
50 | 1.93k | pub(crate) fn decode_mcu_ycbcr_progressive( |
51 | 1.93k | &mut self, pixels: &mut [u8], |
52 | 1.93k | ) -> Result<(), DecodeErrors> { |
53 | 1.93k | setup_component_params(self)?; |
54 | | |
55 | | let mut mcu_height; |
56 | | |
57 | | // memory location for decoded pixels for components |
58 | 1.93k | let mut block: [Vec<i16>; MAX_COMPONENTS] = [vec![], vec![], vec![], vec![]]; |
59 | | let mut mcu_width; |
60 | | |
61 | 1.93k | let mut seen_scans = 1; |
62 | | |
63 | 1.93k | if self.input_colorspace == ColorSpace::Luma && self.is_interleaved { |
64 | 1 | warn!("Grayscale image with down-sampled component, resetting component details"); |
65 | 1 | self.reset_params(); |
66 | 1.93k | } |
67 | | |
68 | 1.93k | if self.is_interleaved { |
69 | | // this helps us catch component errors. |
70 | 0 | self.set_upsampling()?; |
71 | 1.93k | } |
72 | 1.93k | if self.is_interleaved { |
73 | 0 | mcu_width = self.mcu_x; |
74 | 0 | mcu_height = self.mcu_y; |
75 | 1.93k | } else { |
76 | 1.93k | mcu_width = (self.info.width as usize + 7) / 8; |
77 | 1.93k | mcu_height = (self.info.height as usize + 7) / 8; |
78 | 1.93k | } |
79 | 1.93k | if self.is_interleaved |
80 | 0 | && self.input_colorspace.num_components() > 1 |
81 | 0 | && self.options.jpeg_get_out_colorspace().num_components() == 1 |
82 | 0 | && (self.sub_sample_ratio == SampleRatios::V |
83 | 0 | || self.sub_sample_ratio == SampleRatios::HV) |
84 | 0 | { |
85 | 0 | // For a specific set of images, e.g interleaved, |
86 | 0 | // when converting from YcbCr to grayscale, we need to |
87 | 0 | // take into account mcu height since the MCU decoding needs to take |
88 | 0 | // it into account for padding purposes and the post processor |
89 | 0 | // parses two rows per mcu width. |
90 | 0 | // |
91 | 0 | // set coeff to be 2 to ensure that we increment two rows |
92 | 0 | // for every mcu processed also |
93 | 0 | mcu_height *= self.v_max; |
94 | 0 | mcu_height /= self.h_max; |
95 | 0 | self.coeff = 2; |
96 | 1.93k | } |
97 | | |
98 | 1.93k | mcu_width *= 64; |
99 | | |
100 | | |
101 | 1.93k | for i in 0..self.input_colorspace.num_components() { |
102 | 1.93k | let comp = &self.components[i]; |
103 | 1.93k | let len = mcu_width * comp.vertical_sample * comp.horizontal_sample * mcu_height; |
104 | 1.93k | |
105 | 1.93k | block[i] = vec![0; len]; |
106 | 1.93k | } |
107 | | |
108 | 1.93k | let mut stream = BitStream::new_progressive( |
109 | 1.93k | self.succ_high, |
110 | 1.93k | self.succ_low, |
111 | 1.93k | self.spec_start, |
112 | 1.93k | self.spec_end |
113 | | ); |
114 | | |
115 | | // there are multiple scans in the stream, this should resolve the first scan |
116 | 1.93k | self.parse_entropy_coded_data(&mut stream, &mut block)?; |
117 | | |
118 | | // extract marker |
119 | 1.81k | let mut marker = stream |
120 | 1.81k | .marker |
121 | 1.81k | .take() |
122 | 1.81k | .ok_or(DecodeErrors::FormatStatic("Marker missing where expected"))?; |
123 | | |
124 | | // if marker is EOI, we are done, otherwise continue scanning. |
125 | | // |
126 | | // In case we have a premature image, we print a warning or return |
127 | | // an error, depending on the strictness of the decoder, so there |
128 | | // is that logic to handle too |
129 | 79.7k | 'eoi: while marker != Marker::EOI { |
130 | 79.6k | match marker { |
131 | | Marker::SOS => { |
132 | 10.5k | parse_sos(self)?; |
133 | | |
134 | 10.5k | stream.update_progressive_params( |
135 | 10.5k | self.succ_high, |
136 | 10.5k | self.succ_low, |
137 | 10.5k | self.spec_start, |
138 | 10.5k | self.spec_end |
139 | | ); |
140 | | // after every SOS, marker, parse data for that scan. |
141 | 10.5k | self.parse_entropy_coded_data(&mut stream, &mut block)?; |
142 | | // extract marker, might either indicate end of image or we continue |
143 | | // scanning(hence the continue statement to determine). |
144 | 10.2k | match get_marker(&mut self.stream, &mut stream) { |
145 | 9.70k | Ok(marker_n) => { |
146 | 9.70k | marker = marker_n; |
147 | 9.70k | seen_scans += 1; |
148 | 9.70k | if seen_scans > self.options.jpeg_get_max_scans() { |
149 | 12 | return Err(DecodeErrors::Format(format!( |
150 | 12 | "Too many scans, exceeded limit of {}", |
151 | 12 | self.options.jpeg_get_max_scans() |
152 | 12 | ))); |
153 | 9.69k | } |
154 | | |
155 | 9.69k | stream.reset(); |
156 | 9.69k | continue 'eoi; |
157 | | } |
158 | 535 | Err(msg) => { |
159 | 535 | if self.options.get_strict_mode() { |
160 | 535 | return Err(msg); |
161 | 0 | } |
162 | 0 | error!("{:?}", msg); |
163 | 0 | break 'eoi; |
164 | | } |
165 | | } |
166 | | } |
167 | 1.20k | Marker::RST(_n) => { |
168 | 1.20k | self.handle_rst(&mut stream)?; |
169 | | } |
170 | | _ => { |
171 | 67.8k | self.parse_marker_inner(marker)?; |
172 | | } |
173 | | } |
174 | | |
175 | 68.8k | match get_marker(&mut self.stream, &mut stream) { |
176 | 68.5k | Ok(marker_n) => { |
177 | 68.5k | marker = marker_n; |
178 | 68.5k | } |
179 | 341 | Err(e) => { |
180 | 341 | if self.options.get_strict_mode() { |
181 | 341 | return Err(e); |
182 | 0 | } |
183 | 0 | error!("{}", e); |
184 | | } |
185 | | } |
186 | | } |
187 | | |
188 | 102 | self.finish_progressive_decoding(&block, mcu_width, pixels) |
189 | 1.93k | } Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_progressive Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::decode_mcu_ycbcr_progressive <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_progressive Line | Count | Source | 50 | 1.93k | pub(crate) fn decode_mcu_ycbcr_progressive( | 51 | 1.93k | &mut self, pixels: &mut [u8], | 52 | 1.93k | ) -> Result<(), DecodeErrors> { | 53 | 1.93k | setup_component_params(self)?; | 54 | | | 55 | | let mut mcu_height; | 56 | | | 57 | | // memory location for decoded pixels for components | 58 | 1.93k | let mut block: [Vec<i16>; MAX_COMPONENTS] = [vec![], vec![], vec![], vec![]]; | 59 | | let mut mcu_width; | 60 | | | 61 | 1.93k | let mut seen_scans = 1; | 62 | | | 63 | 1.93k | if self.input_colorspace == ColorSpace::Luma && self.is_interleaved { | 64 | 1 | warn!("Grayscale image with down-sampled component, resetting component details"); | 65 | 1 | self.reset_params(); | 66 | 1.93k | } | 67 | | | 68 | 1.93k | if self.is_interleaved { | 69 | | // this helps us catch component errors. | 70 | 0 | self.set_upsampling()?; | 71 | 1.93k | } | 72 | 1.93k | if self.is_interleaved { | 73 | 0 | mcu_width = self.mcu_x; | 74 | 0 | mcu_height = self.mcu_y; | 75 | 1.93k | } else { | 76 | 1.93k | mcu_width = (self.info.width as usize + 7) / 8; | 77 | 1.93k | mcu_height = (self.info.height as usize + 7) / 8; | 78 | 1.93k | } | 79 | 1.93k | if self.is_interleaved | 80 | 0 | && self.input_colorspace.num_components() > 1 | 81 | 0 | && self.options.jpeg_get_out_colorspace().num_components() == 1 | 82 | 0 | && (self.sub_sample_ratio == SampleRatios::V | 83 | 0 | || self.sub_sample_ratio == SampleRatios::HV) | 84 | 0 | { | 85 | 0 | // For a specific set of images, e.g interleaved, | 86 | 0 | // when converting from YcbCr to grayscale, we need to | 87 | 0 | // take into account mcu height since the MCU decoding needs to take | 88 | 0 | // it into account for padding purposes and the post processor | 89 | 0 | // parses two rows per mcu width. | 90 | 0 | // | 91 | 0 | // set coeff to be 2 to ensure that we increment two rows | 92 | 0 | // for every mcu processed also | 93 | 0 | mcu_height *= self.v_max; | 94 | 0 | mcu_height /= self.h_max; | 95 | 0 | self.coeff = 2; | 96 | 1.93k | } | 97 | | | 98 | 1.93k | mcu_width *= 64; | 99 | | | 100 | | | 101 | 1.93k | for i in 0..self.input_colorspace.num_components() { | 102 | 1.93k | let comp = &self.components[i]; | 103 | 1.93k | let len = mcu_width * comp.vertical_sample * comp.horizontal_sample * mcu_height; | 104 | 1.93k | | 105 | 1.93k | block[i] = vec![0; len]; | 106 | 1.93k | } | 107 | | | 108 | 1.93k | let mut stream = BitStream::new_progressive( | 109 | 1.93k | self.succ_high, | 110 | 1.93k | self.succ_low, | 111 | 1.93k | self.spec_start, | 112 | 1.93k | self.spec_end | 113 | | ); | 114 | | | 115 | | // there are multiple scans in the stream, this should resolve the first scan | 116 | 1.93k | self.parse_entropy_coded_data(&mut stream, &mut block)?; | 117 | | | 118 | | // extract marker | 119 | 1.81k | let mut marker = stream | 120 | 1.81k | .marker | 121 | 1.81k | .take() | 122 | 1.81k | .ok_or(DecodeErrors::FormatStatic("Marker missing where expected"))?; | 123 | | | 124 | | // if marker is EOI, we are done, otherwise continue scanning. | 125 | | // | 126 | | // In case we have a premature image, we print a warning or return | 127 | | // an error, depending on the strictness of the decoder, so there | 128 | | // is that logic to handle too | 129 | 79.7k | 'eoi: while marker != Marker::EOI { | 130 | 79.6k | match marker { | 131 | | Marker::SOS => { | 132 | 10.5k | parse_sos(self)?; | 133 | | | 134 | 10.5k | stream.update_progressive_params( | 135 | 10.5k | self.succ_high, | 136 | 10.5k | self.succ_low, | 137 | 10.5k | self.spec_start, | 138 | 10.5k | self.spec_end | 139 | | ); | 140 | | // after every SOS, marker, parse data for that scan. | 141 | 10.5k | self.parse_entropy_coded_data(&mut stream, &mut block)?; | 142 | | // extract marker, might either indicate end of image or we continue | 143 | | // scanning(hence the continue statement to determine). | 144 | 10.2k | match get_marker(&mut self.stream, &mut stream) { | 145 | 9.70k | Ok(marker_n) => { | 146 | 9.70k | marker = marker_n; | 147 | 9.70k | seen_scans += 1; | 148 | 9.70k | if seen_scans > self.options.jpeg_get_max_scans() { | 149 | 12 | return Err(DecodeErrors::Format(format!( | 150 | 12 | "Too many scans, exceeded limit of {}", | 151 | 12 | self.options.jpeg_get_max_scans() | 152 | 12 | ))); | 153 | 9.69k | } | 154 | | | 155 | 9.69k | stream.reset(); | 156 | 9.69k | continue 'eoi; | 157 | | } | 158 | 535 | Err(msg) => { | 159 | 535 | if self.options.get_strict_mode() { | 160 | 535 | return Err(msg); | 161 | 0 | } | 162 | 0 | error!("{:?}", msg); | 163 | 0 | break 'eoi; | 164 | | } | 165 | | } | 166 | | } | 167 | 1.20k | Marker::RST(_n) => { | 168 | 1.20k | self.handle_rst(&mut stream)?; | 169 | | } | 170 | | _ => { | 171 | 67.8k | self.parse_marker_inner(marker)?; | 172 | | } | 173 | | } | 174 | | | 175 | 68.8k | match get_marker(&mut self.stream, &mut stream) { | 176 | 68.5k | Ok(marker_n) => { | 177 | 68.5k | marker = marker_n; | 178 | 68.5k | } | 179 | 341 | Err(e) => { | 180 | 341 | if self.options.get_strict_mode() { | 181 | 341 | return Err(e); | 182 | 0 | } | 183 | 0 | error!("{}", e); | 184 | | } | 185 | | } | 186 | | } | 187 | | | 188 | 102 | self.finish_progressive_decoding(&block, mcu_width, pixels) | 189 | 1.93k | } |
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_progressive Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_progressive Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_progressive Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_progressive Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_progressive Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_progressive Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_progressive Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_progressive Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_progressive |
190 | | |
191 | | /// Reset progressive parameters |
192 | 12.4k | fn reset_prog_params(&mut self, stream: &mut BitStream) { |
193 | 12.4k | stream.reset(); |
194 | 12.4k | self.components.iter_mut().for_each(|x| x.dc_pred = 0); |
195 | | |
196 | | // Also reset JPEG restart intervals |
197 | 12.4k | self.todo = if self.restart_interval != 0 { self.restart_interval } else { usize::MAX }; |
198 | 12.4k | } Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_prog_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::reset_prog_params <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_prog_params Line | Count | Source | 192 | 12.4k | fn reset_prog_params(&mut self, stream: &mut BitStream) { | 193 | 12.4k | stream.reset(); | 194 | 12.4k | self.components.iter_mut().for_each(|x| x.dc_pred = 0); | 195 | | | 196 | | // Also reset JPEG restart intervals | 197 | 12.4k | self.todo = if self.restart_interval != 0 { self.restart_interval } else { usize::MAX }; | 198 | 12.4k | } |
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_prog_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_prog_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_prog_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_prog_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_prog_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_prog_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_prog_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_prog_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_prog_params |
199 | | |
200 | | #[allow(clippy::too_many_lines, clippy::cast_sign_loss)] |
201 | 12.4k | fn parse_entropy_coded_data( |
202 | 12.4k | &mut self, stream: &mut BitStream, buffer: &mut [Vec<i16>; MAX_COMPONENTS] |
203 | 12.4k | ) -> Result<(), DecodeErrors> { |
204 | 12.4k | self.reset_prog_params(stream); |
205 | | |
206 | 12.4k | if usize::from(self.num_scans) > self.input_colorspace.num_components() { |
207 | 0 | return Err(DecodeErrors::Format(format!( |
208 | 0 | "Number of scans {} cannot be greater than number of components, {}", |
209 | 0 | self.num_scans, |
210 | 0 | self.input_colorspace.num_components() |
211 | 0 | ))); |
212 | 12.4k | } |
213 | 12.4k | if self.num_scans == 1 { |
214 | | // Safety checks |
215 | 12.4k | if self.spec_end != 0 && self.spec_start == 0 { |
216 | 3 | return Err(DecodeErrors::FormatStatic( |
217 | 3 | "Can't merge DC and AC corrupt jpeg" |
218 | 3 | )); |
219 | 12.4k | } |
220 | | // non interleaved data, process one block at a time in trivial scanline order |
221 | | |
222 | 12.4k | let k = self.z_order[0]; |
223 | | |
224 | 12.4k | if k >= self.components.len() { |
225 | 0 | return Err(DecodeErrors::Format(format!( |
226 | 0 | "Cannot find component {k}, corrupt image" |
227 | 0 | ))); |
228 | 12.4k | } |
229 | | |
230 | | let (mcu_width, mcu_height); |
231 | | |
232 | 12.4k | if self.components[k].component_id == ComponentID::Y |
233 | 12.4k | && (self.components[k].vertical_sample != 1 |
234 | 12.4k | || self.components[k].horizontal_sample != 1) |
235 | 12.4k | || !self.is_interleaved |
236 | 12.4k | { |
237 | 12.4k | // For Y channel or non interleaved scans , |
238 | 12.4k | // mcu's is the image dimensions divided by 8 |
239 | 12.4k | mcu_width = ((self.info.width + 7) / 8) as usize; |
240 | 12.4k | mcu_height = ((self.info.height + 7) / 8) as usize; |
241 | 12.4k | } else { |
242 | 0 | // For other channels, in an interleaved mcu, number of MCU's |
243 | 0 | // are determined by some weird maths done in headers.rs->parse_sos() |
244 | 0 | mcu_width = self.mcu_x; |
245 | 0 | mcu_height = self.mcu_y; |
246 | 0 | } |
247 | | |
248 | 546k | for i in 0..mcu_height { |
249 | 112M | for j in 0..mcu_width { |
250 | 112M | if self.spec_start != 0 && self.succ_high == 0 && stream.eob_run > 0 { |
251 | 61.5k | // handle EOB runs here. |
252 | 61.5k | stream.eob_run -= 1; |
253 | 61.5k | } else { |
254 | 112M | let start = 64 * (j + i * (self.components[k].width_stride / 8)); |
255 | | |
256 | 112M | let data: &mut [i16; 64] = buffer |
257 | 112M | .get_mut(k) |
258 | 112M | .unwrap() |
259 | 112M | .get_mut(start..start + 64) |
260 | 112M | .unwrap() |
261 | 112M | .try_into() |
262 | 112M | .unwrap(); |
263 | | |
264 | 112M | if self.spec_start == 0 { |
265 | 61.8M | let pos = self.components[k].dc_huff_table & (MAX_COMPONENTS - 1); |
266 | 61.8M | let dc_table = self |
267 | 61.8M | .dc_huffman_tables |
268 | 61.8M | .get(pos) |
269 | 61.8M | .ok_or(DecodeErrors::FormatStatic( |
270 | 61.8M | "No huffman table for DC component" |
271 | 61.8M | ))? |
272 | 61.8M | .as_ref() |
273 | 61.8M | .ok_or(DecodeErrors::FormatStatic( |
274 | 61.8M | "Huffman table at index {} not initialized" |
275 | 61.8M | ))?; |
276 | | |
277 | 61.8M | let dc_pred = &mut self.components[k].dc_pred; |
278 | | |
279 | 61.8M | if self.succ_high == 0 { |
280 | | // first scan for this mcu |
281 | 43.0M | stream.decode_prog_dc_first( |
282 | 43.0M | &mut self.stream, |
283 | 43.0M | dc_table, |
284 | 43.0M | &mut data[0], |
285 | 43.0M | dc_pred |
286 | 75 | )?; |
287 | | } else { |
288 | | // refining scans for this MCU |
289 | 18.7M | stream.decode_prog_dc_refine(&mut self.stream, &mut data[0])?; |
290 | | } |
291 | | } else { |
292 | 50.9M | let pos = self.components[k].ac_huff_table; |
293 | 50.9M | let ac_table = self |
294 | 50.9M | .ac_huffman_tables |
295 | 50.9M | .get(pos) |
296 | 50.9M | .ok_or_else(|| { |
297 | 0 | DecodeErrors::Format(format!( |
298 | 0 | "No huffman table for component:{pos}" |
299 | 0 | )) |
300 | 0 | })? Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#0}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::parse_entropy_coded_data::{closure#0}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#0}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#0}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#0}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#0}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#0}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#0}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#0}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#0}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#0}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#0} |
301 | 50.9M | .as_ref() |
302 | 50.9M | .ok_or_else(|| { |
303 | 0 | DecodeErrors::Format(format!( |
304 | 0 | "Huffman table at index {pos} not initialized" |
305 | 0 | )) |
306 | 0 | })?; Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#1}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::parse_entropy_coded_data::{closure#1}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#1}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#1}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#1}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#1}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#1}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#1}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#1}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#1}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#1}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#1} |
307 | | |
308 | 50.9M | if self.succ_high == 0 { |
309 | 14.3M | debug_assert!(stream.eob_run == 0, "EOB run is not zero"); |
310 | | |
311 | 14.3M | stream.decode_mcu_ac_first(&mut self.stream, ac_table, data)?; |
312 | | } else { |
313 | | // refinement scan |
314 | 36.5M | stream.decode_mcu_ac_refine(&mut self.stream, ac_table, data)?; |
315 | | } |
316 | | } |
317 | | } |
318 | | |
319 | | // + EOB and investigate effect. |
320 | 112M | self.todo -= 1; |
321 | | |
322 | 112M | self.handle_rst_main(stream)?; |
323 | | } |
324 | | } |
325 | | } else { |
326 | 0 | if self.spec_end != 0 { |
327 | 0 | return Err(DecodeErrors::HuffmanDecode( |
328 | 0 | "Can't merge dc and AC corrupt jpeg".to_string() |
329 | 0 | )); |
330 | 0 | } |
331 | | // process scan n elements in order |
332 | | |
333 | | // Do the error checking with allocs here. |
334 | | // Make the one in the inner loop free of allocations. |
335 | 0 | for k in 0..self.num_scans { |
336 | 0 | let n = self.z_order[k as usize]; |
337 | | |
338 | 0 | if n >= self.components.len() { |
339 | 0 | return Err(DecodeErrors::Format(format!( |
340 | 0 | "Cannot find component {n}, corrupt image" |
341 | 0 | ))); |
342 | 0 | } |
343 | | |
344 | 0 | let component = &mut self.components[n]; |
345 | 0 | let _ = self |
346 | 0 | .dc_huffman_tables |
347 | 0 | .get(component.dc_huff_table) |
348 | 0 | .ok_or_else(|| { |
349 | 0 | DecodeErrors::Format(format!( |
350 | 0 | "No huffman table for component:{}", |
351 | 0 | component.dc_huff_table |
352 | 0 | )) |
353 | 0 | })? Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#2}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::parse_entropy_coded_data::{closure#2}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#2}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#2}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#2}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#2}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#2}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#2}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#2}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#2}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#2}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#2} |
354 | 0 | .as_ref() |
355 | 0 | .ok_or_else(|| { |
356 | 0 | DecodeErrors::Format(format!( |
357 | 0 | "Huffman table at index {} not initialized", |
358 | 0 | component.dc_huff_table |
359 | 0 | )) |
360 | 0 | })?; Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#3}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::parse_entropy_coded_data::{closure#3}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#3}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#3}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#3}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#3}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#3}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#3}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#3}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#3}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#3}Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data::{closure#3} |
361 | | } |
362 | | // Interleaved scan |
363 | | |
364 | | // Components shall not be interleaved in progressive mode, except for |
365 | | // the DC coefficients in the first scan for each component of a progressive frame. |
366 | 0 | for i in 0..self.mcu_y { |
367 | 0 | for j in 0..self.mcu_x { |
368 | | // process scan n elements in order |
369 | 0 | for k in 0..self.num_scans { |
370 | 0 | let n = self.z_order[k as usize]; |
371 | 0 | let component = &mut self.components[n]; |
372 | 0 | let huff_table = self |
373 | 0 | .dc_huffman_tables |
374 | 0 | .get(component.dc_huff_table) |
375 | 0 | .ok_or(DecodeErrors::FormatStatic("No huffman table for component"))? |
376 | 0 | .as_ref() |
377 | 0 | .ok_or(DecodeErrors::FormatStatic( |
378 | 0 | "Huffman table at index not initialized" |
379 | 0 | ))?; |
380 | | |
381 | 0 | for v_samp in 0..component.vertical_sample { |
382 | 0 | for h_samp in 0..component.horizontal_sample { |
383 | 0 | let x2 = j * component.horizontal_sample + h_samp; |
384 | 0 | let y2 = i * component.vertical_sample + v_samp; |
385 | 0 | let position = 64 * (x2 + y2 * component.width_stride / 8); |
386 | 0 | let buf_n = &mut buffer[n]; |
387 | | |
388 | 0 | let Some(data) = &mut buf_n.get_mut(position) else { |
389 | | // TODO: (CAE), this is another weird sub-sampling bug, so on fix |
390 | | // remove this |
391 | 0 | return Err(DecodeErrors::FormatStatic("Invalid image")); |
392 | | }; |
393 | | |
394 | 0 | if self.succ_high == 0 { |
395 | 0 | stream.decode_prog_dc_first( |
396 | 0 | &mut self.stream, |
397 | 0 | huff_table, |
398 | 0 | data, |
399 | 0 | &mut component.dc_pred |
400 | 0 | )?; |
401 | | } else { |
402 | 0 | stream.decode_prog_dc_refine(&mut self.stream, data)?; |
403 | | } |
404 | | } |
405 | | } |
406 | | } |
407 | | // We want wrapping subtraction here because it means |
408 | | // we get a higher number in the case this underflows |
409 | 0 | self.todo -= 1; |
410 | | // after every scan that's a mcu, count down restart markers. |
411 | 0 | self.handle_rst_main(stream)?; |
412 | | } |
413 | | } |
414 | | } |
415 | 12.0k | return Ok(()); |
416 | 12.4k | } Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::parse_entropy_coded_data <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data Line | Count | Source | 201 | 12.4k | fn parse_entropy_coded_data( | 202 | 12.4k | &mut self, stream: &mut BitStream, buffer: &mut [Vec<i16>; MAX_COMPONENTS] | 203 | 12.4k | ) -> Result<(), DecodeErrors> { | 204 | 12.4k | self.reset_prog_params(stream); | 205 | | | 206 | 12.4k | if usize::from(self.num_scans) > self.input_colorspace.num_components() { | 207 | 0 | return Err(DecodeErrors::Format(format!( | 208 | 0 | "Number of scans {} cannot be greater than number of components, {}", | 209 | 0 | self.num_scans, | 210 | 0 | self.input_colorspace.num_components() | 211 | 0 | ))); | 212 | 12.4k | } | 213 | 12.4k | if self.num_scans == 1 { | 214 | | // Safety checks | 215 | 12.4k | if self.spec_end != 0 && self.spec_start == 0 { | 216 | 3 | return Err(DecodeErrors::FormatStatic( | 217 | 3 | "Can't merge DC and AC corrupt jpeg" | 218 | 3 | )); | 219 | 12.4k | } | 220 | | // non interleaved data, process one block at a time in trivial scanline order | 221 | | | 222 | 12.4k | let k = self.z_order[0]; | 223 | | | 224 | 12.4k | if k >= self.components.len() { | 225 | 0 | return Err(DecodeErrors::Format(format!( | 226 | 0 | "Cannot find component {k}, corrupt image" | 227 | 0 | ))); | 228 | 12.4k | } | 229 | | | 230 | | let (mcu_width, mcu_height); | 231 | | | 232 | 12.4k | if self.components[k].component_id == ComponentID::Y | 233 | 12.4k | && (self.components[k].vertical_sample != 1 | 234 | 12.4k | || self.components[k].horizontal_sample != 1) | 235 | 12.4k | || !self.is_interleaved | 236 | 12.4k | { | 237 | 12.4k | // For Y channel or non interleaved scans , | 238 | 12.4k | // mcu's is the image dimensions divided by 8 | 239 | 12.4k | mcu_width = ((self.info.width + 7) / 8) as usize; | 240 | 12.4k | mcu_height = ((self.info.height + 7) / 8) as usize; | 241 | 12.4k | } else { | 242 | 0 | // For other channels, in an interleaved mcu, number of MCU's | 243 | 0 | // are determined by some weird maths done in headers.rs->parse_sos() | 244 | 0 | mcu_width = self.mcu_x; | 245 | 0 | mcu_height = self.mcu_y; | 246 | 0 | } | 247 | | | 248 | 546k | for i in 0..mcu_height { | 249 | 112M | for j in 0..mcu_width { | 250 | 112M | if self.spec_start != 0 && self.succ_high == 0 && stream.eob_run > 0 { | 251 | 61.5k | // handle EOB runs here. | 252 | 61.5k | stream.eob_run -= 1; | 253 | 61.5k | } else { | 254 | 112M | let start = 64 * (j + i * (self.components[k].width_stride / 8)); | 255 | | | 256 | 112M | let data: &mut [i16; 64] = buffer | 257 | 112M | .get_mut(k) | 258 | 112M | .unwrap() | 259 | 112M | .get_mut(start..start + 64) | 260 | 112M | .unwrap() | 261 | 112M | .try_into() | 262 | 112M | .unwrap(); | 263 | | | 264 | 112M | if self.spec_start == 0 { | 265 | 61.8M | let pos = self.components[k].dc_huff_table & (MAX_COMPONENTS - 1); | 266 | 61.8M | let dc_table = self | 267 | 61.8M | .dc_huffman_tables | 268 | 61.8M | .get(pos) | 269 | 61.8M | .ok_or(DecodeErrors::FormatStatic( | 270 | 61.8M | "No huffman table for DC component" | 271 | 61.8M | ))? | 272 | 61.8M | .as_ref() | 273 | 61.8M | .ok_or(DecodeErrors::FormatStatic( | 274 | 61.8M | "Huffman table at index {} not initialized" | 275 | 61.8M | ))?; | 276 | | | 277 | 61.8M | let dc_pred = &mut self.components[k].dc_pred; | 278 | | | 279 | 61.8M | if self.succ_high == 0 { | 280 | | // first scan for this mcu | 281 | 43.0M | stream.decode_prog_dc_first( | 282 | 43.0M | &mut self.stream, | 283 | 43.0M | dc_table, | 284 | 43.0M | &mut data[0], | 285 | 43.0M | dc_pred | 286 | 75 | )?; | 287 | | } else { | 288 | | // refining scans for this MCU | 289 | 18.7M | stream.decode_prog_dc_refine(&mut self.stream, &mut data[0])?; | 290 | | } | 291 | | } else { | 292 | 50.9M | let pos = self.components[k].ac_huff_table; | 293 | 50.9M | let ac_table = self | 294 | 50.9M | .ac_huffman_tables | 295 | 50.9M | .get(pos) | 296 | 50.9M | .ok_or_else(|| { | 297 | | DecodeErrors::Format(format!( | 298 | | "No huffman table for component:{pos}" | 299 | | )) | 300 | 0 | })? | 301 | 50.9M | .as_ref() | 302 | 50.9M | .ok_or_else(|| { | 303 | | DecodeErrors::Format(format!( | 304 | | "Huffman table at index {pos} not initialized" | 305 | | )) | 306 | 0 | })?; | 307 | | | 308 | 50.9M | if self.succ_high == 0 { | 309 | 14.3M | debug_assert!(stream.eob_run == 0, "EOB run is not zero"); | 310 | | | 311 | 14.3M | stream.decode_mcu_ac_first(&mut self.stream, ac_table, data)?; | 312 | | } else { | 313 | | // refinement scan | 314 | 36.5M | stream.decode_mcu_ac_refine(&mut self.stream, ac_table, data)?; | 315 | | } | 316 | | } | 317 | | } | 318 | | | 319 | | // + EOB and investigate effect. | 320 | 112M | self.todo -= 1; | 321 | | | 322 | 112M | self.handle_rst_main(stream)?; | 323 | | } | 324 | | } | 325 | | } else { | 326 | 0 | if self.spec_end != 0 { | 327 | 0 | return Err(DecodeErrors::HuffmanDecode( | 328 | 0 | "Can't merge dc and AC corrupt jpeg".to_string() | 329 | 0 | )); | 330 | 0 | } | 331 | | // process scan n elements in order | 332 | | | 333 | | // Do the error checking with allocs here. | 334 | | // Make the one in the inner loop free of allocations. | 335 | 0 | for k in 0..self.num_scans { | 336 | 0 | let n = self.z_order[k as usize]; | 337 | | | 338 | 0 | if n >= self.components.len() { | 339 | 0 | return Err(DecodeErrors::Format(format!( | 340 | 0 | "Cannot find component {n}, corrupt image" | 341 | 0 | ))); | 342 | 0 | } | 343 | | | 344 | 0 | let component = &mut self.components[n]; | 345 | 0 | let _ = self | 346 | 0 | .dc_huffman_tables | 347 | 0 | .get(component.dc_huff_table) | 348 | 0 | .ok_or_else(|| { | 349 | | DecodeErrors::Format(format!( | 350 | | "No huffman table for component:{}", | 351 | | component.dc_huff_table | 352 | | )) | 353 | 0 | })? | 354 | 0 | .as_ref() | 355 | 0 | .ok_or_else(|| { | 356 | | DecodeErrors::Format(format!( | 357 | | "Huffman table at index {} not initialized", | 358 | | component.dc_huff_table | 359 | | )) | 360 | 0 | })?; | 361 | | } | 362 | | // Interleaved scan | 363 | | | 364 | | // Components shall not be interleaved in progressive mode, except for | 365 | | // the DC coefficients in the first scan for each component of a progressive frame. | 366 | 0 | for i in 0..self.mcu_y { | 367 | 0 | for j in 0..self.mcu_x { | 368 | | // process scan n elements in order | 369 | 0 | for k in 0..self.num_scans { | 370 | 0 | let n = self.z_order[k as usize]; | 371 | 0 | let component = &mut self.components[n]; | 372 | 0 | let huff_table = self | 373 | 0 | .dc_huffman_tables | 374 | 0 | .get(component.dc_huff_table) | 375 | 0 | .ok_or(DecodeErrors::FormatStatic("No huffman table for component"))? | 376 | 0 | .as_ref() | 377 | 0 | .ok_or(DecodeErrors::FormatStatic( | 378 | 0 | "Huffman table at index not initialized" | 379 | 0 | ))?; | 380 | | | 381 | 0 | for v_samp in 0..component.vertical_sample { | 382 | 0 | for h_samp in 0..component.horizontal_sample { | 383 | 0 | let x2 = j * component.horizontal_sample + h_samp; | 384 | 0 | let y2 = i * component.vertical_sample + v_samp; | 385 | 0 | let position = 64 * (x2 + y2 * component.width_stride / 8); | 386 | 0 | let buf_n = &mut buffer[n]; | 387 | | | 388 | 0 | let Some(data) = &mut buf_n.get_mut(position) else { | 389 | | // TODO: (CAE), this is another weird sub-sampling bug, so on fix | 390 | | // remove this | 391 | 0 | return Err(DecodeErrors::FormatStatic("Invalid image")); | 392 | | }; | 393 | | | 394 | 0 | if self.succ_high == 0 { | 395 | 0 | stream.decode_prog_dc_first( | 396 | 0 | &mut self.stream, | 397 | 0 | huff_table, | 398 | 0 | data, | 399 | 0 | &mut component.dc_pred | 400 | 0 | )?; | 401 | | } else { | 402 | 0 | stream.decode_prog_dc_refine(&mut self.stream, data)?; | 403 | | } | 404 | | } | 405 | | } | 406 | | } | 407 | | // We want wrapping subtraction here because it means | 408 | | // we get a higher number in the case this underflows | 409 | 0 | self.todo -= 1; | 410 | | // after every scan that's a mcu, count down restart markers. | 411 | 0 | self.handle_rst_main(stream)?; | 412 | | } | 413 | | } | 414 | | } | 415 | 12.0k | return Ok(()); | 416 | 12.4k | } |
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::parse_entropy_coded_data |
417 | | |
418 | 112M | pub(crate) fn handle_rst_main(&mut self, stream: &mut BitStream) -> Result<(), DecodeErrors> { |
419 | 112M | if self.todo == 0 { |
420 | 8 | stream.refill(&mut self.stream)?; |
421 | 112M | } |
422 | | |
423 | 112M | if self.todo == 0 |
424 | 8 | && self.restart_interval != 0 |
425 | 8 | && stream.marker.is_none() |
426 | 5 | && !stream.seen_eoi |
427 | | { |
428 | | // if no marker and we are to reset RST, look for the marker, this matches |
429 | | // libjpeg-turbo behaviour and allows us to decode images in |
430 | | // https://github.com/etemesi254/zune-image/issues/261 |
431 | 5 | let _start = self.stream.get_position(); |
432 | | // skip bytes until we find marker |
433 | 5 | let marker = get_marker(&mut self.stream, stream)?; |
434 | 1 | let _end = self.stream.get_position(); |
435 | 1 | stream.marker = Some(marker); |
436 | | // NB some warnings may be false positives. |
437 | 1 | warn!( |
438 | | "{} Extraneous bytes before marker {:?}", |
439 | | _end - _start, |
440 | | marker |
441 | | ); |
442 | 112M | } |
443 | 112M | if self.todo == 0 { |
444 | 4 | self.handle_rst(stream)? |
445 | 112M | } |
446 | 112M | Ok(()) |
447 | 112M | } Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst_main Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::handle_rst_main <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst_main Line | Count | Source | 418 | 112M | pub(crate) fn handle_rst_main(&mut self, stream: &mut BitStream) -> Result<(), DecodeErrors> { | 419 | 112M | if self.todo == 0 { | 420 | 8 | stream.refill(&mut self.stream)?; | 421 | 112M | } | 422 | | | 423 | 112M | if self.todo == 0 | 424 | 8 | && self.restart_interval != 0 | 425 | 8 | && stream.marker.is_none() | 426 | 5 | && !stream.seen_eoi | 427 | | { | 428 | | // if no marker and we are to reset RST, look for the marker, this matches | 429 | | // libjpeg-turbo behaviour and allows us to decode images in | 430 | | // https://github.com/etemesi254/zune-image/issues/261 | 431 | 5 | let _start = self.stream.get_position(); | 432 | | // skip bytes until we find marker | 433 | 5 | let marker = get_marker(&mut self.stream, stream)?; | 434 | 1 | let _end = self.stream.get_position(); | 435 | 1 | stream.marker = Some(marker); | 436 | | // NB some warnings may be false positives. | 437 | 1 | warn!( | 438 | | "{} Extraneous bytes before marker {:?}", | 439 | | _end - _start, | 440 | | marker | 441 | | ); | 442 | 112M | } | 443 | 112M | if self.todo == 0 { | 444 | 4 | self.handle_rst(stream)? | 445 | 112M | } | 446 | 112M | Ok(()) | 447 | 112M | } |
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst_main Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst_main Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst_main Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst_main Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst_main Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst_main Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst_main Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst_main Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst_main |
448 | | #[allow(clippy::too_many_lines)] |
449 | | #[allow(clippy::needless_range_loop, clippy::cast_sign_loss)] |
450 | 102 | fn finish_progressive_decoding( |
451 | 102 | &mut self, block: &[Vec<i16>; MAX_COMPONENTS], _mcu_width: usize, pixels: &mut [u8] |
452 | 102 | ) -> Result<(), DecodeErrors> { |
453 | | // This function is complicated because we need to replicate |
454 | | // the function in mcu.rs |
455 | | // |
456 | | // The advantage is that we do very little allocation and very lot |
457 | | // channel reusing. |
458 | | // The trick is to notice that we repeat the same procedure per MCU |
459 | | // width. |
460 | | // |
461 | | // So we can set it up that we only allocate temporary storage large enough |
462 | | // to store a single mcu width, then reuse it per invocation. |
463 | | // |
464 | | // This is advantageous to us. |
465 | | // |
466 | | // Remember we need to have the whole MCU buffer so we store 3 unprocessed |
467 | | // channels in memory, and then we allocate the whole output buffer in memory, both of |
468 | | // which are huge. |
469 | | // |
470 | | // |
471 | | |
472 | 102 | let mcu_height = if self.is_interleaved { |
473 | 0 | self.mcu_y |
474 | | } else { |
475 | | // For non-interleaved images( (1*1) subsampling) |
476 | | // number of MCU's are the widths (+7 to account for paddings) divided by 8. |
477 | 102 | ((self.info.height + 7) / 8) as usize |
478 | | }; |
479 | | |
480 | | // Size of our output image(width*height) |
481 | 102 | let is_hv = usize::from(self.is_interleaved); |
482 | 102 | let upsampler_scratch_size = is_hv * self.components[0].width_stride; |
483 | 102 | let width = usize::from(self.info.width); |
484 | 102 | let padded_width = calculate_padded_width(width, self.sub_sample_ratio); |
485 | | |
486 | | //let mut pixels = vec![0; capacity * out_colorspace_components]; |
487 | 102 | let mut upsampler_scratch_space = vec![0; upsampler_scratch_size]; |
488 | 102 | let mut tmp = [0_i32; DCT_BLOCK]; |
489 | | |
490 | 102 | for (pos, comp) in self.components.iter_mut().enumerate() { |
491 | | // Allocate only needed components. |
492 | | // |
493 | | // For special colorspaces i.e YCCK and CMYK, just allocate all of the needed |
494 | | // components. |
495 | 102 | if min( |
496 | 102 | self.options.jpeg_get_out_colorspace().num_components() - 1, |
497 | 102 | pos, |
498 | 102 | ) == pos |
499 | 0 | || self.input_colorspace == ColorSpace::YCCK |
500 | 0 | || self.input_colorspace == ColorSpace::CMYK |
501 | 102 | { |
502 | 102 | // allocate enough space to hold a whole MCU width |
503 | 102 | // this means we should take into account sampling ratios |
504 | 102 | // `*8` is because each MCU spans 8 widths. |
505 | 102 | let len = comp.width_stride * comp.vertical_sample * 8; |
506 | 102 | |
507 | 102 | comp.needed = true; |
508 | 102 | comp.raw_coeff = vec![0; len]; |
509 | 102 | } else { |
510 | 0 | comp.needed = false; |
511 | 0 | } |
512 | | } |
513 | | |
514 | 102 | let mut pixels_written = 0; |
515 | | |
516 | | // dequantize, idct and color convert. |
517 | 8.67k | for i in 0..mcu_height { |
518 | 8.67k | 'component: for (position, component) in &mut self.components.iter_mut().enumerate() { |
519 | 8.67k | if !component.needed { |
520 | 0 | continue 'component; |
521 | 8.67k | } |
522 | 8.67k | let qt_table = &component.quantization_table; |
523 | | |
524 | | // step is the number of pixels this iteration wil be handling |
525 | | // Given by the number of mcu's height and the length of the component block |
526 | | // Since the component block contains the whole channel as raw pixels |
527 | | // we this evenly divides the pixels into MCU blocks |
528 | | // |
529 | | // For interleaved images, this gives us the exact pixels comprising a whole MCU |
530 | | // block |
531 | 8.67k | let step = block[position].len() / mcu_height; |
532 | | // where we will be reading our pixels from. |
533 | 8.67k | let start = i * step; |
534 | | |
535 | 8.67k | let slice = &block[position][start..start + step]; |
536 | | |
537 | 8.67k | let temp_channel = &mut component.raw_coeff; |
538 | | |
539 | | // The next logical step is to iterate width wise. |
540 | | // To figure out how many pixels we iterate by we use effective pixels |
541 | | // Given to us by component.x |
542 | | // iterate per effective pixels. |
543 | 8.67k | let mcu_x = component.width_stride / 8; |
544 | | |
545 | | // iterate per every vertical sample. |
546 | 8.67k | for k in 0..component.vertical_sample { |
547 | 3.21M | for j in 0..mcu_x { |
548 | | // after writing a single stride, we need to skip 8 rows. |
549 | | // This does the row calculation |
550 | 3.21M | let width_stride = k * 8 * component.width_stride; |
551 | 3.21M | let start = j * 64 + width_stride; |
552 | | |
553 | | // See https://github.com/etemesi254/zune-image/issues/262 sample 3. |
554 | 3.21M | let Some(qt_slice) = slice.get(start..start + 64) else { |
555 | 0 | return Err(DecodeErrors::FormatStatic("Invalid slice , would panic, invalid image")) |
556 | | }; |
557 | | // dequantize |
558 | 205M | for ((x, out), qt_val) in qt_slice |
559 | 3.21M | .iter() |
560 | 3.21M | .zip(tmp.iter_mut()) |
561 | 3.21M | .zip(qt_table.iter()) |
562 | 205M | { |
563 | 205M | *out = i32::from(*x) * qt_val; |
564 | 205M | } |
565 | | // determine where to write. |
566 | 3.21M | let sl = &mut temp_channel[component.idct_pos..]; |
567 | | |
568 | 3.21M | component.idct_pos += 8; |
569 | | // tmp now contains a dequantized block so idct it |
570 | 3.21M | (self.idct_func)(&mut tmp, sl, component.width_stride); |
571 | | } |
572 | | // after every write of 8, skip 7 since idct write stride wise 8 times. |
573 | | // |
574 | | // Remember each MCU is 8x8 block, so each idct will write 8 strides into |
575 | | // sl |
576 | | // |
577 | | // and component.idct_pos is one stride long |
578 | 8.67k | component.idct_pos += 7 * component.width_stride; |
579 | | } |
580 | 8.67k | component.idct_pos = 0; |
581 | | } |
582 | | |
583 | | // process that width up until it's impossible |
584 | 8.67k | self.post_process( |
585 | 8.67k | pixels, |
586 | 8.67k | i, |
587 | 8.67k | mcu_height, |
588 | 8.67k | width, |
589 | 8.67k | padded_width, |
590 | 8.67k | &mut pixels_written, |
591 | 8.67k | &mut upsampler_scratch_space |
592 | 0 | )?; |
593 | | } |
594 | | |
595 | | debug!("Finished decoding image"); |
596 | | |
597 | 102 | return Ok(()); |
598 | 102 | } Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::finish_progressive_decoding Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::finish_progressive_decoding <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::finish_progressive_decoding Line | Count | Source | 450 | 102 | fn finish_progressive_decoding( | 451 | 102 | &mut self, block: &[Vec<i16>; MAX_COMPONENTS], _mcu_width: usize, pixels: &mut [u8] | 452 | 102 | ) -> Result<(), DecodeErrors> { | 453 | | // This function is complicated because we need to replicate | 454 | | // the function in mcu.rs | 455 | | // | 456 | | // The advantage is that we do very little allocation and very lot | 457 | | // channel reusing. | 458 | | // The trick is to notice that we repeat the same procedure per MCU | 459 | | // width. | 460 | | // | 461 | | // So we can set it up that we only allocate temporary storage large enough | 462 | | // to store a single mcu width, then reuse it per invocation. | 463 | | // | 464 | | // This is advantageous to us. | 465 | | // | 466 | | // Remember we need to have the whole MCU buffer so we store 3 unprocessed | 467 | | // channels in memory, and then we allocate the whole output buffer in memory, both of | 468 | | // which are huge. | 469 | | // | 470 | | // | 471 | | | 472 | 102 | let mcu_height = if self.is_interleaved { | 473 | 0 | self.mcu_y | 474 | | } else { | 475 | | // For non-interleaved images( (1*1) subsampling) | 476 | | // number of MCU's are the widths (+7 to account for paddings) divided by 8. | 477 | 102 | ((self.info.height + 7) / 8) as usize | 478 | | }; | 479 | | | 480 | | // Size of our output image(width*height) | 481 | 102 | let is_hv = usize::from(self.is_interleaved); | 482 | 102 | let upsampler_scratch_size = is_hv * self.components[0].width_stride; | 483 | 102 | let width = usize::from(self.info.width); | 484 | 102 | let padded_width = calculate_padded_width(width, self.sub_sample_ratio); | 485 | | | 486 | | //let mut pixels = vec![0; capacity * out_colorspace_components]; | 487 | 102 | let mut upsampler_scratch_space = vec![0; upsampler_scratch_size]; | 488 | 102 | let mut tmp = [0_i32; DCT_BLOCK]; | 489 | | | 490 | 102 | for (pos, comp) in self.components.iter_mut().enumerate() { | 491 | | // Allocate only needed components. | 492 | | // | 493 | | // For special colorspaces i.e YCCK and CMYK, just allocate all of the needed | 494 | | // components. | 495 | 102 | if min( | 496 | 102 | self.options.jpeg_get_out_colorspace().num_components() - 1, | 497 | 102 | pos, | 498 | 102 | ) == pos | 499 | 0 | || self.input_colorspace == ColorSpace::YCCK | 500 | 0 | || self.input_colorspace == ColorSpace::CMYK | 501 | 102 | { | 502 | 102 | // allocate enough space to hold a whole MCU width | 503 | 102 | // this means we should take into account sampling ratios | 504 | 102 | // `*8` is because each MCU spans 8 widths. | 505 | 102 | let len = comp.width_stride * comp.vertical_sample * 8; | 506 | 102 | | 507 | 102 | comp.needed = true; | 508 | 102 | comp.raw_coeff = vec![0; len]; | 509 | 102 | } else { | 510 | 0 | comp.needed = false; | 511 | 0 | } | 512 | | } | 513 | | | 514 | 102 | let mut pixels_written = 0; | 515 | | | 516 | | // dequantize, idct and color convert. | 517 | 8.67k | for i in 0..mcu_height { | 518 | 8.67k | 'component: for (position, component) in &mut self.components.iter_mut().enumerate() { | 519 | 8.67k | if !component.needed { | 520 | 0 | continue 'component; | 521 | 8.67k | } | 522 | 8.67k | let qt_table = &component.quantization_table; | 523 | | | 524 | | // step is the number of pixels this iteration wil be handling | 525 | | // Given by the number of mcu's height and the length of the component block | 526 | | // Since the component block contains the whole channel as raw pixels | 527 | | // we this evenly divides the pixels into MCU blocks | 528 | | // | 529 | | // For interleaved images, this gives us the exact pixels comprising a whole MCU | 530 | | // block | 531 | 8.67k | let step = block[position].len() / mcu_height; | 532 | | // where we will be reading our pixels from. | 533 | 8.67k | let start = i * step; | 534 | | | 535 | 8.67k | let slice = &block[position][start..start + step]; | 536 | | | 537 | 8.67k | let temp_channel = &mut component.raw_coeff; | 538 | | | 539 | | // The next logical step is to iterate width wise. | 540 | | // To figure out how many pixels we iterate by we use effective pixels | 541 | | // Given to us by component.x | 542 | | // iterate per effective pixels. | 543 | 8.67k | let mcu_x = component.width_stride / 8; | 544 | | | 545 | | // iterate per every vertical sample. | 546 | 8.67k | for k in 0..component.vertical_sample { | 547 | 3.21M | for j in 0..mcu_x { | 548 | | // after writing a single stride, we need to skip 8 rows. | 549 | | // This does the row calculation | 550 | 3.21M | let width_stride = k * 8 * component.width_stride; | 551 | 3.21M | let start = j * 64 + width_stride; | 552 | | | 553 | | // See https://github.com/etemesi254/zune-image/issues/262 sample 3. | 554 | 3.21M | let Some(qt_slice) = slice.get(start..start + 64) else { | 555 | 0 | return Err(DecodeErrors::FormatStatic("Invalid slice , would panic, invalid image")) | 556 | | }; | 557 | | // dequantize | 558 | 205M | for ((x, out), qt_val) in qt_slice | 559 | 3.21M | .iter() | 560 | 3.21M | .zip(tmp.iter_mut()) | 561 | 3.21M | .zip(qt_table.iter()) | 562 | 205M | { | 563 | 205M | *out = i32::from(*x) * qt_val; | 564 | 205M | } | 565 | | // determine where to write. | 566 | 3.21M | let sl = &mut temp_channel[component.idct_pos..]; | 567 | | | 568 | 3.21M | component.idct_pos += 8; | 569 | | // tmp now contains a dequantized block so idct it | 570 | 3.21M | (self.idct_func)(&mut tmp, sl, component.width_stride); | 571 | | } | 572 | | // after every write of 8, skip 7 since idct write stride wise 8 times. | 573 | | // | 574 | | // Remember each MCU is 8x8 block, so each idct will write 8 strides into | 575 | | // sl | 576 | | // | 577 | | // and component.idct_pos is one stride long | 578 | 8.67k | component.idct_pos += 7 * component.width_stride; | 579 | | } | 580 | 8.67k | component.idct_pos = 0; | 581 | | } | 582 | | | 583 | | // process that width up until it's impossible | 584 | 8.67k | self.post_process( | 585 | 8.67k | pixels, | 586 | 8.67k | i, | 587 | 8.67k | mcu_height, | 588 | 8.67k | width, | 589 | 8.67k | padded_width, | 590 | 8.67k | &mut pixels_written, | 591 | 8.67k | &mut upsampler_scratch_space | 592 | 0 | )?; | 593 | | } | 594 | | | 595 | | debug!("Finished decoding image"); | 596 | | | 597 | 102 | return Ok(()); | 598 | 102 | } |
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::finish_progressive_decoding Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::finish_progressive_decoding Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::finish_progressive_decoding Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::finish_progressive_decoding Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::finish_progressive_decoding Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::finish_progressive_decoding Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::finish_progressive_decoding Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::finish_progressive_decoding Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::finish_progressive_decoding |
599 | 4 | pub(crate) fn reset_params(&mut self) { |
600 | | /* |
601 | | Apparently, grayscale images which can be down sampled exists, which is weird in the sense |
602 | | that it has one component Y, which is not usually down sampled. |
603 | | |
604 | | This means some calculations will be wrong, so for that we explicitly reset params |
605 | | for such occurrences, warn and reset the image info to appear as if it were |
606 | | a non-sampled image to ensure decoding works |
607 | | */ |
608 | 4 | self.h_max = 1; |
609 | 4 | self.options = self.options.jpeg_set_out_colorspace(ColorSpace::Luma); |
610 | 4 | self.v_max = 1; |
611 | 4 | self.sub_sample_ratio = SampleRatios::None; |
612 | 4 | self.is_interleaved = false; |
613 | 4 | self.components[0].vertical_sample = 1; |
614 | 4 | self.components[0].width_stride = (((self.info.width as usize) + 7) / 8) * 8; |
615 | 4 | self.components[0].horizontal_sample = 1; |
616 | 4 | } Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::reset_params <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_params Line | Count | Source | 599 | 4 | pub(crate) fn reset_params(&mut self) { | 600 | | /* | 601 | | Apparently, grayscale images which can be down sampled exists, which is weird in the sense | 602 | | that it has one component Y, which is not usually down sampled. | 603 | | | 604 | | This means some calculations will be wrong, so for that we explicitly reset params | 605 | | for such occurrences, warn and reset the image info to appear as if it were | 606 | | a non-sampled image to ensure decoding works | 607 | | */ | 608 | 4 | self.h_max = 1; | 609 | 4 | self.options = self.options.jpeg_set_out_colorspace(ColorSpace::Luma); | 610 | 4 | self.v_max = 1; | 611 | 4 | self.sub_sample_ratio = SampleRatios::None; | 612 | 4 | self.is_interleaved = false; | 613 | 4 | self.components[0].vertical_sample = 1; | 614 | 4 | self.components[0].width_stride = (((self.info.width as usize) + 7) / 8) * 8; | 615 | 4 | self.components[0].horizontal_sample = 1; | 616 | 4 | } |
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_params Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::reset_params |
617 | | } |
618 | | |
619 | | ///Get a marker from the bit-stream. |
620 | | /// |
621 | | /// This reads until it gets a marker or end of file is encountered |
622 | 79.4k | pub fn get_marker<T>( |
623 | 79.4k | reader: &mut ZByteReader<T>, stream: &mut BitStream |
624 | 79.4k | ) -> Result<Marker, DecodeErrors> |
625 | 79.4k | where |
626 | 79.4k | T: ZReaderTrait |
627 | | { |
628 | 79.4k | if let Some(marker) = stream.marker { |
629 | 9.50k | stream.marker = None; |
630 | 9.50k | return Ok(marker); |
631 | 69.9k | } |
632 | | |
633 | | // read until we get a marker |
634 | | |
635 | 6.63M | while !reader.eof() { |
636 | 6.63M | let marker = reader.get_u8_err()?; |
637 | | |
638 | 6.63M | if marker == 255 { |
639 | 78.8k | let mut r = reader.get_u8_err()?; |
640 | | // 0xFF 0XFF(some images may be like that) |
641 | 193k | while r == 0xFF { |
642 | 114k | r = reader.get_u8_err()?; |
643 | | } |
644 | | |
645 | 78.8k | if r != 0 { |
646 | 68.9k | return Marker::from_u8(r) |
647 | 68.9k | .ok_or_else(|| DecodeErrors::Format(format!("Unknown marker 0xFF{r:X}")));Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>>::{closure#0}Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<_>::{closure#0}zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>>::{closure#0}Line | Count | Source | 647 | 174 | .ok_or_else(|| DecodeErrors::Format(format!("Unknown marker 0xFF{r:X}"))); |
Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>>::{closure#0}Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>>::{closure#0}Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>>::{closure#0}Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>>::{closure#0}Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>>::{closure#0}Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>>::{closure#0}Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>>::{closure#0}Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>>::{closure#0}Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>>::{closure#0} |
648 | 9.86k | } |
649 | 6.55M | } |
650 | | } |
651 | 970 | return Err(DecodeErrors::ExhaustedData); |
652 | 79.4k | } Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>> Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<_> zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>> Line | Count | Source | 622 | 79.4k | pub fn get_marker<T>( | 623 | 79.4k | reader: &mut ZByteReader<T>, stream: &mut BitStream | 624 | 79.4k | ) -> Result<Marker, DecodeErrors> | 625 | 79.4k | where | 626 | 79.4k | T: ZReaderTrait | 627 | | { | 628 | 79.4k | if let Some(marker) = stream.marker { | 629 | 9.50k | stream.marker = None; | 630 | 9.50k | return Ok(marker); | 631 | 69.9k | } | 632 | | | 633 | | // read until we get a marker | 634 | | | 635 | 6.63M | while !reader.eof() { | 636 | 6.63M | let marker = reader.get_u8_err()?; | 637 | | | 638 | 6.63M | if marker == 255 { | 639 | 78.8k | let mut r = reader.get_u8_err()?; | 640 | | // 0xFF 0XFF(some images may be like that) | 641 | 193k | while r == 0xFF { | 642 | 114k | r = reader.get_u8_err()?; | 643 | | } | 644 | | | 645 | 78.8k | if r != 0 { | 646 | 68.9k | return Marker::from_u8(r) | 647 | 68.9k | .ok_or_else(|| DecodeErrors::Format(format!("Unknown marker 0xFF{r:X}"))); | 648 | 9.86k | } | 649 | 6.55M | } | 650 | | } | 651 | 970 | return Err(DecodeErrors::ExhaustedData); | 652 | 79.4k | } |
Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>> Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>> Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>> Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>> Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>> Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>> Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>> Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>> Unexecuted instantiation: zune_jpeg::mcu_prog::get_marker::<alloc::vec::Vec<u8>> |