Coverage Report

Created: 2025-07-18 06:49

/rust/registry/src/index.crates.io-6f17d22bba15001f/zune-jpeg-0.4.19/src/mcu.rs
Line
Count
Source (jump to first uncovered line)
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
use alloc::{format, vec};
10
use core::cmp::min;
11
use zune_core::bytestream::ZReaderTrait;
12
use zune_core::colorspace::ColorSpace;
13
use zune_core::colorspace::ColorSpace::Luma;
14
use zune_core::log::{error, trace, warn};
15
16
use crate::bitstream::BitStream;
17
use crate::components::SampleRatios;
18
use crate::decoder::MAX_COMPONENTS;
19
use crate::errors::DecodeErrors;
20
use crate::marker::Marker;
21
use crate::mcu_prog::get_marker;
22
use crate::misc::{calculate_padded_width, setup_component_params};
23
use crate::worker::{color_convert, upsample};
24
use crate::JpegDecoder;
25
26
/// The size of a DC block for a MCU.
27
28
pub const DCT_BLOCK: usize = 64;
29
30
impl<T: ZReaderTrait> JpegDecoder<T> {
31
    /// Check for existence of DC and AC Huffman Tables
32
1.89k
    pub(crate) fn check_tables(&self) -> Result<(), DecodeErrors> {
33
        // check that dc and AC tables exist outside the hot path
34
5.58k
        for component in &self.components {
35
3.71k
            let _ = &self
36
3.71k
                .dc_huffman_tables
37
3.71k
                .get(component.dc_huff_table)
38
3.71k
                .as_ref()
39
3.71k
                .ok_or_else(|| {
40
2
                    DecodeErrors::HuffmanDecode(format!(
41
2
                        "No Huffman DC table for component {:?} ",
42
2
                        component.component_id
43
2
                    ))
44
3.71k
                })?
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::check_tables::{closure#0}
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0}
Line
Count
Source
39
1
                .ok_or_else(|| {
40
1
                    DecodeErrors::HuffmanDecode(format!(
41
1
                        "No Huffman DC table for component {:?} ",
42
1
                        component.component_id
43
1
                    ))
44
1
                })?
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0}
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#0}
Line
Count
Source
39
1
                .ok_or_else(|| {
40
1
                    DecodeErrors::HuffmanDecode(format!(
41
1
                        "No Huffman DC table for component {:?} ",
42
1
                        component.component_id
43
1
                    ))
44
1
                })?
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#0}
45
3.70k
                .as_ref()
46
3.70k
                .ok_or_else(|| {
47
5
                    DecodeErrors::HuffmanDecode(format!(
48
5
                        "No DC table for component {:?}",
49
5
                        component.component_id
50
5
                    ))
51
3.70k
                })?;
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::check_tables::{closure#1}
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1}
Line
Count
Source
46
3
                .ok_or_else(|| {
47
3
                    DecodeErrors::HuffmanDecode(format!(
48
3
                        "No DC table for component {:?}",
49
3
                        component.component_id
50
3
                    ))
51
3
                })?;
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1}
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#1}
Line
Count
Source
46
1
                .ok_or_else(|| {
47
1
                    DecodeErrors::HuffmanDecode(format!(
48
1
                        "No DC table for component {:?}",
49
1
                        component.component_id
50
1
                    ))
51
1
                })?;
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#1}
Line
Count
Source
46
1
                .ok_or_else(|| {
47
1
                    DecodeErrors::HuffmanDecode(format!(
48
1
                        "No DC table for component {:?}",
49
1
                        component.component_id
50
1
                    ))
51
1
                })?;
52
53
3.70k
            let _ = &self
54
3.70k
                .ac_huffman_tables
55
3.70k
                .get(component.ac_huff_table)
56
3.70k
                .as_ref()
57
3.70k
                .ok_or_else(|| {
58
4
                    DecodeErrors::HuffmanDecode(format!(
59
4
                        "No Huffman AC table for component {:?} ",
60
4
                        component.component_id
61
4
                    ))
62
3.70k
                })?
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::check_tables::{closure#2}
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2}
Line
Count
Source
57
2
                .ok_or_else(|| {
58
2
                    DecodeErrors::HuffmanDecode(format!(
59
2
                        "No Huffman AC table for component {:?} ",
60
2
                        component.component_id
61
2
                    ))
62
2
                })?
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#2}
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#2}
Line
Count
Source
57
2
                .ok_or_else(|| {
58
2
                    DecodeErrors::HuffmanDecode(format!(
59
2
                        "No Huffman AC table for component {:?} ",
60
2
                        component.component_id
61
2
                    ))
62
2
                })?
63
3.70k
                .as_ref()
64
3.70k
                .ok_or_else(|| {
65
3
                    DecodeErrors::HuffmanDecode(format!(
66
3
                        "No AC table for component {:?}",
67
3
                        component.component_id
68
3
                    ))
69
3.70k
                })?;
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::check_tables::{closure#3}
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3}
Line
Count
Source
64
2
                .ok_or_else(|| {
65
2
                    DecodeErrors::HuffmanDecode(format!(
66
2
                        "No AC table for component {:?}",
67
2
                        component.component_id
68
2
                    ))
69
2
                })?;
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3}
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3}
Line
Count
Source
64
1
                .ok_or_else(|| {
65
1
                    DecodeErrors::HuffmanDecode(format!(
66
1
                        "No AC table for component {:?}",
67
1
                        component.component_id
68
1
                    ))
69
1
                })?;
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables::{closure#3}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables::{closure#3}
70
        }
71
1.87k
        Ok(())
72
1.89k
    }
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::check_tables
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables
Line
Count
Source
32
775
    pub(crate) fn check_tables(&self) -> Result<(), DecodeErrors> {
33
        // check that dc and AC tables exist outside the hot path
34
1.56k
        for component in &self.components {
35
793
            let _ = &self
36
793
                .dc_huffman_tables
37
793
                .get(component.dc_huff_table)
38
793
                .as_ref()
39
793
                .ok_or_else(|| {
40
                    DecodeErrors::HuffmanDecode(format!(
41
                        "No Huffman DC table for component {:?} ",
42
                        component.component_id
43
                    ))
44
793
                })?
45
792
                .as_ref()
46
792
                .ok_or_else(|| {
47
                    DecodeErrors::HuffmanDecode(format!(
48
                        "No DC table for component {:?}",
49
                        component.component_id
50
                    ))
51
792
                })?;
52
53
789
            let _ = &self
54
789
                .ac_huffman_tables
55
789
                .get(component.ac_huff_table)
56
789
                .as_ref()
57
789
                .ok_or_else(|| {
58
                    DecodeErrors::HuffmanDecode(format!(
59
                        "No Huffman AC table for component {:?} ",
60
                        component.component_id
61
                    ))
62
789
                })?
63
787
                .as_ref()
64
787
                .ok_or_else(|| {
65
                    DecodeErrors::HuffmanDecode(format!(
66
                        "No AC table for component {:?}",
67
                        component.component_id
68
                    ))
69
787
                })?;
70
        }
71
767
        Ok(())
72
775
    }
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables
Line
Count
Source
32
371
    pub(crate) fn check_tables(&self) -> Result<(), DecodeErrors> {
33
        // check that dc and AC tables exist outside the hot path
34
1.16k
        for component in &self.components {
35
792
            let _ = &self
36
792
                .dc_huffman_tables
37
792
                .get(component.dc_huff_table)
38
792
                .as_ref()
39
792
                .ok_or_else(|| {
40
                    DecodeErrors::HuffmanDecode(format!(
41
                        "No Huffman DC table for component {:?} ",
42
                        component.component_id
43
                    ))
44
792
                })?
45
792
                .as_ref()
46
792
                .ok_or_else(|| {
47
                    DecodeErrors::HuffmanDecode(format!(
48
                        "No DC table for component {:?}",
49
                        component.component_id
50
                    ))
51
792
                })?;
52
53
792
            let _ = &self
54
792
                .ac_huffman_tables
55
792
                .get(component.ac_huff_table)
56
792
                .as_ref()
57
792
                .ok_or_else(|| {
58
                    DecodeErrors::HuffmanDecode(format!(
59
                        "No Huffman AC table for component {:?} ",
60
                        component.component_id
61
                    ))
62
792
                })?
63
792
                .as_ref()
64
792
                .ok_or_else(|| {
65
                    DecodeErrors::HuffmanDecode(format!(
66
                        "No AC table for component {:?}",
67
                        component.component_id
68
                    ))
69
792
                })?;
70
        }
71
370
        Ok(())
72
371
    }
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::check_tables
Line
Count
Source
32
68
    pub(crate) fn check_tables(&self) -> Result<(), DecodeErrors> {
33
        // check that dc and AC tables exist outside the hot path
34
134
        for component in &self.components {
35
68
            let _ = &self
36
68
                .dc_huffman_tables
37
68
                .get(component.dc_huff_table)
38
68
                .as_ref()
39
68
                .ok_or_else(|| {
40
                    DecodeErrors::HuffmanDecode(format!(
41
                        "No Huffman DC table for component {:?} ",
42
                        component.component_id
43
                    ))
44
68
                })?
45
67
                .as_ref()
46
67
                .ok_or_else(|| {
47
                    DecodeErrors::HuffmanDecode(format!(
48
                        "No DC table for component {:?}",
49
                        component.component_id
50
                    ))
51
67
                })?;
52
53
66
            let _ = &self
54
66
                .ac_huffman_tables
55
66
                .get(component.ac_huff_table)
56
66
                .as_ref()
57
66
                .ok_or_else(|| {
58
                    DecodeErrors::HuffmanDecode(format!(
59
                        "No Huffman AC table for component {:?} ",
60
                        component.component_id
61
                    ))
62
66
                })?
63
66
                .as_ref()
64
66
                .ok_or_else(|| {
65
                    DecodeErrors::HuffmanDecode(format!(
66
                        "No AC table for component {:?}",
67
                        component.component_id
68
                    ))
69
66
                })?;
70
        }
71
66
        Ok(())
72
68
    }
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::check_tables
Line
Count
Source
32
677
    pub(crate) fn check_tables(&self) -> Result<(), DecodeErrors> {
33
        // check that dc and AC tables exist outside the hot path
34
2.73k
        for component in &self.components {
35
2.05k
            let _ = &self
36
2.05k
                .dc_huffman_tables
37
2.05k
                .get(component.dc_huff_table)
38
2.05k
                .as_ref()
39
2.05k
                .ok_or_else(|| {
40
                    DecodeErrors::HuffmanDecode(format!(
41
                        "No Huffman DC table for component {:?} ",
42
                        component.component_id
43
                    ))
44
2.05k
                })?
45
2.05k
                .as_ref()
46
2.05k
                .ok_or_else(|| {
47
                    DecodeErrors::HuffmanDecode(format!(
48
                        "No DC table for component {:?}",
49
                        component.component_id
50
                    ))
51
2.05k
                })?;
52
53
2.05k
            let _ = &self
54
2.05k
                .ac_huffman_tables
55
2.05k
                .get(component.ac_huff_table)
56
2.05k
                .as_ref()
57
2.05k
                .ok_or_else(|| {
58
                    DecodeErrors::HuffmanDecode(format!(
59
                        "No Huffman AC table for component {:?} ",
60
                        component.component_id
61
                    ))
62
2.05k
                })?
63
2.05k
                .as_ref()
64
2.05k
                .ok_or_else(|| {
65
                    DecodeErrors::HuffmanDecode(format!(
66
                        "No AC table for component {:?}",
67
                        component.component_id
68
                    ))
69
2.05k
                })?;
70
        }
71
674
        Ok(())
72
677
    }
73
74
    /// Decode MCUs and carry out post processing.
75
    ///
76
    /// This is the main decoder loop for the library, the hot path.
77
    ///
78
    /// Because of this, we pull in some very crazy optimization tricks hence readability is a pinch
79
    /// here.
80
    #[allow(
81
        clippy::similar_names,
82
        clippy::too_many_lines,
83
        clippy::cast_possible_truncation
84
    )]
85
    #[inline(never)]
86
1.91k
    pub(crate) fn decode_mcu_ycbcr_baseline(
87
1.91k
        &mut self, pixels: &mut [u8]
88
1.91k
    ) -> Result<(), DecodeErrors> {
89
1.91k
        setup_component_params(self)?;
90
91
        // check dc and AC tables
92
1.89k
        self.check_tables()?;
93
94
        let (mut mcu_width, mut mcu_height);
95
96
1.87k
        if self.is_interleaved {
97
            // set upsampling functions
98
681
            self.set_upsampling()?;
99
100
681
            mcu_width = self.mcu_x;
101
681
            mcu_height = self.mcu_y;
102
1.19k
        } else {
103
1.19k
            // For non-interleaved images( (1*1) subsampling)
104
1.19k
            // number of MCU's are the widths (+7 to account for paddings) divided bu 8.
105
1.19k
            mcu_width = ((self.info.width + 7) / 8) as usize;
106
1.19k
            mcu_height = ((self.info.height + 7) / 8) as usize;
107
1.19k
        }
108
1.87k
        if self.is_interleaved
109
681
            && self.input_colorspace.num_components() > 1
110
507
            && self.options.jpeg_get_out_colorspace().num_components() == 1
111
0
            && (self.sub_sample_ratio == SampleRatios::V
112
0
                || self.sub_sample_ratio == SampleRatios::HV)
113
0
        {
114
0
            // For a specific set of images, e.g interleaved,
115
0
            // when converting from YcbCr to grayscale, we need to
116
0
            // take into account mcu height since the MCU decoding needs to take
117
0
            // it into account for padding purposes and the post processor
118
0
            // parses two rows per mcu width.
119
0
            //
120
0
            // set coeff to be 2 to ensure that we increment two rows
121
0
            // for every mcu processed also
122
0
            mcu_height *= self.v_max;
123
0
            mcu_height /= self.h_max;
124
0
            self.coeff = 2;
125
1.87k
        }
126
127
1.87k
        if self.input_colorspace == ColorSpace::Luma && self.is_interleaved {
128
174
            warn!("Grayscale image with down-sampled component, resetting component details");
129
174
130
174
            self.reset_params();
131
174
132
174
            mcu_width = ((self.info.width + 7) / 8) as usize;
133
174
            mcu_height = ((self.info.height + 7) / 8) as usize;
134
1.70k
        }
135
1.87k
        let width = usize::from(self.info.width);
136
1.87k
137
1.87k
        let padded_width = calculate_padded_width(width, self.sub_sample_ratio);
138
1.87k
139
1.87k
        let mut stream = BitStream::new();
140
1.87k
        let mut tmp = [0_i32; DCT_BLOCK];
141
1.87k
142
1.87k
        let comp_len = self.components.len();
143
144
3.69k
        for (pos, comp) in self.components.iter_mut().enumerate() {
145
            // Allocate only needed components.
146
            //
147
            // For special colorspaces i.e YCCK and CMYK, just allocate all of the needed
148
            // components.
149
3.69k
            if min(
150
3.69k
                self.options.jpeg_get_out_colorspace().num_components() - 1,
151
3.69k
                pos
152
3.69k
            ) == pos
153
287
                || comp_len == 4
154
            // Special colorspace
155
3.69k
            {
156
3.69k
                // allocate enough space to hold a whole MCU width
157
3.69k
                // this means we should take into account sampling ratios
158
3.69k
                // `*8` is because each MCU spans 8 widths.
159
3.69k
                let len = comp.width_stride * comp.vertical_sample * 8;
160
3.69k
161
3.69k
                comp.needed = true;
162
3.69k
                comp.raw_coeff = vec![0; len];
163
3.69k
            } else {
164
0
                comp.needed = false;
165
0
            }
166
        }
167
168
1.87k
        let mut pixels_written = 0;
169
1.87k
170
1.87k
        let is_hv = usize::from(self.is_interleaved);
171
1.87k
        let upsampler_scratch_size = is_hv * self.components[0].width_stride;
172
1.87k
        let mut upsampler_scratch_space = vec![0; upsampler_scratch_size];
173
174
191k
        for i in 0..mcu_height {
175
            // Report if we have no more bytes
176
            // This may generate false negatives since we over-read bytes
177
            // hence that why 37 is chosen(we assume if we over-read more than 37 bytes, we have a problem)
178
191k
            if stream.overread_by > 37
179
            // favourite number :)
180
            {
181
0
                if self.options.get_strict_mode() {
182
0
                    return Err(DecodeErrors::FormatStatic("Premature end of buffer"));
183
0
                };
184
0
185
0
                error!("Premature end of buffer");
186
0
                break;
187
191k
            }
188
189
            // decode a whole MCU width,
190
            // this takes into account interleaved components.
191
191k
            let terminate = self.decode_mcu_width(mcu_width, &mut tmp, &mut stream)?;
192
            // if i >=7{
193
            //     panic!()
194
            // }
195
            // process that width up until it's impossible
196
197
190k
            self.post_process(
198
190k
                pixels,
199
190k
                i,
200
190k
                mcu_height,
201
190k
                width,
202
190k
                padded_width,
203
190k
                &mut pixels_written,
204
190k
                &mut upsampler_scratch_space
205
190k
            )?;
206
190k
            if terminate {
207
25
                warn!("Got terminate signal, will not process further");
208
25
                return Ok(());
209
190k
            }
210
        }
211
        // it may happen that some images don't have the whole buffer
212
        // so we can't panic in case of that
213
        // assert_eq!(pixels_written, pixels.len());
214
215
        // For UHD usecases that tie two images separating them with EOI and
216
        // SOI markers, it may happen that we do not reach this image end of image
217
        // So this ensures we reach it
218
        // Ensure we read EOI
219
914
        if !stream.seen_eoi {
220
730
            let marker = get_marker(&mut self.stream, &mut stream);
221
730
            match marker {
222
77
                Ok(_m) => {
223
77
                    trace!("Found marker {:?}", _m);
224
77
                }
225
653
                Err(_) => {
226
653
                    // ignore error
227
653
                }
228
            }
229
184
        }
230
231
        trace!("Finished decoding image");
232
233
914
        Ok(())
234
1.91k
    }
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::decode_mcu_ycbcr_baseline
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline
Line
Count
Source
86
776
    pub(crate) fn decode_mcu_ycbcr_baseline(
87
776
        &mut self, pixels: &mut [u8]
88
776
    ) -> Result<(), DecodeErrors> {
89
776
        setup_component_params(self)?;
90
91
        // check dc and AC tables
92
775
        self.check_tables()?;
93
94
        let (mut mcu_width, mut mcu_height);
95
96
767
        if self.is_interleaved {
97
            // set upsampling functions
98
16
            self.set_upsampling()?;
99
100
16
            mcu_width = self.mcu_x;
101
16
            mcu_height = self.mcu_y;
102
751
        } else {
103
751
            // For non-interleaved images( (1*1) subsampling)
104
751
            // number of MCU's are the widths (+7 to account for paddings) divided bu 8.
105
751
            mcu_width = ((self.info.width + 7) / 8) as usize;
106
751
            mcu_height = ((self.info.height + 7) / 8) as usize;
107
751
        }
108
767
        if self.is_interleaved
109
16
            && self.input_colorspace.num_components() > 1
110
3
            && self.options.jpeg_get_out_colorspace().num_components() == 1
111
0
            && (self.sub_sample_ratio == SampleRatios::V
112
0
                || self.sub_sample_ratio == SampleRatios::HV)
113
0
        {
114
0
            // For a specific set of images, e.g interleaved,
115
0
            // when converting from YcbCr to grayscale, we need to
116
0
            // take into account mcu height since the MCU decoding needs to take
117
0
            // it into account for padding purposes and the post processor
118
0
            // parses two rows per mcu width.
119
0
            //
120
0
            // set coeff to be 2 to ensure that we increment two rows
121
0
            // for every mcu processed also
122
0
            mcu_height *= self.v_max;
123
0
            mcu_height /= self.h_max;
124
0
            self.coeff = 2;
125
767
        }
126
127
767
        if self.input_colorspace == ColorSpace::Luma && self.is_interleaved {
128
13
            warn!("Grayscale image with down-sampled component, resetting component details");
129
13
130
13
            self.reset_params();
131
13
132
13
            mcu_width = ((self.info.width + 7) / 8) as usize;
133
13
            mcu_height = ((self.info.height + 7) / 8) as usize;
134
754
        }
135
767
        let width = usize::from(self.info.width);
136
767
137
767
        let padded_width = calculate_padded_width(width, self.sub_sample_ratio);
138
767
139
767
        let mut stream = BitStream::new();
140
767
        let mut tmp = [0_i32; DCT_BLOCK];
141
767
142
767
        let comp_len = self.components.len();
143
144
785
        for (pos, comp) in self.components.iter_mut().enumerate() {
145
            // Allocate only needed components.
146
            //
147
            // For special colorspaces i.e YCCK and CMYK, just allocate all of the needed
148
            // components.
149
785
            if min(
150
785
                self.options.jpeg_get_out_colorspace().num_components() - 1,
151
785
                pos
152
785
            ) == pos
153
6
                || comp_len == 4
154
            // Special colorspace
155
785
            {
156
785
                // allocate enough space to hold a whole MCU width
157
785
                // this means we should take into account sampling ratios
158
785
                // `*8` is because each MCU spans 8 widths.
159
785
                let len = comp.width_stride * comp.vertical_sample * 8;
160
785
161
785
                comp.needed = true;
162
785
                comp.raw_coeff = vec![0; len];
163
785
            } else {
164
0
                comp.needed = false;
165
0
            }
166
        }
167
168
767
        let mut pixels_written = 0;
169
767
170
767
        let is_hv = usize::from(self.is_interleaved);
171
767
        let upsampler_scratch_size = is_hv * self.components[0].width_stride;
172
767
        let mut upsampler_scratch_space = vec![0; upsampler_scratch_size];
173
174
95.0k
        for i in 0..mcu_height {
175
            // Report if we have no more bytes
176
            // This may generate false negatives since we over-read bytes
177
            // hence that why 37 is chosen(we assume if we over-read more than 37 bytes, we have a problem)
178
95.0k
            if stream.overread_by > 37
179
            // favourite number :)
180
            {
181
0
                if self.options.get_strict_mode() {
182
0
                    return Err(DecodeErrors::FormatStatic("Premature end of buffer"));
183
0
                };
184
0
185
0
                error!("Premature end of buffer");
186
0
                break;
187
95.0k
            }
188
189
            // decode a whole MCU width,
190
            // this takes into account interleaved components.
191
95.0k
            let terminate = self.decode_mcu_width(mcu_width, &mut tmp, &mut stream)?;
192
            // if i >=7{
193
            //     panic!()
194
            // }
195
            // process that width up until it's impossible
196
197
94.6k
            self.post_process(
198
94.6k
                pixels,
199
94.6k
                i,
200
94.6k
                mcu_height,
201
94.6k
                width,
202
94.6k
                padded_width,
203
94.6k
                &mut pixels_written,
204
94.6k
                &mut upsampler_scratch_space
205
94.6k
            )?;
206
94.6k
            if terminate {
207
0
                warn!("Got terminate signal, will not process further");
208
0
                return Ok(());
209
94.6k
            }
210
        }
211
        // it may happen that some images don't have the whole buffer
212
        // so we can't panic in case of that
213
        // assert_eq!(pixels_written, pixels.len());
214
215
        // For UHD usecases that tie two images separating them with EOI and
216
        // SOI markers, it may happen that we do not reach this image end of image
217
        // So this ensures we reach it
218
        // Ensure we read EOI
219
375
        if !stream.seen_eoi {
220
272
            let marker = get_marker(&mut self.stream, &mut stream);
221
272
            match marker {
222
42
                Ok(_m) => {
223
42
                    trace!("Found marker {:?}", _m);
224
42
                }
225
230
                Err(_) => {
226
230
                    // ignore error
227
230
                }
228
            }
229
103
        }
230
231
        trace!("Finished decoding image");
232
233
375
        Ok(())
234
776
    }
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline
Line
Count
Source
86
388
    pub(crate) fn decode_mcu_ycbcr_baseline(
87
388
        &mut self, pixels: &mut [u8]
88
388
    ) -> Result<(), DecodeErrors> {
89
388
        setup_component_params(self)?;
90
91
        // check dc and AC tables
92
371
        self.check_tables()?;
93
94
        let (mut mcu_width, mut mcu_height);
95
96
370
        if self.is_interleaved {
97
            // set upsampling functions
98
355
            self.set_upsampling()?;
99
100
355
            mcu_width = self.mcu_x;
101
355
            mcu_height = self.mcu_y;
102
15
        } else {
103
15
            // For non-interleaved images( (1*1) subsampling)
104
15
            // number of MCU's are the widths (+7 to account for paddings) divided bu 8.
105
15
            mcu_width = ((self.info.width + 7) / 8) as usize;
106
15
            mcu_height = ((self.info.height + 7) / 8) as usize;
107
15
        }
108
370
        if self.is_interleaved
109
355
            && self.input_colorspace.num_components() > 1
110
194
            && self.options.jpeg_get_out_colorspace().num_components() == 1
111
0
            && (self.sub_sample_ratio == SampleRatios::V
112
0
                || self.sub_sample_ratio == SampleRatios::HV)
113
0
        {
114
0
            // For a specific set of images, e.g interleaved,
115
0
            // when converting from YcbCr to grayscale, we need to
116
0
            // take into account mcu height since the MCU decoding needs to take
117
0
            // it into account for padding purposes and the post processor
118
0
            // parses two rows per mcu width.
119
0
            //
120
0
            // set coeff to be 2 to ensure that we increment two rows
121
0
            // for every mcu processed also
122
0
            mcu_height *= self.v_max;
123
0
            mcu_height /= self.h_max;
124
0
            self.coeff = 2;
125
370
        }
126
127
370
        if self.input_colorspace == ColorSpace::Luma && self.is_interleaved {
128
161
            warn!("Grayscale image with down-sampled component, resetting component details");
129
161
130
161
            self.reset_params();
131
161
132
161
            mcu_width = ((self.info.width + 7) / 8) as usize;
133
161
            mcu_height = ((self.info.height + 7) / 8) as usize;
134
209
        }
135
370
        let width = usize::from(self.info.width);
136
370
137
370
        let padded_width = calculate_padded_width(width, self.sub_sample_ratio);
138
370
139
370
        let mut stream = BitStream::new();
140
370
        let mut tmp = [0_i32; DCT_BLOCK];
141
370
142
370
        let comp_len = self.components.len();
143
144
791
        for (pos, comp) in self.components.iter_mut().enumerate() {
145
            // Allocate only needed components.
146
            //
147
            // For special colorspaces i.e YCCK and CMYK, just allocate all of the needed
148
            // components.
149
791
            if min(
150
791
                self.options.jpeg_get_out_colorspace().num_components() - 1,
151
791
                pos
152
791
            ) == pos
153
3
                || comp_len == 4
154
            // Special colorspace
155
791
            {
156
791
                // allocate enough space to hold a whole MCU width
157
791
                // this means we should take into account sampling ratios
158
791
                // `*8` is because each MCU spans 8 widths.
159
791
                let len = comp.width_stride * comp.vertical_sample * 8;
160
791
161
791
                comp.needed = true;
162
791
                comp.raw_coeff = vec![0; len];
163
791
            } else {
164
0
                comp.needed = false;
165
0
            }
166
        }
167
168
370
        let mut pixels_written = 0;
169
370
170
370
        let is_hv = usize::from(self.is_interleaved);
171
370
        let upsampler_scratch_size = is_hv * self.components[0].width_stride;
172
370
        let mut upsampler_scratch_space = vec![0; upsampler_scratch_size];
173
174
45.5k
        for i in 0..mcu_height {
175
            // Report if we have no more bytes
176
            // This may generate false negatives since we over-read bytes
177
            // hence that why 37 is chosen(we assume if we over-read more than 37 bytes, we have a problem)
178
45.5k
            if stream.overread_by > 37
179
            // favourite number :)
180
            {
181
0
                if self.options.get_strict_mode() {
182
0
                    return Err(DecodeErrors::FormatStatic("Premature end of buffer"));
183
0
                };
184
0
185
0
                error!("Premature end of buffer");
186
0
                break;
187
45.5k
            }
188
189
            // decode a whole MCU width,
190
            // this takes into account interleaved components.
191
45.5k
            let terminate = self.decode_mcu_width(mcu_width, &mut tmp, &mut stream)?;
192
            // if i >=7{
193
            //     panic!()
194
            // }
195
            // process that width up until it's impossible
196
197
45.3k
            self.post_process(
198
45.3k
                pixels,
199
45.3k
                i,
200
45.3k
                mcu_height,
201
45.3k
                width,
202
45.3k
                padded_width,
203
45.3k
                &mut pixels_written,
204
45.3k
                &mut upsampler_scratch_space
205
45.3k
            )?;
206
45.3k
            if terminate {
207
9
                warn!("Got terminate signal, will not process further");
208
9
                return Ok(());
209
45.3k
            }
210
        }
211
        // it may happen that some images don't have the whole buffer
212
        // so we can't panic in case of that
213
        // assert_eq!(pixels_written, pixels.len());
214
215
        // For UHD usecases that tie two images separating them with EOI and
216
        // SOI markers, it may happen that we do not reach this image end of image
217
        // So this ensures we reach it
218
        // Ensure we read EOI
219
128
        if !stream.seen_eoi {
220
100
            let marker = get_marker(&mut self.stream, &mut stream);
221
100
            match marker {
222
1
                Ok(_m) => {
223
1
                    trace!("Found marker {:?}", _m);
224
1
                }
225
99
                Err(_) => {
226
99
                    // ignore error
227
99
                }
228
            }
229
28
        }
230
231
        trace!("Finished decoding image");
232
233
128
        Ok(())
234
388
    }
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_ycbcr_baseline
Line
Count
Source
86
68
    pub(crate) fn decode_mcu_ycbcr_baseline(
87
68
        &mut self, pixels: &mut [u8]
88
68
    ) -> Result<(), DecodeErrors> {
89
68
        setup_component_params(self)?;
90
91
        // check dc and AC tables
92
68
        self.check_tables()?;
93
94
        let (mut mcu_width, mut mcu_height);
95
96
66
        if self.is_interleaved {
97
            // set upsampling functions
98
0
            self.set_upsampling()?;
99
100
0
            mcu_width = self.mcu_x;
101
0
            mcu_height = self.mcu_y;
102
66
        } else {
103
66
            // For non-interleaved images( (1*1) subsampling)
104
66
            // number of MCU's are the widths (+7 to account for paddings) divided bu 8.
105
66
            mcu_width = ((self.info.width + 7) / 8) as usize;
106
66
            mcu_height = ((self.info.height + 7) / 8) as usize;
107
66
        }
108
66
        if self.is_interleaved
109
0
            && self.input_colorspace.num_components() > 1
110
0
            && self.options.jpeg_get_out_colorspace().num_components() == 1
111
0
            && (self.sub_sample_ratio == SampleRatios::V
112
0
                || self.sub_sample_ratio == SampleRatios::HV)
113
0
        {
114
0
            // For a specific set of images, e.g interleaved,
115
0
            // when converting from YcbCr to grayscale, we need to
116
0
            // take into account mcu height since the MCU decoding needs to take
117
0
            // it into account for padding purposes and the post processor
118
0
            // parses two rows per mcu width.
119
0
            //
120
0
            // set coeff to be 2 to ensure that we increment two rows
121
0
            // for every mcu processed also
122
0
            mcu_height *= self.v_max;
123
0
            mcu_height /= self.h_max;
124
0
            self.coeff = 2;
125
66
        }
126
127
66
        if self.input_colorspace == ColorSpace::Luma && self.is_interleaved {
128
0
            warn!("Grayscale image with down-sampled component, resetting component details");
129
0
130
0
            self.reset_params();
131
0
132
0
            mcu_width = ((self.info.width + 7) / 8) as usize;
133
0
            mcu_height = ((self.info.height + 7) / 8) as usize;
134
66
        }
135
66
        let width = usize::from(self.info.width);
136
66
137
66
        let padded_width = calculate_padded_width(width, self.sub_sample_ratio);
138
66
139
66
        let mut stream = BitStream::new();
140
66
        let mut tmp = [0_i32; DCT_BLOCK];
141
66
142
66
        let comp_len = self.components.len();
143
144
66
        for (pos, comp) in self.components.iter_mut().enumerate() {
145
            // Allocate only needed components.
146
            //
147
            // For special colorspaces i.e YCCK and CMYK, just allocate all of the needed
148
            // components.
149
66
            if min(
150
66
                self.options.jpeg_get_out_colorspace().num_components() - 1,
151
66
                pos
152
66
            ) == pos
153
0
                || comp_len == 4
154
            // Special colorspace
155
66
            {
156
66
                // allocate enough space to hold a whole MCU width
157
66
                // this means we should take into account sampling ratios
158
66
                // `*8` is because each MCU spans 8 widths.
159
66
                let len = comp.width_stride * comp.vertical_sample * 8;
160
66
161
66
                comp.needed = true;
162
66
                comp.raw_coeff = vec![0; len];
163
66
            } else {
164
0
                comp.needed = false;
165
0
            }
166
        }
167
168
66
        let mut pixels_written = 0;
169
66
170
66
        let is_hv = usize::from(self.is_interleaved);
171
66
        let upsampler_scratch_size = is_hv * self.components[0].width_stride;
172
66
        let mut upsampler_scratch_space = vec![0; upsampler_scratch_size];
173
174
871
        for i in 0..mcu_height {
175
            // Report if we have no more bytes
176
            // This may generate false negatives since we over-read bytes
177
            // hence that why 37 is chosen(we assume if we over-read more than 37 bytes, we have a problem)
178
871
            if stream.overread_by > 37
179
            // favourite number :)
180
            {
181
0
                if self.options.get_strict_mode() {
182
0
                    return Err(DecodeErrors::FormatStatic("Premature end of buffer"));
183
0
                };
184
0
185
0
                error!("Premature end of buffer");
186
0
                break;
187
871
            }
188
189
            // decode a whole MCU width,
190
            // this takes into account interleaved components.
191
871
            let terminate = self.decode_mcu_width(mcu_width, &mut tmp, &mut stream)?;
192
            // if i >=7{
193
            //     panic!()
194
            // }
195
            // process that width up until it's impossible
196
197
851
            self.post_process(
198
851
                pixels,
199
851
                i,
200
851
                mcu_height,
201
851
                width,
202
851
                padded_width,
203
851
                &mut pixels_written,
204
851
                &mut upsampler_scratch_space
205
851
            )?;
206
851
            if terminate {
207
0
                warn!("Got terminate signal, will not process further");
208
0
                return Ok(());
209
851
            }
210
        }
211
        // it may happen that some images don't have the whole buffer
212
        // so we can't panic in case of that
213
        // assert_eq!(pixels_written, pixels.len());
214
215
        // For UHD usecases that tie two images separating them with EOI and
216
        // SOI markers, it may happen that we do not reach this image end of image
217
        // So this ensures we reach it
218
        // Ensure we read EOI
219
46
        if !stream.seen_eoi {
220
28
            let marker = get_marker(&mut self.stream, &mut stream);
221
28
            match marker {
222
3
                Ok(_m) => {
223
3
                    trace!("Found marker {:?}", _m);
224
3
                }
225
25
                Err(_) => {
226
25
                    // ignore error
227
25
                }
228
            }
229
18
        }
230
231
        trace!("Finished decoding image");
232
233
46
        Ok(())
234
68
    }
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_ycbcr_baseline
Line
Count
Source
86
685
    pub(crate) fn decode_mcu_ycbcr_baseline(
87
685
        &mut self, pixels: &mut [u8]
88
685
    ) -> Result<(), DecodeErrors> {
89
685
        setup_component_params(self)?;
90
91
        // check dc and AC tables
92
677
        self.check_tables()?;
93
94
        let (mut mcu_width, mut mcu_height);
95
96
674
        if self.is_interleaved {
97
            // set upsampling functions
98
310
            self.set_upsampling()?;
99
100
310
            mcu_width = self.mcu_x;
101
310
            mcu_height = self.mcu_y;
102
364
        } else {
103
364
            // For non-interleaved images( (1*1) subsampling)
104
364
            // number of MCU's are the widths (+7 to account for paddings) divided bu 8.
105
364
            mcu_width = ((self.info.width + 7) / 8) as usize;
106
364
            mcu_height = ((self.info.height + 7) / 8) as usize;
107
364
        }
108
674
        if self.is_interleaved
109
310
            && self.input_colorspace.num_components() > 1
110
310
            && self.options.jpeg_get_out_colorspace().num_components() == 1
111
0
            && (self.sub_sample_ratio == SampleRatios::V
112
0
                || self.sub_sample_ratio == SampleRatios::HV)
113
0
        {
114
0
            // For a specific set of images, e.g interleaved,
115
0
            // when converting from YcbCr to grayscale, we need to
116
0
            // take into account mcu height since the MCU decoding needs to take
117
0
            // it into account for padding purposes and the post processor
118
0
            // parses two rows per mcu width.
119
0
            //
120
0
            // set coeff to be 2 to ensure that we increment two rows
121
0
            // for every mcu processed also
122
0
            mcu_height *= self.v_max;
123
0
            mcu_height /= self.h_max;
124
0
            self.coeff = 2;
125
674
        }
126
127
674
        if self.input_colorspace == ColorSpace::Luma && self.is_interleaved {
128
0
            warn!("Grayscale image with down-sampled component, resetting component details");
129
0
130
0
            self.reset_params();
131
0
132
0
            mcu_width = ((self.info.width + 7) / 8) as usize;
133
0
            mcu_height = ((self.info.height + 7) / 8) as usize;
134
674
        }
135
674
        let width = usize::from(self.info.width);
136
674
137
674
        let padded_width = calculate_padded_width(width, self.sub_sample_ratio);
138
674
139
674
        let mut stream = BitStream::new();
140
674
        let mut tmp = [0_i32; DCT_BLOCK];
141
674
142
674
        let comp_len = self.components.len();
143
144
2.05k
        for (pos, comp) in self.components.iter_mut().enumerate() {
145
            // Allocate only needed components.
146
            //
147
            // For special colorspaces i.e YCCK and CMYK, just allocate all of the needed
148
            // components.
149
2.05k
            if min(
150
2.05k
                self.options.jpeg_get_out_colorspace().num_components() - 1,
151
2.05k
                pos
152
2.05k
            ) == pos
153
278
                || comp_len == 4
154
            // Special colorspace
155
2.05k
            {
156
2.05k
                // allocate enough space to hold a whole MCU width
157
2.05k
                // this means we should take into account sampling ratios
158
2.05k
                // `*8` is because each MCU spans 8 widths.
159
2.05k
                let len = comp.width_stride * comp.vertical_sample * 8;
160
2.05k
161
2.05k
                comp.needed = true;
162
2.05k
                comp.raw_coeff = vec![0; len];
163
2.05k
            } else {
164
0
                comp.needed = false;
165
0
            }
166
        }
167
168
674
        let mut pixels_written = 0;
169
674
170
674
        let is_hv = usize::from(self.is_interleaved);
171
674
        let upsampler_scratch_size = is_hv * self.components[0].width_stride;
172
674
        let mut upsampler_scratch_space = vec![0; upsampler_scratch_size];
173
174
49.5k
        for i in 0..mcu_height {
175
            // Report if we have no more bytes
176
            // This may generate false negatives since we over-read bytes
177
            // hence that why 37 is chosen(we assume if we over-read more than 37 bytes, we have a problem)
178
49.5k
            if stream.overread_by > 37
179
            // favourite number :)
180
            {
181
0
                if self.options.get_strict_mode() {
182
0
                    return Err(DecodeErrors::FormatStatic("Premature end of buffer"));
183
0
                };
184
0
185
0
                error!("Premature end of buffer");
186
0
                break;
187
49.5k
            }
188
189
            // decode a whole MCU width,
190
            // this takes into account interleaved components.
191
49.5k
            let terminate = self.decode_mcu_width(mcu_width, &mut tmp, &mut stream)?;
192
            // if i >=7{
193
            //     panic!()
194
            // }
195
            // process that width up until it's impossible
196
197
49.2k
            self.post_process(
198
49.2k
                pixels,
199
49.2k
                i,
200
49.2k
                mcu_height,
201
49.2k
                width,
202
49.2k
                padded_width,
203
49.2k
                &mut pixels_written,
204
49.2k
                &mut upsampler_scratch_space
205
49.2k
            )?;
206
49.2k
            if terminate {
207
16
                warn!("Got terminate signal, will not process further");
208
16
                return Ok(());
209
49.2k
            }
210
        }
211
        // it may happen that some images don't have the whole buffer
212
        // so we can't panic in case of that
213
        // assert_eq!(pixels_written, pixels.len());
214
215
        // For UHD usecases that tie two images separating them with EOI and
216
        // SOI markers, it may happen that we do not reach this image end of image
217
        // So this ensures we reach it
218
        // Ensure we read EOI
219
365
        if !stream.seen_eoi {
220
330
            let marker = get_marker(&mut self.stream, &mut stream);
221
330
            match marker {
222
31
                Ok(_m) => {
223
31
                    trace!("Found marker {:?}", _m);
224
31
                }
225
299
                Err(_) => {
226
299
                    // ignore error
227
299
                }
228
            }
229
35
        }
230
231
        trace!("Finished decoding image");
232
233
365
        Ok(())
234
685
    }
235
191k
    fn decode_mcu_width(
236
191k
        &mut self, mcu_width: usize, tmp: &mut [i32; 64], stream: &mut BitStream
237
191k
    ) -> Result<bool, DecodeErrors> {
238
66.6M
        for j in 0..mcu_width {
239
            // iterate over components
240
147M
            for component in &mut self.components {
241
80.9M
                let dc_table = self.dc_huffman_tables[component.dc_huff_table % MAX_COMPONENTS]
242
80.9M
                    .as_ref()
243
80.9M
                    .unwrap();
244
80.9M
245
80.9M
                let ac_table = self.ac_huffman_tables[component.ac_huff_table % MAX_COMPONENTS]
246
80.9M
                    .as_ref()
247
80.9M
                    .unwrap();
248
80.9M
249
80.9M
                let qt_table = &component.quantization_table;
250
80.9M
                let channel = &mut component.raw_coeff;
251
252
                // If image is interleaved iterate over scan components,
253
                // otherwise if it-s non-interleaved, these routines iterate in
254
                // trivial scanline order(Y,Cb,Cr)
255
85.9M
                for v_samp in 0..component.vertical_sample {
256
92.9M
                    for h_samp in 0..component.horizontal_sample {
257
                        // Fill the array with zeroes, decode_mcu_block expects
258
                        // a zero based array.
259
92.9M
                        tmp.fill(0);
260
92.9M
261
92.9M
                        stream.decode_mcu_block(
262
92.9M
                            &mut self.stream,
263
92.9M
                            dc_table,
264
92.9M
                            ac_table,
265
92.9M
                            qt_table,
266
92.9M
                            tmp,
267
92.9M
                            &mut component.dc_pred
268
92.9M
                        )?;
269
270
92.9M
                        if component.needed {
271
92.9M
                            let idct_position = {
272
92.9M
                                // derived from stb and rewritten for my tastes
273
92.9M
                                let c2 = v_samp * 8;
274
92.9M
                                let c3 = ((j * component.horizontal_sample) + h_samp) * 8;
275
92.9M
276
92.9M
                                component.width_stride * c2 + c3
277
92.9M
                            };
278
92.9M
279
92.9M
                            let idct_pos = channel.get_mut(idct_position..).unwrap();
280
92.9M
                            //  call idct.
281
92.9M
                            (self.idct_func)(tmp, idct_pos, component.width_stride);
282
92.9M
                        }
283
                    }
284
                }
285
            }
286
66.6M
            self.todo = self.todo.wrapping_sub(1);
287
66.6M
288
66.6M
            if self.todo == 0 {
289
86.7k
                self.handle_rst_main(stream)?;
290
66.5M
            }
291
292
            // After all interleaved components, that's an MCU
293
            // handle stream markers
294
            //
295
            // In some corrupt images, it may occur that header markers occur in the stream.
296
            // The spec EXPLICITLY FORBIDS this, specifically, in
297
            // routine F.2.2.5  it says
298
            // `The only valid marker which may occur within the Huffman coded data is the RSTm marker.`
299
            //
300
            // But libjpeg-turbo allows it because of some weird reason. so I'll also
301
            // allow it because of some weird reason.
302
66.6M
            if let Some(m) = stream.marker {
303
7.58M
                if m == Marker::EOI {
304
201
                    // acknowledge and ignore EOI marker.
305
201
                    stream.marker.take();
306
201
                    trace!("Found EOI marker");
307
201
                    // Google Introduced the Ultra-HD image format which is basically
308
201
                    // stitching two images into one container.
309
201
                    // They basically separate two images via a EOI and SOI marker
310
201
                    // so let's just ensure if we ever see EOI, we never read past that
311
201
                    // ever.
312
201
                    // https://github.com/google/libultrahdr
313
201
                    stream.seen_eoi = true;
314
7.58M
                } else if let Marker::RST(_) = m {
315
                    //debug_assert_eq!(self.todo, 0);
316
7.58M
                    if self.todo == 0 {
317
0
                        self.handle_rst(stream)?;
318
7.58M
                    }
319
                } else {
320
825
                    if self.options.get_strict_mode() {
321
101
                        return Err(DecodeErrors::Format(format!(
322
101
                            "Marker {m:?} found where not expected"
323
101
                        )));
324
724
                    }
325
724
                    error!(
326
724
                        "Marker `{:?}` Found within Huffman Stream, possibly corrupt jpeg",
327
724
                        m
328
724
                    );
329
724
                    self.parse_marker_inner(m)?;
330
516
                    if m == Marker::SOS {
331
25
                        return Ok(true);
332
491
                    }
333
                }
334
59.0M
            }
335
        }
336
190k
        Ok(false)
337
191k
    }
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::decode_mcu_width
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width
Line
Count
Source
235
95.0k
    fn decode_mcu_width(
236
95.0k
        &mut self, mcu_width: usize, tmp: &mut [i32; 64], stream: &mut BitStream
237
95.0k
    ) -> Result<bool, DecodeErrors> {
238
3.48M
        for j in 0..mcu_width {
239
            // iterate over components
240
6.97M
            for component in &mut self.components {
241
3.48M
                let dc_table = self.dc_huffman_tables[component.dc_huff_table % MAX_COMPONENTS]
242
3.48M
                    .as_ref()
243
3.48M
                    .unwrap();
244
3.48M
245
3.48M
                let ac_table = self.ac_huffman_tables[component.ac_huff_table % MAX_COMPONENTS]
246
3.48M
                    .as_ref()
247
3.48M
                    .unwrap();
248
3.48M
249
3.48M
                let qt_table = &component.quantization_table;
250
3.48M
                let channel = &mut component.raw_coeff;
251
252
                // If image is interleaved iterate over scan components,
253
                // otherwise if it-s non-interleaved, these routines iterate in
254
                // trivial scanline order(Y,Cb,Cr)
255
3.48M
                for v_samp in 0..component.vertical_sample {
256
3.48M
                    for h_samp in 0..component.horizontal_sample {
257
                        // Fill the array with zeroes, decode_mcu_block expects
258
                        // a zero based array.
259
3.48M
                        tmp.fill(0);
260
3.48M
261
3.48M
                        stream.decode_mcu_block(
262
3.48M
                            &mut self.stream,
263
3.48M
                            dc_table,
264
3.48M
                            ac_table,
265
3.48M
                            qt_table,
266
3.48M
                            tmp,
267
3.48M
                            &mut component.dc_pred
268
3.48M
                        )?;
269
270
3.48M
                        if component.needed {
271
3.48M
                            let idct_position = {
272
3.48M
                                // derived from stb and rewritten for my tastes
273
3.48M
                                let c2 = v_samp * 8;
274
3.48M
                                let c3 = ((j * component.horizontal_sample) + h_samp) * 8;
275
3.48M
276
3.48M
                                component.width_stride * c2 + c3
277
3.48M
                            };
278
3.48M
279
3.48M
                            let idct_pos = channel.get_mut(idct_position..).unwrap();
280
3.48M
                            //  call idct.
281
3.48M
                            (self.idct_func)(tmp, idct_pos, component.width_stride);
282
3.48M
                        }
283
                    }
284
                }
285
            }
286
3.48M
            self.todo = self.todo.wrapping_sub(1);
287
3.48M
288
3.48M
            if self.todo == 0 {
289
0
                self.handle_rst_main(stream)?;
290
3.48M
            }
291
292
            // After all interleaved components, that's an MCU
293
            // handle stream markers
294
            //
295
            // In some corrupt images, it may occur that header markers occur in the stream.
296
            // The spec EXPLICITLY FORBIDS this, specifically, in
297
            // routine F.2.2.5  it says
298
            // `The only valid marker which may occur within the Huffman coded data is the RSTm marker.`
299
            //
300
            // But libjpeg-turbo allows it because of some weird reason. so I'll also
301
            // allow it because of some weird reason.
302
3.48M
            if let Some(m) = stream.marker {
303
242k
                if m == Marker::EOI {
304
120
                    // acknowledge and ignore EOI marker.
305
120
                    stream.marker.take();
306
120
                    trace!("Found EOI marker");
307
120
                    // Google Introduced the Ultra-HD image format which is basically
308
120
                    // stitching two images into one container.
309
120
                    // They basically separate two images via a EOI and SOI marker
310
120
                    // so let's just ensure if we ever see EOI, we never read past that
311
120
                    // ever.
312
120
                    // https://github.com/google/libultrahdr
313
120
                    stream.seen_eoi = true;
314
242k
                } else if let Marker::RST(_) = m {
315
                    //debug_assert_eq!(self.todo, 0);
316
242k
                    if self.todo == 0 {
317
0
                        self.handle_rst(stream)?;
318
242k
                    }
319
                } else {
320
89
                    if self.options.get_strict_mode() {
321
89
                        return Err(DecodeErrors::Format(format!(
322
89
                            "Marker {m:?} found where not expected"
323
89
                        )));
324
0
                    }
325
0
                    error!(
326
0
                        "Marker `{:?}` Found within Huffman Stream, possibly corrupt jpeg",
327
0
                        m
328
0
                    );
329
0
                    self.parse_marker_inner(m)?;
330
0
                    if m == Marker::SOS {
331
0
                        return Ok(true);
332
0
                    }
333
                }
334
3.24M
            }
335
        }
336
94.6k
        Ok(false)
337
95.0k
    }
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width
Line
Count
Source
235
45.5k
    fn decode_mcu_width(
236
45.5k
        &mut self, mcu_width: usize, tmp: &mut [i32; 64], stream: &mut BitStream
237
45.5k
    ) -> Result<bool, DecodeErrors> {
238
58.9M
        for j in 0..mcu_width {
239
            // iterate over components
240
121M
            for component in &mut self.components {
241
63.0M
                let dc_table = self.dc_huffman_tables[component.dc_huff_table % MAX_COMPONENTS]
242
63.0M
                    .as_ref()
243
63.0M
                    .unwrap();
244
63.0M
245
63.0M
                let ac_table = self.ac_huffman_tables[component.ac_huff_table % MAX_COMPONENTS]
246
63.0M
                    .as_ref()
247
63.0M
                    .unwrap();
248
63.0M
249
63.0M
                let qt_table = &component.quantization_table;
250
63.0M
                let channel = &mut component.raw_coeff;
251
252
                // If image is interleaved iterate over scan components,
253
                // otherwise if it-s non-interleaved, these routines iterate in
254
                // trivial scanline order(Y,Cb,Cr)
255
66.6M
                for v_samp in 0..component.vertical_sample {
256
69.3M
                    for h_samp in 0..component.horizontal_sample {
257
                        // Fill the array with zeroes, decode_mcu_block expects
258
                        // a zero based array.
259
69.3M
                        tmp.fill(0);
260
69.3M
261
69.3M
                        stream.decode_mcu_block(
262
69.3M
                            &mut self.stream,
263
69.3M
                            dc_table,
264
69.3M
                            ac_table,
265
69.3M
                            qt_table,
266
69.3M
                            tmp,
267
69.3M
                            &mut component.dc_pred
268
69.3M
                        )?;
269
270
69.3M
                        if component.needed {
271
69.3M
                            let idct_position = {
272
69.3M
                                // derived from stb and rewritten for my tastes
273
69.3M
                                let c2 = v_samp * 8;
274
69.3M
                                let c3 = ((j * component.horizontal_sample) + h_samp) * 8;
275
69.3M
276
69.3M
                                component.width_stride * c2 + c3
277
69.3M
                            };
278
69.3M
279
69.3M
                            let idct_pos = channel.get_mut(idct_position..).unwrap();
280
69.3M
                            //  call idct.
281
69.3M
                            (self.idct_func)(tmp, idct_pos, component.width_stride);
282
69.3M
                        }
283
                    }
284
                }
285
            }
286
58.9M
            self.todo = self.todo.wrapping_sub(1);
287
58.9M
288
58.9M
            if self.todo == 0 {
289
63.3k
                self.handle_rst_main(stream)?;
290
58.8M
            }
291
292
            // After all interleaved components, that's an MCU
293
            // handle stream markers
294
            //
295
            // In some corrupt images, it may occur that header markers occur in the stream.
296
            // The spec EXPLICITLY FORBIDS this, specifically, in
297
            // routine F.2.2.5  it says
298
            // `The only valid marker which may occur within the Huffman coded data is the RSTm marker.`
299
            //
300
            // But libjpeg-turbo allows it because of some weird reason. so I'll also
301
            // allow it because of some weird reason.
302
58.9M
            if let Some(m) = stream.marker {
303
7.16M
                if m == Marker::EOI {
304
28
                    // acknowledge and ignore EOI marker.
305
28
                    stream.marker.take();
306
28
                    trace!("Found EOI marker");
307
28
                    // Google Introduced the Ultra-HD image format which is basically
308
28
                    // stitching two images into one container.
309
28
                    // They basically separate two images via a EOI and SOI marker
310
28
                    // so let's just ensure if we ever see EOI, we never read past that
311
28
                    // ever.
312
28
                    // https://github.com/google/libultrahdr
313
28
                    stream.seen_eoi = true;
314
7.16M
                } else if let Marker::RST(_) = m {
315
                    //debug_assert_eq!(self.todo, 0);
316
7.16M
                    if self.todo == 0 {
317
0
                        self.handle_rst(stream)?;
318
7.16M
                    }
319
                } else {
320
428
                    if self.options.get_strict_mode() {
321
0
                        return Err(DecodeErrors::Format(format!(
322
0
                            "Marker {m:?} found where not expected"
323
0
                        )));
324
428
                    }
325
428
                    error!(
326
428
                        "Marker `{:?}` Found within Huffman Stream, possibly corrupt jpeg",
327
428
                        m
328
428
                    );
329
428
                    self.parse_marker_inner(m)?;
330
322
                    if m == Marker::SOS {
331
9
                        return Ok(true);
332
313
                    }
333
                }
334
51.7M
            }
335
        }
336
45.3k
        Ok(false)
337
45.5k
    }
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::decode_mcu_width
Line
Count
Source
235
871
    fn decode_mcu_width(
236
871
        &mut self, mcu_width: usize, tmp: &mut [i32; 64], stream: &mut BitStream
237
871
    ) -> Result<bool, DecodeErrors> {
238
22.0k
        for j in 0..mcu_width {
239
            // iterate over components
240
44.0k
            for component in &mut self.components {
241
22.0k
                let dc_table = self.dc_huffman_tables[component.dc_huff_table % MAX_COMPONENTS]
242
22.0k
                    .as_ref()
243
22.0k
                    .unwrap();
244
22.0k
245
22.0k
                let ac_table = self.ac_huffman_tables[component.ac_huff_table % MAX_COMPONENTS]
246
22.0k
                    .as_ref()
247
22.0k
                    .unwrap();
248
22.0k
249
22.0k
                let qt_table = &component.quantization_table;
250
22.0k
                let channel = &mut component.raw_coeff;
251
252
                // If image is interleaved iterate over scan components,
253
                // otherwise if it-s non-interleaved, these routines iterate in
254
                // trivial scanline order(Y,Cb,Cr)
255
22.0k
                for v_samp in 0..component.vertical_sample {
256
22.0k
                    for h_samp in 0..component.horizontal_sample {
257
                        // Fill the array with zeroes, decode_mcu_block expects
258
                        // a zero based array.
259
22.0k
                        tmp.fill(0);
260
22.0k
261
22.0k
                        stream.decode_mcu_block(
262
22.0k
                            &mut self.stream,
263
22.0k
                            dc_table,
264
22.0k
                            ac_table,
265
22.0k
                            qt_table,
266
22.0k
                            tmp,
267
22.0k
                            &mut component.dc_pred
268
22.0k
                        )?;
269
270
22.0k
                        if component.needed {
271
22.0k
                            let idct_position = {
272
22.0k
                                // derived from stb and rewritten for my tastes
273
22.0k
                                let c2 = v_samp * 8;
274
22.0k
                                let c3 = ((j * component.horizontal_sample) + h_samp) * 8;
275
22.0k
276
22.0k
                                component.width_stride * c2 + c3
277
22.0k
                            };
278
22.0k
279
22.0k
                            let idct_pos = channel.get_mut(idct_position..).unwrap();
280
22.0k
                            //  call idct.
281
22.0k
                            (self.idct_func)(tmp, idct_pos, component.width_stride);
282
22.0k
                        }
283
                    }
284
                }
285
            }
286
22.0k
            self.todo = self.todo.wrapping_sub(1);
287
22.0k
288
22.0k
            if self.todo == 0 {
289
0
                self.handle_rst_main(stream)?;
290
22.0k
            }
291
292
            // After all interleaved components, that's an MCU
293
            // handle stream markers
294
            //
295
            // In some corrupt images, it may occur that header markers occur in the stream.
296
            // The spec EXPLICITLY FORBIDS this, specifically, in
297
            // routine F.2.2.5  it says
298
            // `The only valid marker which may occur within the Huffman coded data is the RSTm marker.`
299
            //
300
            // But libjpeg-turbo allows it because of some weird reason. so I'll also
301
            // allow it because of some weird reason.
302
22.0k
            if let Some(m) = stream.marker {
303
30
                if m == Marker::EOI {
304
18
                    // acknowledge and ignore EOI marker.
305
18
                    stream.marker.take();
306
18
                    trace!("Found EOI marker");
307
18
                    // Google Introduced the Ultra-HD image format which is basically
308
18
                    // stitching two images into one container.
309
18
                    // They basically separate two images via a EOI and SOI marker
310
18
                    // so let's just ensure if we ever see EOI, we never read past that
311
18
                    // ever.
312
18
                    // https://github.com/google/libultrahdr
313
18
                    stream.seen_eoi = true;
314
18
                } else if let Marker::RST(_) = m {
315
                    //debug_assert_eq!(self.todo, 0);
316
0
                    if self.todo == 0 {
317
0
                        self.handle_rst(stream)?;
318
0
                    }
319
                } else {
320
12
                    if self.options.get_strict_mode() {
321
12
                        return Err(DecodeErrors::Format(format!(
322
12
                            "Marker {m:?} found where not expected"
323
12
                        )));
324
0
                    }
325
0
                    error!(
326
0
                        "Marker `{:?}` Found within Huffman Stream, possibly corrupt jpeg",
327
0
                        m
328
0
                    );
329
0
                    self.parse_marker_inner(m)?;
330
0
                    if m == Marker::SOS {
331
0
                        return Ok(true);
332
0
                    }
333
                }
334
22.0k
            }
335
        }
336
851
        Ok(false)
337
871
    }
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::decode_mcu_width
Line
Count
Source
235
49.5k
    fn decode_mcu_width(
236
49.5k
        &mut self, mcu_width: usize, tmp: &mut [i32; 64], stream: &mut BitStream
237
49.5k
    ) -> Result<bool, DecodeErrors> {
238
4.21M
        for j in 0..mcu_width {
239
            // iterate over components
240
18.6M
            for component in &mut self.components {
241
14.4M
                let dc_table = self.dc_huffman_tables[component.dc_huff_table % MAX_COMPONENTS]
242
14.4M
                    .as_ref()
243
14.4M
                    .unwrap();
244
14.4M
245
14.4M
                let ac_table = self.ac_huffman_tables[component.ac_huff_table % MAX_COMPONENTS]
246
14.4M
                    .as_ref()
247
14.4M
                    .unwrap();
248
14.4M
249
14.4M
                let qt_table = &component.quantization_table;
250
14.4M
                let channel = &mut component.raw_coeff;
251
252
                // If image is interleaved iterate over scan components,
253
                // otherwise if it-s non-interleaved, these routines iterate in
254
                // trivial scanline order(Y,Cb,Cr)
255
15.8M
                for v_samp in 0..component.vertical_sample {
256
20.0M
                    for h_samp in 0..component.horizontal_sample {
257
                        // Fill the array with zeroes, decode_mcu_block expects
258
                        // a zero based array.
259
20.0M
                        tmp.fill(0);
260
20.0M
261
20.0M
                        stream.decode_mcu_block(
262
20.0M
                            &mut self.stream,
263
20.0M
                            dc_table,
264
20.0M
                            ac_table,
265
20.0M
                            qt_table,
266
20.0M
                            tmp,
267
20.0M
                            &mut component.dc_pred
268
20.0M
                        )?;
269
270
20.0M
                        if component.needed {
271
20.0M
                            let idct_position = {
272
20.0M
                                // derived from stb and rewritten for my tastes
273
20.0M
                                let c2 = v_samp * 8;
274
20.0M
                                let c3 = ((j * component.horizontal_sample) + h_samp) * 8;
275
20.0M
276
20.0M
                                component.width_stride * c2 + c3
277
20.0M
                            };
278
20.0M
279
20.0M
                            let idct_pos = channel.get_mut(idct_position..).unwrap();
280
20.0M
                            //  call idct.
281
20.0M
                            (self.idct_func)(tmp, idct_pos, component.width_stride);
282
20.0M
                        }
283
                    }
284
                }
285
            }
286
4.21M
            self.todo = self.todo.wrapping_sub(1);
287
4.21M
288
4.21M
            if self.todo == 0 {
289
23.3k
                self.handle_rst_main(stream)?;
290
4.19M
            }
291
292
            // After all interleaved components, that's an MCU
293
            // handle stream markers
294
            //
295
            // In some corrupt images, it may occur that header markers occur in the stream.
296
            // The spec EXPLICITLY FORBIDS this, specifically, in
297
            // routine F.2.2.5  it says
298
            // `The only valid marker which may occur within the Huffman coded data is the RSTm marker.`
299
            //
300
            // But libjpeg-turbo allows it because of some weird reason. so I'll also
301
            // allow it because of some weird reason.
302
4.21M
            if let Some(m) = stream.marker {
303
181k
                if m == Marker::EOI {
304
35
                    // acknowledge and ignore EOI marker.
305
35
                    stream.marker.take();
306
35
                    trace!("Found EOI marker");
307
35
                    // Google Introduced the Ultra-HD image format which is basically
308
35
                    // stitching two images into one container.
309
35
                    // They basically separate two images via a EOI and SOI marker
310
35
                    // so let's just ensure if we ever see EOI, we never read past that
311
35
                    // ever.
312
35
                    // https://github.com/google/libultrahdr
313
35
                    stream.seen_eoi = true;
314
181k
                } else if let Marker::RST(_) = m {
315
                    //debug_assert_eq!(self.todo, 0);
316
180k
                    if self.todo == 0 {
317
0
                        self.handle_rst(stream)?;
318
180k
                    }
319
                } else {
320
296
                    if self.options.get_strict_mode() {
321
0
                        return Err(DecodeErrors::Format(format!(
322
0
                            "Marker {m:?} found where not expected"
323
0
                        )));
324
296
                    }
325
296
                    error!(
326
296
                        "Marker `{:?}` Found within Huffman Stream, possibly corrupt jpeg",
327
296
                        m
328
296
                    );
329
296
                    self.parse_marker_inner(m)?;
330
194
                    if m == Marker::SOS {
331
16
                        return Ok(true);
332
178
                    }
333
                }
334
4.03M
            }
335
        }
336
49.2k
        Ok(false)
337
49.5k
    }
338
    // handle RST markers.
339
    // No-op if not using restarts
340
    // this routine is shared with mcu_prog
341
    #[cold]
342
95.7k
    pub(crate) fn handle_rst(&mut self, stream: &mut BitStream) -> Result<(), DecodeErrors> {
343
95.7k
        self.todo = self.restart_interval;
344
345
95.7k
        if let Some(marker) = stream.marker {
346
            // Found a marker
347
            // Read stream and see what marker is stored there
348
60.2k
            match marker {
349
59.5k
                Marker::RST(_) => {
350
59.5k
                    // reset stream
351
59.5k
                    stream.reset();
352
59.5k
                    // Initialize dc predictions to zero for all components
353
177k
                    self.components.iter_mut().for_each(|x| x.dc_pred = 0);
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0}
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0}
Line
Count
Source
353
119k
                    self.components.iter_mut().for_each(|x| x.dc_pred = 0);
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst::{closure#0}
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst::{closure#0}
Line
Count
Source
353
58.1k
                    self.components.iter_mut().for_each(|x| x.dc_pred = 0);
354
59.5k
                    // Start iterating again. from position.
355
59.5k
                }
356
660
                Marker::EOI => {
357
660
                    // silent pass
358
660
                }
359
                _ => {
360
23
                    return Err(DecodeErrors::MCUError(format!(
361
23
                        "Marker {marker:?} found in bitstream, possibly corrupt jpeg"
362
23
                    )));
363
                }
364
            }
365
35.5k
        }
366
95.7k
        Ok(())
367
95.7k
    }
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::handle_rst
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst
Line
Count
Source
342
5
    pub(crate) fn handle_rst(&mut self, stream: &mut BitStream) -> Result<(), DecodeErrors> {
343
5
        self.todo = self.restart_interval;
344
345
5
        if let Some(marker) = stream.marker {
346
            // Found a marker
347
            // Read stream and see what marker is stored there
348
0
            match marker {
349
0
                Marker::RST(_) => {
350
0
                    // reset stream
351
0
                    stream.reset();
352
0
                    // Initialize dc predictions to zero for all components
353
0
                    self.components.iter_mut().for_each(|x| x.dc_pred = 0);
354
0
                    // Start iterating again. from position.
355
0
                }
356
0
                Marker::EOI => {
357
0
                    // silent pass
358
0
                }
359
                _ => {
360
0
                    return Err(DecodeErrors::MCUError(format!(
361
0
                        "Marker {marker:?} found in bitstream, possibly corrupt jpeg"
362
0
                    )));
363
                }
364
            }
365
5
        }
366
5
        Ok(())
367
5
    }
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst
Line
Count
Source
342
65.0k
    pub(crate) fn handle_rst(&mut self, stream: &mut BitStream) -> Result<(), DecodeErrors> {
343
65.0k
        self.todo = self.restart_interval;
344
345
65.0k
        if let Some(marker) = stream.marker {
346
            // Found a marker
347
            // Read stream and see what marker is stored there
348
40.6k
            match marker {
349
39.9k
                Marker::RST(_) => {
350
39.9k
                    // reset stream
351
39.9k
                    stream.reset();
352
39.9k
                    // Initialize dc predictions to zero for all components
353
39.9k
                    self.components.iter_mut().for_each(|x| x.dc_pred = 0);
354
39.9k
                    // Start iterating again. from position.
355
39.9k
                }
356
647
                Marker::EOI => {
357
647
                    // silent pass
358
647
                }
359
                _ => {
360
10
                    return Err(DecodeErrors::MCUError(format!(
361
10
                        "Marker {marker:?} found in bitstream, possibly corrupt jpeg"
362
10
                    )));
363
                }
364
            }
365
24.4k
        }
366
65.0k
        Ok(())
367
65.0k
    }
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::handle_rst
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::handle_rst
Line
Count
Source
342
30.7k
    pub(crate) fn handle_rst(&mut self, stream: &mut BitStream) -> Result<(), DecodeErrors> {
343
30.7k
        self.todo = self.restart_interval;
344
345
30.7k
        if let Some(marker) = stream.marker {
346
            // Found a marker
347
            // Read stream and see what marker is stored there
348
19.5k
            match marker {
349
19.5k
                Marker::RST(_) => {
350
19.5k
                    // reset stream
351
19.5k
                    stream.reset();
352
19.5k
                    // Initialize dc predictions to zero for all components
353
19.5k
                    self.components.iter_mut().for_each(|x| x.dc_pred = 0);
354
19.5k
                    // Start iterating again. from position.
355
19.5k
                }
356
13
                Marker::EOI => {
357
13
                    // silent pass
358
13
                }
359
                _ => {
360
13
                    return Err(DecodeErrors::MCUError(format!(
361
13
                        "Marker {marker:?} found in bitstream, possibly corrupt jpeg"
362
13
                    )));
363
                }
364
            }
365
11.1k
        }
366
30.6k
        Ok(())
367
30.7k
    }
368
    #[allow(clippy::too_many_lines, clippy::too_many_arguments)]
369
489k
    pub(crate) fn post_process(
370
489k
        &mut self, pixels: &mut [u8], i: usize, mcu_height: usize, width: usize,
371
489k
        padded_width: usize, pixels_written: &mut usize, upsampler_scratch_space: &mut [i16]
372
489k
    ) -> Result<(), DecodeErrors> {
373
489k
        let out_colorspace_components = self.options.jpeg_get_out_colorspace().num_components();
374
489k
375
489k
        let mut px = *pixels_written;
376
489k
        // indicates whether image is vertically up-sampled
377
489k
        let is_vertically_sampled = self
378
489k
            .components
379
489k
            .iter()
380
726k
            .any(|c| c.sample_ratio == SampleRatios::HV || c.sample_ratio == SampleRatios::V);
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::post_process::{closure#0}
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0}
Line
Count
Source
380
94.6k
            .any(|c| c.sample_ratio == SampleRatios::HV || c.sample_ratio == SampleRatios::V);
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0}
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0}
Line
Count
Source
380
180k
            .any(|c| c.sample_ratio == SampleRatios::HV || c.sample_ratio == SampleRatios::V);
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0}
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#0}
Line
Count
Source
380
851
            .any(|c| c.sample_ratio == SampleRatios::HV || c.sample_ratio == SampleRatios::V);
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#0}
Line
Count
Source
380
450k
            .any(|c| c.sample_ratio == SampleRatios::HV || c.sample_ratio == SampleRatios::V);
381
489k
382
489k
        let mut comp_len = self.components.len();
383
489k
384
489k
        // If we are moving from YCbCr-> Luma, we do not allocate storage for other components, so we
385
489k
        // will panic when we are trying to read samples, so for that case,
386
489k
        // hardcode it so that we  don't panic when doing
387
489k
        //   *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width]
388
489k
        if out_colorspace_components < comp_len && self.options.jpeg_get_out_colorspace() == Luma {
389
0
            comp_len = out_colorspace_components;
390
489k
        }
391
489k
        let mut color_conv_function =
392
542k
            |num_iters: usize, samples: [&[i16]; 4]| -> Result<(), DecodeErrors> {
393
4.36M
                for (pos, output) in pixels[px..]
394
542k
                    .chunks_exact_mut(width * out_colorspace_components)
395
542k
                    .take(num_iters)
396
542k
                    .enumerate()
397
                {
398
4.36M
                    let mut raw_samples: [&[i16]; 4] = [&[], &[], &[], &[]];
399
400
                    // iterate over each line, since color-convert needs only
401
                    // one line
402
7.73M
                    for (j, samp) in raw_samples.iter_mut().enumerate().take(comp_len) {
403
7.73M
                        *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width];
404
7.73M
                    }
405
4.36M
                    color_convert(
406
4.36M
                        &raw_samples,
407
4.36M
                        self.color_convert_16,
408
4.36M
                        self.input_colorspace,
409
4.36M
                        self.options.jpeg_get_out_colorspace(),
410
4.36M
                        output,
411
4.36M
                        width,
412
4.36M
                        padded_width
413
4.36M
                    )?;
414
4.36M
                    px += width * out_colorspace_components;
415
                }
416
542k
                Ok(())
417
542k
            };
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::post_process::{closure#1}
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1}
Line
Count
Source
392
94.6k
            |num_iters: usize, samples: [&[i16]; 4]| -> Result<(), DecodeErrors> {
393
756k
                for (pos, output) in pixels[px..]
394
94.6k
                    .chunks_exact_mut(width * out_colorspace_components)
395
94.6k
                    .take(num_iters)
396
94.6k
                    .enumerate()
397
                {
398
756k
                    let mut raw_samples: [&[i16]; 4] = [&[], &[], &[], &[]];
399
400
                    // iterate over each line, since color-convert needs only
401
                    // one line
402
756k
                    for (j, samp) in raw_samples.iter_mut().enumerate().take(comp_len) {
403
756k
                        *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width];
404
756k
                    }
405
756k
                    color_convert(
406
756k
                        &raw_samples,
407
756k
                        self.color_convert_16,
408
756k
                        self.input_colorspace,
409
756k
                        self.options.jpeg_get_out_colorspace(),
410
756k
                        output,
411
756k
                        width,
412
756k
                        padded_width
413
756k
                    )?;
414
756k
                    px += width * out_colorspace_components;
415
                }
416
94.6k
                Ok(())
417
94.6k
            };
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1}
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1}
Line
Count
Source
392
180k
            |num_iters: usize, samples: [&[i16]; 4]| -> Result<(), DecodeErrors> {
393
1.46M
                for (pos, output) in pixels[px..]
394
180k
                    .chunks_exact_mut(width * out_colorspace_components)
395
180k
                    .take(num_iters)
396
180k
                    .enumerate()
397
                {
398
1.46M
                    let mut raw_samples: [&[i16]; 4] = [&[], &[], &[], &[]];
399
400
                    // iterate over each line, since color-convert needs only
401
                    // one line
402
2.43M
                    for (j, samp) in raw_samples.iter_mut().enumerate().take(comp_len) {
403
2.43M
                        *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width];
404
2.43M
                    }
405
1.46M
                    color_convert(
406
1.46M
                        &raw_samples,
407
1.46M
                        self.color_convert_16,
408
1.46M
                        self.input_colorspace,
409
1.46M
                        self.options.jpeg_get_out_colorspace(),
410
1.46M
                        output,
411
1.46M
                        width,
412
1.46M
                        padded_width
413
1.46M
                    )?;
414
1.46M
                    px += width * out_colorspace_components;
415
                }
416
180k
                Ok(())
417
180k
            };
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1}
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#1}
Line
Count
Source
392
851
            |num_iters: usize, samples: [&[i16]; 4]| -> Result<(), DecodeErrors> {
393
6.70k
                for (pos, output) in pixels[px..]
394
851
                    .chunks_exact_mut(width * out_colorspace_components)
395
851
                    .take(num_iters)
396
851
                    .enumerate()
397
                {
398
6.70k
                    let mut raw_samples: [&[i16]; 4] = [&[], &[], &[], &[]];
399
400
                    // iterate over each line, since color-convert needs only
401
                    // one line
402
6.70k
                    for (j, samp) in raw_samples.iter_mut().enumerate().take(comp_len) {
403
6.70k
                        *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width];
404
6.70k
                    }
405
6.70k
                    color_convert(
406
6.70k
                        &raw_samples,
407
6.70k
                        self.color_convert_16,
408
6.70k
                        self.input_colorspace,
409
6.70k
                        self.options.jpeg_get_out_colorspace(),
410
6.70k
                        output,
411
6.70k
                        width,
412
6.70k
                        padded_width
413
6.70k
                    )?;
414
6.70k
                    px += width * out_colorspace_components;
415
                }
416
851
                Ok(())
417
851
            };
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#1}
Line
Count
Source
392
266k
            |num_iters: usize, samples: [&[i16]; 4]| -> Result<(), DecodeErrors> {
393
2.13M
                for (pos, output) in pixels[px..]
394
266k
                    .chunks_exact_mut(width * out_colorspace_components)
395
266k
                    .take(num_iters)
396
266k
                    .enumerate()
397
                {
398
2.13M
                    let mut raw_samples: [&[i16]; 4] = [&[], &[], &[], &[]];
399
400
                    // iterate over each line, since color-convert needs only
401
                    // one line
402
4.53M
                    for (j, samp) in raw_samples.iter_mut().enumerate().take(comp_len) {
403
4.53M
                        *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width];
404
4.53M
                    }
405
2.13M
                    color_convert(
406
2.13M
                        &raw_samples,
407
2.13M
                        self.color_convert_16,
408
2.13M
                        self.input_colorspace,
409
2.13M
                        self.options.jpeg_get_out_colorspace(),
410
2.13M
                        output,
411
2.13M
                        width,
412
2.13M
                        padded_width
413
2.13M
                    )?;
414
2.13M
                    px += width * out_colorspace_components;
415
                }
416
266k
                Ok(())
417
266k
            };
418
419
489k
        let comps = &mut self.components[..];
420
489k
421
489k
        if self.is_interleaved && self.options.jpeg_get_out_colorspace() != ColorSpace::Luma {
422
            {
423
                // duplicated so that we can check that samples match
424
                // Fixes bug https://github.com/etemesi254/zune-image/issues/151
425
82.3k
                let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]];
426
427
247k
                for (samp, component) in samples.iter_mut().zip(comps.iter()) {
428
247k
                    *samp = if component.sample_ratio == SampleRatios::None {
429
81.7k
                        &component.raw_coeff
430
                    } else {
431
166k
                        &component.upsample_dest
432
                    };
433
                }
434
            }
435
247k
            for comp in comps.iter_mut() {
436
247k
                upsample(
437
247k
                    comp,
438
247k
                    mcu_height,
439
247k
                    i,
440
247k
                    upsampler_scratch_space,
441
247k
                    is_vertically_sampled
442
247k
                );
443
247k
            }
444
445
82.3k
            if is_vertically_sampled {
446
53.4k
                if i > 0 {
447
                    // write the last line, it wasn't  up-sampled as we didn't have row_down
448
                    // yet
449
52.7k
                    let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]];
450
451
158k
                    for (samp, component) in samples.iter_mut().zip(comps.iter()) {
452
158k
                        *samp = &component.first_row_upsample_dest;
453
158k
                    }
454
455
                    // ensure length matches for all samples
456
52.7k
                    let _first_len = samples[0].len();
457
52.7k
458
52.7k
                    // This was a good check, but can be caused to panic, esp on invalid/corrupt images.
459
52.7k
                    // See one in issue https://github.com/etemesi254/zune-image/issues/262, so for now
460
52.7k
                    // we just ignore and generate invalid images at the end.
461
52.7k
462
52.7k
                    //
463
52.7k
                    //
464
52.7k
                    // for samp in samples.iter().take(comp_len) {
465
52.7k
                    //     assert_eq!(first_len, samp.len());
466
52.7k
                    // }
467
52.7k
                    let num_iters = self.coeff * self.v_max;
468
52.7k
469
52.7k
                    color_conv_function(num_iters, samples)?;
470
761
                }
471
472
                // After up-sampling the last row, save  any row that can be used for
473
                // a later up-sampling,
474
                //
475
                // E.g the Y sample is not sampled but we haven't finished upsampling the last row of
476
                // the previous mcu, since we don't have the down row, so save it
477
160k
                for component in comps.iter_mut() {
478
160k
                    if component.sample_ratio != SampleRatios::H {
479
152k
                        // We don't care about H sampling factors, since it's copied in the workers function
480
152k
481
152k
                        // copy last row to be used for the  next color conversion
482
152k
                        let size = component.vertical_sample
483
152k
                            * component.width_stride
484
152k
                            * component.sample_ratio.sample();
485
152k
486
152k
                        let last_bytes =
487
152k
                            component.raw_coeff.rchunks_exact_mut(size).next().unwrap();
488
152k
489
152k
                        component
490
152k
                            .first_row_upsample_dest
491
152k
                            .copy_from_slice(last_bytes);
492
152k
                    }
493
                }
494
28.8k
            }
495
496
82.3k
            let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]];
497
498
247k
            for (samp, component) in samples.iter_mut().zip(comps.iter()) {
499
247k
                *samp = if component.sample_ratio == SampleRatios::None {
500
81.7k
                    &component.raw_coeff
501
                } else {
502
166k
                    &component.upsample_dest
503
                };
504
            }
505
506
            // we either do 7 or 8 MCU's depending on the state, this only applies to
507
            // vertically sampled images
508
            //
509
            // for rows up until the last MCU, we do not upsample the last stride of the MCU
510
            // which means that the number of iterations should take that into account is one less the
511
            // up-sampled size
512
            //
513
            // For the last MCU, we upsample the last stride, meaning that if we hit the last MCU, we
514
            // should sample full raw coeffs
515
82.3k
            let is_last_considered = is_vertically_sampled && (i != mcu_height.saturating_sub(1));
516
517
82.3k
            let num_iters = (8 - usize::from(is_last_considered)) * self.coeff * self.v_max;
518
82.3k
519
82.3k
            color_conv_function(num_iters, samples)?;
520
        } else {
521
407k
            let mut channels_ref: [&[i16]; MAX_COMPONENTS] = [&[]; MAX_COMPONENTS];
522
407k
523
407k
            self.components
524
407k
                .iter()
525
407k
                .enumerate()
526
550k
                .for_each(|(pos, x)| channels_ref[pos] = &x.raw_coeff);
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::post_process::{closure#2}
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2}
Line
Count
Source
526
94.6k
                .for_each(|(pos, x)| channels_ref[pos] = &x.raw_coeff);
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2}
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2}
Line
Count
Source
526
127k
                .for_each(|(pos, x)| channels_ref[pos] = &x.raw_coeff);
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2}
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2}
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process::{closure#2}
Line
Count
Source
526
851
                .for_each(|(pos, x)| channels_ref[pos] = &x.raw_coeff);
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process::{closure#2}
Line
Count
Source
526
327k
                .for_each(|(pos, x)| channels_ref[pos] = &x.raw_coeff);
527
407k
528
407k
            color_conv_function(8 * self.coeff, channels_ref)?;
529
        }
530
531
489k
        *pixels_written = px;
532
489k
        Ok(())
533
489k
    }
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<_>>::post_process
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process
Line
Count
Source
369
94.6k
    pub(crate) fn post_process(
370
94.6k
        &mut self, pixels: &mut [u8], i: usize, mcu_height: usize, width: usize,
371
94.6k
        padded_width: usize, pixels_written: &mut usize, upsampler_scratch_space: &mut [i16]
372
94.6k
    ) -> Result<(), DecodeErrors> {
373
94.6k
        let out_colorspace_components = self.options.jpeg_get_out_colorspace().num_components();
374
94.6k
375
94.6k
        let mut px = *pixels_written;
376
94.6k
        // indicates whether image is vertically up-sampled
377
94.6k
        let is_vertically_sampled = self
378
94.6k
            .components
379
94.6k
            .iter()
380
94.6k
            .any(|c| c.sample_ratio == SampleRatios::HV || c.sample_ratio == SampleRatios::V);
381
94.6k
382
94.6k
        let mut comp_len = self.components.len();
383
94.6k
384
94.6k
        // If we are moving from YCbCr-> Luma, we do not allocate storage for other components, so we
385
94.6k
        // will panic when we are trying to read samples, so for that case,
386
94.6k
        // hardcode it so that we  don't panic when doing
387
94.6k
        //   *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width]
388
94.6k
        if out_colorspace_components < comp_len && self.options.jpeg_get_out_colorspace() == Luma {
389
0
            comp_len = out_colorspace_components;
390
94.6k
        }
391
94.6k
        let mut color_conv_function =
392
            |num_iters: usize, samples: [&[i16]; 4]| -> Result<(), DecodeErrors> {
393
                for (pos, output) in pixels[px..]
394
                    .chunks_exact_mut(width * out_colorspace_components)
395
                    .take(num_iters)
396
                    .enumerate()
397
                {
398
                    let mut raw_samples: [&[i16]; 4] = [&[], &[], &[], &[]];
399
400
                    // iterate over each line, since color-convert needs only
401
                    // one line
402
                    for (j, samp) in raw_samples.iter_mut().enumerate().take(comp_len) {
403
                        *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width];
404
                    }
405
                    color_convert(
406
                        &raw_samples,
407
                        self.color_convert_16,
408
                        self.input_colorspace,
409
                        self.options.jpeg_get_out_colorspace(),
410
                        output,
411
                        width,
412
                        padded_width
413
                    )?;
414
                    px += width * out_colorspace_components;
415
                }
416
                Ok(())
417
            };
418
419
94.6k
        let comps = &mut self.components[..];
420
94.6k
421
94.6k
        if self.is_interleaved && self.options.jpeg_get_out_colorspace() != ColorSpace::Luma {
422
            {
423
                // duplicated so that we can check that samples match
424
                // Fixes bug https://github.com/etemesi254/zune-image/issues/151
425
0
                let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]];
426
427
0
                for (samp, component) in samples.iter_mut().zip(comps.iter()) {
428
0
                    *samp = if component.sample_ratio == SampleRatios::None {
429
0
                        &component.raw_coeff
430
                    } else {
431
0
                        &component.upsample_dest
432
                    };
433
                }
434
            }
435
0
            for comp in comps.iter_mut() {
436
0
                upsample(
437
0
                    comp,
438
0
                    mcu_height,
439
0
                    i,
440
0
                    upsampler_scratch_space,
441
0
                    is_vertically_sampled
442
0
                );
443
0
            }
444
445
0
            if is_vertically_sampled {
446
0
                if i > 0 {
447
                    // write the last line, it wasn't  up-sampled as we didn't have row_down
448
                    // yet
449
0
                    let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]];
450
451
0
                    for (samp, component) in samples.iter_mut().zip(comps.iter()) {
452
0
                        *samp = &component.first_row_upsample_dest;
453
0
                    }
454
455
                    // ensure length matches for all samples
456
0
                    let _first_len = samples[0].len();
457
0
458
0
                    // This was a good check, but can be caused to panic, esp on invalid/corrupt images.
459
0
                    // See one in issue https://github.com/etemesi254/zune-image/issues/262, so for now
460
0
                    // we just ignore and generate invalid images at the end.
461
0
462
0
                    //
463
0
                    //
464
0
                    // for samp in samples.iter().take(comp_len) {
465
0
                    //     assert_eq!(first_len, samp.len());
466
0
                    // }
467
0
                    let num_iters = self.coeff * self.v_max;
468
0
469
0
                    color_conv_function(num_iters, samples)?;
470
0
                }
471
472
                // After up-sampling the last row, save  any row that can be used for
473
                // a later up-sampling,
474
                //
475
                // E.g the Y sample is not sampled but we haven't finished upsampling the last row of
476
                // the previous mcu, since we don't have the down row, so save it
477
0
                for component in comps.iter_mut() {
478
0
                    if component.sample_ratio != SampleRatios::H {
479
0
                        // We don't care about H sampling factors, since it's copied in the workers function
480
0
481
0
                        // copy last row to be used for the  next color conversion
482
0
                        let size = component.vertical_sample
483
0
                            * component.width_stride
484
0
                            * component.sample_ratio.sample();
485
0
486
0
                        let last_bytes =
487
0
                            component.raw_coeff.rchunks_exact_mut(size).next().unwrap();
488
0
489
0
                        component
490
0
                            .first_row_upsample_dest
491
0
                            .copy_from_slice(last_bytes);
492
0
                    }
493
                }
494
0
            }
495
496
0
            let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]];
497
498
0
            for (samp, component) in samples.iter_mut().zip(comps.iter()) {
499
0
                *samp = if component.sample_ratio == SampleRatios::None {
500
0
                    &component.raw_coeff
501
                } else {
502
0
                    &component.upsample_dest
503
                };
504
            }
505
506
            // we either do 7 or 8 MCU's depending on the state, this only applies to
507
            // vertically sampled images
508
            //
509
            // for rows up until the last MCU, we do not upsample the last stride of the MCU
510
            // which means that the number of iterations should take that into account is one less the
511
            // up-sampled size
512
            //
513
            // For the last MCU, we upsample the last stride, meaning that if we hit the last MCU, we
514
            // should sample full raw coeffs
515
0
            let is_last_considered = is_vertically_sampled && (i != mcu_height.saturating_sub(1));
516
517
0
            let num_iters = (8 - usize::from(is_last_considered)) * self.coeff * self.v_max;
518
0
519
0
            color_conv_function(num_iters, samples)?;
520
        } else {
521
94.6k
            let mut channels_ref: [&[i16]; MAX_COMPONENTS] = [&[]; MAX_COMPONENTS];
522
94.6k
523
94.6k
            self.components
524
94.6k
                .iter()
525
94.6k
                .enumerate()
526
94.6k
                .for_each(|(pos, x)| channels_ref[pos] = &x.raw_coeff);
527
94.6k
528
94.6k
            color_conv_function(8 * self.coeff, channels_ref)?;
529
        }
530
531
94.6k
        *pixels_written = px;
532
94.6k
        Ok(())
533
94.6k
    }
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process
Line
Count
Source
369
154k
    pub(crate) fn post_process(
370
154k
        &mut self, pixels: &mut [u8], i: usize, mcu_height: usize, width: usize,
371
154k
        padded_width: usize, pixels_written: &mut usize, upsampler_scratch_space: &mut [i16]
372
154k
    ) -> Result<(), DecodeErrors> {
373
154k
        let out_colorspace_components = self.options.jpeg_get_out_colorspace().num_components();
374
154k
375
154k
        let mut px = *pixels_written;
376
154k
        // indicates whether image is vertically up-sampled
377
154k
        let is_vertically_sampled = self
378
154k
            .components
379
154k
            .iter()
380
154k
            .any(|c| c.sample_ratio == SampleRatios::HV || c.sample_ratio == SampleRatios::V);
381
154k
382
154k
        let mut comp_len = self.components.len();
383
154k
384
154k
        // If we are moving from YCbCr-> Luma, we do not allocate storage for other components, so we
385
154k
        // will panic when we are trying to read samples, so for that case,
386
154k
        // hardcode it so that we  don't panic when doing
387
154k
        //   *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width]
388
154k
        if out_colorspace_components < comp_len && self.options.jpeg_get_out_colorspace() == Luma {
389
0
            comp_len = out_colorspace_components;
390
154k
        }
391
154k
        let mut color_conv_function =
392
            |num_iters: usize, samples: [&[i16]; 4]| -> Result<(), DecodeErrors> {
393
                for (pos, output) in pixels[px..]
394
                    .chunks_exact_mut(width * out_colorspace_components)
395
                    .take(num_iters)
396
                    .enumerate()
397
                {
398
                    let mut raw_samples: [&[i16]; 4] = [&[], &[], &[], &[]];
399
400
                    // iterate over each line, since color-convert needs only
401
                    // one line
402
                    for (j, samp) in raw_samples.iter_mut().enumerate().take(comp_len) {
403
                        *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width];
404
                    }
405
                    color_convert(
406
                        &raw_samples,
407
                        self.color_convert_16,
408
                        self.input_colorspace,
409
                        self.options.jpeg_get_out_colorspace(),
410
                        output,
411
                        width,
412
                        padded_width
413
                    )?;
414
                    px += width * out_colorspace_components;
415
                }
416
                Ok(())
417
            };
418
419
154k
        let comps = &mut self.components[..];
420
154k
421
154k
        if self.is_interleaved && self.options.jpeg_get_out_colorspace() != ColorSpace::Luma {
422
            {
423
                // duplicated so that we can check that samples match
424
                // Fixes bug https://github.com/etemesi254/zune-image/issues/151
425
30.6k
                let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]];
426
427
91.9k
                for (samp, component) in samples.iter_mut().zip(comps.iter()) {
428
91.9k
                    *samp = if component.sample_ratio == SampleRatios::None {
429
35.5k
                        &component.raw_coeff
430
                    } else {
431
56.4k
                        &component.upsample_dest
432
                    };
433
                }
434
            }
435
91.9k
            for comp in comps.iter_mut() {
436
91.9k
                upsample(
437
91.9k
                    comp,
438
91.9k
                    mcu_height,
439
91.9k
                    i,
440
91.9k
                    upsampler_scratch_space,
441
91.9k
                    is_vertically_sampled
442
91.9k
                );
443
91.9k
            }
444
445
30.6k
            if is_vertically_sampled {
446
26.4k
                if i > 0 {
447
                    // write the last line, it wasn't  up-sampled as we didn't have row_down
448
                    // yet
449
25.8k
                    let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]];
450
451
77.5k
                    for (samp, component) in samples.iter_mut().zip(comps.iter()) {
452
77.5k
                        *samp = &component.first_row_upsample_dest;
453
77.5k
                    }
454
455
                    // ensure length matches for all samples
456
25.8k
                    let _first_len = samples[0].len();
457
25.8k
458
25.8k
                    // This was a good check, but can be caused to panic, esp on invalid/corrupt images.
459
25.8k
                    // See one in issue https://github.com/etemesi254/zune-image/issues/262, so for now
460
25.8k
                    // we just ignore and generate invalid images at the end.
461
25.8k
462
25.8k
                    //
463
25.8k
                    //
464
25.8k
                    // for samp in samples.iter().take(comp_len) {
465
25.8k
                    //     assert_eq!(first_len, samp.len());
466
25.8k
                    // }
467
25.8k
                    let num_iters = self.coeff * self.v_max;
468
25.8k
469
25.8k
                    color_conv_function(num_iters, samples)?;
470
613
                }
471
472
                // After up-sampling the last row, save  any row that can be used for
473
                // a later up-sampling,
474
                //
475
                // E.g the Y sample is not sampled but we haven't finished upsampling the last row of
476
                // the previous mcu, since we don't have the down row, so save it
477
79.4k
                for component in comps.iter_mut() {
478
79.4k
                    if component.sample_ratio != SampleRatios::H {
479
77.3k
                        // We don't care about H sampling factors, since it's copied in the workers function
480
77.3k
481
77.3k
                        // copy last row to be used for the  next color conversion
482
77.3k
                        let size = component.vertical_sample
483
77.3k
                            * component.width_stride
484
77.3k
                            * component.sample_ratio.sample();
485
77.3k
486
77.3k
                        let last_bytes =
487
77.3k
                            component.raw_coeff.rchunks_exact_mut(size).next().unwrap();
488
77.3k
489
77.3k
                        component
490
77.3k
                            .first_row_upsample_dest
491
77.3k
                            .copy_from_slice(last_bytes);
492
77.3k
                    }
493
                }
494
4.17k
            }
495
496
30.6k
            let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]];
497
498
91.9k
            for (samp, component) in samples.iter_mut().zip(comps.iter()) {
499
91.9k
                *samp = if component.sample_ratio == SampleRatios::None {
500
35.5k
                    &component.raw_coeff
501
                } else {
502
56.4k
                    &component.upsample_dest
503
                };
504
            }
505
506
            // we either do 7 or 8 MCU's depending on the state, this only applies to
507
            // vertically sampled images
508
            //
509
            // for rows up until the last MCU, we do not upsample the last stride of the MCU
510
            // which means that the number of iterations should take that into account is one less the
511
            // up-sampled size
512
            //
513
            // For the last MCU, we upsample the last stride, meaning that if we hit the last MCU, we
514
            // should sample full raw coeffs
515
30.6k
            let is_last_considered = is_vertically_sampled && (i != mcu_height.saturating_sub(1));
516
517
30.6k
            let num_iters = (8 - usize::from(is_last_considered)) * self.coeff * self.v_max;
518
30.6k
519
30.6k
            color_conv_function(num_iters, samples)?;
520
        } else {
521
124k
            let mut channels_ref: [&[i16]; MAX_COMPONENTS] = [&[]; MAX_COMPONENTS];
522
124k
523
124k
            self.components
524
124k
                .iter()
525
124k
                .enumerate()
526
124k
                .for_each(|(pos, x)| channels_ref[pos] = &x.raw_coeff);
527
124k
528
124k
            color_conv_function(8 * self.coeff, channels_ref)?;
529
        }
530
531
154k
        *pixels_written = px;
532
154k
        Ok(())
533
154k
    }
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process
Unexecuted instantiation: <zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process
<zune_jpeg::decoder::JpegDecoder<alloc::vec::Vec<u8>>>::post_process
Line
Count
Source
369
851
    pub(crate) fn post_process(
370
851
        &mut self, pixels: &mut [u8], i: usize, mcu_height: usize, width: usize,
371
851
        padded_width: usize, pixels_written: &mut usize, upsampler_scratch_space: &mut [i16]
372
851
    ) -> Result<(), DecodeErrors> {
373
851
        let out_colorspace_components = self.options.jpeg_get_out_colorspace().num_components();
374
851
375
851
        let mut px = *pixels_written;
376
851
        // indicates whether image is vertically up-sampled
377
851
        let is_vertically_sampled = self
378
851
            .components
379
851
            .iter()
380
851
            .any(|c| c.sample_ratio == SampleRatios::HV || c.sample_ratio == SampleRatios::V);
381
851
382
851
        let mut comp_len = self.components.len();
383
851
384
851
        // If we are moving from YCbCr-> Luma, we do not allocate storage for other components, so we
385
851
        // will panic when we are trying to read samples, so for that case,
386
851
        // hardcode it so that we  don't panic when doing
387
851
        //   *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width]
388
851
        if out_colorspace_components < comp_len && self.options.jpeg_get_out_colorspace() == Luma {
389
0
            comp_len = out_colorspace_components;
390
851
        }
391
851
        let mut color_conv_function =
392
            |num_iters: usize, samples: [&[i16]; 4]| -> Result<(), DecodeErrors> {
393
                for (pos, output) in pixels[px..]
394
                    .chunks_exact_mut(width * out_colorspace_components)
395
                    .take(num_iters)
396
                    .enumerate()
397
                {
398
                    let mut raw_samples: [&[i16]; 4] = [&[], &[], &[], &[]];
399
400
                    // iterate over each line, since color-convert needs only
401
                    // one line
402
                    for (j, samp) in raw_samples.iter_mut().enumerate().take(comp_len) {
403
                        *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width];
404
                    }
405
                    color_convert(
406
                        &raw_samples,
407
                        self.color_convert_16,
408
                        self.input_colorspace,
409
                        self.options.jpeg_get_out_colorspace(),
410
                        output,
411
                        width,
412
                        padded_width
413
                    )?;
414
                    px += width * out_colorspace_components;
415
                }
416
                Ok(())
417
            };
418
419
851
        let comps = &mut self.components[..];
420
851
421
851
        if self.is_interleaved && self.options.jpeg_get_out_colorspace() != ColorSpace::Luma {
422
            {
423
                // duplicated so that we can check that samples match
424
                // Fixes bug https://github.com/etemesi254/zune-image/issues/151
425
0
                let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]];
426
427
0
                for (samp, component) in samples.iter_mut().zip(comps.iter()) {
428
0
                    *samp = if component.sample_ratio == SampleRatios::None {
429
0
                        &component.raw_coeff
430
                    } else {
431
0
                        &component.upsample_dest
432
                    };
433
                }
434
            }
435
0
            for comp in comps.iter_mut() {
436
0
                upsample(
437
0
                    comp,
438
0
                    mcu_height,
439
0
                    i,
440
0
                    upsampler_scratch_space,
441
0
                    is_vertically_sampled
442
0
                );
443
0
            }
444
445
0
            if is_vertically_sampled {
446
0
                if i > 0 {
447
                    // write the last line, it wasn't  up-sampled as we didn't have row_down
448
                    // yet
449
0
                    let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]];
450
451
0
                    for (samp, component) in samples.iter_mut().zip(comps.iter()) {
452
0
                        *samp = &component.first_row_upsample_dest;
453
0
                    }
454
455
                    // ensure length matches for all samples
456
0
                    let _first_len = samples[0].len();
457
0
458
0
                    // This was a good check, but can be caused to panic, esp on invalid/corrupt images.
459
0
                    // See one in issue https://github.com/etemesi254/zune-image/issues/262, so for now
460
0
                    // we just ignore and generate invalid images at the end.
461
0
462
0
                    //
463
0
                    //
464
0
                    // for samp in samples.iter().take(comp_len) {
465
0
                    //     assert_eq!(first_len, samp.len());
466
0
                    // }
467
0
                    let num_iters = self.coeff * self.v_max;
468
0
469
0
                    color_conv_function(num_iters, samples)?;
470
0
                }
471
472
                // After up-sampling the last row, save  any row that can be used for
473
                // a later up-sampling,
474
                //
475
                // E.g the Y sample is not sampled but we haven't finished upsampling the last row of
476
                // the previous mcu, since we don't have the down row, so save it
477
0
                for component in comps.iter_mut() {
478
0
                    if component.sample_ratio != SampleRatios::H {
479
0
                        // We don't care about H sampling factors, since it's copied in the workers function
480
0
481
0
                        // copy last row to be used for the  next color conversion
482
0
                        let size = component.vertical_sample
483
0
                            * component.width_stride
484
0
                            * component.sample_ratio.sample();
485
0
486
0
                        let last_bytes =
487
0
                            component.raw_coeff.rchunks_exact_mut(size).next().unwrap();
488
0
489
0
                        component
490
0
                            .first_row_upsample_dest
491
0
                            .copy_from_slice(last_bytes);
492
0
                    }
493
                }
494
0
            }
495
496
0
            let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]];
497
498
0
            for (samp, component) in samples.iter_mut().zip(comps.iter()) {
499
0
                *samp = if component.sample_ratio == SampleRatios::None {
500
0
                    &component.raw_coeff
501
                } else {
502
0
                    &component.upsample_dest
503
                };
504
            }
505
506
            // we either do 7 or 8 MCU's depending on the state, this only applies to
507
            // vertically sampled images
508
            //
509
            // for rows up until the last MCU, we do not upsample the last stride of the MCU
510
            // which means that the number of iterations should take that into account is one less the
511
            // up-sampled size
512
            //
513
            // For the last MCU, we upsample the last stride, meaning that if we hit the last MCU, we
514
            // should sample full raw coeffs
515
0
            let is_last_considered = is_vertically_sampled && (i != mcu_height.saturating_sub(1));
516
517
0
            let num_iters = (8 - usize::from(is_last_considered)) * self.coeff * self.v_max;
518
0
519
0
            color_conv_function(num_iters, samples)?;
520
        } else {
521
851
            let mut channels_ref: [&[i16]; MAX_COMPONENTS] = [&[]; MAX_COMPONENTS];
522
851
523
851
            self.components
524
851
                .iter()
525
851
                .enumerate()
526
851
                .for_each(|(pos, x)| channels_ref[pos] = &x.raw_coeff);
527
851
528
851
            color_conv_function(8 * self.coeff, channels_ref)?;
529
        }
530
531
851
        *pixels_written = px;
532
851
        Ok(())
533
851
    }
<zune_jpeg::decoder::JpegDecoder<&[u8]>>::post_process
Line
Count
Source
369
239k
    pub(crate) fn post_process(
370
239k
        &mut self, pixels: &mut [u8], i: usize, mcu_height: usize, width: usize,
371
239k
        padded_width: usize, pixels_written: &mut usize, upsampler_scratch_space: &mut [i16]
372
239k
    ) -> Result<(), DecodeErrors> {
373
239k
        let out_colorspace_components = self.options.jpeg_get_out_colorspace().num_components();
374
239k
375
239k
        let mut px = *pixels_written;
376
239k
        // indicates whether image is vertically up-sampled
377
239k
        let is_vertically_sampled = self
378
239k
            .components
379
239k
            .iter()
380
239k
            .any(|c| c.sample_ratio == SampleRatios::HV || c.sample_ratio == SampleRatios::V);
381
239k
382
239k
        let mut comp_len = self.components.len();
383
239k
384
239k
        // If we are moving from YCbCr-> Luma, we do not allocate storage for other components, so we
385
239k
        // will panic when we are trying to read samples, so for that case,
386
239k
        // hardcode it so that we  don't panic when doing
387
239k
        //   *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width]
388
239k
        if out_colorspace_components < comp_len && self.options.jpeg_get_out_colorspace() == Luma {
389
0
            comp_len = out_colorspace_components;
390
239k
        }
391
239k
        let mut color_conv_function =
392
            |num_iters: usize, samples: [&[i16]; 4]| -> Result<(), DecodeErrors> {
393
                for (pos, output) in pixels[px..]
394
                    .chunks_exact_mut(width * out_colorspace_components)
395
                    .take(num_iters)
396
                    .enumerate()
397
                {
398
                    let mut raw_samples: [&[i16]; 4] = [&[], &[], &[], &[]];
399
400
                    // iterate over each line, since color-convert needs only
401
                    // one line
402
                    for (j, samp) in raw_samples.iter_mut().enumerate().take(comp_len) {
403
                        *samp = &samples[j][pos * padded_width..(pos + 1) * padded_width];
404
                    }
405
                    color_convert(
406
                        &raw_samples,
407
                        self.color_convert_16,
408
                        self.input_colorspace,
409
                        self.options.jpeg_get_out_colorspace(),
410
                        output,
411
                        width,
412
                        padded_width
413
                    )?;
414
                    px += width * out_colorspace_components;
415
                }
416
                Ok(())
417
            };
418
419
239k
        let comps = &mut self.components[..];
420
239k
421
239k
        if self.is_interleaved && self.options.jpeg_get_out_colorspace() != ColorSpace::Luma {
422
            {
423
                // duplicated so that we can check that samples match
424
                // Fixes bug https://github.com/etemesi254/zune-image/issues/151
425
51.6k
                let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]];
426
427
155k
                for (samp, component) in samples.iter_mut().zip(comps.iter()) {
428
155k
                    *samp = if component.sample_ratio == SampleRatios::None {
429
46.2k
                        &component.raw_coeff
430
                    } else {
431
109k
                        &component.upsample_dest
432
                    };
433
                }
434
            }
435
155k
            for comp in comps.iter_mut() {
436
155k
                upsample(
437
155k
                    comp,
438
155k
                    mcu_height,
439
155k
                    i,
440
155k
                    upsampler_scratch_space,
441
155k
                    is_vertically_sampled
442
155k
                );
443
155k
            }
444
445
51.6k
            if is_vertically_sampled {
446
27.0k
                if i > 0 {
447
                    // write the last line, it wasn't  up-sampled as we didn't have row_down
448
                    // yet
449
26.8k
                    let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]];
450
451
80.8k
                    for (samp, component) in samples.iter_mut().zip(comps.iter()) {
452
80.8k
                        *samp = &component.first_row_upsample_dest;
453
80.8k
                    }
454
455
                    // ensure length matches for all samples
456
26.8k
                    let _first_len = samples[0].len();
457
26.8k
458
26.8k
                    // This was a good check, but can be caused to panic, esp on invalid/corrupt images.
459
26.8k
                    // See one in issue https://github.com/etemesi254/zune-image/issues/262, so for now
460
26.8k
                    // we just ignore and generate invalid images at the end.
461
26.8k
462
26.8k
                    //
463
26.8k
                    //
464
26.8k
                    // for samp in samples.iter().take(comp_len) {
465
26.8k
                    //     assert_eq!(first_len, samp.len());
466
26.8k
                    // }
467
26.8k
                    let num_iters = self.coeff * self.v_max;
468
26.8k
469
26.8k
                    color_conv_function(num_iters, samples)?;
470
148
                }
471
472
                // After up-sampling the last row, save  any row that can be used for
473
                // a later up-sampling,
474
                //
475
                // E.g the Y sample is not sampled but we haven't finished upsampling the last row of
476
                // the previous mcu, since we don't have the down row, so save it
477
81.2k
                for component in comps.iter_mut() {
478
81.2k
                    if component.sample_ratio != SampleRatios::H {
479
75.0k
                        // We don't care about H sampling factors, since it's copied in the workers function
480
75.0k
481
75.0k
                        // copy last row to be used for the  next color conversion
482
75.0k
                        let size = component.vertical_sample
483
75.0k
                            * component.width_stride
484
75.0k
                            * component.sample_ratio.sample();
485
75.0k
486
75.0k
                        let last_bytes =
487
75.0k
                            component.raw_coeff.rchunks_exact_mut(size).next().unwrap();
488
75.0k
489
75.0k
                        component
490
75.0k
                            .first_row_upsample_dest
491
75.0k
                            .copy_from_slice(last_bytes);
492
75.0k
                    }
493
                }
494
24.6k
            }
495
496
51.6k
            let mut samples: [&[i16]; 4] = [&[], &[], &[], &[]];
497
498
155k
            for (samp, component) in samples.iter_mut().zip(comps.iter()) {
499
155k
                *samp = if component.sample_ratio == SampleRatios::None {
500
46.2k
                    &component.raw_coeff
501
                } else {
502
109k
                    &component.upsample_dest
503
                };
504
            }
505
506
            // we either do 7 or 8 MCU's depending on the state, this only applies to
507
            // vertically sampled images
508
            //
509
            // for rows up until the last MCU, we do not upsample the last stride of the MCU
510
            // which means that the number of iterations should take that into account is one less the
511
            // up-sampled size
512
            //
513
            // For the last MCU, we upsample the last stride, meaning that if we hit the last MCU, we
514
            // should sample full raw coeffs
515
51.6k
            let is_last_considered = is_vertically_sampled && (i != mcu_height.saturating_sub(1));
516
517
51.6k
            let num_iters = (8 - usize::from(is_last_considered)) * self.coeff * self.v_max;
518
51.6k
519
51.6k
            color_conv_function(num_iters, samples)?;
520
        } else {
521
187k
            let mut channels_ref: [&[i16]; MAX_COMPONENTS] = [&[]; MAX_COMPONENTS];
522
187k
523
187k
            self.components
524
187k
                .iter()
525
187k
                .enumerate()
526
187k
                .for_each(|(pos, x)| channels_ref[pos] = &x.raw_coeff);
527
187k
528
187k
            color_conv_function(8 * self.coeff, channels_ref)?;
529
        }
530
531
239k
        *pixels_written = px;
532
239k
        Ok(())
533
239k
    }
534
}