Coverage Report

Created: 2026-03-07 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/zune-jpeg-0.5.12/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::ZByteReaderTrait;
18
use zune_core::colorspace::ColorSpace;
19
use zune_core::log::{debug, trace, warn};
20
21
use core::cmp::max;
22
23
use crate::components::{Components, SampleRatios};
24
use crate::decoder::{GainMapInfo, ICCChunk, JpegDecoder, MAX_COMPONENTS};
25
use crate::errors::DecodeErrors;
26
use crate::huffman::HuffmanTable;
27
use crate::misc::{SOFMarkers, UN_ZIGZAG};
28
29
///**B.2.4.2 Huffman table-specification syntax**
30
#[allow(clippy::similar_names, clippy::cast_sign_loss)]
31
76.2k
pub(crate) fn parse_huffman<T: ZByteReaderTrait>(
32
76.2k
    decoder: &mut JpegDecoder<T>
33
76.2k
) -> Result<(), DecodeErrors>
34
76.2k
where
35
{
36
    // Read the length of the Huffman table
37
76.2k
    let mut dht_length = i32::from(decoder.stream.get_u16_be_err()?.checked_sub(2).ok_or(
38
76.1k
        DecodeErrors::FormatStatic("Invalid Huffman length in image")
39
17
    )?);
40
41
191k
    while dht_length > 16 {
42
        // HT information
43
117k
        let ht_info = decoder.stream.read_u8_err()?;
44
        // third bit indicates whether the huffman encoding is DC or AC type
45
117k
        let dc_or_ac = (ht_info >> 4) & 0xF;
46
        // Indicate the position of this table, should be less than 4;
47
117k
        let index = (ht_info & 0xF) as usize;
48
        // read the number of symbols
49
117k
        let mut num_symbols: [u8; 17] = [0; 17];
50
51
117k
        if index >= MAX_COMPONENTS {
52
83
            return Err(DecodeErrors::HuffmanDecode(format!(
53
83
                "Invalid DHT index {index}, expected between 0 and 3"
54
83
            )));
55
117k
        }
56
57
117k
        if dc_or_ac > 1 {
58
30
            return Err(DecodeErrors::HuffmanDecode(format!(
59
30
                "Invalid DHT position {dc_or_ac}, should be 0 or 1"
60
30
            )));
61
117k
        }
62
63
117k
        decoder.stream.read_exact_bytes(&mut num_symbols[1..17])?;
64
65
116k
        dht_length -= 1 + 16;
66
67
1.98M
        let symbols_sum: i32 = num_symbols.iter().map(|f| i32::from(*f)).sum();
zune_jpeg::headers::parse_huffman::<zune_core::bytestream::reader::no_std_readers::ZCursor<alloc::vec::Vec<u8>>>::{closure#0}
Line
Count
Source
67
850k
        let symbols_sum: i32 = num_symbols.iter().map(|f| i32::from(*f)).sum();
Unexecuted instantiation: zune_jpeg::headers::parse_huffman::<zune_core::bytestream::reader::no_std_readers::ZCursor<&alloc::vec::Vec<u8>>>::{closure#0}
zune_jpeg::headers::parse_huffman::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>::{closure#0}
Line
Count
Source
67
1.13M
        let symbols_sum: i32 = num_symbols.iter().map(|f| i32::from(*f)).sum();
Unexecuted instantiation: zune_jpeg::headers::parse_huffman::<_>::{closure#0}
68
69
        // The sum of the number of symbols cannot be greater than 256;
70
116k
        if symbols_sum > 256 {
71
122
            return Err(DecodeErrors::FormatStatic(
72
122
                "Encountered Huffman table with excessive length in DHT"
73
122
            ));
74
116k
        }
75
116k
        if symbols_sum > dht_length {
76
51
            return Err(DecodeErrors::HuffmanDecode(format!(
77
51
                "Excessive Huffman table of length {symbols_sum} found when header length is {dht_length}"
78
51
            )));
79
116k
        }
80
116k
        dht_length -= symbols_sum;
81
        // A table containing symbols in increasing code length
82
116k
        let mut symbols = [0; 256];
83
84
116k
        decoder
85
116k
            .stream
86
116k
            .read_exact_bytes(&mut symbols[0..(symbols_sum as usize)])?;
87
        // store
88
116k
        match dc_or_ac {
89
            0 => {
90
59.5k
                decoder.dc_huffman_tables[index] = Some(HuffmanTable::new(
91
59.5k
                    &num_symbols,
92
59.5k
                    symbols,
93
                    true,
94
59.5k
                    decoder.is_progressive
95
858
                )?);
96
            }
97
            _ => {
98
56.8k
                decoder.ac_huffman_tables[index] = Some(HuffmanTable::new(
99
56.8k
                    &num_symbols,
100
56.8k
                    symbols,
101
                    false,
102
56.8k
                    decoder.is_progressive
103
41
                )?);
104
            }
105
        }
106
    }
107
108
74.0k
    if dht_length > 0 {
109
37
        return Err(DecodeErrors::FormatStatic("Bogus Huffman table definition"));
110
73.9k
    }
111
112
73.9k
    Ok(())
113
76.2k
}
zune_jpeg::headers::parse_huffman::<zune_core::bytestream::reader::no_std_readers::ZCursor<alloc::vec::Vec<u8>>>
Line
Count
Source
31
37.3k
pub(crate) fn parse_huffman<T: ZByteReaderTrait>(
32
37.3k
    decoder: &mut JpegDecoder<T>
33
37.3k
) -> Result<(), DecodeErrors>
34
37.3k
where
35
{
36
    // Read the length of the Huffman table
37
37.3k
    let mut dht_length = i32::from(decoder.stream.get_u16_be_err()?.checked_sub(2).ok_or(
38
37.3k
        DecodeErrors::FormatStatic("Invalid Huffman length in image")
39
5
    )?);
40
41
86.9k
    while dht_length > 16 {
42
        // HT information
43
50.2k
        let ht_info = decoder.stream.read_u8_err()?;
44
        // third bit indicates whether the huffman encoding is DC or AC type
45
50.2k
        let dc_or_ac = (ht_info >> 4) & 0xF;
46
        // Indicate the position of this table, should be less than 4;
47
50.2k
        let index = (ht_info & 0xF) as usize;
48
        // read the number of symbols
49
50.2k
        let mut num_symbols: [u8; 17] = [0; 17];
50
51
50.2k
        if index >= MAX_COMPONENTS {
52
32
            return Err(DecodeErrors::HuffmanDecode(format!(
53
32
                "Invalid DHT index {index}, expected between 0 and 3"
54
32
            )));
55
50.1k
        }
56
57
50.1k
        if dc_or_ac > 1 {
58
14
            return Err(DecodeErrors::HuffmanDecode(format!(
59
14
                "Invalid DHT position {dc_or_ac}, should be 0 or 1"
60
14
            )));
61
50.1k
        }
62
63
50.1k
        decoder.stream.read_exact_bytes(&mut num_symbols[1..17])?;
64
65
50.0k
        dht_length -= 1 + 16;
66
67
50.0k
        let symbols_sum: i32 = num_symbols.iter().map(|f| i32::from(*f)).sum();
68
69
        // The sum of the number of symbols cannot be greater than 256;
70
50.0k
        if symbols_sum > 256 {
71
47
            return Err(DecodeErrors::FormatStatic(
72
47
                "Encountered Huffman table with excessive length in DHT"
73
47
            ));
74
49.9k
        }
75
49.9k
        if symbols_sum > dht_length {
76
21
            return Err(DecodeErrors::HuffmanDecode(format!(
77
21
                "Excessive Huffman table of length {symbols_sum} found when header length is {dht_length}"
78
21
            )));
79
49.9k
        }
80
49.9k
        dht_length -= symbols_sum;
81
        // A table containing symbols in increasing code length
82
49.9k
        let mut symbols = [0; 256];
83
84
49.9k
        decoder
85
49.9k
            .stream
86
49.9k
            .read_exact_bytes(&mut symbols[0..(symbols_sum as usize)])?;
87
        // store
88
49.8k
        match dc_or_ac {
89
            0 => {
90
21.4k
                decoder.dc_huffman_tables[index] = Some(HuffmanTable::new(
91
21.4k
                    &num_symbols,
92
21.4k
                    symbols,
93
                    true,
94
21.4k
                    decoder.is_progressive
95
263
                )?);
96
            }
97
            _ => {
98
28.4k
                decoder.ac_huffman_tables[index] = Some(HuffmanTable::new(
99
28.4k
                    &num_symbols,
100
28.4k
                    symbols,
101
                    false,
102
28.4k
                    decoder.is_progressive
103
6
                )?);
104
            }
105
        }
106
    }
107
108
36.7k
    if dht_length > 0 {
109
8
        return Err(DecodeErrors::FormatStatic("Bogus Huffman table definition"));
110
36.6k
    }
111
112
36.6k
    Ok(())
113
37.3k
}
Unexecuted instantiation: zune_jpeg::headers::parse_huffman::<zune_core::bytestream::reader::no_std_readers::ZCursor<&alloc::vec::Vec<u8>>>
zune_jpeg::headers::parse_huffman::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Line
Count
Source
31
38.8k
pub(crate) fn parse_huffman<T: ZByteReaderTrait>(
32
38.8k
    decoder: &mut JpegDecoder<T>
33
38.8k
) -> Result<(), DecodeErrors>
34
38.8k
where
35
{
36
    // Read the length of the Huffman table
37
38.8k
    let mut dht_length = i32::from(decoder.stream.get_u16_be_err()?.checked_sub(2).ok_or(
38
38.7k
        DecodeErrors::FormatStatic("Invalid Huffman length in image")
39
12
    )?);
40
41
104k
    while dht_length > 16 {
42
        // HT information
43
67.3k
        let ht_info = decoder.stream.read_u8_err()?;
44
        // third bit indicates whether the huffman encoding is DC or AC type
45
66.9k
        let dc_or_ac = (ht_info >> 4) & 0xF;
46
        // Indicate the position of this table, should be less than 4;
47
66.9k
        let index = (ht_info & 0xF) as usize;
48
        // read the number of symbols
49
66.9k
        let mut num_symbols: [u8; 17] = [0; 17];
50
51
66.9k
        if index >= MAX_COMPONENTS {
52
51
            return Err(DecodeErrors::HuffmanDecode(format!(
53
51
                "Invalid DHT index {index}, expected between 0 and 3"
54
51
            )));
55
66.9k
        }
56
57
66.9k
        if dc_or_ac > 1 {
58
16
            return Err(DecodeErrors::HuffmanDecode(format!(
59
16
                "Invalid DHT position {dc_or_ac}, should be 0 or 1"
60
16
            )));
61
66.9k
        }
62
63
66.9k
        decoder.stream.read_exact_bytes(&mut num_symbols[1..17])?;
64
65
66.7k
        dht_length -= 1 + 16;
66
67
66.7k
        let symbols_sum: i32 = num_symbols.iter().map(|f| i32::from(*f)).sum();
68
69
        // The sum of the number of symbols cannot be greater than 256;
70
66.7k
        if symbols_sum > 256 {
71
75
            return Err(DecodeErrors::FormatStatic(
72
75
                "Encountered Huffman table with excessive length in DHT"
73
75
            ));
74
66.6k
        }
75
66.6k
        if symbols_sum > dht_length {
76
30
            return Err(DecodeErrors::HuffmanDecode(format!(
77
30
                "Excessive Huffman table of length {symbols_sum} found when header length is {dht_length}"
78
30
            )));
79
66.6k
        }
80
66.6k
        dht_length -= symbols_sum;
81
        // A table containing symbols in increasing code length
82
66.6k
        let mut symbols = [0; 256];
83
84
66.6k
        decoder
85
66.6k
            .stream
86
66.6k
            .read_exact_bytes(&mut symbols[0..(symbols_sum as usize)])?;
87
        // store
88
66.5k
        match dc_or_ac {
89
            0 => {
90
38.1k
                decoder.dc_huffman_tables[index] = Some(HuffmanTable::new(
91
38.1k
                    &num_symbols,
92
38.1k
                    symbols,
93
                    true,
94
38.1k
                    decoder.is_progressive
95
595
                )?);
96
            }
97
            _ => {
98
28.4k
                decoder.ac_huffman_tables[index] = Some(HuffmanTable::new(
99
28.4k
                    &num_symbols,
100
28.4k
                    symbols,
101
                    false,
102
28.4k
                    decoder.is_progressive
103
35
                )?);
104
            }
105
        }
106
    }
107
108
37.3k
    if dht_length > 0 {
109
29
        return Err(DecodeErrors::FormatStatic("Bogus Huffman table definition"));
110
37.2k
    }
111
112
37.2k
    Ok(())
113
38.8k
}
Unexecuted instantiation: zune_jpeg::headers::parse_huffman::<_>
114
115
///**B.2.4.1 Quantization table-specification syntax**
116
#[allow(clippy::cast_possible_truncation, clippy::needless_range_loop)]
117
151k
pub(crate) fn parse_dqt<T: ZByteReaderTrait>(img: &mut JpegDecoder<T>) -> Result<(), DecodeErrors> {
118
    // read length
119
151k
    let mut qt_length =
120
151k
        img.stream
121
151k
            .get_u16_be_err()?
122
151k
            .checked_sub(2)
123
151k
            .ok_or(DecodeErrors::FormatStatic(
124
151k
                "Invalid DQT length. Length should be greater than 2"
125
151k
            ))?;
126
    // A single DQT header may have multiple QT's
127
297k
    while qt_length > 0 {
128
146k
        let qt_info = img.stream.read_u8_err()?;
129
        // 0 = 8 bit otherwise 16 bit dqt
130
146k
        let precision = (qt_info >> 4) as usize;
131
        // last 4 bits give us position
132
146k
        let table_position = (qt_info & 0x0f) as usize;
133
146k
        let precision_value = 64 * (precision + 1);
134
135
146k
        if (precision_value + 1) as u16 > qt_length {
136
49
            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)));
137
146k
        }
138
139
146k
        let dct_table = match precision {
140
            0 => {
141
143k
                let mut qt_values = [0; 64];
142
143
143k
                img.stream.read_exact_bytes(&mut qt_values)?;
144
145
143k
                qt_length -= (precision_value as u16) + 1 /*QT BIT*/;
146
                // carry out un zig-zag here
147
143k
                un_zig_zag(&qt_values)
148
            }
149
            1 => {
150
                // 16 bit quantization tables
151
2.84k
                let mut qt_values = [0_u16; 64];
152
153
179k
                for i in 0..64 {
154
176k
                    qt_values[i] = img.stream.get_u16_be_err()?;
155
                }
156
2.73k
                qt_length -= (precision_value as u16) + 1;
157
158
2.73k
                un_zig_zag(&qt_values)
159
            }
160
            _ => {
161
76
                return Err(DecodeErrors::DqtError(format!(
162
76
                    "Expected QT precision value of either 0 or 1, found {precision:?}"
163
76
                )));
164
            }
165
        };
166
167
146k
        if table_position >= MAX_COMPONENTS {
168
22
            return Err(DecodeErrors::DqtError(format!(
169
22
                "Too large table position for QT :{table_position}, expected between 0 and 3"
170
22
            )));
171
146k
        }
172
173
        trace!("Assigning qt table {table_position} with precision {precision}");
174
146k
        img.qt_tables[table_position] = Some(dct_table);
175
    }
176
177
150k
    return Ok(());
178
151k
}
zune_jpeg::headers::parse_dqt::<zune_core::bytestream::reader::no_std_readers::ZCursor<alloc::vec::Vec<u8>>>
Line
Count
Source
117
63.1k
pub(crate) fn parse_dqt<T: ZByteReaderTrait>(img: &mut JpegDecoder<T>) -> Result<(), DecodeErrors> {
118
    // read length
119
63.1k
    let mut qt_length =
120
63.1k
        img.stream
121
63.1k
            .get_u16_be_err()?
122
63.1k
            .checked_sub(2)
123
63.1k
            .ok_or(DecodeErrors::FormatStatic(
124
63.1k
                "Invalid DQT length. Length should be greater than 2"
125
63.1k
            ))?;
126
    // A single DQT header may have multiple QT's
127
129k
    while qt_length > 0 {
128
66.0k
        let qt_info = img.stream.read_u8_err()?;
129
        // 0 = 8 bit otherwise 16 bit dqt
130
66.0k
        let precision = (qt_info >> 4) as usize;
131
        // last 4 bits give us position
132
66.0k
        let table_position = (qt_info & 0x0f) as usize;
133
66.0k
        let precision_value = 64 * (precision + 1);
134
135
66.0k
        if (precision_value + 1) as u16 > qt_length {
136
16
            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)));
137
66.0k
        }
138
139
66.0k
        let dct_table = match precision {
140
            0 => {
141
65.7k
                let mut qt_values = [0; 64];
142
143
65.7k
                img.stream.read_exact_bytes(&mut qt_values)?;
144
145
65.6k
                qt_length -= (precision_value as u16) + 1 /*QT BIT*/;
146
                // carry out un zig-zag here
147
65.6k
                un_zig_zag(&qt_values)
148
            }
149
            1 => {
150
                // 16 bit quantization tables
151
309
                let mut qt_values = [0_u16; 64];
152
153
18.4k
                for i in 0..64 {
154
18.1k
                    qt_values[i] = img.stream.get_u16_be_err()?;
155
                }
156
275
                qt_length -= (precision_value as u16) + 1;
157
158
275
                un_zig_zag(&qt_values)
159
            }
160
            _ => {
161
30
                return Err(DecodeErrors::DqtError(format!(
162
30
                    "Expected QT precision value of either 0 or 1, found {precision:?}"
163
30
                )));
164
            }
165
        };
166
167
65.8k
        if table_position >= MAX_COMPONENTS {
168
15
            return Err(DecodeErrors::DqtError(format!(
169
15
                "Too large table position for QT :{table_position}, expected between 0 and 3"
170
15
            )));
171
65.8k
        }
172
173
        trace!("Assigning qt table {table_position} with precision {precision}");
174
65.8k
        img.qt_tables[table_position] = Some(dct_table);
175
    }
176
177
62.9k
    return Ok(());
178
63.1k
}
Unexecuted instantiation: zune_jpeg::headers::parse_dqt::<zune_core::bytestream::reader::no_std_readers::ZCursor<&alloc::vec::Vec<u8>>>
zune_jpeg::headers::parse_dqt::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Line
Count
Source
117
88.1k
pub(crate) fn parse_dqt<T: ZByteReaderTrait>(img: &mut JpegDecoder<T>) -> Result<(), DecodeErrors> {
118
    // read length
119
88.1k
    let mut qt_length =
120
88.1k
        img.stream
121
88.1k
            .get_u16_be_err()?
122
88.1k
            .checked_sub(2)
123
88.1k
            .ok_or(DecodeErrors::FormatStatic(
124
88.1k
                "Invalid DQT length. Length should be greater than 2"
125
88.1k
            ))?;
126
    // A single DQT header may have multiple QT's
127
168k
    while qt_length > 0 {
128
80.6k
        let qt_info = img.stream.read_u8_err()?;
129
        // 0 = 8 bit otherwise 16 bit dqt
130
80.6k
        let precision = (qt_info >> 4) as usize;
131
        // last 4 bits give us position
132
80.6k
        let table_position = (qt_info & 0x0f) as usize;
133
80.6k
        let precision_value = 64 * (precision + 1);
134
135
80.6k
        if (precision_value + 1) as u16 > qt_length {
136
33
            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)));
137
80.5k
        }
138
139
80.5k
        let dct_table = match precision {
140
            0 => {
141
78.0k
                let mut qt_values = [0; 64];
142
143
78.0k
                img.stream.read_exact_bytes(&mut qt_values)?;
144
145
77.8k
                qt_length -= (precision_value as u16) + 1 /*QT BIT*/;
146
                // carry out un zig-zag here
147
77.8k
                un_zig_zag(&qt_values)
148
            }
149
            1 => {
150
                // 16 bit quantization tables
151
2.53k
                let mut qt_values = [0_u16; 64];
152
153
160k
                for i in 0..64 {
154
158k
                    qt_values[i] = img.stream.get_u16_be_err()?;
155
                }
156
2.46k
                qt_length -= (precision_value as u16) + 1;
157
158
2.46k
                un_zig_zag(&qt_values)
159
            }
160
            _ => {
161
46
                return Err(DecodeErrors::DqtError(format!(
162
46
                    "Expected QT precision value of either 0 or 1, found {precision:?}"
163
46
                )));
164
            }
165
        };
166
167
80.3k
        if table_position >= MAX_COMPONENTS {
168
7
            return Err(DecodeErrors::DqtError(format!(
169
7
                "Too large table position for QT :{table_position}, expected between 0 and 3"
170
7
            )));
171
80.3k
        }
172
173
        trace!("Assigning qt table {table_position} with precision {precision}");
174
80.3k
        img.qt_tables[table_position] = Some(dct_table);
175
    }
176
177
87.8k
    return Ok(());
178
88.1k
}
Unexecuted instantiation: zune_jpeg::headers::parse_dqt::<_>
179
180
/// Section:`B.2.2 Frame header syntax`
181
182
27.4k
pub(crate) fn parse_start_of_frame<T: ZByteReaderTrait>(
183
27.4k
    sof: SOFMarkers, img: &mut JpegDecoder<T>
184
27.4k
) -> Result<(), DecodeErrors> {
185
27.4k
    if img.seen_sof {
186
161
        return Err(DecodeErrors::SofError(
187
161
            "Two Start of Frame Markers".to_string()
188
161
        ));
189
27.2k
    }
190
    // Get length of the frame header
191
27.2k
    let length = img.stream.get_u16_be_err()?;
192
    // usually 8, but can be 12 and 16, we currently support only 8
193
    // so sorry about that 12 bit images
194
27.2k
    let dt_precision = img.stream.read_u8_err()?;
195
196
27.2k
    if dt_precision != 8 {
197
27
        return Err(DecodeErrors::SofError(format!(
198
27
            "The library can only parse 8-bit images, the image has {dt_precision} bits of precision"
199
27
        )));
200
27.2k
    }
201
202
27.2k
    img.info.set_density(dt_precision);
203
204
    // read  and set the image height.
205
27.2k
    let img_height = img.stream.get_u16_be_err()?;
206
27.2k
    img.info.set_height(img_height);
207
208
    // read and set the image width
209
27.2k
    let img_width = img.stream.get_u16_be_err()?;
210
27.1k
    img.info.set_width(img_width);
211
212
    trace!("Image width  :{}", img_width);
213
    trace!("Image height :{}", img_height);
214
215
27.1k
    if usize::from(img_width) > img.options.max_width() {
216
2
        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.max_width())));
217
27.1k
    }
218
219
27.1k
    if usize::from(img_height) > img.options.max_height() {
220
15
        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.max_height())));
221
27.1k
    }
222
223
    // Check image width or height is zero
224
27.1k
    if img_width == 0 || img_height == 0 {
225
9
        return Err(DecodeErrors::ZeroError);
226
27.1k
    }
227
228
    // Number of components for the image.
229
27.1k
    let num_components = img.stream.read_u8_err()?;
230
231
27.1k
    if num_components == 0 {
232
5
        return Err(DecodeErrors::SofError(
233
5
            "Number of components cannot be zero.".to_string()
234
5
        ));
235
27.1k
    }
236
237
27.1k
    let expected = 8 + 3 * u16::from(num_components);
238
    // length should be equal to num components
239
27.1k
    if length != expected {
240
76
        return Err(DecodeErrors::SofError(format!(
241
76
            "Length of start of frame differs from expected {expected},value is {length}"
242
76
        )));
243
27.0k
    }
244
245
    trace!("Image components : {}", num_components);
246
247
27.0k
    if num_components == 1 {
248
16.8k
        // SOF sets the number of image components
249
16.8k
        // and that to us translates to setting input and output
250
16.8k
        // colorspaces to zero
251
16.8k
        img.input_colorspace = ColorSpace::Luma;
252
16.8k
        //img.options = img.options.jpeg_set_out_colorspace(ColorSpace::Luma);
253
16.8k
        debug!("Overriding default colorspace set to Luma");
254
16.8k
    }
255
27.0k
    if num_components == 4 && img.input_colorspace == ColorSpace::YCbCr {
256
3.56k
        trace!("Input image has 4 components, defaulting to CMYK colorspace");
257
3.56k
        // https://entropymine.wordpress.com/2018/10/22/how-is-a-jpeg-images-color-type-determined/
258
3.56k
        img.input_colorspace = ColorSpace::CMYK;
259
23.4k
    }
260
261
    // set number of components
262
27.0k
    img.info.components = num_components;
263
264
27.0k
    let mut components = Vec::with_capacity(num_components as usize);
265
27.0k
    let mut temp = [0; 3];
266
267
51.5k
    for pos in 0..num_components {
268
        // read 3 bytes for each component
269
51.5k
        img.stream.read_exact_bytes(&mut temp)?;
270
271
        // create a component.
272
51.5k
        let component = Components::from(temp, pos)?;
273
274
51.4k
        components.push(component);
275
    }
276
26.9k
    img.seen_sof = true;
277
278
26.9k
    img.info.set_sof_marker(sof);
279
280
26.9k
    img.components = components;
281
282
26.9k
    let mut h_max = 1;
283
26.9k
    let mut v_max = 1;
284
285
78.3k
    for comp in &img.components {
286
51.4k
        h_max = max(h_max, comp.horizontal_sample);
287
51.4k
        v_max = max(v_max, comp.vertical_sample);
288
51.4k
    }
289
290
26.9k
    img.info.sample_ratio = match (h_max, v_max) {
291
11.1k
        (1, 1) => SampleRatios::None,
292
2.22k
        (1, 2) => SampleRatios::V,
293
4.02k
        (2, 1) => SampleRatios::H,
294
4.87k
        (2, 2) => SampleRatios::HV,
295
4.65k
        (hs, vs) => SampleRatios::Generic(hs, vs)
296
    };
297
298
26.9k
    Ok(())
299
27.4k
}
zune_jpeg::headers::parse_start_of_frame::<zune_core::bytestream::reader::no_std_readers::ZCursor<alloc::vec::Vec<u8>>>
Line
Count
Source
182
9.95k
pub(crate) fn parse_start_of_frame<T: ZByteReaderTrait>(
183
9.95k
    sof: SOFMarkers, img: &mut JpegDecoder<T>
184
9.95k
) -> Result<(), DecodeErrors> {
185
9.95k
    if img.seen_sof {
186
66
        return Err(DecodeErrors::SofError(
187
66
            "Two Start of Frame Markers".to_string()
188
66
        ));
189
9.89k
    }
190
    // Get length of the frame header
191
9.89k
    let length = img.stream.get_u16_be_err()?;
192
    // usually 8, but can be 12 and 16, we currently support only 8
193
    // so sorry about that 12 bit images
194
9.88k
    let dt_precision = img.stream.read_u8_err()?;
195
196
9.88k
    if dt_precision != 8 {
197
12
        return Err(DecodeErrors::SofError(format!(
198
12
            "The library can only parse 8-bit images, the image has {dt_precision} bits of precision"
199
12
        )));
200
9.87k
    }
201
202
9.87k
    img.info.set_density(dt_precision);
203
204
    // read  and set the image height.
205
9.87k
    let img_height = img.stream.get_u16_be_err()?;
206
9.86k
    img.info.set_height(img_height);
207
208
    // read and set the image width
209
9.86k
    let img_width = img.stream.get_u16_be_err()?;
210
9.86k
    img.info.set_width(img_width);
211
212
    trace!("Image width  :{}", img_width);
213
    trace!("Image height :{}", img_height);
214
215
9.86k
    if usize::from(img_width) > img.options.max_width() {
216
2
        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.max_width())));
217
9.86k
    }
218
219
9.86k
    if usize::from(img_height) > img.options.max_height() {
220
15
        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.max_height())));
221
9.84k
    }
222
223
    // Check image width or height is zero
224
9.84k
    if img_width == 0 || img_height == 0 {
225
5
        return Err(DecodeErrors::ZeroError);
226
9.84k
    }
227
228
    // Number of components for the image.
229
9.84k
    let num_components = img.stream.read_u8_err()?;
230
231
9.83k
    if num_components == 0 {
232
2
        return Err(DecodeErrors::SofError(
233
2
            "Number of components cannot be zero.".to_string()
234
2
        ));
235
9.83k
    }
236
237
9.83k
    let expected = 8 + 3 * u16::from(num_components);
238
    // length should be equal to num components
239
9.83k
    if length != expected {
240
31
        return Err(DecodeErrors::SofError(format!(
241
31
            "Length of start of frame differs from expected {expected},value is {length}"
242
31
        )));
243
9.80k
    }
244
245
    trace!("Image components : {}", num_components);
246
247
9.80k
    if num_components == 1 {
248
5.84k
        // SOF sets the number of image components
249
5.84k
        // and that to us translates to setting input and output
250
5.84k
        // colorspaces to zero
251
5.84k
        img.input_colorspace = ColorSpace::Luma;
252
5.84k
        //img.options = img.options.jpeg_set_out_colorspace(ColorSpace::Luma);
253
5.84k
        debug!("Overriding default colorspace set to Luma");
254
5.84k
    }
255
9.80k
    if num_components == 4 && img.input_colorspace == ColorSpace::YCbCr {
256
2.90k
        trace!("Input image has 4 components, defaulting to CMYK colorspace");
257
2.90k
        // https://entropymine.wordpress.com/2018/10/22/how-is-a-jpeg-images-color-type-determined/
258
2.90k
        img.input_colorspace = ColorSpace::CMYK;
259
6.90k
    }
260
261
    // set number of components
262
9.80k
    img.info.components = num_components;
263
264
9.80k
    let mut components = Vec::with_capacity(num_components as usize);
265
9.80k
    let mut temp = [0; 3];
266
267
20.9k
    for pos in 0..num_components {
268
        // read 3 bytes for each component
269
20.9k
        img.stream.read_exact_bytes(&mut temp)?;
270
271
        // create a component.
272
20.9k
        let component = Components::from(temp, pos)?;
273
274
20.9k
        components.push(component);
275
    }
276
9.78k
    img.seen_sof = true;
277
278
9.78k
    img.info.set_sof_marker(sof);
279
280
9.78k
    img.components = components;
281
282
9.78k
    let mut h_max = 1;
283
9.78k
    let mut v_max = 1;
284
285
30.6k
    for comp in &img.components {
286
20.8k
        h_max = max(h_max, comp.horizontal_sample);
287
20.8k
        v_max = max(v_max, comp.vertical_sample);
288
20.8k
    }
289
290
9.78k
    img.info.sample_ratio = match (h_max, v_max) {
291
6.62k
        (1, 1) => SampleRatios::None,
292
743
        (1, 2) => SampleRatios::V,
293
245
        (2, 1) => SampleRatios::H,
294
413
        (2, 2) => SampleRatios::HV,
295
1.75k
        (hs, vs) => SampleRatios::Generic(hs, vs)
296
    };
297
298
9.78k
    Ok(())
299
9.95k
}
Unexecuted instantiation: zune_jpeg::headers::parse_start_of_frame::<zune_core::bytestream::reader::no_std_readers::ZCursor<&alloc::vec::Vec<u8>>>
zune_jpeg::headers::parse_start_of_frame::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Line
Count
Source
182
17.4k
pub(crate) fn parse_start_of_frame<T: ZByteReaderTrait>(
183
17.4k
    sof: SOFMarkers, img: &mut JpegDecoder<T>
184
17.4k
) -> Result<(), DecodeErrors> {
185
17.4k
    if img.seen_sof {
186
95
        return Err(DecodeErrors::SofError(
187
95
            "Two Start of Frame Markers".to_string()
188
95
        ));
189
17.3k
    }
190
    // Get length of the frame header
191
17.3k
    let length = img.stream.get_u16_be_err()?;
192
    // usually 8, but can be 12 and 16, we currently support only 8
193
    // so sorry about that 12 bit images
194
17.3k
    let dt_precision = img.stream.read_u8_err()?;
195
196
17.3k
    if dt_precision != 8 {
197
15
        return Err(DecodeErrors::SofError(format!(
198
15
            "The library can only parse 8-bit images, the image has {dt_precision} bits of precision"
199
15
        )));
200
17.3k
    }
201
202
17.3k
    img.info.set_density(dt_precision);
203
204
    // read  and set the image height.
205
17.3k
    let img_height = img.stream.get_u16_be_err()?;
206
17.3k
    img.info.set_height(img_height);
207
208
    // read and set the image width
209
17.3k
    let img_width = img.stream.get_u16_be_err()?;
210
17.3k
    img.info.set_width(img_width);
211
212
    trace!("Image width  :{}", img_width);
213
    trace!("Image height :{}", img_height);
214
215
17.3k
    if usize::from(img_width) > img.options.max_width() {
216
0
        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.max_width())));
217
17.3k
    }
218
219
17.3k
    if usize::from(img_height) > img.options.max_height() {
220
0
        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.max_height())));
221
17.3k
    }
222
223
    // Check image width or height is zero
224
17.3k
    if img_width == 0 || img_height == 0 {
225
4
        return Err(DecodeErrors::ZeroError);
226
17.3k
    }
227
228
    // Number of components for the image.
229
17.3k
    let num_components = img.stream.read_u8_err()?;
230
231
17.2k
    if num_components == 0 {
232
3
        return Err(DecodeErrors::SofError(
233
3
            "Number of components cannot be zero.".to_string()
234
3
        ));
235
17.2k
    }
236
237
17.2k
    let expected = 8 + 3 * u16::from(num_components);
238
    // length should be equal to num components
239
17.2k
    if length != expected {
240
45
        return Err(DecodeErrors::SofError(format!(
241
45
            "Length of start of frame differs from expected {expected},value is {length}"
242
45
        )));
243
17.2k
    }
244
245
    trace!("Image components : {}", num_components);
246
247
17.2k
    if num_components == 1 {
248
10.9k
        // SOF sets the number of image components
249
10.9k
        // and that to us translates to setting input and output
250
10.9k
        // colorspaces to zero
251
10.9k
        img.input_colorspace = ColorSpace::Luma;
252
10.9k
        //img.options = img.options.jpeg_set_out_colorspace(ColorSpace::Luma);
253
10.9k
        debug!("Overriding default colorspace set to Luma");
254
10.9k
    }
255
17.2k
    if num_components == 4 && img.input_colorspace == ColorSpace::YCbCr {
256
668
        trace!("Input image has 4 components, defaulting to CMYK colorspace");
257
668
        // https://entropymine.wordpress.com/2018/10/22/how-is-a-jpeg-images-color-type-determined/
258
668
        img.input_colorspace = ColorSpace::CMYK;
259
16.5k
    }
260
261
    // set number of components
262
17.2k
    img.info.components = num_components;
263
264
17.2k
    let mut components = Vec::with_capacity(num_components as usize);
265
17.2k
    let mut temp = [0; 3];
266
267
30.6k
    for pos in 0..num_components {
268
        // read 3 bytes for each component
269
30.6k
        img.stream.read_exact_bytes(&mut temp)?;
270
271
        // create a component.
272
30.6k
        let component = Components::from(temp, pos)?;
273
274
30.5k
        components.push(component);
275
    }
276
17.1k
    img.seen_sof = true;
277
278
17.1k
    img.info.set_sof_marker(sof);
279
280
17.1k
    img.components = components;
281
282
17.1k
    let mut h_max = 1;
283
17.1k
    let mut v_max = 1;
284
285
47.7k
    for comp in &img.components {
286
30.5k
        h_max = max(h_max, comp.horizontal_sample);
287
30.5k
        v_max = max(v_max, comp.vertical_sample);
288
30.5k
    }
289
290
17.1k
    img.info.sample_ratio = match (h_max, v_max) {
291
4.57k
        (1, 1) => SampleRatios::None,
292
1.47k
        (1, 2) => SampleRatios::V,
293
3.77k
        (2, 1) => SampleRatios::H,
294
4.45k
        (2, 2) => SampleRatios::HV,
295
2.89k
        (hs, vs) => SampleRatios::Generic(hs, vs)
296
    };
297
298
17.1k
    Ok(())
299
17.4k
}
Unexecuted instantiation: zune_jpeg::headers::parse_start_of_frame::<_>
300
301
/// Parse a start of scan data
302
123k
pub(crate) fn parse_sos<T: ZByteReaderTrait>(
303
123k
    image: &mut JpegDecoder<T>
304
123k
) -> Result<(), DecodeErrors> {
305
    // Scan header length
306
123k
    let ls = usize::from(image.stream.get_u16_be_err()?);
307
    // Number of image components in scan
308
123k
    let ns = image.stream.read_u8_err()?;
309
310
123k
    let mut seen: [_; 5] = [-1; { MAX_COMPONENTS + 1 }];
311
312
123k
    image.num_scans = ns;
313
123k
    let smallest_size = 6 + 2 * usize::from(ns);
314
315
123k
    if ls != smallest_size {
316
243
        return Err(DecodeErrors::SosError(format!(
317
243
            "Bad SOS length {ls},corrupt jpeg"
318
243
        )));
319
123k
    }
320
321
    // Check number of components.
322
123k
    if !(1..5).contains(&ns) {
323
8
        return Err(DecodeErrors::SosError(format!(
324
8
            "Invalid number of components in start of scan {ns}, expected in range 1..5"
325
8
        )));
326
123k
    }
327
328
123k
    if image.info.components == 0 {
329
212
        return Err(DecodeErrors::FormatStatic(
330
212
            "Error decoding SOF Marker, Number of components cannot be zero."
331
212
        ));
332
123k
    }
333
334
    // consume spec parameters
335
123k
    image.scan_subsampled = false;
336
337
210k
    for i in 0..ns {
338
210k
        let id = image.stream.read_u8_err()?;
339
340
210k
        if seen.contains(&i32::from(id)) {
341
28
            return Err(DecodeErrors::SofError(format!(
342
28
                "Duplicate ID {id} seen twice in the same component"
343
28
            )));
344
210k
        }
345
346
210k
        seen[usize::from(i)] = i32::from(id);
347
        // DC and AC huffman table position
348
        // top 4 bits contain dc huffman destination table
349
        // lower four bits contain ac huffman destination table
350
210k
        let y = image.stream.read_u8_err()?;
351
352
210k
        let mut j = 0;
353
354
385k
        while j < image.info.components {
355
385k
            if image.components[j as usize].id == id {
356
210k
                break;
357
175k
            }
358
359
175k
            j += 1;
360
        }
361
362
210k
        if j == image.info.components {
363
226
            return Err(DecodeErrors::SofError(format!(
364
226
                "Invalid component id {}, expected one one of {:?}",
365
                id,
366
226
                image.components.iter().map(|c| c.id).collect::<Vec<_>>()
367
            )));
368
210k
        }
369
370
210k
        let component = &mut image.components[usize::from(j)];
371
210k
        component.dc_huff_table = usize::from((y >> 4) & 0xF);
372
210k
        component.ac_huff_table = usize::from(y & 0xF);
373
210k
        image.z_order[i as usize] = j as usize;
374
375
210k
        if component.vertical_sample != 1 || component.horizontal_sample != 1 {
376
64.1k
            image.scan_subsampled = true;
377
145k
        }
378
379
        trace!(
380
            "Assigned huffman tables {}/{} to component {j}, id={}",
381
            image.components[usize::from(j)].dc_huff_table,
382
            image.components[usize::from(j)].ac_huff_table,
383
            image.components[usize::from(j)].id,
384
        );
385
    }
386
387
    // Collect the component spec parameters
388
    // This is only needed for progressive images but I'll read
389
    // them in order to ensure they are correct according to the spec
390
391
    // Extract progressive information
392
393
    // https://www.w3.org/Graphics/JPEG/itu-t81.pdf
394
    // Page 42
395
396
    // Start of spectral / predictor selection. (between 0 and 63)
397
122k
    image.spec_start = image.stream.read_u8_err()?;
398
    // End of spectral selection
399
122k
    image.spec_end = image.stream.read_u8_err()?;
400
401
122k
    let bit_approx = image.stream.read_u8_err()?;
402
    // successive approximation bit position high
403
122k
    image.succ_high = bit_approx >> 4;
404
405
122k
    if image.spec_end > 63 {
406
53
        return Err(DecodeErrors::SosError(format!(
407
53
            "Invalid Se parameter {}, range should be 0-63",
408
53
            image.spec_end
409
53
        )));
410
122k
    }
411
122k
    if image.spec_start > 63 {
412
19
        return Err(DecodeErrors::SosError(format!(
413
19
            "Invalid Ss parameter {}, range should be 0-63",
414
19
            image.spec_start
415
19
        )));
416
122k
    }
417
122k
    if image.succ_high > 13 {
418
14
        return Err(DecodeErrors::SosError(format!(
419
14
            "Invalid Ah parameter {}, range should be 0-13",
420
14
            image.succ_low
421
14
        )));
422
122k
    }
423
    // successive approximation bit position low
424
122k
    image.succ_low = bit_approx & 0xF;
425
426
122k
    if image.succ_low > 13 {
427
18
        return Err(DecodeErrors::SosError(format!(
428
18
            "Invalid Al parameter {}, range should be 0-13",
429
18
            image.succ_low
430
18
        )));
431
122k
    }
432
    // skip any bytes not read
433
122k
    image.stream.skip(smallest_size.saturating_sub(ls))?;
434
435
    trace!(
436
        "Ss={}, Se={} Ah={} Al={}",
437
        image.spec_start,
438
        image.spec_end,
439
        image.succ_high,
440
        image.succ_low
441
    );
442
443
122k
    Ok(())
444
123k
}
zune_jpeg::headers::parse_sos::<zune_core::bytestream::reader::no_std_readers::ZCursor<alloc::vec::Vec<u8>>>
Line
Count
Source
302
59.8k
pub(crate) fn parse_sos<T: ZByteReaderTrait>(
303
59.8k
    image: &mut JpegDecoder<T>
304
59.8k
) -> Result<(), DecodeErrors> {
305
    // Scan header length
306
59.8k
    let ls = usize::from(image.stream.get_u16_be_err()?);
307
    // Number of image components in scan
308
59.8k
    let ns = image.stream.read_u8_err()?;
309
310
59.8k
    let mut seen: [_; 5] = [-1; { MAX_COMPONENTS + 1 }];
311
312
59.8k
    image.num_scans = ns;
313
59.8k
    let smallest_size = 6 + 2 * usize::from(ns);
314
315
59.8k
    if ls != smallest_size {
316
80
        return Err(DecodeErrors::SosError(format!(
317
80
            "Bad SOS length {ls},corrupt jpeg"
318
80
        )));
319
59.7k
    }
320
321
    // Check number of components.
322
59.7k
    if !(1..5).contains(&ns) {
323
3
        return Err(DecodeErrors::SosError(format!(
324
3
            "Invalid number of components in start of scan {ns}, expected in range 1..5"
325
3
        )));
326
59.7k
    }
327
328
59.7k
    if image.info.components == 0 {
329
187
        return Err(DecodeErrors::FormatStatic(
330
187
            "Error decoding SOF Marker, Number of components cannot be zero."
331
187
        ));
332
59.6k
    }
333
334
    // consume spec parameters
335
59.6k
    image.scan_subsampled = false;
336
337
111k
    for i in 0..ns {
338
111k
        let id = image.stream.read_u8_err()?;
339
340
111k
        if seen.contains(&i32::from(id)) {
341
16
            return Err(DecodeErrors::SofError(format!(
342
16
                "Duplicate ID {id} seen twice in the same component"
343
16
            )));
344
111k
        }
345
346
111k
        seen[usize::from(i)] = i32::from(id);
347
        // DC and AC huffman table position
348
        // top 4 bits contain dc huffman destination table
349
        // lower four bits contain ac huffman destination table
350
111k
        let y = image.stream.read_u8_err()?;
351
352
111k
        let mut j = 0;
353
354
227k
        while j < image.info.components {
355
227k
            if image.components[j as usize].id == id {
356
111k
                break;
357
116k
            }
358
359
116k
            j += 1;
360
        }
361
362
111k
        if j == image.info.components {
363
78
            return Err(DecodeErrors::SofError(format!(
364
78
                "Invalid component id {}, expected one one of {:?}",
365
                id,
366
78
                image.components.iter().map(|c| c.id).collect::<Vec<_>>()
367
            )));
368
111k
        }
369
370
111k
        let component = &mut image.components[usize::from(j)];
371
111k
        component.dc_huff_table = usize::from((y >> 4) & 0xF);
372
111k
        component.ac_huff_table = usize::from(y & 0xF);
373
111k
        image.z_order[i as usize] = j as usize;
374
375
111k
        if component.vertical_sample != 1 || component.horizontal_sample != 1 {
376
18.7k
            image.scan_subsampled = true;
377
92.3k
        }
378
379
        trace!(
380
            "Assigned huffman tables {}/{} to component {j}, id={}",
381
            image.components[usize::from(j)].dc_huff_table,
382
            image.components[usize::from(j)].ac_huff_table,
383
            image.components[usize::from(j)].id,
384
        );
385
    }
386
387
    // Collect the component spec parameters
388
    // This is only needed for progressive images but I'll read
389
    // them in order to ensure they are correct according to the spec
390
391
    // Extract progressive information
392
393
    // https://www.w3.org/Graphics/JPEG/itu-t81.pdf
394
    // Page 42
395
396
    // Start of spectral / predictor selection. (between 0 and 63)
397
59.4k
    image.spec_start = image.stream.read_u8_err()?;
398
    // End of spectral selection
399
59.4k
    image.spec_end = image.stream.read_u8_err()?;
400
401
59.4k
    let bit_approx = image.stream.read_u8_err()?;
402
    // successive approximation bit position high
403
59.4k
    image.succ_high = bit_approx >> 4;
404
405
59.4k
    if image.spec_end > 63 {
406
13
        return Err(DecodeErrors::SosError(format!(
407
13
            "Invalid Se parameter {}, range should be 0-63",
408
13
            image.spec_end
409
13
        )));
410
59.4k
    }
411
59.4k
    if image.spec_start > 63 {
412
4
        return Err(DecodeErrors::SosError(format!(
413
4
            "Invalid Ss parameter {}, range should be 0-63",
414
4
            image.spec_start
415
4
        )));
416
59.4k
    }
417
59.4k
    if image.succ_high > 13 {
418
6
        return Err(DecodeErrors::SosError(format!(
419
6
            "Invalid Ah parameter {}, range should be 0-13",
420
6
            image.succ_low
421
6
        )));
422
59.4k
    }
423
    // successive approximation bit position low
424
59.4k
    image.succ_low = bit_approx & 0xF;
425
426
59.4k
    if image.succ_low > 13 {
427
7
        return Err(DecodeErrors::SosError(format!(
428
7
            "Invalid Al parameter {}, range should be 0-13",
429
7
            image.succ_low
430
7
        )));
431
59.4k
    }
432
    // skip any bytes not read
433
59.4k
    image.stream.skip(smallest_size.saturating_sub(ls))?;
434
435
    trace!(
436
        "Ss={}, Se={} Ah={} Al={}",
437
        image.spec_start,
438
        image.spec_end,
439
        image.succ_high,
440
        image.succ_low
441
    );
442
443
59.4k
    Ok(())
444
59.8k
}
Unexecuted instantiation: zune_jpeg::headers::parse_sos::<zune_core::bytestream::reader::no_std_readers::ZCursor<&alloc::vec::Vec<u8>>>
zune_jpeg::headers::parse_sos::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Line
Count
Source
302
63.7k
pub(crate) fn parse_sos<T: ZByteReaderTrait>(
303
63.7k
    image: &mut JpegDecoder<T>
304
63.7k
) -> Result<(), DecodeErrors> {
305
    // Scan header length
306
63.7k
    let ls = usize::from(image.stream.get_u16_be_err()?);
307
    // Number of image components in scan
308
63.6k
    let ns = image.stream.read_u8_err()?;
309
310
63.6k
    let mut seen: [_; 5] = [-1; { MAX_COMPONENTS + 1 }];
311
312
63.6k
    image.num_scans = ns;
313
63.6k
    let smallest_size = 6 + 2 * usize::from(ns);
314
315
63.6k
    if ls != smallest_size {
316
163
        return Err(DecodeErrors::SosError(format!(
317
163
            "Bad SOS length {ls},corrupt jpeg"
318
163
        )));
319
63.5k
    }
320
321
    // Check number of components.
322
63.5k
    if !(1..5).contains(&ns) {
323
5
        return Err(DecodeErrors::SosError(format!(
324
5
            "Invalid number of components in start of scan {ns}, expected in range 1..5"
325
5
        )));
326
63.5k
    }
327
328
63.5k
    if image.info.components == 0 {
329
25
        return Err(DecodeErrors::FormatStatic(
330
25
            "Error decoding SOF Marker, Number of components cannot be zero."
331
25
        ));
332
63.4k
    }
333
334
    // consume spec parameters
335
63.4k
    image.scan_subsampled = false;
336
337
99.1k
    for i in 0..ns {
338
99.1k
        let id = image.stream.read_u8_err()?;
339
340
99.1k
        if seen.contains(&i32::from(id)) {
341
12
            return Err(DecodeErrors::SofError(format!(
342
12
                "Duplicate ID {id} seen twice in the same component"
343
12
            )));
344
99.1k
        }
345
346
99.1k
        seen[usize::from(i)] = i32::from(id);
347
        // DC and AC huffman table position
348
        // top 4 bits contain dc huffman destination table
349
        // lower four bits contain ac huffman destination table
350
99.1k
        let y = image.stream.read_u8_err()?;
351
352
99.1k
        let mut j = 0;
353
354
158k
        while j < image.info.components {
355
158k
            if image.components[j as usize].id == id {
356
98.9k
                break;
357
59.0k
            }
358
359
59.0k
            j += 1;
360
        }
361
362
99.1k
        if j == image.info.components {
363
148
            return Err(DecodeErrors::SofError(format!(
364
148
                "Invalid component id {}, expected one one of {:?}",
365
                id,
366
148
                image.components.iter().map(|c| c.id).collect::<Vec<_>>()
367
            )));
368
98.9k
        }
369
370
98.9k
        let component = &mut image.components[usize::from(j)];
371
98.9k
        component.dc_huff_table = usize::from((y >> 4) & 0xF);
372
98.9k
        component.ac_huff_table = usize::from(y & 0xF);
373
98.9k
        image.z_order[i as usize] = j as usize;
374
375
98.9k
        if component.vertical_sample != 1 || component.horizontal_sample != 1 {
376
45.4k
            image.scan_subsampled = true;
377
53.5k
        }
378
379
        trace!(
380
            "Assigned huffman tables {}/{} to component {j}, id={}",
381
            image.components[usize::from(j)].dc_huff_table,
382
            image.components[usize::from(j)].ac_huff_table,
383
            image.components[usize::from(j)].id,
384
        );
385
    }
386
387
    // Collect the component spec parameters
388
    // This is only needed for progressive images but I'll read
389
    // them in order to ensure they are correct according to the spec
390
391
    // Extract progressive information
392
393
    // https://www.w3.org/Graphics/JPEG/itu-t81.pdf
394
    // Page 42
395
396
    // Start of spectral / predictor selection. (between 0 and 63)
397
63.2k
    image.spec_start = image.stream.read_u8_err()?;
398
    // End of spectral selection
399
63.2k
    image.spec_end = image.stream.read_u8_err()?;
400
401
63.2k
    let bit_approx = image.stream.read_u8_err()?;
402
    // successive approximation bit position high
403
63.2k
    image.succ_high = bit_approx >> 4;
404
405
63.2k
    if image.spec_end > 63 {
406
40
        return Err(DecodeErrors::SosError(format!(
407
40
            "Invalid Se parameter {}, range should be 0-63",
408
40
            image.spec_end
409
40
        )));
410
63.2k
    }
411
63.2k
    if image.spec_start > 63 {
412
15
        return Err(DecodeErrors::SosError(format!(
413
15
            "Invalid Ss parameter {}, range should be 0-63",
414
15
            image.spec_start
415
15
        )));
416
63.1k
    }
417
63.1k
    if image.succ_high > 13 {
418
8
        return Err(DecodeErrors::SosError(format!(
419
8
            "Invalid Ah parameter {}, range should be 0-13",
420
8
            image.succ_low
421
8
        )));
422
63.1k
    }
423
    // successive approximation bit position low
424
63.1k
    image.succ_low = bit_approx & 0xF;
425
426
63.1k
    if image.succ_low > 13 {
427
11
        return Err(DecodeErrors::SosError(format!(
428
11
            "Invalid Al parameter {}, range should be 0-13",
429
11
            image.succ_low
430
11
        )));
431
63.1k
    }
432
    // skip any bytes not read
433
63.1k
    image.stream.skip(smallest_size.saturating_sub(ls))?;
434
435
    trace!(
436
        "Ss={}, Se={} Ah={} Al={}",
437
        image.spec_start,
438
        image.spec_end,
439
        image.succ_high,
440
        image.succ_low
441
    );
442
443
63.1k
    Ok(())
444
63.7k
}
Unexecuted instantiation: zune_jpeg::headers::parse_sos::<_>
445
446
/// Parse the APP13 (IPTC) segment.
447
64.7k
pub(crate) fn parse_app13<T: ZByteReaderTrait>(
448
64.7k
    decoder: &mut JpegDecoder<T>
449
64.7k
) -> Result<(), DecodeErrors> {
450
    const IPTC_PREFIX: &[u8] = b"Photoshop 3.0\0";
451
    // skip length.
452
64.7k
    let mut length = usize::from(decoder.stream.get_u16_be());
453
454
64.7k
    if length < 2 {
455
14
        return Err(DecodeErrors::FormatStatic("Too small APP13 length"));
456
64.7k
    }
457
    // length bytes.
458
64.7k
    length -= 2;
459
460
64.7k
    if length > IPTC_PREFIX.len() && decoder.stream.peek_at(0, IPTC_PREFIX.len())? == IPTC_PREFIX {
461
        // skip bytes we read above.
462
11.5k
        decoder.stream.skip(IPTC_PREFIX.len())?;
463
11.5k
        length -= IPTC_PREFIX.len();
464
465
11.5k
        let iptc_bytes = decoder.stream.peek_at(0, length)?.to_vec();
466
467
11.4k
        decoder.info.iptc_data = Some(iptc_bytes);
468
53.1k
    }
469
470
64.6k
    decoder.stream.skip(length)?;
471
64.6k
    Ok(())
472
64.7k
}
zune_jpeg::headers::parse_app13::<zune_core::bytestream::reader::no_std_readers::ZCursor<alloc::vec::Vec<u8>>>
Line
Count
Source
447
10.3k
pub(crate) fn parse_app13<T: ZByteReaderTrait>(
448
10.3k
    decoder: &mut JpegDecoder<T>
449
10.3k
) -> Result<(), DecodeErrors> {
450
    const IPTC_PREFIX: &[u8] = b"Photoshop 3.0\0";
451
    // skip length.
452
10.3k
    let mut length = usize::from(decoder.stream.get_u16_be());
453
454
10.3k
    if length < 2 {
455
5
        return Err(DecodeErrors::FormatStatic("Too small APP13 length"));
456
10.3k
    }
457
    // length bytes.
458
10.3k
    length -= 2;
459
460
10.3k
    if length > IPTC_PREFIX.len() && decoder.stream.peek_at(0, IPTC_PREFIX.len())? == IPTC_PREFIX {
461
        // skip bytes we read above.
462
2.72k
        decoder.stream.skip(IPTC_PREFIX.len())?;
463
2.72k
        length -= IPTC_PREFIX.len();
464
465
2.72k
        let iptc_bytes = decoder.stream.peek_at(0, length)?.to_vec();
466
467
2.69k
        decoder.info.iptc_data = Some(iptc_bytes);
468
7.62k
    }
469
470
10.3k
    decoder.stream.skip(length)?;
471
10.3k
    Ok(())
472
10.3k
}
Unexecuted instantiation: zune_jpeg::headers::parse_app13::<zune_core::bytestream::reader::no_std_readers::ZCursor<&alloc::vec::Vec<u8>>>
zune_jpeg::headers::parse_app13::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Line
Count
Source
447
54.4k
pub(crate) fn parse_app13<T: ZByteReaderTrait>(
448
54.4k
    decoder: &mut JpegDecoder<T>
449
54.4k
) -> Result<(), DecodeErrors> {
450
    const IPTC_PREFIX: &[u8] = b"Photoshop 3.0\0";
451
    // skip length.
452
54.4k
    let mut length = usize::from(decoder.stream.get_u16_be());
453
454
54.4k
    if length < 2 {
455
9
        return Err(DecodeErrors::FormatStatic("Too small APP13 length"));
456
54.4k
    }
457
    // length bytes.
458
54.4k
    length -= 2;
459
460
54.4k
    if length > IPTC_PREFIX.len() && decoder.stream.peek_at(0, IPTC_PREFIX.len())? == IPTC_PREFIX {
461
        // skip bytes we read above.
462
8.80k
        decoder.stream.skip(IPTC_PREFIX.len())?;
463
8.80k
        length -= IPTC_PREFIX.len();
464
465
8.80k
        let iptc_bytes = decoder.stream.peek_at(0, length)?.to_vec();
466
467
8.78k
        decoder.info.iptc_data = Some(iptc_bytes);
468
45.5k
    }
469
470
54.3k
    decoder.stream.skip(length)?;
471
54.3k
    Ok(())
472
54.4k
}
Unexecuted instantiation: zune_jpeg::headers::parse_app13::<_>
473
474
/// Parse Adobe App14 segment
475
109k
pub(crate) fn parse_app14<T: ZByteReaderTrait>(
476
109k
    decoder: &mut JpegDecoder<T>
477
109k
) -> Result<(), DecodeErrors> {
478
    // skip length
479
109k
    let mut length = usize::from(decoder.stream.get_u16_be());
480
481
109k
    if length < 2 {
482
25
        return Err(DecodeErrors::FormatStatic("Too small APP14 length"));
483
109k
    }
484
485
109k
    if decoder.stream.peek_at(0, 5)? == b"Adobe" {
486
27.9k
        if length < 14 {
487
8
            return Err(DecodeErrors::FormatStatic(
488
8
                "Too short of a length for App14 segment"
489
8
            ));
490
27.8k
        }
491
        // move stream 6 bytes to remove adobe id
492
27.8k
        decoder.stream.skip(6)?;
493
        // skip version, flags0 and flags1
494
27.8k
        decoder.stream.skip(5)?;
495
        // get color transform
496
27.8k
        let transform = decoder.stream.read_u8();
497
        // https://exiftool.org/TagNames/JPEG.html#Adobe
498
27.8k
        match transform {
499
24.7k
            0 => decoder.input_colorspace = ColorSpace::CMYK,
500
268
            1 => decoder.input_colorspace = ColorSpace::YCbCr,
501
2.81k
            2 => decoder.input_colorspace = ColorSpace::YCCK,
502
            _ => {
503
26
                return Err(DecodeErrors::Format(format!(
504
26
                    "Unknown Adobe colorspace {transform}"
505
26
                )))
506
            }
507
        }
508
        // length   = 2
509
        // adobe id = 6
510
        // version =  5
511
        // transform = 1
512
27.8k
        length = length.saturating_sub(14);
513
81.0k
    } else {
514
81.0k
        warn!("Not a valid Adobe APP14 Segment, skipping {} bytes", length);
515
81.0k
        length = length.saturating_sub(2);
516
81.0k
    }
517
    // skip any proceeding lengths.
518
    // we do not need them
519
108k
    decoder.stream.skip(length)?;
520
521
108k
    Ok(())
522
109k
}
zune_jpeg::headers::parse_app14::<zune_core::bytestream::reader::no_std_readers::ZCursor<alloc::vec::Vec<u8>>>
Line
Count
Source
475
24.0k
pub(crate) fn parse_app14<T: ZByteReaderTrait>(
476
24.0k
    decoder: &mut JpegDecoder<T>
477
24.0k
) -> Result<(), DecodeErrors> {
478
    // skip length
479
24.0k
    let mut length = usize::from(decoder.stream.get_u16_be());
480
481
24.0k
    if length < 2 {
482
10
        return Err(DecodeErrors::FormatStatic("Too small APP14 length"));
483
24.0k
    }
484
485
24.0k
    if decoder.stream.peek_at(0, 5)? == b"Adobe" {
486
6.54k
        if length < 14 {
487
3
            return Err(DecodeErrors::FormatStatic(
488
3
                "Too short of a length for App14 segment"
489
3
            ));
490
6.54k
        }
491
        // move stream 6 bytes to remove adobe id
492
6.54k
        decoder.stream.skip(6)?;
493
        // skip version, flags0 and flags1
494
6.54k
        decoder.stream.skip(5)?;
495
        // get color transform
496
6.54k
        let transform = decoder.stream.read_u8();
497
        // https://exiftool.org/TagNames/JPEG.html#Adobe
498
6.54k
        match transform {
499
4.54k
            0 => decoder.input_colorspace = ColorSpace::CMYK,
500
92
            1 => decoder.input_colorspace = ColorSpace::YCbCr,
501
1.89k
            2 => decoder.input_colorspace = ColorSpace::YCCK,
502
            _ => {
503
9
                return Err(DecodeErrors::Format(format!(
504
9
                    "Unknown Adobe colorspace {transform}"
505
9
                )))
506
            }
507
        }
508
        // length   = 2
509
        // adobe id = 6
510
        // version =  5
511
        // transform = 1
512
6.53k
        length = length.saturating_sub(14);
513
17.5k
    } else {
514
17.5k
        warn!("Not a valid Adobe APP14 Segment, skipping {} bytes", length);
515
17.5k
        length = length.saturating_sub(2);
516
17.5k
    }
517
    // skip any proceeding lengths.
518
    // we do not need them
519
24.0k
    decoder.stream.skip(length)?;
520
521
24.0k
    Ok(())
522
24.0k
}
Unexecuted instantiation: zune_jpeg::headers::parse_app14::<zune_core::bytestream::reader::no_std_readers::ZCursor<&alloc::vec::Vec<u8>>>
zune_jpeg::headers::parse_app14::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Line
Count
Source
475
84.9k
pub(crate) fn parse_app14<T: ZByteReaderTrait>(
476
84.9k
    decoder: &mut JpegDecoder<T>
477
84.9k
) -> Result<(), DecodeErrors> {
478
    // skip length
479
84.9k
    let mut length = usize::from(decoder.stream.get_u16_be());
480
481
84.9k
    if length < 2 {
482
15
        return Err(DecodeErrors::FormatStatic("Too small APP14 length"));
483
84.9k
    }
484
485
84.9k
    if decoder.stream.peek_at(0, 5)? == b"Adobe" {
486
21.3k
        if length < 14 {
487
5
            return Err(DecodeErrors::FormatStatic(
488
5
                "Too short of a length for App14 segment"
489
5
            ));
490
21.3k
        }
491
        // move stream 6 bytes to remove adobe id
492
21.3k
        decoder.stream.skip(6)?;
493
        // skip version, flags0 and flags1
494
21.3k
        decoder.stream.skip(5)?;
495
        // get color transform
496
21.3k
        let transform = decoder.stream.read_u8();
497
        // https://exiftool.org/TagNames/JPEG.html#Adobe
498
21.3k
        match transform {
499
20.2k
            0 => decoder.input_colorspace = ColorSpace::CMYK,
500
176
            1 => decoder.input_colorspace = ColorSpace::YCbCr,
501
922
            2 => decoder.input_colorspace = ColorSpace::YCCK,
502
            _ => {
503
17
                return Err(DecodeErrors::Format(format!(
504
17
                    "Unknown Adobe colorspace {transform}"
505
17
                )))
506
            }
507
        }
508
        // length   = 2
509
        // adobe id = 6
510
        // version =  5
511
        // transform = 1
512
21.3k
        length = length.saturating_sub(14);
513
63.5k
    } else {
514
63.5k
        warn!("Not a valid Adobe APP14 Segment, skipping {} bytes", length);
515
63.5k
        length = length.saturating_sub(2);
516
63.5k
    }
517
    // skip any proceeding lengths.
518
    // we do not need them
519
84.8k
    decoder.stream.skip(length)?;
520
521
84.8k
    Ok(())
522
84.9k
}
Unexecuted instantiation: zune_jpeg::headers::parse_app14::<_>
523
524
/// Parse the APP1 segment
525
///
526
/// This contains the exif tag
527
192k
pub(crate) fn parse_app1<T: ZByteReaderTrait>(
528
192k
    decoder: &mut JpegDecoder<T>
529
192k
) -> Result<(), DecodeErrors> {
530
    const XMP_NAMESPACE_PREFIX: &[u8] = b"http://ns.adobe.com/xap/1.0/\0";
531
532
    // contains exif data
533
192k
    let mut length = usize::from(decoder.stream.get_u16_be());
534
535
192k
    if length < 2 {
536
35
        return Err(DecodeErrors::FormatStatic("Too small app1 length"));
537
192k
    }
538
    // length bytes
539
192k
    length -= 2;
540
541
192k
    if length > 6 && decoder.stream.peek_at(0, 6)? == b"Exif\x00\x00" {
542
        trace!("Exif segment present");
543
        // skip bytes we read above
544
59.4k
        decoder.stream.skip(6)?;
545
59.4k
        length -= 6;
546
547
59.4k
        let exif_bytes = decoder.stream.peek_at(0, length)?.to_vec();
548
549
59.3k
        decoder.info.exif_data = Some(exif_bytes);
550
133k
    } else if length > XMP_NAMESPACE_PREFIX.len()
551
75.8k
        && decoder.stream.peek_at(0, XMP_NAMESPACE_PREFIX.len())? == XMP_NAMESPACE_PREFIX
552
    {
553
        trace!("XMP Data Present");
554
2.94k
        decoder.stream.skip(XMP_NAMESPACE_PREFIX.len())?;
555
2.94k
        length -= XMP_NAMESPACE_PREFIX.len();
556
2.94k
        let xmp_data = decoder.stream.peek_at(0, length)?.to_vec();
557
2.89k
        decoder.info.xmp_data = Some(xmp_data);
558
130k
    } else {
559
130k
        warn!("Unknown format for APP1 tag, skipping");
560
130k
    }
561
562
192k
    decoder.stream.skip(length)?;
563
192k
    Ok(())
564
192k
}
zune_jpeg::headers::parse_app1::<zune_core::bytestream::reader::no_std_readers::ZCursor<alloc::vec::Vec<u8>>>
Line
Count
Source
527
31.5k
pub(crate) fn parse_app1<T: ZByteReaderTrait>(
528
31.5k
    decoder: &mut JpegDecoder<T>
529
31.5k
) -> Result<(), DecodeErrors> {
530
    const XMP_NAMESPACE_PREFIX: &[u8] = b"http://ns.adobe.com/xap/1.0/\0";
531
532
    // contains exif data
533
31.5k
    let mut length = usize::from(decoder.stream.get_u16_be());
534
535
31.5k
    if length < 2 {
536
19
        return Err(DecodeErrors::FormatStatic("Too small app1 length"));
537
31.5k
    }
538
    // length bytes
539
31.5k
    length -= 2;
540
541
31.5k
    if length > 6 && decoder.stream.peek_at(0, 6)? == b"Exif\x00\x00" {
542
        trace!("Exif segment present");
543
        // skip bytes we read above
544
520
        decoder.stream.skip(6)?;
545
520
        length -= 6;
546
547
520
        let exif_bytes = decoder.stream.peek_at(0, length)?.to_vec();
548
549
492
        decoder.info.exif_data = Some(exif_bytes);
550
31.0k
    } else if length > XMP_NAMESPACE_PREFIX.len()
551
4.11k
        && decoder.stream.peek_at(0, XMP_NAMESPACE_PREFIX.len())? == XMP_NAMESPACE_PREFIX
552
    {
553
        trace!("XMP Data Present");
554
1.66k
        decoder.stream.skip(XMP_NAMESPACE_PREFIX.len())?;
555
1.66k
        length -= XMP_NAMESPACE_PREFIX.len();
556
1.66k
        let xmp_data = decoder.stream.peek_at(0, length)?.to_vec();
557
1.64k
        decoder.info.xmp_data = Some(xmp_data);
558
29.3k
    } else {
559
29.3k
        warn!("Unknown format for APP1 tag, skipping");
560
29.3k
    }
561
562
31.4k
    decoder.stream.skip(length)?;
563
31.4k
    Ok(())
564
31.5k
}
Unexecuted instantiation: zune_jpeg::headers::parse_app1::<zune_core::bytestream::reader::no_std_readers::ZCursor<&alloc::vec::Vec<u8>>>
zune_jpeg::headers::parse_app1::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Line
Count
Source
527
161k
pub(crate) fn parse_app1<T: ZByteReaderTrait>(
528
161k
    decoder: &mut JpegDecoder<T>
529
161k
) -> Result<(), DecodeErrors> {
530
    const XMP_NAMESPACE_PREFIX: &[u8] = b"http://ns.adobe.com/xap/1.0/\0";
531
532
    // contains exif data
533
161k
    let mut length = usize::from(decoder.stream.get_u16_be());
534
535
161k
    if length < 2 {
536
16
        return Err(DecodeErrors::FormatStatic("Too small app1 length"));
537
161k
    }
538
    // length bytes
539
161k
    length -= 2;
540
541
161k
    if length > 6 && decoder.stream.peek_at(0, 6)? == b"Exif\x00\x00" {
542
        trace!("Exif segment present");
543
        // skip bytes we read above
544
58.9k
        decoder.stream.skip(6)?;
545
58.9k
        length -= 6;
546
547
58.9k
        let exif_bytes = decoder.stream.peek_at(0, length)?.to_vec();
548
549
58.8k
        decoder.info.exif_data = Some(exif_bytes);
550
102k
    } else if length > XMP_NAMESPACE_PREFIX.len()
551
71.7k
        && decoder.stream.peek_at(0, XMP_NAMESPACE_PREFIX.len())? == XMP_NAMESPACE_PREFIX
552
    {
553
        trace!("XMP Data Present");
554
1.28k
        decoder.stream.skip(XMP_NAMESPACE_PREFIX.len())?;
555
1.28k
        length -= XMP_NAMESPACE_PREFIX.len();
556
1.28k
        let xmp_data = decoder.stream.peek_at(0, length)?.to_vec();
557
1.25k
        decoder.info.xmp_data = Some(xmp_data);
558
101k
    } else {
559
101k
        warn!("Unknown format for APP1 tag, skipping");
560
101k
    }
561
562
161k
    decoder.stream.skip(length)?;
563
161k
    Ok(())
564
161k
}
Unexecuted instantiation: zune_jpeg::headers::parse_app1::<_>
565
566
552k
pub(crate) fn parse_app2<T: ZByteReaderTrait>(
567
552k
    decoder: &mut JpegDecoder<T>
568
552k
) -> Result<(), DecodeErrors> {
569
    static HDR_META: &[u8] = b"urn:iso:std:iso:ts:21496:-1\0";
570
    static MPF_DATA: &[u8] = b"MPF\0";
571
572
552k
    let mut length = usize::from(decoder.stream.get_u16_be());
573
574
552k
    if length < 2 {
575
35
        return Err(DecodeErrors::FormatStatic("Too small app2 segment"));
576
552k
    }
577
    // length bytes
578
552k
    length -= 2;
579
580
552k
    if length > 14 && decoder.stream.peek_at(0, 12)? == *b"ICC_PROFILE\0" {
581
        trace!("ICC Profile present");
582
        // skip 12 bytes which indicate ICC profile
583
257k
        length -= 12;
584
257k
        decoder.stream.skip(12)?;
585
257k
        let seq_no = decoder.stream.read_u8();
586
257k
        let num_markers = decoder.stream.read_u8();
587
        // deduct the two bytes we read above
588
257k
        length -= 2;
589
590
257k
        let data = decoder.stream.peek_at(0, length)?.to_vec();
591
592
257k
        let icc_chunk = ICCChunk {
593
257k
            seq_no,
594
257k
            num_markers,
595
257k
            data
596
257k
        };
597
257k
        decoder.icc_data.push(icc_chunk);
598
295k
    } else if length > HDR_META.len() && decoder.stream.peek_at(0, HDR_META.len())? == HDR_META {
599
28.6k
        length = length.saturating_sub(HDR_META.len());
600
28.6k
        decoder.stream.skip(HDR_META.len())?;
601
        trace!("Gain Map metadata found");
602
24.6k
        match length {
603
4.03k
            4 => {
604
4.03k
                // If gain map metadata length == 4 then here it variables
605
4.03k
                // https://github.com/google/libultrahdr/blob/bf2aa439eea9ad5da483003fa44182f990f74091/lib/src/jpegr.cpp#L1076C1-L1077C35
606
4.03k
                // 2 bytes minimum_version: (00 00)
607
4.03k
                // 2 bytes writer_version: (00 00)
608
4.03k
                // Perhaps nothing to do with it ?
609
4.03k
                let _ = decoder.stream.get_u16_be();
610
4.03k
                let _ = decoder.stream.get_u16_be();
611
4.03k
                length -= 4;
612
4.03k
                decoder
613
4.03k
                    .info
614
4.03k
                    .gain_map_info
615
4.03k
                    .push(GainMapInfo { data: Vec::new() });
616
4.03k
            }
617
24.6k
            n if n > 4 => {
618
                // If there is perhaps useful gain map info
619
                // we'll read this until end
620
                // https://github.com/google/libultrahdr/blob/bf2aa439eea9ad5da483003fa44182f990f74091/lib/src/jpegr.cpp#L1323
621
21.1k
                let data = decoder.stream.peek_at(0, length)?.to_vec();
622
21.0k
                length -= data.len();
623
21.0k
                decoder.stream.skip(data.len())?;
624
625
21.0k
                decoder.info.gain_map_info.push(GainMapInfo { data });
626
            }
627
3.52k
            _ => {}
628
        }
629
266k
    } else if length > MPF_DATA.len() && decoder.stream.peek_at(0, MPF_DATA.len())? == MPF_DATA {
630
        trace!("MPF Signature present");
631
110k
        length = length.saturating_sub(MPF_DATA.len());
632
110k
        decoder.stream.skip(MPF_DATA.len())?;
633
        // MPF signature taken from here
634
        // https://github.com/google/libultrahdr/blob/bf2aa439eea9ad5da483003fa44182f990f74091/lib/include/ultrahdr/multipictureformat.h#L50
635
        // https://github.com/google/libultrahdr/blob/bf2aa439eea9ad5da483003fa44182f990f74091/lib/src/multipictureformat.cpp#L36
636
        // More info https://www.cipa.jp/std/documents/e/DC-X007-KEY_E.pdf
637
110k
        let data = decoder.stream.peek_at(0, length)?.to_vec();
638
110k
        length -= data.len();
639
110k
        decoder.stream.skip(data.len())?;
640
110k
        decoder.info.multi_picture_information = Some(data);
641
155k
    }
642
643
552k
    decoder.stream.skip(length)?;
644
645
552k
    Ok(())
646
552k
}
zune_jpeg::headers::parse_app2::<zune_core::bytestream::reader::no_std_readers::ZCursor<alloc::vec::Vec<u8>>>
Line
Count
Source
566
132k
pub(crate) fn parse_app2<T: ZByteReaderTrait>(
567
132k
    decoder: &mut JpegDecoder<T>
568
132k
) -> Result<(), DecodeErrors> {
569
    static HDR_META: &[u8] = b"urn:iso:std:iso:ts:21496:-1\0";
570
    static MPF_DATA: &[u8] = b"MPF\0";
571
572
132k
    let mut length = usize::from(decoder.stream.get_u16_be());
573
574
132k
    if length < 2 {
575
8
        return Err(DecodeErrors::FormatStatic("Too small app2 segment"));
576
132k
    }
577
    // length bytes
578
132k
    length -= 2;
579
580
132k
    if length > 14 && decoder.stream.peek_at(0, 12)? == *b"ICC_PROFILE\0" {
581
        trace!("ICC Profile present");
582
        // skip 12 bytes which indicate ICC profile
583
23.7k
        length -= 12;
584
23.7k
        decoder.stream.skip(12)?;
585
23.7k
        let seq_no = decoder.stream.read_u8();
586
23.7k
        let num_markers = decoder.stream.read_u8();
587
        // deduct the two bytes we read above
588
23.7k
        length -= 2;
589
590
23.7k
        let data = decoder.stream.peek_at(0, length)?.to_vec();
591
592
23.7k
        let icc_chunk = ICCChunk {
593
23.7k
            seq_no,
594
23.7k
            num_markers,
595
23.7k
            data
596
23.7k
        };
597
23.7k
        decoder.icc_data.push(icc_chunk);
598
108k
    } else if length > HDR_META.len() && decoder.stream.peek_at(0, HDR_META.len())? == HDR_META {
599
13.6k
        length = length.saturating_sub(HDR_META.len());
600
13.6k
        decoder.stream.skip(HDR_META.len())?;
601
        trace!("Gain Map metadata found");
602
12.7k
        match length {
603
890
            4 => {
604
890
                // If gain map metadata length == 4 then here it variables
605
890
                // https://github.com/google/libultrahdr/blob/bf2aa439eea9ad5da483003fa44182f990f74091/lib/src/jpegr.cpp#L1076C1-L1077C35
606
890
                // 2 bytes minimum_version: (00 00)
607
890
                // 2 bytes writer_version: (00 00)
608
890
                // Perhaps nothing to do with it ?
609
890
                let _ = decoder.stream.get_u16_be();
610
890
                let _ = decoder.stream.get_u16_be();
611
890
                length -= 4;
612
890
                decoder
613
890
                    .info
614
890
                    .gain_map_info
615
890
                    .push(GainMapInfo { data: Vec::new() });
616
890
            }
617
12.7k
            n if n > 4 => {
618
                // If there is perhaps useful gain map info
619
                // we'll read this until end
620
                // https://github.com/google/libultrahdr/blob/bf2aa439eea9ad5da483003fa44182f990f74091/lib/src/jpegr.cpp#L1323
621
11.7k
                let data = decoder.stream.peek_at(0, length)?.to_vec();
622
11.7k
                length -= data.len();
623
11.7k
                decoder.stream.skip(data.len())?;
624
625
11.7k
                decoder.info.gain_map_info.push(GainMapInfo { data });
626
            }
627
997
            _ => {}
628
        }
629
95.0k
    } else if length > MPF_DATA.len() && decoder.stream.peek_at(0, MPF_DATA.len())? == MPF_DATA {
630
        trace!("MPF Signature present");
631
5.33k
        length = length.saturating_sub(MPF_DATA.len());
632
5.33k
        decoder.stream.skip(MPF_DATA.len())?;
633
        // MPF signature taken from here
634
        // https://github.com/google/libultrahdr/blob/bf2aa439eea9ad5da483003fa44182f990f74091/lib/include/ultrahdr/multipictureformat.h#L50
635
        // https://github.com/google/libultrahdr/blob/bf2aa439eea9ad5da483003fa44182f990f74091/lib/src/multipictureformat.cpp#L36
636
        // More info https://www.cipa.jp/std/documents/e/DC-X007-KEY_E.pdf
637
5.33k
        let data = decoder.stream.peek_at(0, length)?.to_vec();
638
5.31k
        length -= data.len();
639
5.31k
        decoder.stream.skip(data.len())?;
640
5.31k
        decoder.info.multi_picture_information = Some(data);
641
89.7k
    }
642
643
132k
    decoder.stream.skip(length)?;
644
645
132k
    Ok(())
646
132k
}
Unexecuted instantiation: zune_jpeg::headers::parse_app2::<zune_core::bytestream::reader::no_std_readers::ZCursor<&alloc::vec::Vec<u8>>>
zune_jpeg::headers::parse_app2::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Line
Count
Source
566
420k
pub(crate) fn parse_app2<T: ZByteReaderTrait>(
567
420k
    decoder: &mut JpegDecoder<T>
568
420k
) -> Result<(), DecodeErrors> {
569
    static HDR_META: &[u8] = b"urn:iso:std:iso:ts:21496:-1\0";
570
    static MPF_DATA: &[u8] = b"MPF\0";
571
572
420k
    let mut length = usize::from(decoder.stream.get_u16_be());
573
574
420k
    if length < 2 {
575
27
        return Err(DecodeErrors::FormatStatic("Too small app2 segment"));
576
420k
    }
577
    // length bytes
578
420k
    length -= 2;
579
580
420k
    if length > 14 && decoder.stream.peek_at(0, 12)? == *b"ICC_PROFILE\0" {
581
        trace!("ICC Profile present");
582
        // skip 12 bytes which indicate ICC profile
583
233k
        length -= 12;
584
233k
        decoder.stream.skip(12)?;
585
233k
        let seq_no = decoder.stream.read_u8();
586
233k
        let num_markers = decoder.stream.read_u8();
587
        // deduct the two bytes we read above
588
233k
        length -= 2;
589
590
233k
        let data = decoder.stream.peek_at(0, length)?.to_vec();
591
592
233k
        let icc_chunk = ICCChunk {
593
233k
            seq_no,
594
233k
            num_markers,
595
233k
            data
596
233k
        };
597
233k
        decoder.icc_data.push(icc_chunk);
598
186k
    } else if length > HDR_META.len() && decoder.stream.peek_at(0, HDR_META.len())? == HDR_META {
599
15.0k
        length = length.saturating_sub(HDR_META.len());
600
15.0k
        decoder.stream.skip(HDR_META.len())?;
601
        trace!("Gain Map metadata found");
602
11.9k
        match length {
603
3.14k
            4 => {
604
3.14k
                // If gain map metadata length == 4 then here it variables
605
3.14k
                // https://github.com/google/libultrahdr/blob/bf2aa439eea9ad5da483003fa44182f990f74091/lib/src/jpegr.cpp#L1076C1-L1077C35
606
3.14k
                // 2 bytes minimum_version: (00 00)
607
3.14k
                // 2 bytes writer_version: (00 00)
608
3.14k
                // Perhaps nothing to do with it ?
609
3.14k
                let _ = decoder.stream.get_u16_be();
610
3.14k
                let _ = decoder.stream.get_u16_be();
611
3.14k
                length -= 4;
612
3.14k
                decoder
613
3.14k
                    .info
614
3.14k
                    .gain_map_info
615
3.14k
                    .push(GainMapInfo { data: Vec::new() });
616
3.14k
            }
617
11.9k
            n if n > 4 => {
618
                // If there is perhaps useful gain map info
619
                // we'll read this until end
620
                // https://github.com/google/libultrahdr/blob/bf2aa439eea9ad5da483003fa44182f990f74091/lib/src/jpegr.cpp#L1323
621
9.40k
                let data = decoder.stream.peek_at(0, length)?.to_vec();
622
9.37k
                length -= data.len();
623
9.37k
                decoder.stream.skip(data.len())?;
624
625
9.37k
                decoder.info.gain_map_info.push(GainMapInfo { data });
626
            }
627
2.52k
            _ => {}
628
        }
629
171k
    } else if length > MPF_DATA.len() && decoder.stream.peek_at(0, MPF_DATA.len())? == MPF_DATA {
630
        trace!("MPF Signature present");
631
104k
        length = length.saturating_sub(MPF_DATA.len());
632
104k
        decoder.stream.skip(MPF_DATA.len())?;
633
        // MPF signature taken from here
634
        // https://github.com/google/libultrahdr/blob/bf2aa439eea9ad5da483003fa44182f990f74091/lib/include/ultrahdr/multipictureformat.h#L50
635
        // https://github.com/google/libultrahdr/blob/bf2aa439eea9ad5da483003fa44182f990f74091/lib/src/multipictureformat.cpp#L36
636
        // More info https://www.cipa.jp/std/documents/e/DC-X007-KEY_E.pdf
637
104k
        let data = decoder.stream.peek_at(0, length)?.to_vec();
638
104k
        length -= data.len();
639
104k
        decoder.stream.skip(data.len())?;
640
104k
        decoder.info.multi_picture_information = Some(data);
641
66.2k
    }
642
643
420k
    decoder.stream.skip(length)?;
644
645
420k
    Ok(())
646
420k
}
Unexecuted instantiation: zune_jpeg::headers::parse_app2::<_>
647
648
/// Small utility function to print Un-zig-zagged quantization tables
649
650
146k
fn un_zig_zag<T>(a: &[T]) -> [i32; 64]
651
146k
where
652
146k
    T: Default + Copy,
653
146k
    i32: core::convert::From<T>
654
{
655
146k
    let mut output = [i32::default(); 64];
656
657
9.50M
    for i in 0..64 {
658
9.35M
        output[UN_ZIGZAG[i]] = i32::from(a[i]);
659
9.35M
    }
660
661
146k
    output
662
146k
}
zune_jpeg::headers::un_zig_zag::<u8>
Line
Count
Source
650
143k
fn un_zig_zag<T>(a: &[T]) -> [i32; 64]
651
143k
where
652
143k
    T: Default + Copy,
653
143k
    i32: core::convert::From<T>
654
{
655
143k
    let mut output = [i32::default(); 64];
656
657
9.32M
    for i in 0..64 {
658
9.18M
        output[UN_ZIGZAG[i]] = i32::from(a[i]);
659
9.18M
    }
660
661
143k
    output
662
143k
}
zune_jpeg::headers::un_zig_zag::<u16>
Line
Count
Source
650
2.73k
fn un_zig_zag<T>(a: &[T]) -> [i32; 64]
651
2.73k
where
652
2.73k
    T: Default + Copy,
653
2.73k
    i32: core::convert::From<T>
654
{
655
2.73k
    let mut output = [i32::default(); 64];
656
657
178k
    for i in 0..64 {
658
175k
        output[UN_ZIGZAG[i]] = i32::from(a[i]);
659
175k
    }
660
661
2.73k
    output
662
2.73k
}
Unexecuted instantiation: zune_jpeg::headers::un_zig_zag::<_>