Coverage Report

Created: 2025-10-12 08:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/zune-jpeg-0.4.21/src/bitstream.rs
Line
Count
Source
1
/*
2
 * Copyright (c) 2023.
3
 *
4
 * This software is free software;
5
 *
6
 * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license
7
 */
8
9
#![allow(
10
    clippy::if_not_else,
11
    clippy::similar_names,
12
    clippy::inline_always,
13
    clippy::doc_markdown,
14
    clippy::cast_sign_loss,
15
    clippy::cast_possible_truncation
16
)]
17
18
//! This file exposes a single struct that can decode a huffman encoded
19
//! Bitstream in a JPEG file
20
//!
21
//! This code is optimized for speed.
22
//! It's meant to be super duper super fast, because everyone else depends on this being fast.
23
//! It's (annoyingly) serial hence we cant use parallel bitstreams(it's variable length coding.)
24
//!
25
//! Furthermore, on the case of refills, we have to do bytewise processing because the standard decided
26
//! that we want to support markers in the middle of streams(seriously few people use RST markers).
27
//!
28
//! So we pull in all optimization steps:
29
//! - use `inline[always]`? ✅ ,
30
//! - pre-execute most common cases ✅,
31
//! - add random comments ✅
32
//! -  fast paths ✅.
33
//!
34
//! Speed-wise: It is probably the fastest JPEG BitStream decoder to ever sail the seven seas because of
35
//! a couple of optimization tricks.
36
//! 1. Fast refills from libjpeg-turbo
37
//! 2. As few as possible branches in decoder fast paths.
38
//! 3. Accelerated AC table decoding borrowed from stb_image.h written by Fabian Gissen (@ rygorous),
39
//! improved by me to handle more cases.
40
//! 4. Safe and extensible routines(e.g. cool ways to eliminate bounds check)
41
//! 5. No unsafe here
42
//!
43
//! Readability comes as a second priority(I tried with variable names this time, and we are wayy better than libjpeg).
44
//!
45
//! Anyway if you are reading this it means your cool and I hope you get whatever part of the code you are looking for
46
//! (or learn something cool)
47
//!
48
//! Knock yourself out.
49
use alloc::string::ToString;
50
use core::cmp::min;
51
use alloc::format;
52
53
use zune_core::bytestream::{ZByteReader, ZReaderTrait};
54
55
use crate::errors::DecodeErrors;
56
use crate::huffman::{HuffmanTable, HUFF_LOOKAHEAD};
57
use crate::marker::Marker;
58
use crate::mcu::DCT_BLOCK;
59
use crate::misc::UN_ZIGZAG;
60
61
macro_rules! decode_huff {
62
    ($stream:tt,$symbol:tt,$table:tt) => {
63
        let mut code_length = $symbol >> HUFF_LOOKAHEAD;
64
65
        ($symbol) &= (1 << HUFF_LOOKAHEAD) - 1;
66
67
        if code_length > i32::from(HUFF_LOOKAHEAD)
68
        {
69
            // if the symbol cannot be resolved in the first HUFF_LOOKAHEAD bits,
70
            // we know it lies somewhere between HUFF_LOOKAHEAD and 16 bits since jpeg imposes 16 bit
71
            // limit, we can therefore look 16 bits ahead and try to resolve the symbol
72
            // starting from 1+HUFF_LOOKAHEAD bits.
73
            $symbol = ($stream).peek_bits::<16>() as i32;
74
            // (Credits to Sean T. Barrett stb library for this optimization)
75
            // maxcode is pre-shifted 16 bytes long so that it has (16-code_length)
76
            // zeroes at the end hence we do not need to shift in the inner loop.
77
            while code_length < 17{
78
                if $symbol < $table.maxcode[code_length as usize]  {
79
                    break;
80
                }
81
                code_length += 1;
82
            }
83
84
            if code_length == 17{
85
                // symbol could not be decoded.
86
                //
87
                // We may think, lets fake zeroes, noo
88
                // panic, because Huffman codes are sensitive, probably everything
89
                // after this will be corrupt, so no need to continue.
90
                // panic!("Bad Huffman code length");
91
                return Err(DecodeErrors::Format(format!("Bad Huffman Code 0x{:X}, corrupt JPEG",$symbol)))
92
            }
93
94
            $symbol >>= (16-code_length);
95
            ($symbol) = i32::from(
96
                ($table).values
97
                    [(($symbol + ($table).offset[code_length as usize]) & 0xFF) as usize],
98
            );
99
        }
100
        // drop bits read
101
        ($stream).drop_bits(code_length as u8);
102
    };
103
}
104
105
/// A `BitStream` struct, a bit by bit reader with super powers
106
///
107
pub(crate) struct BitStream {
108
    /// A MSB type buffer that is used for some certain operations
109
    pub buffer: u64,
110
    /// A TOP  aligned MSB type buffer that is used to accelerate some operations like
111
    /// peek_bits and get_bits.
112
    ///
113
    /// By top aligned, I mean the top bit (63) represents the top bit in the buffer.
114
    aligned_buffer: u64,
115
    /// Tell us the bits left the two buffer
116
    pub(crate) bits_left: u8,
117
    /// Did we find a marker(RST/EOF) during decoding?
118
    pub marker: Option<Marker>,
119
120
    /// Progressive decoding
121
    pub successive_high: u8,
122
    pub successive_low: u8,
123
    spec_start: u8,
124
    spec_end: u8,
125
    pub eob_run: i32,
126
    pub overread_by: usize,
127
    /// True if we have seen end of image marker.
128
    /// Don't read anything after that.
129
    pub seen_eoi: bool,
130
}
131
132
impl BitStream {
133
    /// Create a new BitStream
134
556
    pub(crate) const fn new() -> BitStream {
135
556
        BitStream {
136
556
            buffer: 0,
137
556
            aligned_buffer: 0,
138
556
            bits_left: 0,
139
556
            marker: None,
140
556
            successive_high: 0,
141
556
            successive_low: 0,
142
556
            spec_start: 0,
143
556
            spec_end: 0,
144
556
            eob_run: 0,
145
556
            overread_by: 0,
146
556
            seen_eoi: false,
147
556
        }
148
556
    }
149
150
    /// Create a new Bitstream for progressive decoding
151
    #[allow(clippy::redundant_field_names)]
152
1.92k
    pub(crate) fn new_progressive(ah: u8, al: u8, spec_start: u8, spec_end: u8) -> BitStream {
153
1.92k
        BitStream {
154
1.92k
            buffer: 0,
155
1.92k
            aligned_buffer: 0,
156
1.92k
            bits_left: 0,
157
1.92k
            marker: None,
158
1.92k
            successive_high: ah,
159
1.92k
            successive_low: al,
160
1.92k
            spec_start: spec_start,
161
1.92k
            spec_end: spec_end,
162
1.92k
            eob_run: 0,
163
1.92k
            overread_by: 0,
164
1.92k
            seen_eoi: false,
165
1.92k
        }
166
1.92k
    }
167
168
    /// Refill the bit buffer by (a maximum of) 32 bits
169
    ///
170
    /// # Arguments
171
    ///  - `reader`:`&mut BufReader<R>`: A mutable reference to an underlying
172
    ///    File/Memory buffer containing a valid JPEG stream
173
    ///
174
    /// This function will only refill if `self.count` is less than 32
175
    #[inline(always)] // to many call sites? ( perf improvement by 4%)
176
538M
    pub(crate) fn refill<T>(&mut self, reader: &mut ZByteReader<T>) -> Result<bool, DecodeErrors>
177
538M
    where
178
538M
        T: ZReaderTrait
179
    {
180
        /// Macro version of a single byte refill.
181
        /// Arguments
182
        /// buffer-> our io buffer, because rust macros cannot get values from
183
        /// the surrounding environment bits_left-> number of bits left
184
        /// to full refill
185
        macro_rules! refill {
186
            ($buffer:expr,$byte:expr,$bits_left:expr) => {
187
                // read a byte from the stream
188
                $byte = u64::from(reader.get_u8());
189
                self.overread_by += usize::from(reader.eof());
190
                // append to the buffer
191
                // JPEG is a MSB type buffer so that means we append this
192
                // to the lower end (0..8) of the buffer and push the rest bits above..
193
                $buffer = ($buffer << 8) | $byte;
194
                // Increment bits left
195
                $bits_left += 8;
196
                // Check for special case  of OxFF, to see if it's a stream or a marker
197
                if $byte == 0xff {
198
                    // read next byte
199
                    let mut next_byte = u64::from(reader.get_u8());
200
                    // Byte snuffing, if we encounter byte snuff, we skip the byte
201
                    if next_byte != 0x00 {
202
                        // skip that byte we read
203
                        while next_byte == 0xFF {
204
                            next_byte = u64::from(reader.get_u8());
205
                        }
206
207
                        if next_byte != 0x00 {
208
                            // Undo the byte append and return
209
                            $buffer >>= 8;
210
                            $bits_left -= 8;
211
212
                            if $bits_left != 0 {
213
                                self.aligned_buffer = $buffer << (64 - $bits_left);
214
                            }
215
216
                            self.marker = Marker::from_u8(next_byte as u8);
217
                            if next_byte == 0xD9 {
218
                                // special handling for eoi, fill some bytes,even if its zero,
219
                                // removes some panics
220
                                self.buffer <<= 8;
221
                                self.bits_left += 8;
222
                                self.aligned_buffer = self.buffer << (64 - self.bits_left);
223
224
                            }
225
226
                            return Ok(false);
227
                        }
228
                    }
229
                }
230
            };
231
        }
232
233
234
        // 32 bits is enough for a decode(16 bits) and receive_extend(max 16 bits)
235
538M
        if self.bits_left < 32 {
236
69.6M
            if self.marker.is_some() || self.overread_by > 0  || self.seen_eoi{
237
                // found a marker, or we are in EOI
238
                // also we are in over-reading mode, where we fill it with zeroes
239
240
                // fill with zeroes
241
66.9M
                self.buffer <<= 32;
242
66.9M
                self.bits_left += 32;
243
66.9M
                self.aligned_buffer = self.buffer << (64 - self.bits_left);
244
66.9M
                return Ok(true);
245
2.64M
            }
246
247
248
            // we optimize for the case where we don't have 255 in the stream and have 4 bytes left
249
            // as it is the common case
250
            //
251
            // so we always read 4 bytes, if read_fixed_bytes errors out, the cursor is
252
            // guaranteed not to advance in case of failure (is this true), so
253
            // we revert the read later on (if we have 255), if this fails, we use the normal
254
            // byte at a time read
255
256
2.64M
            if let Ok(bytes) = reader.get_fixed_bytes_or_err::<4>() {
257
                // we have 4 bytes to spare, read the 4 bytes into a temporary buffer
258
                // create buffer
259
2.64M
                let msb_buf = u32::from_be_bytes(bytes);
260
                // check if we have 0xff
261
2.64M
                if !has_byte(msb_buf, 255) {
262
1.91M
                    self.bits_left += 32;
263
1.91M
                    self.buffer <<= 32;
264
1.91M
                    self.buffer |= u64::from(msb_buf);
265
1.91M
                    self.aligned_buffer = self.buffer << (64 - self.bits_left);
266
1.91M
                    return Ok(true);
267
732k
                }
268
269
732k
                reader.rewind(4);
270
1.01k
            }
271
            // This serves two reasons,
272
            // 1: Make clippy shut up
273
            // 2: Favour register reuse
274
            let mut byte;
275
            // 4 refills, if all succeed the stream should contain enough bits to decode a
276
            // value
277
733k
            refill!(self.buffer, byte, self.bits_left);
278
577k
            refill!(self.buffer, byte, self.bits_left);
279
476k
            refill!(self.buffer, byte, self.bits_left);
280
383k
            refill!(self.buffer, byte, self.bits_left);
281
            // Construct an MSB buffer whose top bits are the bitstream we are currently holding.
282
238k
            self.aligned_buffer = self.buffer << (64 - self.bits_left);
283
468M
        }
284
469M
        return Ok(true);
285
538M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<_>
<zune_jpeg::bitstream::BitStream>::refill::<alloc::vec::Vec<u8>>
Line
Count
Source
176
538M
    pub(crate) fn refill<T>(&mut self, reader: &mut ZByteReader<T>) -> Result<bool, DecodeErrors>
177
538M
    where
178
538M
        T: ZReaderTrait
179
    {
180
        /// Macro version of a single byte refill.
181
        /// Arguments
182
        /// buffer-> our io buffer, because rust macros cannot get values from
183
        /// the surrounding environment bits_left-> number of bits left
184
        /// to full refill
185
        macro_rules! refill {
186
            ($buffer:expr,$byte:expr,$bits_left:expr) => {
187
                // read a byte from the stream
188
                $byte = u64::from(reader.get_u8());
189
                self.overread_by += usize::from(reader.eof());
190
                // append to the buffer
191
                // JPEG is a MSB type buffer so that means we append this
192
                // to the lower end (0..8) of the buffer and push the rest bits above..
193
                $buffer = ($buffer << 8) | $byte;
194
                // Increment bits left
195
                $bits_left += 8;
196
                // Check for special case  of OxFF, to see if it's a stream or a marker
197
                if $byte == 0xff {
198
                    // read next byte
199
                    let mut next_byte = u64::from(reader.get_u8());
200
                    // Byte snuffing, if we encounter byte snuff, we skip the byte
201
                    if next_byte != 0x00 {
202
                        // skip that byte we read
203
                        while next_byte == 0xFF {
204
                            next_byte = u64::from(reader.get_u8());
205
                        }
206
207
                        if next_byte != 0x00 {
208
                            // Undo the byte append and return
209
                            $buffer >>= 8;
210
                            $bits_left -= 8;
211
212
                            if $bits_left != 0 {
213
                                self.aligned_buffer = $buffer << (64 - $bits_left);
214
                            }
215
216
                            self.marker = Marker::from_u8(next_byte as u8);
217
                            if next_byte == 0xD9 {
218
                                // special handling for eoi, fill some bytes,even if its zero,
219
                                // removes some panics
220
                                self.buffer <<= 8;
221
                                self.bits_left += 8;
222
                                self.aligned_buffer = self.buffer << (64 - self.bits_left);
223
224
                            }
225
226
                            return Ok(false);
227
                        }
228
                    }
229
                }
230
            };
231
        }
232
233
234
        // 32 bits is enough for a decode(16 bits) and receive_extend(max 16 bits)
235
538M
        if self.bits_left < 32 {
236
69.6M
            if self.marker.is_some() || self.overread_by > 0  || self.seen_eoi{
237
                // found a marker, or we are in EOI
238
                // also we are in over-reading mode, where we fill it with zeroes
239
240
                // fill with zeroes
241
66.9M
                self.buffer <<= 32;
242
66.9M
                self.bits_left += 32;
243
66.9M
                self.aligned_buffer = self.buffer << (64 - self.bits_left);
244
66.9M
                return Ok(true);
245
2.64M
            }
246
247
248
            // we optimize for the case where we don't have 255 in the stream and have 4 bytes left
249
            // as it is the common case
250
            //
251
            // so we always read 4 bytes, if read_fixed_bytes errors out, the cursor is
252
            // guaranteed not to advance in case of failure (is this true), so
253
            // we revert the read later on (if we have 255), if this fails, we use the normal
254
            // byte at a time read
255
256
2.64M
            if let Ok(bytes) = reader.get_fixed_bytes_or_err::<4>() {
257
                // we have 4 bytes to spare, read the 4 bytes into a temporary buffer
258
                // create buffer
259
2.64M
                let msb_buf = u32::from_be_bytes(bytes);
260
                // check if we have 0xff
261
2.64M
                if !has_byte(msb_buf, 255) {
262
1.91M
                    self.bits_left += 32;
263
1.91M
                    self.buffer <<= 32;
264
1.91M
                    self.buffer |= u64::from(msb_buf);
265
1.91M
                    self.aligned_buffer = self.buffer << (64 - self.bits_left);
266
1.91M
                    return Ok(true);
267
732k
                }
268
269
732k
                reader.rewind(4);
270
1.01k
            }
271
            // This serves two reasons,
272
            // 1: Make clippy shut up
273
            // 2: Favour register reuse
274
            let mut byte;
275
            // 4 refills, if all succeed the stream should contain enough bits to decode a
276
            // value
277
733k
            refill!(self.buffer, byte, self.bits_left);
278
577k
            refill!(self.buffer, byte, self.bits_left);
279
476k
            refill!(self.buffer, byte, self.bits_left);
280
383k
            refill!(self.buffer, byte, self.bits_left);
281
            // Construct an MSB buffer whose top bits are the bitstream we are currently holding.
282
238k
            self.aligned_buffer = self.buffer << (64 - self.bits_left);
283
468M
        }
284
469M
        return Ok(true);
285
538M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<&[u8]>
286
    /// Decode the DC coefficient in a MCU block.
287
    ///
288
    /// The decoded coefficient is written to `dc_prediction`
289
    ///
290
    #[allow(
291
        clippy::cast_possible_truncation,
292
        clippy::cast_sign_loss,
293
        clippy::unwrap_used
294
    )]
295
    #[inline(always)]
296
40.0M
    fn decode_dc<T>(
297
40.0M
        &mut self, reader: &mut ZByteReader<T>, dc_table: &HuffmanTable, dc_prediction: &mut i32
298
40.0M
    ) -> Result<bool, DecodeErrors>
299
40.0M
    where
300
40.0M
        T: ZReaderTrait
301
    {
302
        let (mut symbol, r);
303
304
40.0M
        if self.bits_left < 32 {
305
5.23M
            self.refill(reader)?;
306
34.7M
        };
307
        // look a head HUFF_LOOKAHEAD bits into the bitstream
308
40.0M
        symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
309
40.0M
        symbol = dc_table.lookup[symbol as usize];
310
311
40.0M
        decode_huff!(self, symbol, dc_table);
312
313
40.0M
        if symbol != 0 {
314
22.6M
            r = self.get_bits(symbol as u8);
315
22.6M
            symbol = huff_extend(r, symbol);
316
22.6M
        }
317
        // Update DC prediction
318
40.0M
        *dc_prediction = dc_prediction.wrapping_add(symbol);
319
320
40.0M
        return Ok(true);
321
40.0M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<_>
<zune_jpeg::bitstream::BitStream>::decode_dc::<alloc::vec::Vec<u8>>
Line
Count
Source
296
40.0M
    fn decode_dc<T>(
297
40.0M
        &mut self, reader: &mut ZByteReader<T>, dc_table: &HuffmanTable, dc_prediction: &mut i32
298
40.0M
    ) -> Result<bool, DecodeErrors>
299
40.0M
    where
300
40.0M
        T: ZReaderTrait
301
    {
302
        let (mut symbol, r);
303
304
40.0M
        if self.bits_left < 32 {
305
5.23M
            self.refill(reader)?;
306
34.7M
        };
307
        // look a head HUFF_LOOKAHEAD bits into the bitstream
308
40.0M
        symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
309
40.0M
        symbol = dc_table.lookup[symbol as usize];
310
311
40.0M
        decode_huff!(self, symbol, dc_table);
312
313
40.0M
        if symbol != 0 {
314
22.6M
            r = self.get_bits(symbol as u8);
315
22.6M
            symbol = huff_extend(r, symbol);
316
22.6M
        }
317
        // Update DC prediction
318
40.0M
        *dc_prediction = dc_prediction.wrapping_add(symbol);
319
320
40.0M
        return Ok(true);
321
40.0M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<&[u8]>
322
323
    /// Decode a Minimum Code Unit(MCU) as quickly as possible
324
    ///
325
    /// # Arguments
326
    /// - reader: The bitstream from where we read more bits.
327
    /// - dc_table: The Huffman table used to decode the DC coefficient
328
    /// - ac_table: The Huffman table used to decode AC values
329
    /// - block: A memory region where we will write out the decoded values
330
    /// - DC prediction: Last DC value for this component
331
    ///
332
    #[allow(
333
        clippy::many_single_char_names,
334
        clippy::cast_possible_truncation,
335
        clippy::cast_sign_loss
336
    )]
337
    #[inline(never)]
338
8.34M
    pub fn decode_mcu_block<T>(
339
8.34M
        &mut self, reader: &mut ZByteReader<T>, dc_table: &HuffmanTable, ac_table: &HuffmanTable,
340
8.34M
        qt_table: &[i32; DCT_BLOCK], block: &mut [i32; 64], dc_prediction: &mut i32
341
8.34M
    ) -> Result<(), DecodeErrors>
342
8.34M
    where
343
8.34M
        T: ZReaderTrait
344
    {
345
        // Get fast AC table as a reference before we enter the hot path
346
8.34M
        let ac_lookup = ac_table.ac_lookup.as_ref().unwrap();
347
348
        let (mut symbol, mut r, mut fast_ac);
349
        // Decode AC coefficients
350
8.34M
        let mut pos: usize = 1;
351
352
        // decode DC, dc prediction will contain the value
353
8.34M
        self.decode_dc(reader, dc_table, dc_prediction)?;
354
355
        // set dc to be the dc prediction.
356
8.34M
        block[0] = *dc_prediction * qt_table[0];
357
358
378M
        while pos < 64 {
359
372M
            self.refill(reader)?;
360
372M
            symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
361
372M
            fast_ac = ac_lookup[symbol as usize];
362
372M
            symbol = ac_table.lookup[symbol as usize];
363
364
372M
            if fast_ac != 0 {
365
369M
                //  FAST AC path
366
369M
                pos += ((fast_ac >> 4) & 15) as usize; // run
367
369M
                let t_pos = UN_ZIGZAG[min(pos, 63)] & 63;
368
369M
369
369M
                block[t_pos] = i32::from(fast_ac >> 8) * (qt_table[t_pos]); // Value
370
369M
                self.drop_bits((fast_ac & 15) as u8);
371
369M
                pos += 1;
372
369M
            } else {
373
2.64M
                decode_huff!(self, symbol, ac_table);
374
375
2.64M
                r = symbol >> 4;
376
2.64M
                symbol &= 15;
377
378
2.64M
                if symbol != 0 {
379
172k
                    pos += r as usize;
380
172k
                    r = self.get_bits(symbol as u8);
381
172k
                    symbol = huff_extend(r, symbol);
382
172k
                    let t_pos = UN_ZIGZAG[pos & 63] & 63;
383
172k
384
172k
                    block[t_pos] = symbol * qt_table[t_pos];
385
172k
386
172k
                    pos += 1;
387
2.47M
                } else if r != 15 {
388
2.47M
                    return Ok(());
389
534
                } else {
390
534
                    pos += 16;
391
534
                }
392
            }
393
        }
394
5.86M
        return Ok(());
395
8.34M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<_>
<zune_jpeg::bitstream::BitStream>::decode_mcu_block::<alloc::vec::Vec<u8>>
Line
Count
Source
338
8.34M
    pub fn decode_mcu_block<T>(
339
8.34M
        &mut self, reader: &mut ZByteReader<T>, dc_table: &HuffmanTable, ac_table: &HuffmanTable,
340
8.34M
        qt_table: &[i32; DCT_BLOCK], block: &mut [i32; 64], dc_prediction: &mut i32
341
8.34M
    ) -> Result<(), DecodeErrors>
342
8.34M
    where
343
8.34M
        T: ZReaderTrait
344
    {
345
        // Get fast AC table as a reference before we enter the hot path
346
8.34M
        let ac_lookup = ac_table.ac_lookup.as_ref().unwrap();
347
348
        let (mut symbol, mut r, mut fast_ac);
349
        // Decode AC coefficients
350
8.34M
        let mut pos: usize = 1;
351
352
        // decode DC, dc prediction will contain the value
353
8.34M
        self.decode_dc(reader, dc_table, dc_prediction)?;
354
355
        // set dc to be the dc prediction.
356
8.34M
        block[0] = *dc_prediction * qt_table[0];
357
358
378M
        while pos < 64 {
359
372M
            self.refill(reader)?;
360
372M
            symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
361
372M
            fast_ac = ac_lookup[symbol as usize];
362
372M
            symbol = ac_table.lookup[symbol as usize];
363
364
372M
            if fast_ac != 0 {
365
369M
                //  FAST AC path
366
369M
                pos += ((fast_ac >> 4) & 15) as usize; // run
367
369M
                let t_pos = UN_ZIGZAG[min(pos, 63)] & 63;
368
369M
369
369M
                block[t_pos] = i32::from(fast_ac >> 8) * (qt_table[t_pos]); // Value
370
369M
                self.drop_bits((fast_ac & 15) as u8);
371
369M
                pos += 1;
372
369M
            } else {
373
2.64M
                decode_huff!(self, symbol, ac_table);
374
375
2.64M
                r = symbol >> 4;
376
2.64M
                symbol &= 15;
377
378
2.64M
                if symbol != 0 {
379
172k
                    pos += r as usize;
380
172k
                    r = self.get_bits(symbol as u8);
381
172k
                    symbol = huff_extend(r, symbol);
382
172k
                    let t_pos = UN_ZIGZAG[pos & 63] & 63;
383
172k
384
172k
                    block[t_pos] = symbol * qt_table[t_pos];
385
172k
386
172k
                    pos += 1;
387
2.47M
                } else if r != 15 {
388
2.47M
                    return Ok(());
389
534
                } else {
390
534
                    pos += 16;
391
534
                }
392
            }
393
        }
394
5.86M
        return Ok(());
395
8.34M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<&[u8]>
396
397
    /// Peek `look_ahead` bits ahead without discarding them from the buffer
398
    #[inline(always)]
399
    #[allow(clippy::cast_possible_truncation)]
400
565M
    const fn peek_bits<const LOOKAHEAD: u8>(&self) -> i32 {
401
565M
        (self.aligned_buffer >> (64 - LOOKAHEAD)) as i32
402
565M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<_>
<zune_jpeg::bitstream::BitStream>::peek_bits::<16>
Line
Count
Source
400
54.1k
    const fn peek_bits<const LOOKAHEAD: u8>(&self) -> i32 {
401
54.1k
        (self.aligned_buffer >> (64 - LOOKAHEAD)) as i32
402
54.1k
    }
<zune_jpeg::bitstream::BitStream>::peek_bits::<9>
Line
Count
Source
400
565M
    const fn peek_bits<const LOOKAHEAD: u8>(&self) -> i32 {
401
565M
        (self.aligned_buffer >> (64 - LOOKAHEAD)) as i32
402
565M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9>
403
404
    /// Discard the next `N` bits without checking
405
    #[inline]
406
1.04G
    fn drop_bits(&mut self, n: u8) {
407
1.04G
        debug_assert!(self.bits_left >= n);
408
        //self.bits_left -= n;
409
1.04G
        self.bits_left = self.bits_left.saturating_sub(n);
410
1.04G
        self.aligned_buffer <<= n;
411
1.04G
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits
<zune_jpeg::bitstream::BitStream>::drop_bits
Line
Count
Source
406
475M
    fn drop_bits(&mut self, n: u8) {
407
475M
        debug_assert!(self.bits_left >= n);
408
        //self.bits_left -= n;
409
475M
        self.bits_left = self.bits_left.saturating_sub(n);
410
475M
        self.aligned_buffer <<= n;
411
475M
    }
<zune_jpeg::bitstream::BitStream>::drop_bits
Line
Count
Source
406
565M
    fn drop_bits(&mut self, n: u8) {
407
565M
        debug_assert!(self.bits_left >= n);
408
        //self.bits_left -= n;
409
565M
        self.bits_left = self.bits_left.saturating_sub(n);
410
565M
        self.aligned_buffer <<= n;
411
565M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits
412
413
    /// Read `n_bits` from the buffer  and discard them
414
    #[inline(always)]
415
    #[allow(clippy::cast_possible_truncation)]
416
34.8M
    fn get_bits(&mut self, n_bits: u8) -> i32 {
417
34.8M
        let mask = (1_u64 << n_bits) - 1;
418
419
34.8M
        self.aligned_buffer = self.aligned_buffer.rotate_left(u32::from(n_bits));
420
34.8M
        let bits = (self.aligned_buffer & mask) as i32;
421
34.8M
        self.bits_left = self.bits_left.wrapping_sub(n_bits);
422
34.8M
        bits
423
34.8M
    }
424
425
    /// Decode a DC block
426
    #[allow(clippy::cast_possible_truncation)]
427
    #[inline]
428
31.6M
    pub(crate) fn decode_prog_dc_first<T>(
429
31.6M
        &mut self, reader: &mut ZByteReader<T>, dc_table: &HuffmanTable, block: &mut i16,
430
31.6M
        dc_prediction: &mut i32
431
31.6M
    ) -> Result<(), DecodeErrors>
432
31.6M
    where
433
31.6M
        T: ZReaderTrait
434
    {
435
31.6M
        self.decode_dc(reader, dc_table, dc_prediction)?;
436
31.6M
        *block = (*dc_prediction as i16).wrapping_mul(1_i16 << self.successive_low);
437
31.6M
        return Ok(());
438
31.6M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<_>
<zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<alloc::vec::Vec<u8>>
Line
Count
Source
428
31.6M
    pub(crate) fn decode_prog_dc_first<T>(
429
31.6M
        &mut self, reader: &mut ZByteReader<T>, dc_table: &HuffmanTable, block: &mut i16,
430
31.6M
        dc_prediction: &mut i32
431
31.6M
    ) -> Result<(), DecodeErrors>
432
31.6M
    where
433
31.6M
        T: ZReaderTrait
434
    {
435
31.6M
        self.decode_dc(reader, dc_table, dc_prediction)?;
436
31.6M
        *block = (*dc_prediction as i16).wrapping_mul(1_i16 << self.successive_low);
437
31.6M
        return Ok(());
438
31.6M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<&[u8]>
439
    #[inline]
440
21.0M
    pub(crate) fn decode_prog_dc_refine<T>(
441
21.0M
        &mut self, reader: &mut ZByteReader<T>, block: &mut i16
442
21.0M
    ) -> Result<(), DecodeErrors>
443
21.0M
    where
444
21.0M
        T: ZReaderTrait
445
    {
446
        // refinement scan
447
21.0M
        if self.bits_left < 1 {
448
668k
            self.refill(reader)?;
449
20.3M
        }
450
451
21.0M
        if self.get_bit() == 1 {
452
1.21M
            *block = block.wrapping_add(1 << self.successive_low);
453
19.8M
        }
454
455
21.0M
        Ok(())
456
21.0M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<_>
<zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<alloc::vec::Vec<u8>>
Line
Count
Source
440
21.0M
    pub(crate) fn decode_prog_dc_refine<T>(
441
21.0M
        &mut self, reader: &mut ZByteReader<T>, block: &mut i16
442
21.0M
    ) -> Result<(), DecodeErrors>
443
21.0M
    where
444
21.0M
        T: ZReaderTrait
445
    {
446
        // refinement scan
447
21.0M
        if self.bits_left < 1 {
448
668k
            self.refill(reader)?;
449
20.3M
        }
450
451
21.0M
        if self.get_bit() == 1 {
452
1.21M
            *block = block.wrapping_add(1 << self.successive_low);
453
19.8M
        }
454
455
21.0M
        Ok(())
456
21.0M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<&[u8]>
457
458
    /// Get a single bit from the bitstream
459
475M
    fn get_bit(&mut self) -> u8 {
460
475M
        let k = (self.aligned_buffer >> 63) as u8;
461
        // discard a bit
462
475M
        self.drop_bits(1);
463
475M
        return k;
464
475M
    }
465
13.7M
    pub(crate) fn decode_mcu_ac_first<T>(
466
13.7M
        &mut self, reader: &mut ZByteReader<T>, ac_table: &HuffmanTable, block: &mut [i16; 64]
467
13.7M
    ) -> Result<bool, DecodeErrors>
468
13.7M
    where
469
13.7M
        T: ZReaderTrait
470
    {
471
13.7M
        let shift = self.successive_low;
472
13.7M
        let fast_ac = ac_table.ac_lookup.as_ref().unwrap();
473
474
13.7M
        let mut k = self.spec_start as usize;
475
        let (mut symbol, mut r, mut fac);
476
477
        // EOB runs are handled in mcu_prog.rs
478
        'block: loop {
479
17.7M
            self.refill(reader)?;
480
481
17.7M
            symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
482
17.7M
            fac = fast_ac[symbol as usize];
483
17.7M
            symbol = ac_table.lookup[symbol as usize];
484
485
17.7M
            if fac != 0 {
486
6.21M
                // fast ac path
487
6.21M
                k += ((fac >> 4) & 15) as usize; // run
488
6.21M
                block[UN_ZIGZAG[min(k, 63)] & 63] = (fac >> 8).wrapping_mul(1 << shift); // value
489
6.21M
                self.drop_bits((fac & 15) as u8);
490
6.21M
                k += 1;
491
6.21M
            } else {
492
11.5M
                decode_huff!(self, symbol, ac_table);
493
494
11.5M
                r = symbol >> 4;
495
11.5M
                symbol &= 15;
496
497
11.5M
                if symbol != 0 {
498
9.27M
                    k += r as usize;
499
9.27M
                    r = self.get_bits(symbol as u8);
500
9.27M
                    symbol = huff_extend(r, symbol);
501
9.27M
                    block[UN_ZIGZAG[k & 63] & 63] = (symbol as i16).wrapping_mul(1 << shift);
502
9.27M
                    k += 1;
503
9.27M
                } else {
504
2.24M
                    if r != 15 {
505
2.22M
                        self.eob_run = 1 << r;
506
2.22M
                        self.eob_run += self.get_bits(r as u8);
507
2.22M
                        self.eob_run -= 1;
508
2.22M
                        break;
509
19.7k
                    }
510
511
19.7k
                    k += 16;
512
                }
513
            }
514
515
15.5M
            if k > self.spec_end as usize {
516
11.4M
                break 'block;
517
4.02M
            }
518
        }
519
13.7M
        return Ok(true);
520
13.7M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<_>
<zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<alloc::vec::Vec<u8>>
Line
Count
Source
465
13.7M
    pub(crate) fn decode_mcu_ac_first<T>(
466
13.7M
        &mut self, reader: &mut ZByteReader<T>, ac_table: &HuffmanTable, block: &mut [i16; 64]
467
13.7M
    ) -> Result<bool, DecodeErrors>
468
13.7M
    where
469
13.7M
        T: ZReaderTrait
470
    {
471
13.7M
        let shift = self.successive_low;
472
13.7M
        let fast_ac = ac_table.ac_lookup.as_ref().unwrap();
473
474
13.7M
        let mut k = self.spec_start as usize;
475
        let (mut symbol, mut r, mut fac);
476
477
        // EOB runs are handled in mcu_prog.rs
478
        'block: loop {
479
17.7M
            self.refill(reader)?;
480
481
17.7M
            symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
482
17.7M
            fac = fast_ac[symbol as usize];
483
17.7M
            symbol = ac_table.lookup[symbol as usize];
484
485
17.7M
            if fac != 0 {
486
6.21M
                // fast ac path
487
6.21M
                k += ((fac >> 4) & 15) as usize; // run
488
6.21M
                block[UN_ZIGZAG[min(k, 63)] & 63] = (fac >> 8).wrapping_mul(1 << shift); // value
489
6.21M
                self.drop_bits((fac & 15) as u8);
490
6.21M
                k += 1;
491
6.21M
            } else {
492
11.5M
                decode_huff!(self, symbol, ac_table);
493
494
11.5M
                r = symbol >> 4;
495
11.5M
                symbol &= 15;
496
497
11.5M
                if symbol != 0 {
498
9.27M
                    k += r as usize;
499
9.27M
                    r = self.get_bits(symbol as u8);
500
9.27M
                    symbol = huff_extend(r, symbol);
501
9.27M
                    block[UN_ZIGZAG[k & 63] & 63] = (symbol as i16).wrapping_mul(1 << shift);
502
9.27M
                    k += 1;
503
9.27M
                } else {
504
2.24M
                    if r != 15 {
505
2.22M
                        self.eob_run = 1 << r;
506
2.22M
                        self.eob_run += self.get_bits(r as u8);
507
2.22M
                        self.eob_run -= 1;
508
2.22M
                        break;
509
19.7k
                    }
510
511
19.7k
                    k += 16;
512
                }
513
            }
514
515
15.5M
            if k > self.spec_end as usize {
516
11.4M
                break 'block;
517
4.02M
            }
518
        }
519
13.7M
        return Ok(true);
520
13.7M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<&[u8]>
521
    #[allow(clippy::too_many_lines, clippy::op_ref)]
522
28.5M
    pub(crate) fn decode_mcu_ac_refine<T>(
523
28.5M
        &mut self, reader: &mut ZByteReader<T>, table: &HuffmanTable, block: &mut [i16; 64]
524
28.5M
    ) -> Result<bool, DecodeErrors>
525
28.5M
    where
526
28.5M
        T: ZReaderTrait
527
    {
528
28.5M
        let bit = (1 << self.successive_low) as i16;
529
530
28.5M
        let mut k = self.spec_start;
531
        let (mut symbol, mut r);
532
533
28.5M
        if self.eob_run == 0 {
534
            'no_eob: loop {
535
                // Decode a coefficient from the bit stream
536
135M
                self.refill(reader)?;
537
538
135M
                symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
539
135M
                symbol = table.lookup[symbol as usize];
540
541
135M
                decode_huff!(self, symbol, table);
542
543
135M
                r = symbol >> 4;
544
135M
                symbol &= 15;
545
546
135M
                if symbol == 0 {
547
574k
                    if r != 15 {
548
                        // EOB run is 2^r + bits
549
573k
                        self.eob_run = 1 << r;
550
573k
                        self.eob_run += self.get_bits(r as u8);
551
                        // EOB runs are handled by the eob logic
552
573k
                        break 'no_eob;
553
234
                    }
554
                } else {
555
134M
                    if symbol != 1 {
556
126
                        return Err(DecodeErrors::HuffmanDecode(
557
126
                            "Bad Huffman code, corrupt JPEG?".to_string()
558
126
                        ));
559
134M
                    }
560
                    // get sign bit
561
                    // We assume we have enough bits, which should be correct for sane images
562
                    // since we refill by 32 above
563
134M
                    if self.get_bit() == 1 {
564
94.3k
                        symbol = i32::from(bit);
565
134M
                    } else {
566
134M
                        symbol = i32::from(-bit);
567
134M
                    }
568
                }
569
570
                // Advance over already nonzero coefficients  appending
571
                // correction bits to the non-zeroes.
572
                // A correction bit is 1 if the absolute value of the coefficient must be increased
573
574
134M
                if k <= self.spec_end {
575
                    'advance_nonzero: loop {
576
395M
                        let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63];
577
578
395M
                        if *coefficient != 0 {
579
277M
                            if self.get_bit() == 1 && (*coefficient & bit) == 0 {
580
9.50k
                                if *coefficient >= 0 {
581
5.74k
                                    *coefficient += bit;
582
5.74k
                                } else {
583
3.76k
                                    *coefficient -= bit;
584
3.76k
                                }
585
277M
                            }
586
587
277M
                            if self.bits_left < 1 {
588
950k
                                self.refill(reader)?;
589
276M
                            }
590
                        } else {
591
117M
                            r -= 1;
592
593
117M
                            if r < 0 {
594
                                // reached target zero coefficient.
595
117M
                                break 'advance_nonzero;
596
13.8k
                            }
597
                        };
598
599
277M
                        if k == self.spec_end {
600
16.5M
                            break 'advance_nonzero;
601
261M
                        }
602
603
261M
                        k += 1;
604
                    }
605
929k
                }
606
607
134M
                if symbol != 0 {
608
134M
                    let pos = UN_ZIGZAG[k as usize & 63];
609
134M
                    // output new non-zero coefficient.
610
134M
                    block[pos & 63] = symbol as i16;
611
134M
                }
612
613
134M
                k += 1;
614
615
134M
                if k > self.spec_end {
616
22.2M
                    break 'no_eob;
617
112M
                }
618
            }
619
5.74M
        }
620
28.5M
        if self.eob_run > 0 {
621
            // only run if block does not consists of purely zeroes
622
6.32M
            if &block[1..] != &[0; 63] {
623
6.22M
                self.refill(reader)?;
624
625
64.5M
                while k <= self.spec_end {
626
58.3M
                    let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63];
627
628
58.3M
                    if *coefficient != 0 && self.get_bit() == 1 {
629
                        // check if we already modified it, if so do nothing, otherwise
630
                        // append the correction bit.
631
2.28M
                        if (*coefficient & bit) == 0 {
632
51.9k
                            if *coefficient >= 0 {
633
44.4k
                                *coefficient = coefficient.wrapping_add(bit);
634
44.4k
                            } else {
635
7.55k
                                *coefficient = coefficient.wrapping_sub(bit);
636
7.55k
                            }
637
2.23M
                        }
638
56.0M
                    }
639
58.3M
                    if self.bits_left < 1 {
640
                        // refill at the last possible moment
641
26.7k
                        self.refill(reader)?;
642
58.3M
                    }
643
58.3M
                    k += 1;
644
                }
645
95.5k
            }
646
            // count a block completed in EOB run
647
6.32M
            self.eob_run -= 1;
648
22.2M
        }
649
28.5M
        return Ok(true);
650
28.5M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<_>
<zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<alloc::vec::Vec<u8>>
Line
Count
Source
522
28.5M
    pub(crate) fn decode_mcu_ac_refine<T>(
523
28.5M
        &mut self, reader: &mut ZByteReader<T>, table: &HuffmanTable, block: &mut [i16; 64]
524
28.5M
    ) -> Result<bool, DecodeErrors>
525
28.5M
    where
526
28.5M
        T: ZReaderTrait
527
    {
528
28.5M
        let bit = (1 << self.successive_low) as i16;
529
530
28.5M
        let mut k = self.spec_start;
531
        let (mut symbol, mut r);
532
533
28.5M
        if self.eob_run == 0 {
534
            'no_eob: loop {
535
                // Decode a coefficient from the bit stream
536
135M
                self.refill(reader)?;
537
538
135M
                symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
539
135M
                symbol = table.lookup[symbol as usize];
540
541
135M
                decode_huff!(self, symbol, table);
542
543
135M
                r = symbol >> 4;
544
135M
                symbol &= 15;
545
546
135M
                if symbol == 0 {
547
574k
                    if r != 15 {
548
                        // EOB run is 2^r + bits
549
573k
                        self.eob_run = 1 << r;
550
573k
                        self.eob_run += self.get_bits(r as u8);
551
                        // EOB runs are handled by the eob logic
552
573k
                        break 'no_eob;
553
234
                    }
554
                } else {
555
134M
                    if symbol != 1 {
556
126
                        return Err(DecodeErrors::HuffmanDecode(
557
126
                            "Bad Huffman code, corrupt JPEG?".to_string()
558
126
                        ));
559
134M
                    }
560
                    // get sign bit
561
                    // We assume we have enough bits, which should be correct for sane images
562
                    // since we refill by 32 above
563
134M
                    if self.get_bit() == 1 {
564
94.3k
                        symbol = i32::from(bit);
565
134M
                    } else {
566
134M
                        symbol = i32::from(-bit);
567
134M
                    }
568
                }
569
570
                // Advance over already nonzero coefficients  appending
571
                // correction bits to the non-zeroes.
572
                // A correction bit is 1 if the absolute value of the coefficient must be increased
573
574
134M
                if k <= self.spec_end {
575
                    'advance_nonzero: loop {
576
395M
                        let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63];
577
578
395M
                        if *coefficient != 0 {
579
277M
                            if self.get_bit() == 1 && (*coefficient & bit) == 0 {
580
9.50k
                                if *coefficient >= 0 {
581
5.74k
                                    *coefficient += bit;
582
5.74k
                                } else {
583
3.76k
                                    *coefficient -= bit;
584
3.76k
                                }
585
277M
                            }
586
587
277M
                            if self.bits_left < 1 {
588
950k
                                self.refill(reader)?;
589
276M
                            }
590
                        } else {
591
117M
                            r -= 1;
592
593
117M
                            if r < 0 {
594
                                // reached target zero coefficient.
595
117M
                                break 'advance_nonzero;
596
13.8k
                            }
597
                        };
598
599
277M
                        if k == self.spec_end {
600
16.5M
                            break 'advance_nonzero;
601
261M
                        }
602
603
261M
                        k += 1;
604
                    }
605
929k
                }
606
607
134M
                if symbol != 0 {
608
134M
                    let pos = UN_ZIGZAG[k as usize & 63];
609
134M
                    // output new non-zero coefficient.
610
134M
                    block[pos & 63] = symbol as i16;
611
134M
                }
612
613
134M
                k += 1;
614
615
134M
                if k > self.spec_end {
616
22.2M
                    break 'no_eob;
617
112M
                }
618
            }
619
5.74M
        }
620
28.5M
        if self.eob_run > 0 {
621
            // only run if block does not consists of purely zeroes
622
6.32M
            if &block[1..] != &[0; 63] {
623
6.22M
                self.refill(reader)?;
624
625
64.5M
                while k <= self.spec_end {
626
58.3M
                    let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63];
627
628
58.3M
                    if *coefficient != 0 && self.get_bit() == 1 {
629
                        // check if we already modified it, if so do nothing, otherwise
630
                        // append the correction bit.
631
2.28M
                        if (*coefficient & bit) == 0 {
632
51.9k
                            if *coefficient >= 0 {
633
44.4k
                                *coefficient = coefficient.wrapping_add(bit);
634
44.4k
                            } else {
635
7.55k
                                *coefficient = coefficient.wrapping_sub(bit);
636
7.55k
                            }
637
2.23M
                        }
638
56.0M
                    }
639
58.3M
                    if self.bits_left < 1 {
640
                        // refill at the last possible moment
641
26.7k
                        self.refill(reader)?;
642
58.3M
                    }
643
58.3M
                    k += 1;
644
                }
645
95.5k
            }
646
            // count a block completed in EOB run
647
6.32M
            self.eob_run -= 1;
648
22.2M
        }
649
28.5M
        return Ok(true);
650
28.5M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<&[u8]>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<alloc::vec::Vec<u8>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<&[u8]>
651
652
12.2k
    pub fn update_progressive_params(&mut self, ah: u8, al: u8, spec_start: u8, spec_end: u8) {
653
12.2k
        self.successive_high = ah;
654
12.2k
        self.successive_low = al;
655
12.2k
        self.spec_start = spec_start;
656
12.2k
        self.spec_end = spec_end;
657
12.2k
    }
658
659
    /// Reset the stream if we have a restart marker
660
    ///
661
    /// Restart markers indicate drop those bits in the stream and zero out
662
    /// everything
663
    #[cold]
664
25.6k
    pub fn reset(&mut self) {
665
25.6k
        self.bits_left = 0;
666
25.6k
        self.marker = None;
667
25.6k
        self.buffer = 0;
668
25.6k
        self.aligned_buffer = 0;
669
25.6k
        self.eob_run = 0;
670
25.6k
    }
671
}
672
673
/// Do the equivalent of JPEG HUFF_EXTEND
674
#[inline(always)]
675
32.0M
fn huff_extend(x: i32, s: i32) -> i32 {
676
    // if x<s return x else return x+offset[s] where offset[s] = ( (-1<<s)+1)
677
32.0M
    (x) + ((((x) - (1 << ((s) - 1))) >> 31) & (((-1) << (s)) + 1))
678
32.0M
}
679
680
2.64M
const fn has_zero(v: u32) -> bool {
681
    // Retrieved from Stanford bithacks
682
    // @ https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
683
2.64M
    return !((((v & 0x7F7F_7F7F) + 0x7F7F_7F7F) | v) | 0x7F7F_7F7F) != 0;
684
2.64M
}
685
686
2.64M
const fn has_byte(b: u32, val: u8) -> bool {
687
    // Retrieved from Stanford bithacks
688
    // @ https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
689
2.64M
    has_zero(b ^ ((!0_u32 / 255) * (val as u32)))
690
2.64M
}
691
692
// mod tests {
693
//     use zune_core::bytestream::ZCursor;
694
//     use crate::JpegDecoder;
695
//
696
//     #[test]
697
//     fn test_image() {
698
//         let img = "/Users/etemesi/Downloads/PHO00008.JPG";
699
//         let data = std::fs::read(img).unwrap();
700
//         let mut decoder = JpegDecoder::new(ZCursor::new(&data[..]));
701
//         decoder.decode().unwrap();
702
//     }
703
// }