Coverage Report

Created: 2025-07-18 06:49

/rust/registry/src/index.crates.io-6f17d22bba15001f/gif-0.13.3/src/reader/converter.rs
Line
Count
Source (jump to first uncovered line)
1
use std::borrow::Cow;
2
use std::io;
3
use std::mem;
4
use std::iter;
5
use crate::common::Frame;
6
use crate::MemoryLimit;
7
8
use super::decoder::{DecodingError, OutputBuffer, PLTE_CHANNELS};
9
10
pub(crate) const N_CHANNELS: usize = 4;
11
12
/// Output mode for the image data
13
#[derive(Clone, Copy, Debug, PartialEq)]
14
#[repr(u8)]
15
pub 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
26
pub(crate) type FillBufferCallback<'a> = &'a mut dyn FnMut(&mut OutputBuffer<'_>) -> Result<usize, DecodingError>;
27
28
/// Deinterlaces and expands to RGBA if needed
29
pub(crate) struct PixelConverter {
30
    memory_limit: MemoryLimit,
31
    color_output: ColorOutput,
32
    buffer: Vec<u8>,
33
    global_palette: Option<Vec<u8>>,
34
}
35
36
impl PixelConverter {
37
2.11k
    pub(crate) const fn new(color_output: ColorOutput, memory_limit: MemoryLimit) -> Self {
38
2.11k
        Self {
39
2.11k
            memory_limit,
40
2.11k
            color_output,
41
2.11k
            buffer: Vec::new(),
42
2.11k
            global_palette: None,
43
2.11k
        }
44
2.11k
    }
45
46
0
    pub(crate) fn check_buffer_size(&self, frame: &Frame<'_>) -> Result<usize, DecodingError> {
47
0
        let pixel_bytes = self.memory_limit
48
0
            .buffer_size(self.color_output, frame.width, frame.height)
49
0
            .ok_or_else(|| io::Error::new(io::ErrorKind::OutOfMemory, "image is too large"))?;
50
51
0
        debug_assert_eq!(
52
0
            pixel_bytes, self.buffer_size(frame).unwrap(),
53
0
            "Checked computation diverges from required buffer size"
54
        );
55
0
        Ok(pixel_bytes)
56
0
    }
57
58
    #[inline]
59
0
    pub(crate) fn read_frame(&mut self, frame: &mut Frame<'_>, data_callback: FillBufferCallback<'_>) -> Result<(), DecodingError> {
60
0
        let pixel_bytes = self.check_buffer_size(frame)?;
61
0
        let mut vec = match mem::replace(&mut frame.buffer, Cow::Borrowed(&[])) {
62
            // reuse buffer if possible without reallocating
63
0
            Cow::Owned(mut vec) if vec.capacity() >= pixel_bytes => {
64
0
                vec.resize(pixel_bytes, 0);
65
0
                vec
66
            },
67
            // resizing would realloc anyway, and 0-init is faster than a copy
68
0
            _ => vec![0; pixel_bytes],
69
        };
70
0
        self.read_into_buffer(frame, &mut vec, data_callback)?;
71
0
        frame.buffer = Cow::Owned(vec);
72
0
        frame.interlaced = false;
73
0
        Ok(())
74
0
    }
75
76
    #[inline]
77
779
    pub(crate) const fn buffer_size(&self, frame: &Frame<'_>) -> Option<usize> {
78
779
        self.line_length(frame).checked_mul(frame.height as usize)
79
779
    }
80
81
    #[inline]
82
1.56k
    pub(crate) const fn line_length(&self, frame: &Frame<'_>) -> usize {
83
        use self::ColorOutput::{Indexed, RGBA};
84
1.56k
        match self.color_output {
85
1.56k
            RGBA => frame.width as usize * N_CHANNELS,
86
0
            Indexed => frame.width as usize,
87
        }
88
1.56k
    }
89
90
    /// Use `read_into_buffer` to deinterlace
91
    #[inline(never)]
92
172k
    pub(crate) fn fill_buffer(&mut self, current_frame: &Frame<'_>, mut buf: &mut [u8], data_callback: FillBufferCallback<'_>) -> Result<bool, DecodingError> {
93
        loop {
94
385k
            let decode_into = match self.color_output {
95
                // When decoding indexed data, LZW can write the pixels directly
96
0
                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
385k
                    let buffer_size = buf.len() / N_CHANNELS;
101
385k
                    if buffer_size == 0 {
102
5
                        return Err(DecodingError::format("odd-sized buffer"));
103
385k
                    }
104
385k
                    if self.buffer.len() < buffer_size {
105
1.50k
                        self.buffer.resize(buffer_size, 0);
106
383k
                    }
107
385k
                    &mut self.buffer[..buffer_size]
108
                }
109
            };
110
385k
            match data_callback(&mut OutputBuffer::Slice(decode_into))? {
111
120
                0 => return Ok(false),
112
383k
                bytes_decoded => {
113
383k
                    match self.color_output {
114
                        ColorOutput::RGBA => {
115
383k
                            let transparent = current_frame.transparent;
116
383k
                            let palette: &[u8] = current_frame.palette.as_deref()
117
383k
                                .or(self.global_palette.as_deref())
118
383k
                                .unwrap_or_default(); // next_frame_info already checked it won't happen
119
383k
120
383k
                            let (pixels, rest) = buf.split_at_mut(bytes_decoded * N_CHANNELS);
121
383k
                            buf = rest;
122
123
50.2M
                            for (rgba, idx) in pixels.chunks_exact_mut(N_CHANNELS).zip(self.buffer.iter().copied().take(bytes_decoded)) {
124
50.2M
                                let plte_offset = PLTE_CHANNELS * idx as usize;
125
50.2M
                                if let Some(colors) = palette.get(plte_offset..plte_offset+PLTE_CHANNELS) {
126
49.6M
                                    rgba[0] = colors[0];
127
49.6M
                                    rgba[1] = colors[1];
128
49.6M
                                    rgba[2] = colors[2];
129
49.6M
                                    rgba[3] = if let Some(t) = transparent {
130
7.58M
                                        if t == idx { 0x00 } else { 0xFF }
131
                                    } else {
132
42.0M
                                        0xFF
133
                                    };
134
565k
                                }
135
                            }
136
                        },
137
0
                        ColorOutput::Indexed => {
138
0
                            buf = &mut buf[bytes_decoded..];
139
0
                        }
140
                    }
141
383k
                    if buf.is_empty() {
142
170k
                        return Ok(true);
143
212k
                    }
144
                },
145
            }
146
        }
147
172k
    }
148
149
3.08k
    pub(crate) fn global_palette(&self) -> Option<&[u8]> {
150
3.08k
        self.global_palette.as_deref()
151
3.08k
    }
152
153
2.00k
    pub(crate) fn set_global_palette(&mut self, palette: Vec<u8>) {
154
2.00k
        self.global_palette = if !palette.is_empty() {
155
1.43k
            Some(palette)
156
        } else {
157
570
            None
158
        };
159
2.00k
    }
160
161
    /// Applies deinterlacing
162
    ///
163
    /// Set `frame.interlaced = false` afterwards if you're putting the buffer back into the `Frame`
164
1.56k
    pub(crate) fn read_into_buffer(&mut self, frame: &Frame<'_>, buf: &mut [u8], data_callback: FillBufferCallback<'_>) -> Result<(), DecodingError> {
165
1.56k
        if frame.interlaced {
166
789
            let width = self.line_length(frame);
167
171k
            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
171k
                let start = row * width;
170
                // Handle a too-small buffer and 32-bit usize overflow without panicking
171
171k
                let line = buf.get_mut(start..).and_then(|b| b.get_mut(..width))
172
171k
                    .ok_or_else(|| DecodingError::format("buffer too small"))?;
173
171k
                if !self.fill_buffer(frame, line, data_callback)? {
174
93
                    return Err(DecodingError::format("image truncated"));
175
170k
                }
176
            }
177
        } else {
178
779
            let buf = self.buffer_size(frame).and_then(|buffer_size| buf.get_mut(..buffer_size))
179
779
                .ok_or_else(|| DecodingError::format("buffer too small"))?;
180
779
            if !self.fill_buffer(frame, buf, data_callback)? {
181
27
                return Err(DecodingError::format("image truncated"));
182
43
            }
183
        };
184
130
        Ok(())
185
1.56k
    }
186
}
187
188
struct InterlaceIterator {
189
    len: u16,
190
    next: usize,
191
    pass: usize,
192
}
193
194
impl iter::Iterator for InterlaceIterator {
195
    type Item = usize;
196
197
    #[inline]
198
171k
    fn next(&mut self) -> Option<Self::Item> {
199
171k
        if self.len == 0 {
200
62
            return None;
201
171k
        }
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
171k
        let mut next = self.next + *[8, 8, 4, 2].get(self.pass)?;
205
171k
        while next >= self.len as usize {
206
316
            debug_assert!(self.pass < 4);
207
316
            next = *[4, 2, 1, 0].get(self.pass)?;
208
316
            self.pass += 1;
209
        }
210
171k
        mem::swap(&mut next, &mut self.next);
211
171k
        Some(next)
212
171k
    }
213
}
214
215
#[cfg(test)]
216
mod 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
}