Skip to main content

gufo_jpeg/
segments.rs

1use std::io::Read;
2
3use gufo_common::physical_dimension::{
4    PhysicalDimensionUnit, PixelDensity, PixelsPerPhysicalDimension,
5};
6use zerocopy::big_endian::U16;
7
8use super::Error;
9
10#[derive(Debug)]
11pub struct Dqt_<T> {
12    /// Quantization table destination identifier
13    tq: u8,
14    /// Quantization table elements
15    qk: [T; 64],
16}
17
18/// Quantization Table
19#[derive(Debug)]
20pub enum Dqt {
21    /// Table definition with 8 bit elements
22    Dqt8(Dqt_<u8>),
23    /// Table definition with 16 bit elements
24    Dqt16(Dqt_<u16>),
25}
26
27impl Dqt {
28    pub fn tq(&self) -> u8 {
29        match self {
30            Self::Dqt8(x) => x.tq,
31            Self::Dqt16(x) => x.tq,
32        }
33    }
34
35    /// Quantization table elements in 16 bit
36    ///
37    /// This resturns the data in 16 bit, even if defined as 8 bit. The 8-bit
38    /// data is not scaled to 16-bit.
39    pub fn qk(&self) -> [u16; 64] {
40        match self {
41            Self::Dqt8(dqt) => {
42                let mut qk = [0; 64];
43                for (n, i) in dqt.qk.into_iter().enumerate() {
44                    qk[n] = i.into();
45                }
46                qk
47            }
48            Self::Dqt16(dqt) => dqt.qk,
49        }
50    }
51
52    /// Quantization table in non-zig-zag order
53    ///
54    /// Otherwise same as `qk()`
55    pub fn qk_ordered(&self) -> [u16; 64] {
56        const IDX: [[usize; 8]; 8] = [
57            [0, 1, 5, 6, 14, 15, 27, 28],
58            [2, 4, 7, 13, 16, 26, 29, 42],
59            [3, 8, 12, 17, 25, 30, 41, 43],
60            [9, 11, 18, 24, 31, 40, 44, 53],
61            [10, 19, 23, 32, 39, 45, 52, 54],
62            [20, 22, 33, 38, 46, 51, 55, 60],
63            [21, 34, 37, 47, 50, 56, 59, 61],
64            [35, 36, 48, 49, 57, 58, 62, 63],
65        ];
66
67        let qk = self.qk();
68
69        let mut qk_ordered = [0; 64];
70
71        for (i, n) in IDX.into_iter().flatten().enumerate() {
72            qk_ordered[i] = qk[n];
73        }
74
75        qk_ordered
76    }
77
78    pub fn from_data(mut value: &[u8]) -> Result<Vec<Self>, Error> {
79        let mut dqts = Vec::new();
80        while !value.is_empty() {
81            let mut pq_tq = [0; 1];
82            value
83                .read_exact(&mut pq_tq)
84                .map_err(|_| Error::UnexpectedEof)?;
85            let pq_tq = pq_tq[0];
86
87            let pq = pq_tq >> 4;
88            let tq = pq_tq & 0b1111;
89
90            tracing::debug!("Loading DQT entry with Pq={pq}, Tq={tq}");
91
92            // Matrix entries can be 8bit and 16bit precision
93            match pq {
94                0 => {
95                    let mut qk = [0; 64];
96                    value
97                        .read_exact(&mut qk)
98                        .map_err(|_| Error::UnexpectedEof)?;
99                    dqts.push(Self::Dqt8(Dqt_ { tq, qk }))
100                }
101                1 => {
102                    let mut qk_raw = [0; 64 * 2];
103                    value
104                        .read_exact(&mut qk_raw)
105                        .map_err(|_| Error::UnexpectedEof)?;
106
107                    let mut qk = [0; 64];
108                    for (n, i) in qk_raw.chunks_exact(2).enumerate() {
109                        let entry = u16::from_be_bytes(i.try_into().unwrap());
110                        qk[n] = entry;
111                    }
112
113                    dqts.push(Self::Dqt16(Dqt_ { tq, qk }))
114                }
115                unkown_pq => return Err(Error::UnknownPq(unkown_pq)),
116            }
117        }
118
119        Ok(dqts)
120    }
121}
122
123/// Frame Header / Start of Frame
124#[derive(Debug)]
125pub struct Sof {
126    /// Sample precision
127    pub p: u8,
128    /// Number of lines
129    pub y: u16,
130    /// Number of samples per line
131    pub x: u16,
132    /// Component specification parameters
133    pub parameters: Vec<ComponentSpecificationParameters>,
134}
135
136impl Sof {
137    pub fn from_data(mut data: &[u8]) -> Result<Self, Error> {
138        let p = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
139        let y = data.read_be_u16().map_err(|_| Error::UnexpectedEof)?;
140        let x = data.read_be_u16().map_err(|_| Error::UnexpectedEof)?;
141        let nf = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
142
143        let mut parameters = Vec::with_capacity(nf as usize);
144        let buf = &mut [0; 3];
145        for _ in 0..nf {
146            data.read_exact(buf).map_err(|_| Error::UnexpectedEof)?;
147            parameters.push(ComponentSpecificationParameters::from_data(buf)?);
148        }
149
150        Ok(Self {
151            p,
152            y,
153            x,
154            parameters,
155        })
156    }
157}
158
159/// Component specification parameters
160#[derive(Debug, Clone, Copy)]
161pub struct ComponentSpecificationParameters {
162    /// Component identifier
163    pub c: u8,
164    /// Horizontal sampling factor
165    pub h: u8,
166    /// Vertical sampling factor
167    pub v: u8,
168    /// Quantization table destination selector
169    pub tq: u8,
170}
171
172impl ComponentSpecificationParameters {
173    pub fn from_data(mut data: &[u8]) -> Result<Self, Error> {
174        let c = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
175        let h_v = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
176        let tq = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
177
178        let h = h_v >> 4;
179        let v = h_v & 0b1111;
180
181        Ok(Self { c, h, v, tq })
182    }
183}
184
185pub trait ReadExt: Read {
186    fn read_u8(&mut self) -> std::io::Result<u8> {
187        let buf = &mut [0; 1];
188        self.read_exact(buf)?;
189        Ok(buf[0])
190    }
191
192    fn read_be_u16(&mut self) -> std::io::Result<u16> {
193        let buf = &mut [0; 2];
194        self.read_exact(buf)?;
195        Ok(u16::from_be_bytes(*buf))
196    }
197}
198
199impl<T: Read> ReadExt for T {}
200
201/// Scan Header / Start of Scan
202#[derive(Debug)]
203pub struct Sos {
204    /// List of components (channels)
205    pub components_specifications: Vec<ComponentSpecification>,
206    /// Start of spectral or predictor selection
207    pub ss: u8,
208    /// End of spectral selection
209    pub se: u8,
210    /// Successive approximation bit position high
211    pub ah: u8,
212    /// Successive approximation bit position low or point transform
213    pub al: u8,
214}
215
216impl Sos {
217    pub fn from_data(mut data: &[u8]) -> Result<Self, Error> {
218        let ns = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
219
220        let mut components_specifications = Vec::with_capacity(ns as usize);
221        let buf = &mut [0; 2];
222        for _ in 0..ns {
223            data.read_exact(buf).map_err(|_| Error::UnexpectedEof)?;
224            components_specifications.push(ComponentSpecification::from_data(buf)?);
225        }
226
227        let ss = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
228        let se = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
229        let ah_al = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
230        let ah = ah_al >> 4;
231        let al = ah_al & 0b1111;
232
233        Ok(Self {
234            components_specifications,
235            ss,
236            se,
237            ah,
238            al,
239        })
240    }
241}
242
243#[derive(Debug)]
244pub struct ComponentSpecification {
245    /// Scan component selector
246    ///
247    /// References a `c` value in
248    /// `ComponentSpecificationParameters`](ComponentSpecificationParameters#
249    /// structfield.c).
250    pub cs: u8,
251    /// DC entropy coding table
252    pub td: u8,
253    /// AC entropy coding table
254    pub ta: u8,
255}
256
257impl ComponentSpecification {
258    pub fn from_data(mut data: &[u8]) -> Result<ComponentSpecification, Error> {
259        let cs = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
260        let td_ta = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
261        let td = td_ta >> 4;
262        let ta = td_ta & 0b1111;
263
264        Ok(Self { cs, td, ta })
265    }
266}
267
268#[derive(zerocopy::FromBytes, zerocopy::KnownLayout, zerocopy::Immutable, Clone, Debug)]
269#[repr(C)]
270pub struct Jfif {
271    pub major_verson: u8,
272    pub minor_version: u8,
273    pub pixel_density_unit: u8,
274    pub pixel_density_x: U16,
275    pub pixel_density_y: U16,
276    pub thumbnail_width: u8,
277    pub thunbnail_height: u8,
278}
279
280impl Jfif {
281    pub fn pixel_density(&self) -> Option<PixelDensity> {
282        let unit = match self.pixel_density_unit {
283            0 => None,
284            1 => Some(PhysicalDimensionUnit::Inch),
285            2 => Some(PhysicalDimensionUnit::Centimeter),
286            u => {
287                tracing::warn!("Unknown pixel density unit: {u}");
288                None
289            }
290        }?;
291
292        Some(PixelDensity::new(
293            PixelsPerPhysicalDimension::new(self.pixel_density_x.get() as f64, unit),
294            PixelsPerPhysicalDimension::new(self.pixel_density_y.get() as f64, unit),
295        ))
296    }
297}