png/decoder/
unfiltering_buffer.rs

1use super::stream::{DecodingError, FormatErrorInner};
2use crate::common::BytesPerPixel;
3use crate::filter::{unfilter, FilterType};
4
5// Buffer for temporarily holding decompressed, not-yet-`unfilter`-ed rows.
6pub(crate) struct UnfilteringBuffer {
7    /// Vec containing the uncompressed image data currently being processed.
8    data_stream: Vec<u8>,
9    /// Index in `data_stream` where the previous row starts.
10    /// This excludes the filter type byte - it points at the first byte of actual pixel data.
11    /// The pixel data is already-`unfilter`-ed.
12    /// If `prev_start == current_start` then it means that there is no previous row.
13    prev_start: usize,
14    /// Index in `data_stream` where the current row starts.
15    /// This points at the filter type byte of the current row (i.e. the actual pixel data starts at `current_start + 1`)
16    /// The pixel data is not-yet-`unfilter`-ed.
17    current_start: usize,
18}
19
20impl UnfilteringBuffer {
21    /// Asserts in debug builds that all the invariants hold.  No-op in release
22    /// builds.  Intended to be called after creating or mutating `self` to
23    /// ensure that the final state preserves the invariants.
24    fn debug_assert_invariants(&self) {
25        debug_assert!(self.prev_start <= self.current_start);
26        debug_assert!(self.prev_start <= self.data_stream.len());
27        debug_assert!(self.current_start <= self.data_stream.len());
28    }
29
30    pub fn new() -> Self {
31        let result = Self {
32            data_stream: Vec::new(),
33            prev_start: 0,
34            current_start: 0,
35        };
36        result.debug_assert_invariants();
37        result
38    }
39
40    /// Called to indicate that there is no previous row (e.g. when the current
41    /// row is the first scanline of a given Adam7 pass).
42    pub fn reset_prev_row(&mut self) {
43        self.prev_start = self.current_start;
44        self.debug_assert_invariants();
45    }
46
47    /// Returns the previous (already `unfilter`-ed) row.
48    pub fn prev_row(&self) -> &[u8] {
49        // No point calling this if there is no previous row.
50        debug_assert!(self.prev_start < self.current_start);
51
52        &self.data_stream[self.prev_start..self.current_start]
53    }
54
55    /// Returns how many bytes of the current row are present in the buffer.
56    pub fn curr_row_len(&self) -> usize {
57        self.data_stream.len() - self.current_start
58    }
59
60    /// Returns a `&mut Vec<u8>` suitable for passing to
61    /// `ReadDecoder.decode_image_data` or `StreamingDecoder.update`.
62    ///
63    /// Invariants of `self` depend on the assumption that the caller will only
64    /// append new bytes to the returned vector (which is indeed the behavior of
65    /// `ReadDecoder` and `StreamingDecoder`).  TODO: Consider protecting the
66    /// invariants by returning an append-only view of the vector
67    /// (`FnMut(&[u8])`??? or maybe `std::io::Write`???).
68    pub fn as_mut_vec(&mut self) -> &mut Vec<u8> {
69        // Opportunistically compact the current buffer by discarding bytes
70        // before `prev_start`.
71        if self.prev_start > 0 {
72            self.data_stream.copy_within(self.prev_start.., 0);
73            self.data_stream
74                .truncate(self.data_stream.len() - self.prev_start);
75            self.current_start -= self.prev_start;
76            self.prev_start = 0;
77            self.debug_assert_invariants();
78        }
79
80        &mut self.data_stream
81    }
82
83    /// Runs `unfilter` on the current row, and then shifts rows so that the current row becomes the previous row.
84    ///
85    /// Will panic if `self.curr_row_len() < rowlen`.
86    pub fn unfilter_curr_row(
87        &mut self,
88        rowlen: usize,
89        bpp: BytesPerPixel,
90    ) -> Result<(), DecodingError> {
91        debug_assert!(rowlen >= 2); // 1 byte for `FilterType` and at least 1 byte of pixel data.
92
93        let (prev, row) = self.data_stream.split_at_mut(self.current_start);
94        let prev: &[u8] = prev; // `prev` is immutable
95        let prev = &prev[self.prev_start..];
96        debug_assert!(prev.is_empty() || prev.len() == (rowlen - 1));
97
98        // Get the filter type.
99        let filter = FilterType::from_u8(row[0]).ok_or(DecodingError::Format(
100            FormatErrorInner::UnknownFilterMethod(row[0]).into(),
101        ))?;
102        let row = &mut row[1..rowlen];
103
104        unfilter(filter, bpp, prev, row);
105
106        self.prev_start = self.current_start + 1;
107        self.current_start += rowlen;
108        self.debug_assert_invariants();
109
110        Ok(())
111    }
112}