Coverage Report

Created: 2025-12-11 07:11

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