gif/reader/
converter.rs

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