/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 | | } |