Coverage Report

Created: 2026-01-10 07:01

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/headers.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
//! Decode Decoder markers/segments
10
//!
11
//! This file deals with decoding header information in a jpeg file
12
//!
13
use alloc::format;
14
use alloc::string::ToString;
15
use alloc::vec::Vec;
16
17
use zune_core::bytestream::ZReaderTrait;
18
use zune_core::colorspace::ColorSpace;
19
use zune_core::log::{debug, error, trace, warn};
20
21
use crate::components::Components;
22
use crate::decoder::{ICCChunk, JpegDecoder, MAX_COMPONENTS};
23
use crate::errors::DecodeErrors;
24
use crate::huffman::HuffmanTable;
25
use crate::misc::{SOFMarkers, UN_ZIGZAG};
26
27
///**B.2.4.2 Huffman table-specification syntax**
28
#[allow(clippy::similar_names, clippy::cast_sign_loss)]
29
22.8k
pub(crate) fn parse_huffman<T: ZReaderTrait>(
30
22.8k
    decoder: &mut JpegDecoder<T>
31
22.8k
) -> Result<(), DecodeErrors>
32
22.8k
where
33
{
34
    // Read the length of the Huffman table
35
22.8k
    let mut dht_length = i32::from(decoder.stream.get_u16_be_err()?.checked_sub(2).ok_or(
36
22.8k
        DecodeErrors::FormatStatic("Invalid Huffman length in image")
37
7
    )?);
38
39
64.3k
    while dht_length > 16 {
40
        // HT information
41
42.1k
        let ht_info = decoder.stream.get_u8_err()?;
42
        // third bit indicates whether the huffman encoding is DC or AC type
43
42.1k
        let dc_or_ac = (ht_info >> 4) & 0xF;
44
        // Indicate the position of this table, should be less than 4;
45
42.1k
        let index = (ht_info & 0xF) as usize;
46
        // read the number of symbols
47
42.1k
        let mut num_symbols: [u8; 17] = [0; 17];
48
49
42.1k
        if index >= MAX_COMPONENTS {
50
15
            return Err(DecodeErrors::HuffmanDecode(format!(
51
15
                "Invalid DHT index {index}, expected between 0 and 3"
52
15
            )));
53
42.0k
        }
54
55
42.0k
        if dc_or_ac > 1 {
56
7
            return Err(DecodeErrors::HuffmanDecode(format!(
57
7
                "Invalid DHT position {dc_or_ac}, should be 0 or 1"
58
7
            )));
59
42.0k
        }
60
61
42.0k
        decoder
62
42.0k
            .stream
63
42.0k
            .read_exact(&mut num_symbols[1..17])
64
42.0k
            .map_err(|_| DecodeErrors::ExhaustedData)?;
65
66
41.9k
        dht_length -= 1 + 16;
67
68
713k
        let symbols_sum: i32 = num_symbols.iter().map(|f| i32::from(*f)).sum();
zune_jpeg::headers::parse_huffman::<alloc::vec::Vec<u8>>::{closure#1}
Line
Count
Source
68
713k
        let symbols_sum: i32 = num_symbols.iter().map(|f| i32::from(*f)).sum();
Unexecuted instantiation: zune_jpeg::headers::parse_huffman::<_>::{closure#1}
69
70
        // The sum of the number of symbols cannot be greater than 256;
71
41.9k
        if symbols_sum > 256 {
72
73
            return Err(DecodeErrors::FormatStatic(
73
73
                "Encountered Huffman table with excessive length in DHT"
74
73
            ));
75
41.9k
        }
76
41.9k
        if symbols_sum > dht_length {
77
24
            return Err(DecodeErrors::HuffmanDecode(format!(
78
24
                "Excessive Huffman table of length {symbols_sum} found when header length is {dht_length}"
79
24
            )));
80
41.8k
        }
81
41.8k
        dht_length -= symbols_sum;
82
        // A table containing symbols in increasing code length
83
41.8k
        let mut symbols = [0; 256];
84
85
41.8k
        decoder
86
41.8k
            .stream
87
41.8k
            .read_exact(&mut symbols[0..(symbols_sum as usize)])
88
41.8k
            .map_err(|x| {
89
49
                DecodeErrors::Format(format!("Could not read symbols into the buffer\n{x}"))
90
49
            })?;
zune_jpeg::headers::parse_huffman::<alloc::vec::Vec<u8>>::{closure#2}
Line
Count
Source
88
49
            .map_err(|x| {
89
49
                DecodeErrors::Format(format!("Could not read symbols into the buffer\n{x}"))
90
49
            })?;
Unexecuted instantiation: zune_jpeg::headers::parse_huffman::<_>::{closure#2}
91
        // store
92
41.8k
        match dc_or_ac {
93
            0 => {
94
24.6k
                decoder.dc_huffman_tables[index] = Some(HuffmanTable::new(
95
24.6k
                    &num_symbols,
96
24.6k
                    symbols,
97
                    true,
98
24.6k
                    decoder.is_progressive
99
274
                )?);
100
            }
101
            _ => {
102
17.1k
                decoder.ac_huffman_tables[index] = Some(HuffmanTable::new(
103
17.1k
                    &num_symbols,
104
17.1k
                    symbols,
105
                    false,
106
17.1k
                    decoder.is_progressive
107
11
                )?);
108
            }
109
        }
110
    }
111
112
22.2k
    if dht_length > 0 {
113
33
        return Err(DecodeErrors::FormatStatic("Bogus Huffman table definition"));
114
22.1k
    }
115
116
22.1k
    Ok(())
117
22.8k
}
zune_jpeg::headers::parse_huffman::<alloc::vec::Vec<u8>>
Line
Count
Source
29
22.8k
pub(crate) fn parse_huffman<T: ZReaderTrait>(
30
22.8k
    decoder: &mut JpegDecoder<T>
31
22.8k
) -> Result<(), DecodeErrors>
32
22.8k
where
33
{
34
    // Read the length of the Huffman table
35
22.8k
    let mut dht_length = i32::from(decoder.stream.get_u16_be_err()?.checked_sub(2).ok_or(
36
22.8k
        DecodeErrors::FormatStatic("Invalid Huffman length in image")
37
7
    )?);
38
39
64.3k
    while dht_length > 16 {
40
        // HT information
41
42.1k
        let ht_info = decoder.stream.get_u8_err()?;
42
        // third bit indicates whether the huffman encoding is DC or AC type
43
42.1k
        let dc_or_ac = (ht_info >> 4) & 0xF;
44
        // Indicate the position of this table, should be less than 4;
45
42.1k
        let index = (ht_info & 0xF) as usize;
46
        // read the number of symbols
47
42.1k
        let mut num_symbols: [u8; 17] = [0; 17];
48
49
42.1k
        if index >= MAX_COMPONENTS {
50
15
            return Err(DecodeErrors::HuffmanDecode(format!(
51
15
                "Invalid DHT index {index}, expected between 0 and 3"
52
15
            )));
53
42.0k
        }
54
55
42.0k
        if dc_or_ac > 1 {
56
7
            return Err(DecodeErrors::HuffmanDecode(format!(
57
7
                "Invalid DHT position {dc_or_ac}, should be 0 or 1"
58
7
            )));
59
42.0k
        }
60
61
42.0k
        decoder
62
42.0k
            .stream
63
42.0k
            .read_exact(&mut num_symbols[1..17])
64
42.0k
            .map_err(|_| DecodeErrors::ExhaustedData)?;
65
66
41.9k
        dht_length -= 1 + 16;
67
68
41.9k
        let symbols_sum: i32 = num_symbols.iter().map(|f| i32::from(*f)).sum();
69
70
        // The sum of the number of symbols cannot be greater than 256;
71
41.9k
        if symbols_sum > 256 {
72
73
            return Err(DecodeErrors::FormatStatic(
73
73
                "Encountered Huffman table with excessive length in DHT"
74
73
            ));
75
41.9k
        }
76
41.9k
        if symbols_sum > dht_length {
77
24
            return Err(DecodeErrors::HuffmanDecode(format!(
78
24
                "Excessive Huffman table of length {symbols_sum} found when header length is {dht_length}"
79
24
            )));
80
41.8k
        }
81
41.8k
        dht_length -= symbols_sum;
82
        // A table containing symbols in increasing code length
83
41.8k
        let mut symbols = [0; 256];
84
85
41.8k
        decoder
86
41.8k
            .stream
87
41.8k
            .read_exact(&mut symbols[0..(symbols_sum as usize)])
88
41.8k
            .map_err(|x| {
89
                DecodeErrors::Format(format!("Could not read symbols into the buffer\n{x}"))
90
49
            })?;
91
        // store
92
41.8k
        match dc_or_ac {
93
            0 => {
94
24.6k
                decoder.dc_huffman_tables[index] = Some(HuffmanTable::new(
95
24.6k
                    &num_symbols,
96
24.6k
                    symbols,
97
                    true,
98
24.6k
                    decoder.is_progressive
99
274
                )?);
100
            }
101
            _ => {
102
17.1k
                decoder.ac_huffman_tables[index] = Some(HuffmanTable::new(
103
17.1k
                    &num_symbols,
104
17.1k
                    symbols,
105
                    false,
106
17.1k
                    decoder.is_progressive
107
11
                )?);
108
            }
109
        }
110
    }
111
112
22.2k
    if dht_length > 0 {
113
33
        return Err(DecodeErrors::FormatStatic("Bogus Huffman table definition"));
114
22.1k
    }
115
116
22.1k
    Ok(())
117
22.8k
}
Unexecuted instantiation: zune_jpeg::headers::parse_huffman::<_>
118
119
///**B.2.4.1 Quantization table-specification syntax**
120
#[allow(clippy::cast_possible_truncation, clippy::needless_range_loop)]
121
9.63k
pub(crate) fn parse_dqt<T: ZReaderTrait>(img: &mut JpegDecoder<T>) -> Result<(), DecodeErrors> {
122
    // read length
123
9.63k
    let mut qt_length =
124
9.63k
        img.stream
125
9.63k
            .get_u16_be_err()?
126
9.63k
            .checked_sub(2)
127
9.63k
            .ok_or(DecodeErrors::FormatStatic(
128
9.63k
                "Invalid DQT length. Length should be greater than 2"
129
9.63k
            ))?;
130
    // A single DQT header may have multiple QT's
131
19.8k
    while qt_length > 0 {
132
10.4k
        let qt_info = img.stream.get_u8_err()?;
133
        // 0 = 8 bit otherwise 16 bit dqt
134
10.4k
        let precision = (qt_info >> 4) as usize;
135
        // last 4 bits give us position
136
10.4k
        let table_position = (qt_info & 0x0f) as usize;
137
10.4k
        let precision_value = 64 * (precision + 1);
138
139
10.4k
        if (precision_value + 1) as u16 > qt_length {
140
15
            return Err(DecodeErrors::DqtError(format!("Invalid QT table bytes left :{}. Too small to construct a valid qt table which should be {} long", qt_length, precision_value + 1)));
141
10.3k
        }
142
143
10.3k
        let dct_table = match precision {
144
            0 => {
145
10.1k
                let mut qt_values = [0; 64];
146
147
10.1k
                img.stream.read_exact(&mut qt_values).map_err(|x| {
148
34
                    DecodeErrors::Format(format!("Could not read symbols into the buffer\n{x}"))
149
34
                })?;
zune_jpeg::headers::parse_dqt::<alloc::vec::Vec<u8>>::{closure#0}
Line
Count
Source
147
34
                img.stream.read_exact(&mut qt_values).map_err(|x| {
148
34
                    DecodeErrors::Format(format!("Could not read symbols into the buffer\n{x}"))
149
34
                })?;
Unexecuted instantiation: zune_jpeg::headers::parse_dqt::<_>::{closure#0}
150
10.1k
                qt_length -= (precision_value as u16) + 1 /*QT BIT*/;
151
                // carry out un zig-zag here
152
10.1k
                un_zig_zag(&qt_values)
153
            }
154
            1 => {
155
                // 16 bit quantization tables
156
163
                let mut qt_values = [0_u16; 64];
157
158
9.46k
                for i in 0..64 {
159
9.34k
                    qt_values[i] = img.stream.get_u16_be_err()?;
160
                }
161
125
                qt_length -= (precision_value as u16) + 1;
162
163
125
                un_zig_zag(&qt_values)
164
            }
165
            _ => {
166
33
                return Err(DecodeErrors::DqtError(format!(
167
33
                    "Expected QT precision value of either 0 or 1, found {precision:?}"
168
33
                )));
169
            }
170
        };
171
172
10.2k
        if table_position >= MAX_COMPONENTS {
173
20
            return Err(DecodeErrors::DqtError(format!(
174
20
                "Too large table position for QT :{table_position}, expected between 0 and 3"
175
20
            )));
176
10.2k
        }
177
178
10.2k
        img.qt_tables[table_position] = Some(dct_table);
179
    }
180
181
9.48k
    return Ok(());
182
9.63k
}
zune_jpeg::headers::parse_dqt::<alloc::vec::Vec<u8>>
Line
Count
Source
121
9.63k
pub(crate) fn parse_dqt<T: ZReaderTrait>(img: &mut JpegDecoder<T>) -> Result<(), DecodeErrors> {
122
    // read length
123
9.63k
    let mut qt_length =
124
9.63k
        img.stream
125
9.63k
            .get_u16_be_err()?
126
9.63k
            .checked_sub(2)
127
9.63k
            .ok_or(DecodeErrors::FormatStatic(
128
9.63k
                "Invalid DQT length. Length should be greater than 2"
129
9.63k
            ))?;
130
    // A single DQT header may have multiple QT's
131
19.8k
    while qt_length > 0 {
132
10.4k
        let qt_info = img.stream.get_u8_err()?;
133
        // 0 = 8 bit otherwise 16 bit dqt
134
10.4k
        let precision = (qt_info >> 4) as usize;
135
        // last 4 bits give us position
136
10.4k
        let table_position = (qt_info & 0x0f) as usize;
137
10.4k
        let precision_value = 64 * (precision + 1);
138
139
10.4k
        if (precision_value + 1) as u16 > qt_length {
140
15
            return Err(DecodeErrors::DqtError(format!("Invalid QT table bytes left :{}. Too small to construct a valid qt table which should be {} long", qt_length, precision_value + 1)));
141
10.3k
        }
142
143
10.3k
        let dct_table = match precision {
144
            0 => {
145
10.1k
                let mut qt_values = [0; 64];
146
147
10.1k
                img.stream.read_exact(&mut qt_values).map_err(|x| {
148
                    DecodeErrors::Format(format!("Could not read symbols into the buffer\n{x}"))
149
34
                })?;
150
10.1k
                qt_length -= (precision_value as u16) + 1 /*QT BIT*/;
151
                // carry out un zig-zag here
152
10.1k
                un_zig_zag(&qt_values)
153
            }
154
            1 => {
155
                // 16 bit quantization tables
156
163
                let mut qt_values = [0_u16; 64];
157
158
9.46k
                for i in 0..64 {
159
9.34k
                    qt_values[i] = img.stream.get_u16_be_err()?;
160
                }
161
125
                qt_length -= (precision_value as u16) + 1;
162
163
125
                un_zig_zag(&qt_values)
164
            }
165
            _ => {
166
33
                return Err(DecodeErrors::DqtError(format!(
167
33
                    "Expected QT precision value of either 0 or 1, found {precision:?}"
168
33
                )));
169
            }
170
        };
171
172
10.2k
        if table_position >= MAX_COMPONENTS {
173
20
            return Err(DecodeErrors::DqtError(format!(
174
20
                "Too large table position for QT :{table_position}, expected between 0 and 3"
175
20
            )));
176
10.2k
        }
177
178
10.2k
        img.qt_tables[table_position] = Some(dct_table);
179
    }
180
181
9.48k
    return Ok(());
182
9.63k
}
Unexecuted instantiation: zune_jpeg::headers::parse_dqt::<_>
183
184
/// Section:`B.2.2 Frame header syntax`
185
186
5.84k
pub(crate) fn parse_start_of_frame<T: ZReaderTrait>(
187
5.84k
    sof: SOFMarkers, img: &mut JpegDecoder<T>
188
5.84k
) -> Result<(), DecodeErrors> {
189
5.84k
    if img.seen_sof {
190
52
        return Err(DecodeErrors::SofError(
191
52
            "Two Start of Frame Markers".to_string()
192
52
        ));
193
5.79k
    }
194
    // Get length of the frame header
195
5.79k
    let length = img.stream.get_u16_be_err()?;
196
    // usually 8, but can be 12 and 16, we currently support only 8
197
    // so sorry about that 12 bit images
198
5.79k
    let dt_precision = img.stream.get_u8_err()?;
199
200
5.79k
    if dt_precision != 8 {
201
5
        return Err(DecodeErrors::SofError(format!(
202
5
            "The library can only parse 8-bit images, the image has {dt_precision} bits of precision"
203
5
        )));
204
5.78k
    }
205
206
5.78k
    img.info.set_density(dt_precision);
207
208
    // read  and set the image height.
209
5.78k
    let img_height = img.stream.get_u16_be_err()?;
210
5.78k
    img.info.set_height(img_height);
211
212
    // read and set the image width
213
5.78k
    let img_width = img.stream.get_u16_be_err()?;
214
5.78k
    img.info.set_width(img_width);
215
216
    trace!("Image width  :{}", img_width);
217
    trace!("Image height :{}", img_height);
218
219
5.78k
    if usize::from(img_width) > img.options.get_max_width() {
220
1
        return Err(DecodeErrors::Format(format!("Image width {} greater than width limit {}. If use `set_limits` if you want to support huge images", img_width, img.options.get_max_width())));
221
5.78k
    }
222
223
5.78k
    if usize::from(img_height) > img.options.get_max_height() {
224
2
        return Err(DecodeErrors::Format(format!("Image height {} greater than height limit {}. If use `set_limits` if you want to support huge images", img_height, img.options.get_max_height())));
225
5.78k
    }
226
227
    // Check image width or height is zero
228
5.78k
    if img_width == 0 || img_height == 0 {
229
4
        return Err(DecodeErrors::ZeroError);
230
5.77k
    }
231
232
    // Number of components for the image.
233
5.77k
    let num_components = img.stream.get_u8_err()?;
234
235
5.77k
    if num_components == 0 {
236
1
        return Err(DecodeErrors::SofError(
237
1
            "Number of components cannot be zero.".to_string()
238
1
        ));
239
5.77k
    }
240
241
5.77k
    let expected = 8 + 3 * u16::from(num_components);
242
    // length should be equal to num components
243
5.77k
    if length != expected {
244
8
        return Err(DecodeErrors::SofError(format!(
245
8
            "Length of start of frame differs from expected {expected},value is {length}"
246
8
        )));
247
5.76k
    }
248
249
    trace!("Image components : {}", num_components);
250
251
5.76k
    if num_components == 1 {
252
4.72k
        // SOF sets the number of image components
253
4.72k
        // and that to us translates to setting input and output
254
4.72k
        // colorspaces to zero
255
4.72k
        img.input_colorspace = ColorSpace::Luma;
256
4.72k
        img.options = img.options.jpeg_set_out_colorspace(ColorSpace::Luma);
257
4.72k
        debug!("Overriding default colorspace set to Luma");
258
4.72k
    }
259
5.76k
    if num_components == 4 && img.input_colorspace == ColorSpace::YCbCr {
260
701
        trace!("Input image has 4 components, defaulting to CMYK colorspace");
261
701
        // https://entropymine.wordpress.com/2018/10/22/how-is-a-jpeg-images-color-type-determined/
262
701
        img.input_colorspace = ColorSpace::CMYK;
263
5.06k
    }
264
265
    // set number of components
266
5.76k
    img.info.components = num_components;
267
268
5.76k
    let mut components = Vec::with_capacity(num_components as usize);
269
5.76k
    let mut temp = [0; 3];
270
271
8.55k
    for pos in 0..num_components {
272
        // read 3 bytes for each component
273
8.55k
        img.stream
274
8.55k
            .read_exact(&mut temp)
275
8.55k
            .map_err(|x| DecodeErrors::Format(format!("Could not read component data\n{x}")))?;
zune_jpeg::headers::parse_start_of_frame::<alloc::vec::Vec<u8>>::{closure#0}
Line
Count
Source
275
1
            .map_err(|x| DecodeErrors::Format(format!("Could not read component data\n{x}")))?;
Unexecuted instantiation: zune_jpeg::headers::parse_start_of_frame::<_>::{closure#0}
276
        // create a component.
277
8.55k
        let component = Components::from(temp, pos)?;
278
279
8.54k
        components.push(component);
280
    }
281
5.75k
    img.seen_sof = true;
282
283
5.75k
    img.info.set_sof_marker(sof);
284
285
5.75k
    img.components = components;
286
287
5.75k
    Ok(())
288
5.84k
}
zune_jpeg::headers::parse_start_of_frame::<alloc::vec::Vec<u8>>
Line
Count
Source
186
5.84k
pub(crate) fn parse_start_of_frame<T: ZReaderTrait>(
187
5.84k
    sof: SOFMarkers, img: &mut JpegDecoder<T>
188
5.84k
) -> Result<(), DecodeErrors> {
189
5.84k
    if img.seen_sof {
190
52
        return Err(DecodeErrors::SofError(
191
52
            "Two Start of Frame Markers".to_string()
192
52
        ));
193
5.79k
    }
194
    // Get length of the frame header
195
5.79k
    let length = img.stream.get_u16_be_err()?;
196
    // usually 8, but can be 12 and 16, we currently support only 8
197
    // so sorry about that 12 bit images
198
5.79k
    let dt_precision = img.stream.get_u8_err()?;
199
200
5.79k
    if dt_precision != 8 {
201
5
        return Err(DecodeErrors::SofError(format!(
202
5
            "The library can only parse 8-bit images, the image has {dt_precision} bits of precision"
203
5
        )));
204
5.78k
    }
205
206
5.78k
    img.info.set_density(dt_precision);
207
208
    // read  and set the image height.
209
5.78k
    let img_height = img.stream.get_u16_be_err()?;
210
5.78k
    img.info.set_height(img_height);
211
212
    // read and set the image width
213
5.78k
    let img_width = img.stream.get_u16_be_err()?;
214
5.78k
    img.info.set_width(img_width);
215
216
    trace!("Image width  :{}", img_width);
217
    trace!("Image height :{}", img_height);
218
219
5.78k
    if usize::from(img_width) > img.options.get_max_width() {
220
1
        return Err(DecodeErrors::Format(format!("Image width {} greater than width limit {}. If use `set_limits` if you want to support huge images", img_width, img.options.get_max_width())));
221
5.78k
    }
222
223
5.78k
    if usize::from(img_height) > img.options.get_max_height() {
224
2
        return Err(DecodeErrors::Format(format!("Image height {} greater than height limit {}. If use `set_limits` if you want to support huge images", img_height, img.options.get_max_height())));
225
5.78k
    }
226
227
    // Check image width or height is zero
228
5.78k
    if img_width == 0 || img_height == 0 {
229
4
        return Err(DecodeErrors::ZeroError);
230
5.77k
    }
231
232
    // Number of components for the image.
233
5.77k
    let num_components = img.stream.get_u8_err()?;
234
235
5.77k
    if num_components == 0 {
236
1
        return Err(DecodeErrors::SofError(
237
1
            "Number of components cannot be zero.".to_string()
238
1
        ));
239
5.77k
    }
240
241
5.77k
    let expected = 8 + 3 * u16::from(num_components);
242
    // length should be equal to num components
243
5.77k
    if length != expected {
244
8
        return Err(DecodeErrors::SofError(format!(
245
8
            "Length of start of frame differs from expected {expected},value is {length}"
246
8
        )));
247
5.76k
    }
248
249
    trace!("Image components : {}", num_components);
250
251
5.76k
    if num_components == 1 {
252
4.72k
        // SOF sets the number of image components
253
4.72k
        // and that to us translates to setting input and output
254
4.72k
        // colorspaces to zero
255
4.72k
        img.input_colorspace = ColorSpace::Luma;
256
4.72k
        img.options = img.options.jpeg_set_out_colorspace(ColorSpace::Luma);
257
4.72k
        debug!("Overriding default colorspace set to Luma");
258
4.72k
    }
259
5.76k
    if num_components == 4 && img.input_colorspace == ColorSpace::YCbCr {
260
701
        trace!("Input image has 4 components, defaulting to CMYK colorspace");
261
701
        // https://entropymine.wordpress.com/2018/10/22/how-is-a-jpeg-images-color-type-determined/
262
701
        img.input_colorspace = ColorSpace::CMYK;
263
5.06k
    }
264
265
    // set number of components
266
5.76k
    img.info.components = num_components;
267
268
5.76k
    let mut components = Vec::with_capacity(num_components as usize);
269
5.76k
    let mut temp = [0; 3];
270
271
8.55k
    for pos in 0..num_components {
272
        // read 3 bytes for each component
273
8.55k
        img.stream
274
8.55k
            .read_exact(&mut temp)
275
8.55k
            .map_err(|x| DecodeErrors::Format(format!("Could not read component data\n{x}")))?;
276
        // create a component.
277
8.55k
        let component = Components::from(temp, pos)?;
278
279
8.54k
        components.push(component);
280
    }
281
5.75k
    img.seen_sof = true;
282
283
5.75k
    img.info.set_sof_marker(sof);
284
285
5.75k
    img.components = components;
286
287
5.75k
    Ok(())
288
5.84k
}
Unexecuted instantiation: zune_jpeg::headers::parse_start_of_frame::<_>
289
290
/// Parse a start of scan data
291
28.3k
pub(crate) fn parse_sos<T: ZReaderTrait>(image: &mut JpegDecoder<T>) -> Result<(), DecodeErrors> {
292
    // Scan header length
293
28.3k
    let ls = image.stream.get_u16_be_err()?;
294
    // Number of image components in scan
295
28.2k
    let ns = image.stream.get_u8_err()?;
296
297
28.2k
    let mut seen = [-1; { MAX_COMPONENTS + 1 }];
298
299
28.2k
    image.num_scans = ns;
300
301
28.2k
    if ls != 6 + 2 * u16::from(ns) {
302
68
        return Err(DecodeErrors::SosError(format!(
303
68
            "Bad SOS length {ls},corrupt jpeg"
304
68
        )));
305
28.2k
    }
306
307
    // Check number of components.
308
28.2k
    if !(1..5).contains(&ns) {
309
3
        return Err(DecodeErrors::SosError(format!(
310
3
            "Number of components in start of scan should be less than 3 but more than 0. Found {ns}"
311
3
        )));
312
28.2k
    }
313
314
28.2k
    if image.info.components == 0 {
315
7
        return Err(DecodeErrors::FormatStatic(
316
7
            "Error decoding SOF Marker, Number of components cannot be zero."
317
7
        ));
318
28.2k
    }
319
320
    // consume spec parameters
321
30.9k
    for i in 0..ns {
322
        // CS_i parameter, I don't need it so I might as well delete it
323
30.9k
        let id = image.stream.get_u8_err()?;
324
325
30.9k
        if seen.contains(&i32::from(id)) {
326
4
            return Err(DecodeErrors::SofError(format!(
327
4
                "Duplicate ID {id} seen twice in the same component"
328
4
            )));
329
30.9k
        }
330
331
30.9k
        seen[usize::from(i)] = i32::from(id);
332
        // DC and AC huffman table position
333
        // top 4 bits contain dc huffman destination table
334
        // lower four bits contain ac huffman destination table
335
30.9k
        let y = image.stream.get_u8_err()?;
336
337
30.9k
        let mut j = 0;
338
339
36.2k
        while j < image.info.components {
340
36.2k
            if image.components[j as usize].id == id {
341
30.9k
                break;
342
5.28k
            }
343
344
5.28k
            j += 1;
345
        }
346
347
30.9k
        if j == image.info.components {
348
41
            return Err(DecodeErrors::SofError(format!(
349
41
                "Invalid component id {}, expected a value between 0 and {}",
350
41
                id,
351
41
                image.components.len()
352
41
            )));
353
30.9k
        }
354
355
30.9k
        image.components[usize::from(j)].dc_huff_table = usize::from((y >> 4) & 0xF);
356
30.9k
        image.components[usize::from(j)].ac_huff_table = usize::from(y & 0xF);
357
30.9k
        image.z_order[i as usize] = j as usize;
358
    }
359
360
    // Collect the component spec parameters
361
    // This is only needed for progressive images but I'll read
362
    // them in order to ensure they are correct according to the spec
363
364
    // Extract progressive information
365
366
    // https://www.w3.org/Graphics/JPEG/itu-t81.pdf
367
    // Page 42
368
369
    // Start of spectral / predictor selection. (between 0 and 63)
370
28.1k
    image.spec_start = image.stream.get_u8_err()?;
371
    // End of spectral selection
372
28.1k
    image.spec_end = image.stream.get_u8_err()?;
373
374
28.1k
    let bit_approx = image.stream.get_u8_err()?;
375
    // successive approximation bit position high
376
28.1k
    image.succ_high = bit_approx >> 4;
377
378
28.1k
    if image.spec_end > 63 {
379
15
        return Err(DecodeErrors::SosError(format!(
380
15
            "Invalid Se parameter {}, range should be 0-63",
381
15
            image.spec_end
382
15
        )));
383
28.1k
    }
384
28.1k
    if image.spec_start > 63 {
385
6
        return Err(DecodeErrors::SosError(format!(
386
6
            "Invalid Ss parameter {}, range should be 0-63",
387
6
            image.spec_start
388
6
        )));
389
28.0k
    }
390
28.0k
    if image.succ_high > 13 {
391
5
        return Err(DecodeErrors::SosError(format!(
392
5
            "Invalid Ah parameter {}, range should be 0-13",
393
5
            image.succ_low
394
5
        )));
395
28.0k
    }
396
    // successive approximation bit position low
397
28.0k
    image.succ_low = bit_approx & 0xF;
398
399
28.0k
    if image.succ_low > 13 {
400
2
        return Err(DecodeErrors::SosError(format!(
401
2
            "Invalid Al parameter {}, range should be 0-13",
402
2
            image.succ_low
403
2
        )));
404
28.0k
    }
405
406
    trace!(
407
        "Ss={}, Se={} Ah={} Al={}",
408
        image.spec_start,
409
        image.spec_end,
410
        image.succ_high,
411
        image.succ_low
412
    );
413
414
28.0k
    Ok(())
415
28.3k
}
zune_jpeg::headers::parse_sos::<alloc::vec::Vec<u8>>
Line
Count
Source
291
28.3k
pub(crate) fn parse_sos<T: ZReaderTrait>(image: &mut JpegDecoder<T>) -> Result<(), DecodeErrors> {
292
    // Scan header length
293
28.3k
    let ls = image.stream.get_u16_be_err()?;
294
    // Number of image components in scan
295
28.2k
    let ns = image.stream.get_u8_err()?;
296
297
28.2k
    let mut seen = [-1; { MAX_COMPONENTS + 1 }];
298
299
28.2k
    image.num_scans = ns;
300
301
28.2k
    if ls != 6 + 2 * u16::from(ns) {
302
68
        return Err(DecodeErrors::SosError(format!(
303
68
            "Bad SOS length {ls},corrupt jpeg"
304
68
        )));
305
28.2k
    }
306
307
    // Check number of components.
308
28.2k
    if !(1..5).contains(&ns) {
309
3
        return Err(DecodeErrors::SosError(format!(
310
3
            "Number of components in start of scan should be less than 3 but more than 0. Found {ns}"
311
3
        )));
312
28.2k
    }
313
314
28.2k
    if image.info.components == 0 {
315
7
        return Err(DecodeErrors::FormatStatic(
316
7
            "Error decoding SOF Marker, Number of components cannot be zero."
317
7
        ));
318
28.2k
    }
319
320
    // consume spec parameters
321
30.9k
    for i in 0..ns {
322
        // CS_i parameter, I don't need it so I might as well delete it
323
30.9k
        let id = image.stream.get_u8_err()?;
324
325
30.9k
        if seen.contains(&i32::from(id)) {
326
4
            return Err(DecodeErrors::SofError(format!(
327
4
                "Duplicate ID {id} seen twice in the same component"
328
4
            )));
329
30.9k
        }
330
331
30.9k
        seen[usize::from(i)] = i32::from(id);
332
        // DC and AC huffman table position
333
        // top 4 bits contain dc huffman destination table
334
        // lower four bits contain ac huffman destination table
335
30.9k
        let y = image.stream.get_u8_err()?;
336
337
30.9k
        let mut j = 0;
338
339
36.2k
        while j < image.info.components {
340
36.2k
            if image.components[j as usize].id == id {
341
30.9k
                break;
342
5.28k
            }
343
344
5.28k
            j += 1;
345
        }
346
347
30.9k
        if j == image.info.components {
348
41
            return Err(DecodeErrors::SofError(format!(
349
41
                "Invalid component id {}, expected a value between 0 and {}",
350
41
                id,
351
41
                image.components.len()
352
41
            )));
353
30.9k
        }
354
355
30.9k
        image.components[usize::from(j)].dc_huff_table = usize::from((y >> 4) & 0xF);
356
30.9k
        image.components[usize::from(j)].ac_huff_table = usize::from(y & 0xF);
357
30.9k
        image.z_order[i as usize] = j as usize;
358
    }
359
360
    // Collect the component spec parameters
361
    // This is only needed for progressive images but I'll read
362
    // them in order to ensure they are correct according to the spec
363
364
    // Extract progressive information
365
366
    // https://www.w3.org/Graphics/JPEG/itu-t81.pdf
367
    // Page 42
368
369
    // Start of spectral / predictor selection. (between 0 and 63)
370
28.1k
    image.spec_start = image.stream.get_u8_err()?;
371
    // End of spectral selection
372
28.1k
    image.spec_end = image.stream.get_u8_err()?;
373
374
28.1k
    let bit_approx = image.stream.get_u8_err()?;
375
    // successive approximation bit position high
376
28.1k
    image.succ_high = bit_approx >> 4;
377
378
28.1k
    if image.spec_end > 63 {
379
15
        return Err(DecodeErrors::SosError(format!(
380
15
            "Invalid Se parameter {}, range should be 0-63",
381
15
            image.spec_end
382
15
        )));
383
28.1k
    }
384
28.1k
    if image.spec_start > 63 {
385
6
        return Err(DecodeErrors::SosError(format!(
386
6
            "Invalid Ss parameter {}, range should be 0-63",
387
6
            image.spec_start
388
6
        )));
389
28.0k
    }
390
28.0k
    if image.succ_high > 13 {
391
5
        return Err(DecodeErrors::SosError(format!(
392
5
            "Invalid Ah parameter {}, range should be 0-13",
393
5
            image.succ_low
394
5
        )));
395
28.0k
    }
396
    // successive approximation bit position low
397
28.0k
    image.succ_low = bit_approx & 0xF;
398
399
28.0k
    if image.succ_low > 13 {
400
2
        return Err(DecodeErrors::SosError(format!(
401
2
            "Invalid Al parameter {}, range should be 0-13",
402
2
            image.succ_low
403
2
        )));
404
28.0k
    }
405
406
    trace!(
407
        "Ss={}, Se={} Ah={} Al={}",
408
        image.spec_start,
409
        image.spec_end,
410
        image.succ_high,
411
        image.succ_low
412
    );
413
414
28.0k
    Ok(())
415
28.3k
}
Unexecuted instantiation: zune_jpeg::headers::parse_sos::<_>
416
417
/// Parse the APP13 (IPTC) segment.
418
1.73k
pub(crate) fn parse_app13<T: ZReaderTrait>(
419
1.73k
    decoder: &mut JpegDecoder<T>,
420
1.73k
) -> Result<(), DecodeErrors> {
421
    const IPTC_PREFIX: &[u8] = b"Photoshop 3.0";
422
    // skip length.
423
1.73k
    let mut length = usize::from(decoder.stream.get_u16_be());
424
425
1.73k
    if length < 2 {
426
5
        return Err(DecodeErrors::FormatStatic("Too small APP13 length"));
427
1.73k
    }
428
    // length bytes.
429
1.73k
    length -= 2;
430
431
1.73k
    if length > IPTC_PREFIX.len() && decoder.stream.peek_at(0, IPTC_PREFIX.len())? == IPTC_PREFIX {
432
        // skip bytes we read above.
433
920
        decoder.stream.skip(IPTC_PREFIX.len());
434
920
        length -= IPTC_PREFIX.len();
435
436
920
        let iptc_bytes = decoder.stream.peek_at(0, length)?.to_vec();
437
438
905
        decoder.info.iptc_data = Some(iptc_bytes);
439
809
    }
440
441
1.71k
    decoder.stream.skip(length);
442
1.71k
    Ok(())
443
1.73k
}
zune_jpeg::headers::parse_app13::<alloc::vec::Vec<u8>>
Line
Count
Source
418
1.73k
pub(crate) fn parse_app13<T: ZReaderTrait>(
419
1.73k
    decoder: &mut JpegDecoder<T>,
420
1.73k
) -> Result<(), DecodeErrors> {
421
    const IPTC_PREFIX: &[u8] = b"Photoshop 3.0";
422
    // skip length.
423
1.73k
    let mut length = usize::from(decoder.stream.get_u16_be());
424
425
1.73k
    if length < 2 {
426
5
        return Err(DecodeErrors::FormatStatic("Too small APP13 length"));
427
1.73k
    }
428
    // length bytes.
429
1.73k
    length -= 2;
430
431
1.73k
    if length > IPTC_PREFIX.len() && decoder.stream.peek_at(0, IPTC_PREFIX.len())? == IPTC_PREFIX {
432
        // skip bytes we read above.
433
920
        decoder.stream.skip(IPTC_PREFIX.len());
434
920
        length -= IPTC_PREFIX.len();
435
436
920
        let iptc_bytes = decoder.stream.peek_at(0, length)?.to_vec();
437
438
905
        decoder.info.iptc_data = Some(iptc_bytes);
439
809
    }
440
441
1.71k
    decoder.stream.skip(length);
442
1.71k
    Ok(())
443
1.73k
}
Unexecuted instantiation: zune_jpeg::headers::parse_app13::<_>
444
445
/// Parse Adobe App14 segment
446
177
pub(crate) fn parse_app14<T: ZReaderTrait>(
447
177
    decoder: &mut JpegDecoder<T>
448
177
) -> Result<(), DecodeErrors> {
449
    // skip length
450
177
    let mut length = usize::from(decoder.stream.get_u16_be());
451
452
177
    if length < 2 || !decoder.stream.has(length - 2) {
453
58
        return Err(DecodeErrors::ExhaustedData);
454
119
    }
455
119
    if length < 14 {
456
2
        return Err(DecodeErrors::FormatStatic(
457
2
            "Too short of a length for App14 segment"
458
2
        ));
459
117
    }
460
117
    if decoder.stream.peek_at(0, 5) == Ok(b"Adobe") {
461
        // move stream 6 bytes to remove adobe id
462
70
        decoder.stream.skip(6);
463
        // skip version, flags0 and flags1
464
70
        decoder.stream.skip(5);
465
        // get color transform
466
70
        let transform = decoder.stream.get_u8();
467
        // https://exiftool.org/TagNames/JPEG.html#Adobe
468
70
        match transform {
469
67
            0 => decoder.input_colorspace = ColorSpace::CMYK,
470
0
            1 => decoder.input_colorspace = ColorSpace::YCbCr,
471
0
            2 => decoder.input_colorspace = ColorSpace::YCCK,
472
            _ => {
473
3
                return Err(DecodeErrors::Format(format!(
474
3
                    "Unknown Adobe colorspace {transform}"
475
3
                )))
476
            }
477
        }
478
        // length   = 2
479
        // adobe id = 6
480
        // version =  5
481
        // transform = 1
482
67
        length = length.saturating_sub(14);
483
47
    } else if decoder.options.get_strict_mode() {
484
47
        return Err(DecodeErrors::FormatStatic("Corrupt Adobe App14 segment"));
485
0
    } else {
486
0
        length = length.saturating_sub(2);
487
0
        error!("Not a valid Adobe APP14 Segment");
488
0
    }
489
    // skip any proceeding lengths.
490
    // we do not need them
491
67
    decoder.stream.skip(length);
492
493
67
    Ok(())
494
177
}
zune_jpeg::headers::parse_app14::<alloc::vec::Vec<u8>>
Line
Count
Source
446
177
pub(crate) fn parse_app14<T: ZReaderTrait>(
447
177
    decoder: &mut JpegDecoder<T>
448
177
) -> Result<(), DecodeErrors> {
449
    // skip length
450
177
    let mut length = usize::from(decoder.stream.get_u16_be());
451
452
177
    if length < 2 || !decoder.stream.has(length - 2) {
453
58
        return Err(DecodeErrors::ExhaustedData);
454
119
    }
455
119
    if length < 14 {
456
2
        return Err(DecodeErrors::FormatStatic(
457
2
            "Too short of a length for App14 segment"
458
2
        ));
459
117
    }
460
117
    if decoder.stream.peek_at(0, 5) == Ok(b"Adobe") {
461
        // move stream 6 bytes to remove adobe id
462
70
        decoder.stream.skip(6);
463
        // skip version, flags0 and flags1
464
70
        decoder.stream.skip(5);
465
        // get color transform
466
70
        let transform = decoder.stream.get_u8();
467
        // https://exiftool.org/TagNames/JPEG.html#Adobe
468
70
        match transform {
469
67
            0 => decoder.input_colorspace = ColorSpace::CMYK,
470
0
            1 => decoder.input_colorspace = ColorSpace::YCbCr,
471
0
            2 => decoder.input_colorspace = ColorSpace::YCCK,
472
            _ => {
473
3
                return Err(DecodeErrors::Format(format!(
474
3
                    "Unknown Adobe colorspace {transform}"
475
3
                )))
476
            }
477
        }
478
        // length   = 2
479
        // adobe id = 6
480
        // version =  5
481
        // transform = 1
482
67
        length = length.saturating_sub(14);
483
47
    } else if decoder.options.get_strict_mode() {
484
47
        return Err(DecodeErrors::FormatStatic("Corrupt Adobe App14 segment"));
485
0
    } else {
486
0
        length = length.saturating_sub(2);
487
0
        error!("Not a valid Adobe APP14 Segment");
488
0
    }
489
    // skip any proceeding lengths.
490
    // we do not need them
491
67
    decoder.stream.skip(length);
492
493
67
    Ok(())
494
177
}
Unexecuted instantiation: zune_jpeg::headers::parse_app14::<_>
495
496
/// Parse the APP1 segment
497
///
498
/// This contains the exif tag
499
12.2k
pub(crate) fn parse_app1<T: ZReaderTrait>(
500
12.2k
    decoder: &mut JpegDecoder<T>
501
12.2k
) -> Result<(), DecodeErrors> {
502
    // contains exif data
503
12.2k
    let mut length = usize::from(decoder.stream.get_u16_be());
504
505
12.2k
    if length < 2 || !decoder.stream.has(length - 2) {
506
61
        return Err(DecodeErrors::ExhaustedData);
507
12.1k
    }
508
    // length bytes
509
12.1k
    length -= 2;
510
511
12.1k
    if length > 6 && decoder.stream.peek_at(0, 6).unwrap() == b"Exif\x00\x00" {
512
346
        trace!("Exif segment present");
513
346
        // skip bytes we read above
514
346
        decoder.stream.skip(6);
515
346
        length -= 6;
516
346
517
346
        let exif_bytes = decoder.stream.peek_at(0, length).unwrap().to_vec();
518
346
519
346
        decoder.exif_data = Some(exif_bytes);
520
11.8k
    } else {
521
11.8k
        warn!("Wrongly formatted exif tag");
522
11.8k
    }
523
524
12.1k
    decoder.stream.skip(length);
525
12.1k
    Ok(())
526
12.2k
}
zune_jpeg::headers::parse_app1::<alloc::vec::Vec<u8>>
Line
Count
Source
499
12.2k
pub(crate) fn parse_app1<T: ZReaderTrait>(
500
12.2k
    decoder: &mut JpegDecoder<T>
501
12.2k
) -> Result<(), DecodeErrors> {
502
    // contains exif data
503
12.2k
    let mut length = usize::from(decoder.stream.get_u16_be());
504
505
12.2k
    if length < 2 || !decoder.stream.has(length - 2) {
506
61
        return Err(DecodeErrors::ExhaustedData);
507
12.1k
    }
508
    // length bytes
509
12.1k
    length -= 2;
510
511
12.1k
    if length > 6 && decoder.stream.peek_at(0, 6).unwrap() == b"Exif\x00\x00" {
512
346
        trace!("Exif segment present");
513
346
        // skip bytes we read above
514
346
        decoder.stream.skip(6);
515
346
        length -= 6;
516
346
517
346
        let exif_bytes = decoder.stream.peek_at(0, length).unwrap().to_vec();
518
346
519
346
        decoder.exif_data = Some(exif_bytes);
520
11.8k
    } else {
521
11.8k
        warn!("Wrongly formatted exif tag");
522
11.8k
    }
523
524
12.1k
    decoder.stream.skip(length);
525
12.1k
    Ok(())
526
12.2k
}
Unexecuted instantiation: zune_jpeg::headers::parse_app1::<_>
527
528
63.1k
pub(crate) fn parse_app2<T: ZReaderTrait>(
529
63.1k
    decoder: &mut JpegDecoder<T>
530
63.1k
) -> Result<(), DecodeErrors> {
531
63.1k
    let mut length = usize::from(decoder.stream.get_u16_be());
532
533
63.1k
    if length < 2 || !decoder.stream.has(length - 2) {
534
88
        return Err(DecodeErrors::ExhaustedData);
535
63.0k
    }
536
    // length bytes
537
63.0k
    length -= 2;
538
539
63.0k
    if length > 14 && decoder.stream.peek_at(0, 12).unwrap() == *b"ICC_PROFILE\0" {
540
44.8k
        trace!("ICC Profile present");
541
44.8k
        // skip 12 bytes which indicate ICC profile
542
44.8k
        length -= 12;
543
44.8k
        decoder.stream.skip(12);
544
44.8k
        let seq_no = decoder.stream.get_u8();
545
44.8k
        let num_markers = decoder.stream.get_u8();
546
44.8k
        // deduct the two bytes we read above
547
44.8k
        length -= 2;
548
44.8k
549
44.8k
        let data = decoder.stream.peek_at(0, length).unwrap().to_vec();
550
44.8k
551
44.8k
        let icc_chunk = ICCChunk {
552
44.8k
            seq_no,
553
44.8k
            num_markers,
554
44.8k
            data
555
44.8k
        };
556
44.8k
        decoder.icc_data.push(icc_chunk);
557
44.8k
    }
558
559
63.0k
    decoder.stream.skip(length);
560
561
63.0k
    Ok(())
562
63.1k
}
zune_jpeg::headers::parse_app2::<alloc::vec::Vec<u8>>
Line
Count
Source
528
63.1k
pub(crate) fn parse_app2<T: ZReaderTrait>(
529
63.1k
    decoder: &mut JpegDecoder<T>
530
63.1k
) -> Result<(), DecodeErrors> {
531
63.1k
    let mut length = usize::from(decoder.stream.get_u16_be());
532
533
63.1k
    if length < 2 || !decoder.stream.has(length - 2) {
534
88
        return Err(DecodeErrors::ExhaustedData);
535
63.0k
    }
536
    // length bytes
537
63.0k
    length -= 2;
538
539
63.0k
    if length > 14 && decoder.stream.peek_at(0, 12).unwrap() == *b"ICC_PROFILE\0" {
540
44.8k
        trace!("ICC Profile present");
541
44.8k
        // skip 12 bytes which indicate ICC profile
542
44.8k
        length -= 12;
543
44.8k
        decoder.stream.skip(12);
544
44.8k
        let seq_no = decoder.stream.get_u8();
545
44.8k
        let num_markers = decoder.stream.get_u8();
546
44.8k
        // deduct the two bytes we read above
547
44.8k
        length -= 2;
548
44.8k
549
44.8k
        let data = decoder.stream.peek_at(0, length).unwrap().to_vec();
550
44.8k
551
44.8k
        let icc_chunk = ICCChunk {
552
44.8k
            seq_no,
553
44.8k
            num_markers,
554
44.8k
            data
555
44.8k
        };
556
44.8k
        decoder.icc_data.push(icc_chunk);
557
44.8k
    }
558
559
63.0k
    decoder.stream.skip(length);
560
561
63.0k
    Ok(())
562
63.1k
}
Unexecuted instantiation: zune_jpeg::headers::parse_app2::<_>
563
564
/// Small utility function to print Un-zig-zagged quantization tables
565
566
10.2k
fn un_zig_zag<T>(a: &[T]) -> [i32; 64]
567
10.2k
where
568
10.2k
    T: Default + Copy,
569
10.2k
    i32: core::convert::From<T>
570
{
571
10.2k
    let mut output = [i32::default(); 64];
572
573
668k
    for i in 0..64 {
574
658k
        output[UN_ZIGZAG[i]] = i32::from(a[i]);
575
658k
    }
576
577
10.2k
    output
578
10.2k
}
zune_jpeg::headers::un_zig_zag::<u8>
Line
Count
Source
566
10.1k
fn un_zig_zag<T>(a: &[T]) -> [i32; 64]
567
10.1k
where
568
10.1k
    T: Default + Copy,
569
10.1k
    i32: core::convert::From<T>
570
{
571
10.1k
    let mut output = [i32::default(); 64];
572
573
660k
    for i in 0..64 {
574
650k
        output[UN_ZIGZAG[i]] = i32::from(a[i]);
575
650k
    }
576
577
10.1k
    output
578
10.1k
}
zune_jpeg::headers::un_zig_zag::<u16>
Line
Count
Source
566
125
fn un_zig_zag<T>(a: &[T]) -> [i32; 64]
567
125
where
568
125
    T: Default + Copy,
569
125
    i32: core::convert::From<T>
570
{
571
125
    let mut output = [i32::default(); 64];
572
573
8.12k
    for i in 0..64 {
574
8.00k
        output[UN_ZIGZAG[i]] = i32::from(a[i]);
575
8.00k
    }
576
577
125
    output
578
125
}
Unexecuted instantiation: zune_jpeg::headers::un_zig_zag::<_>