gif/reader/
converter.rs

1use alloc::borrow::Cow;
2use alloc::vec::Vec;
3use core::iter;
4use core::mem;
5
6use super::decoder::{DecodingError, OutputBuffer, PLTE_CHANNELS};
7use crate::common::Frame;
8use crate::MemoryLimit;
9
10pub(crate) const N_CHANNELS: usize = 4;
11
12/// Output mode for the image data
13#[derive(Clone, Copy, Debug, PartialEq)]
14#[repr(u8)]
15pub enum ColorOutput {
16    /// The decoder expands the image data to 32bit RGBA.
17    /// This affects:
18    ///
19    ///  - The buffer buffer of the `Frame` returned by [`Decoder::read_next_frame`].
20    ///  - `Decoder::fill_buffer`, `Decoder::buffer_size` and `Decoder::line_length`.
21    RGBA = 0,
22    /// The decoder returns the raw indexed data.
23    Indexed = 1,
24}
25
26pub(crate) type FillBufferCallback<'a> =
27    &'a mut dyn FnMut(&mut OutputBuffer<'_>) -> Result<usize, DecodingError>;
28
29/// Deinterlaces and expands to RGBA if needed
30pub(crate) struct PixelConverter {
31    color_output: ColorOutput,
32    buffer: Vec<u8>,
33    global_palette: Option<Vec<u8>>,
34}
35
36impl PixelConverter {
37    pub(crate) const fn new(color_output: ColorOutput) -> Self {
38        Self {
39            color_output,
40            buffer: Vec::new(),
41            global_palette: None,
42        }
43    }
44
45    pub(crate) fn check_buffer_size(
46        &self,
47        frame: &Frame<'_>,
48        memory_limit: &MemoryLimit,
49    ) -> Result<usize, DecodingError> {
50        let pixel_bytes = memory_limit
51            .buffer_size(self.color_output, frame.width, frame.height)
52            .ok_or_else(|| DecodingError::OutOfMemory)?;
53
54        debug_assert_eq!(
55            pixel_bytes,
56            self.buffer_size(frame).unwrap(),
57            "Checked computation diverges from required buffer size"
58        );
59        Ok(pixel_bytes)
60    }
61
62    #[inline]
63    pub(crate) fn read_frame(
64        &mut self,
65        frame: &mut Frame<'_>,
66        data_callback: FillBufferCallback<'_>,
67        memory_limit: &MemoryLimit,
68    ) -> Result<(), DecodingError> {
69        let pixel_bytes = self.check_buffer_size(frame, memory_limit)?;
70        let mut vec = match mem::replace(&mut frame.buffer, Cow::Borrowed(&[])) {
71            // reuse buffer if possible without reallocating
72            Cow::Owned(mut vec) if vec.capacity() >= pixel_bytes => {
73                vec.resize(pixel_bytes, 0);
74                vec
75            }
76            // resizing would realloc anyway, and 0-init is faster than a copy
77            _ => vec![0; pixel_bytes],
78        };
79        self.read_into_buffer(frame, &mut vec, data_callback)?;
80        frame.buffer = Cow::Owned(vec);
81        frame.interlaced = false;
82        Ok(())
83    }
84
85    #[inline]
86    pub(crate) const fn buffer_size(&self, frame: &Frame<'_>) -> Option<usize> {
87        self.line_length(frame).checked_mul(frame.height as usize)
88    }
89
90    #[inline]
91    pub(crate) const fn line_length(&self, frame: &Frame<'_>) -> usize {
92        use self::ColorOutput::{Indexed, RGBA};
93        match self.color_output {
94            RGBA => frame.width as usize * N_CHANNELS,
95            Indexed => frame.width as usize,
96        }
97    }
98
99    /// Use `read_into_buffer` to deinterlace
100    #[inline(never)]
101    pub(crate) fn fill_buffer(
102        &mut self,
103        current_frame: &Frame<'_>,
104        mut buf: &mut [u8],
105        data_callback: FillBufferCallback<'_>,
106    ) -> Result<bool, DecodingError> {
107        loop {
108            let decode_into = match self.color_output {
109                // When decoding indexed data, LZW can write the pixels directly
110                ColorOutput::Indexed => &mut buf[..],
111                // When decoding RGBA, the pixel data will be expanded by a factor of 4,
112                // and it's simpler to decode indexed pixels to another buffer first
113                ColorOutput::RGBA => {
114                    let buffer_size = buf.len() / N_CHANNELS;
115                    if buffer_size == 0 {
116                        return Err(DecodingError::format("odd-sized buffer"));
117                    }
118                    if self.buffer.len() < buffer_size {
119                        self.buffer.resize(buffer_size, 0);
120                    }
121                    &mut self.buffer[..buffer_size]
122                }
123            };
124            match data_callback(&mut OutputBuffer::Slice(decode_into))? {
125                0 => return Ok(false),
126                bytes_decoded => {
127                    match self.color_output {
128                        ColorOutput::RGBA => {
129                            let transparent = current_frame.transparent;
130                            let palette: &[u8] = current_frame
131                                .palette
132                                .as_deref()
133                                .or(self.global_palette.as_deref())
134                                .unwrap_or_default(); // next_frame_info already checked it won't happen
135
136                            let (pixels, rest) = buf.split_at_mut(bytes_decoded * N_CHANNELS);
137                            buf = rest;
138
139                            for (rgba, idx) in pixels
140                                .chunks_exact_mut(N_CHANNELS)
141                                .zip(self.buffer.iter().copied().take(bytes_decoded))
142                            {
143                                let plte_offset = PLTE_CHANNELS * idx as usize;
144                                if let Some(colors) =
145                                    palette.get(plte_offset..plte_offset + PLTE_CHANNELS)
146                                {
147                                    rgba[0] = colors[0];
148                                    rgba[1] = colors[1];
149                                    rgba[2] = colors[2];
150                                    rgba[3] = if let Some(t) = transparent {
151                                        if t == idx {
152                                            0x00
153                                        } else {
154                                            0xFF
155                                        }
156                                    } else {
157                                        0xFF
158                                    };
159                                }
160                            }
161                        }
162                        ColorOutput::Indexed => {
163                            buf = &mut buf[bytes_decoded..];
164                        }
165                    }
166                    if buf.is_empty() {
167                        return Ok(true);
168                    }
169                }
170            }
171        }
172    }
173
174    pub(crate) fn global_palette(&self) -> Option<&[u8]> {
175        self.global_palette.as_deref()
176    }
177
178    pub(crate) fn set_global_palette(&mut self, palette: Vec<u8>) {
179        self.global_palette = if !palette.is_empty() {
180            Some(palette)
181        } else {
182            None
183        };
184    }
185
186    /// Applies deinterlacing
187    ///
188    /// Set `frame.interlaced = false` afterwards if you're putting the buffer back into the `Frame`
189    pub(crate) fn read_into_buffer(
190        &mut self,
191        frame: &Frame<'_>,
192        buf: &mut [u8],
193        data_callback: FillBufferCallback<'_>,
194    ) -> Result<(), DecodingError> {
195        if frame.interlaced {
196            let width = self.line_length(frame);
197            for row in (InterlaceIterator {
198                len: frame.height,
199                next: 0,
200                pass: 0,
201            }) {
202                // this can't overflow 32-bit, because row never equals (maximum) height
203                let start = row * width;
204                // Handle a too-small buffer and 32-bit usize overflow without panicking
205                let line = buf
206                    .get_mut(start..)
207                    .and_then(|b| b.get_mut(..width))
208                    .ok_or_else(|| DecodingError::format("buffer too small"))?;
209                if !self.fill_buffer(frame, line, data_callback)? {
210                    return Err(DecodingError::format("image truncated"));
211                }
212            }
213        } else {
214            let buf = self
215                .buffer_size(frame)
216                .and_then(|buffer_size| buf.get_mut(..buffer_size))
217                .ok_or_else(|| DecodingError::format("buffer too small"))?;
218            if !self.fill_buffer(frame, buf, data_callback)? {
219                return Err(DecodingError::format("image truncated"));
220            }
221        };
222        Ok(())
223    }
224}
225
226struct InterlaceIterator {
227    len: u16,
228    next: usize,
229    pass: usize,
230}
231
232impl iter::Iterator for InterlaceIterator {
233    type Item = usize;
234
235    #[inline]
236    fn next(&mut self) -> Option<Self::Item> {
237        if self.len == 0 {
238            return None;
239        }
240        // although the pass never goes out of bounds thanks to len==0,
241        // the optimizer doesn't see it. get()? avoids costlier panicking code.
242        let mut next = self.next + *[8, 8, 4, 2].get(self.pass)?;
243        while next >= self.len as usize {
244            debug_assert!(self.pass < 4);
245            next = *[4, 2, 1, 0].get(self.pass)?;
246            self.pass += 1;
247        }
248        mem::swap(&mut next, &mut self.next);
249        Some(next)
250    }
251}
252
253#[cfg(test)]
254mod test {
255    use alloc::vec::Vec;
256
257    use super::InterlaceIterator;
258
259    #[rustfmt::skip]
260    #[test]
261    fn test_interlace_iterator() {
262        for &(len, expect) in &[
263            (0, &[][..]),
264            (1, &[0][..]),
265            (2, &[0, 1][..]),
266            (3, &[0, 2, 1][..]),
267            (4, &[0, 2, 1, 3][..]),
268            (5, &[0, 4, 2, 1, 3][..]),
269            (6, &[0, 4, 2, 1, 3, 5][..]),
270            (7, &[0, 4, 2, 6, 1, 3, 5][..]),
271            (8, &[0, 4, 2, 6, 1, 3, 5, 7][..]),
272            (9, &[0, 8, 4, 2, 6, 1, 3, 5, 7][..]),
273            (10, &[0, 8, 4, 2, 6, 1, 3, 5, 7, 9][..]),
274            (11, &[0, 8, 4, 2, 6, 10, 1, 3, 5, 7, 9][..]),
275            (12, &[0, 8, 4, 2, 6, 10, 1, 3, 5, 7, 9, 11][..]),
276            (13, &[0, 8, 4, 12, 2, 6, 10, 1, 3, 5, 7, 9, 11][..]),
277            (14, &[0, 8, 4, 12, 2, 6, 10, 1, 3, 5, 7, 9, 11, 13][..]),
278            (15, &[0, 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13][..]),
279            (16, &[0, 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15][..]),
280            (17, &[0, 8, 16, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15][..]),
281        ] {
282            let iter = InterlaceIterator { len, next: 0, pass: 0 };
283            let lines = iter.collect::<Vec<_>>();
284            assert_eq!(lines, expect);
285        }
286    }
287
288    #[test]
289    fn interlace_max() {
290        let iter = InterlaceIterator {
291            len: 0xFFFF,
292            next: 0,
293            pass: 0,
294        };
295        assert_eq!(65533, iter.last().unwrap());
296    }
297}