Coverage Report

Created: 2025-07-11 07:25

/rust/registry/src/index.crates.io-6f17d22bba15001f/zune-jpeg-0.4.19/src/components.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
//! This module exports a single struct to store information about
10
//! JPEG image components
11
//!
12
//! The data is extracted from a SOF header.
13
14
use alloc::vec::Vec;
15
use alloc::{format, vec};
16
17
use zune_core::log::trace;
18
19
use crate::decoder::MAX_COMPONENTS;
20
use crate::errors::DecodeErrors;
21
use crate::upsampler::upsample_no_op;
22
23
/// Represents an up-sampler function, this function will be called to upsample
24
/// a down-sampled image
25
26
pub type UpSampler = fn(
27
    input: &[i16],
28
    in_near: &[i16],
29
    in_far: &[i16],
30
    scratch_space: &mut [i16],
31
    output: &mut [i16]
32
);
33
34
/// Component Data from start of frame
35
#[derive(Clone)]
36
pub(crate) struct Components {
37
    /// The type of component that has the metadata below, can be Y,Cb or Cr
38
    pub component_id: ComponentID,
39
    /// Sub-sampling ratio of this component in the x-plane
40
    pub vertical_sample: usize,
41
    /// Sub-sampling ratio of this component in the y-plane
42
    pub horizontal_sample: usize,
43
    /// DC huffman table position
44
    pub dc_huff_table: usize,
45
    /// AC huffman table position for this element.
46
    pub ac_huff_table: usize,
47
    /// Quantization table number
48
    pub quantization_table_number: u8,
49
    /// Specifies quantization table to use with this component
50
    pub quantization_table: [i32; 64],
51
    /// dc prediction for the component
52
    pub dc_pred: i32,
53
    /// An up-sampling function, can be basic or SSE, depending
54
    /// on the platform
55
    pub up_sampler: UpSampler,
56
    /// How pixels do we need to go to get to the next line?
57
    pub width_stride: usize,
58
    /// Component ID for progressive
59
    pub id: u8,
60
    /// Whether we need to decode this image component.
61
    pub needed: bool,
62
    /// Upsample scanline
63
    pub raw_coeff: Vec<i16>,
64
    /// Upsample destination, stores a scanline worth of sub sampled data
65
    pub upsample_dest: Vec<i16>,
66
    /// previous row, used to handle MCU boundaries
67
    pub row_up: Vec<i16>,
68
    /// current row, used to handle MCU boundaries again
69
    pub row: Vec<i16>,
70
    pub first_row_upsample_dest: Vec<i16>,
71
    pub idct_pos: usize,
72
    pub x: usize,
73
    pub w2: usize,
74
    pub y: usize,
75
    pub sample_ratio: SampleRatios,
76
    // a very annoying bug
77
    pub fix_an_annoying_bug: usize
78
}
79
80
impl Components {
81
    /// Create a new instance from three bytes from the start of frame
82
    #[inline]
83
74
    pub fn from(a: [u8; 3], pos: u8) -> Result<Components, DecodeErrors> {
84
        // it's a unique identifier.
85
        // doesn't have to be ascending
86
        // see tests/inputs/huge_sof_number
87
        //
88
        // For such cases, use the position of the component
89
        // to determine width
90
91
74
        let id = match pos {
92
53
            0 => ComponentID::Y,
93
7
            1 => ComponentID::Cb,
94
7
            2 => ComponentID::Cr,
95
7
            3 => ComponentID::Q,
96
            _ => {
97
0
                return Err(DecodeErrors::Format(format!(
98
0
                    "Unknown component id found,{pos}, expected value between 1 and 4"
99
0
                )))
100
            }
101
        };
102
103
74
        let horizontal_sample = (a[1] >> 4) as usize;
104
74
        let vertical_sample = (a[1] & 0x0f) as usize;
105
74
        let quantization_table_number = a[2];
106
74
        // confirm quantization number is between 0 and MAX_COMPONENTS
107
74
        if usize::from(quantization_table_number) >= MAX_COMPONENTS {
108
1
            return Err(DecodeErrors::Format(format!(
109
1
                "Too large quantization number :{quantization_table_number}, expected value between 0 and {MAX_COMPONENTS}"
110
1
            )));
111
73
        }
112
73
        // check that upsampling ratios are powers of two
113
73
        // if these fail, it's probably a corrupt image.
114
73
        if !horizontal_sample.is_power_of_two() {
115
1
            return Err(DecodeErrors::Format(format!(
116
1
                "Horizontal sample is not a power of two({horizontal_sample}) cannot decode"
117
1
            )));
118
72
        }
119
72
120
72
        if !vertical_sample.is_power_of_two() {
121
0
            return Err(DecodeErrors::Format(format!(
122
0
                "Vertical sub-sample is not power of two({vertical_sample}) cannot decode"
123
0
            )));
124
72
        }
125
72
126
72
        trace!(
127
72
            "Component ID:{:?} \tHS:{} VS:{} QT:{}",
128
72
            id,
129
72
            horizontal_sample,
130
72
            vertical_sample,
131
72
            quantization_table_number
132
72
        );
133
72
134
72
        Ok(Components {
135
72
            component_id: id,
136
72
            vertical_sample,
137
72
            horizontal_sample,
138
72
            quantization_table_number,
139
72
            first_row_upsample_dest: vec![],
140
72
            // These two will be set with sof marker
141
72
            dc_huff_table: 0,
142
72
            ac_huff_table: 0,
143
72
            quantization_table: [0; 64],
144
72
            dc_pred: 0,
145
72
            up_sampler: upsample_no_op,
146
72
            // set later
147
72
            width_stride: horizontal_sample,
148
72
            id: a[0],
149
72
            needed: true,
150
72
            raw_coeff: vec![],
151
72
            upsample_dest: vec![],
152
72
            row_up: vec![],
153
72
            row: vec![],
154
72
            idct_pos: 0,
155
72
            x: 0,
156
72
            y: 0,
157
72
            w2: 0,
158
72
            sample_ratio: SampleRatios::None,
159
72
            fix_an_annoying_bug: 1
160
72
        })
161
74
    }
Unexecuted instantiation: <zune_jpeg::components::Components>::from
Unexecuted instantiation: <zune_jpeg::components::Components>::from
<zune_jpeg::components::Components>::from
Line
Count
Source
83
74
    pub fn from(a: [u8; 3], pos: u8) -> Result<Components, DecodeErrors> {
84
        // it's a unique identifier.
85
        // doesn't have to be ascending
86
        // see tests/inputs/huge_sof_number
87
        //
88
        // For such cases, use the position of the component
89
        // to determine width
90
91
74
        let id = match pos {
92
53
            0 => ComponentID::Y,
93
7
            1 => ComponentID::Cb,
94
7
            2 => ComponentID::Cr,
95
7
            3 => ComponentID::Q,
96
            _ => {
97
0
                return Err(DecodeErrors::Format(format!(
98
0
                    "Unknown component id found,{pos}, expected value between 1 and 4"
99
0
                )))
100
            }
101
        };
102
103
74
        let horizontal_sample = (a[1] >> 4) as usize;
104
74
        let vertical_sample = (a[1] & 0x0f) as usize;
105
74
        let quantization_table_number = a[2];
106
74
        // confirm quantization number is between 0 and MAX_COMPONENTS
107
74
        if usize::from(quantization_table_number) >= MAX_COMPONENTS {
108
1
            return Err(DecodeErrors::Format(format!(
109
1
                "Too large quantization number :{quantization_table_number}, expected value between 0 and {MAX_COMPONENTS}"
110
1
            )));
111
73
        }
112
73
        // check that upsampling ratios are powers of two
113
73
        // if these fail, it's probably a corrupt image.
114
73
        if !horizontal_sample.is_power_of_two() {
115
1
            return Err(DecodeErrors::Format(format!(
116
1
                "Horizontal sample is not a power of two({horizontal_sample}) cannot decode"
117
1
            )));
118
72
        }
119
72
120
72
        if !vertical_sample.is_power_of_two() {
121
0
            return Err(DecodeErrors::Format(format!(
122
0
                "Vertical sub-sample is not power of two({vertical_sample}) cannot decode"
123
0
            )));
124
72
        }
125
72
126
72
        trace!(
127
72
            "Component ID:{:?} \tHS:{} VS:{} QT:{}",
128
72
            id,
129
72
            horizontal_sample,
130
72
            vertical_sample,
131
72
            quantization_table_number
132
72
        );
133
72
134
72
        Ok(Components {
135
72
            component_id: id,
136
72
            vertical_sample,
137
72
            horizontal_sample,
138
72
            quantization_table_number,
139
72
            first_row_upsample_dest: vec![],
140
72
            // These two will be set with sof marker
141
72
            dc_huff_table: 0,
142
72
            ac_huff_table: 0,
143
72
            quantization_table: [0; 64],
144
72
            dc_pred: 0,
145
72
            up_sampler: upsample_no_op,
146
72
            // set later
147
72
            width_stride: horizontal_sample,
148
72
            id: a[0],
149
72
            needed: true,
150
72
            raw_coeff: vec![],
151
72
            upsample_dest: vec![],
152
72
            row_up: vec![],
153
72
            row: vec![],
154
72
            idct_pos: 0,
155
72
            x: 0,
156
72
            y: 0,
157
72
            w2: 0,
158
72
            sample_ratio: SampleRatios::None,
159
72
            fix_an_annoying_bug: 1
160
72
        })
161
74
    }
Unexecuted instantiation: <zune_jpeg::components::Components>::from
Unexecuted instantiation: <zune_jpeg::components::Components>::from
Unexecuted instantiation: <zune_jpeg::components::Components>::from
Unexecuted instantiation: <zune_jpeg::components::Components>::from
Unexecuted instantiation: <zune_jpeg::components::Components>::from
Unexecuted instantiation: <zune_jpeg::components::Components>::from
Unexecuted instantiation: <zune_jpeg::components::Components>::from
Unexecuted instantiation: <zune_jpeg::components::Components>::from
Unexecuted instantiation: <zune_jpeg::components::Components>::from
162
    /// Setup space for upsampling
163
    ///
164
    /// During upsample, we need a reference of the last row so that upsampling can
165
    /// proceed correctly,
166
    /// so we store the last line of every scanline and use it for the next upsampling procedure
167
    /// to store this, but since we don't need it for 1v1 upsampling,
168
    /// we only call this for routines that need upsampling
169
    ///
170
    /// # Requirements
171
    ///  - width stride of this element is set for the component.
172
0
    pub fn setup_upsample_scanline(&mut self) {
173
0
        self.row = vec![0; self.width_stride * self.vertical_sample];
174
0
        self.row_up = vec![0; self.width_stride * self.vertical_sample];
175
0
        self.first_row_upsample_dest =
176
0
            vec![128; self.vertical_sample * self.width_stride * self.sample_ratio.sample()];
177
0
        self.upsample_dest =
178
0
            vec![0; self.width_stride * self.sample_ratio.sample() * self.fix_an_annoying_bug * 8];
179
0
    }
180
}
181
182
/// Component ID's
183
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
184
pub enum ComponentID {
185
    /// Luminance channel
186
    Y,
187
    /// Blue chrominance
188
    Cb,
189
    /// Red chrominance
190
    Cr,
191
    /// Q or fourth component
192
    Q
193
}
194
195
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
196
pub enum SampleRatios {
197
    HV,
198
    V,
199
    H,
200
    Generic(usize, usize),
201
    None
202
}
203
204
impl SampleRatios {
205
0
    pub fn sample(self) -> usize {
206
0
        match self {
207
0
            SampleRatios::HV => 4,
208
0
            SampleRatios::V | SampleRatios::H => 2,
209
0
            SampleRatios::Generic(a, b) => a * b,
210
0
            SampleRatios::None => 1
211
        }
212
0
    }
213
}