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}