1 | use super::stream::{DecodingError, FormatErrorInner}; |
2 | use crate::common::BytesPerPixel; |
3 | use crate::filter::{unfilter, FilterType}; |
4 | |
5 | // Buffer for temporarily holding decompressed, not-yet-`unfilter`-ed rows. |
6 | pub(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 | |
20 | impl 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 | } |
113 | |