Coverage Report

Created: 2025-11-05 08:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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>>