1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use super::Error;
use crate::disposal::Disposal;
use imgref::*;
use rgb::*;
use std::io;
pub struct Screen<PixelType = RGBA8> {
pub pixels: ImgVec<PixelType>,
global_pal: Option<Vec<PixelType>>,
disposal: Disposal<PixelType>,
}
impl Screen<RGBA8> {
pub fn new_reader<T: io::Read>(reader: &gif::Reader<T>) -> Self {
Self::from_reader(reader)
}
}
impl<PixelType: From<RGB8> + Copy + Default> Screen<PixelType> {
pub fn from_reader<T: io::Read>(reader: &gif::Reader<T>) -> Self {
let pal = reader.global_palette().map(convert_pixels);
Self::new(reader.width().into(), reader.height().into(), PixelType::default(), pal)
}
#[inline]
pub fn new(width: usize, height: usize, _bg_color: PixelType, global_pal: Option<Vec<PixelType>>) -> Self {
Screen {
pixels: Img::new(vec![PixelType::default(); width * height], width, height),
global_pal,
disposal: Disposal::default(),
}
}
pub fn blit_frame(&mut self, frame: &gif::Frame<'_>) -> Result<ImgRef<'_, PixelType>, Error> {
let local_pal : Option<Vec<_>> = frame.palette.as_ref().map(|bytes| convert_pixels(bytes));
self.blit(local_pal.as_deref(), frame.dispose,
frame.left, frame.top,
ImgRef::new(&frame.buffer, frame.width.into(), frame.height.into()), frame.transparent)
}
pub fn blit(&mut self, local_pal: Option<&[PixelType]>, method: gif::DisposalMethod, left: u16, top: u16, buffer: ImgRef<'_, u8>, transparent: Option<u8>) -> Result<ImgRef<'_, PixelType>, Error> {
let mut pal = local_pal.or(self.global_pal.as_deref()).ok_or(Error::NoPalette)?;
let mut tmp;
if pal.len() < 256 {
tmp = Vec::with_capacity(256);
tmp.extend_from_slice(pal);
tmp.resize(256, Default::default());
pal = &tmp;
};
let pal = &pal[0..256];
self.disposal.dispose(self.pixels.as_mut());
self.disposal = Disposal::new(method, left, top, buffer.width() as u16, buffer.height() as u16, self.pixels.as_ref());
for (dst, src) in self.pixels.sub_image_mut(left.into(), top.into(), buffer.width(), buffer.height()).pixels_mut().zip(buffer.pixels()) {
if Some(src) == transparent {
continue;
}
*dst = pal[src as usize];
}
Ok(self.pixels.as_ref())
}
}
fn convert_pixels<T: From<RGB8> + Default>(palette_bytes: &[u8]) -> Vec<T> {
let mut res = Vec::with_capacity(256);
res.extend(palette_bytes.chunks(3).map(|byte| RGB8{r:byte[0], g:byte[1], b:byte[2]}.into()));
while res.len() < 256 {
res.push(Default::default());
}
res
}
#[test]
fn screen_rgb_rgba() {
let _ = Screen::new(1, 1, RGBA8::new(0, 0, 0, 0), None);
let _ = Screen::new(1, 1, RGB8::new(0, 0, 0), None);
}