Skip to main content

cursive_image/image/compatibility/
gif.rs

1use super::{
2    super::{format::*, image::*, stream::*},
3    zlib::*,
4};
5
6use {
7    cursive::*,
8    gif::*,
9    std::{fs::*, io, path::*},
10};
11
12impl Image {
13    /// Constructor.
14    ///
15    /// The implementation only supports [RGBA](ImageFormat::RGBA).
16    pub fn new_owned_from_gif_file<PathT>(path: PathT, compress: bool) -> io::Result<Self>
17    where
18        PathT: AsRef<Path>,
19    {
20        let (data, size) = read_gif(path, true)?;
21        let data = if compress { zlib(&data)? } else { data };
22        Ok(Self::new_owned(data, compress, ImageFormat::RGBA, size))
23    }
24
25    /// Constructor.
26    ///
27    /// The implementation only supports [RGBA](ImageFormat::RGBA).
28    pub fn new_stream_from_gif_file<PathT>(path: PathT) -> io::Result<Self>
29    where
30        PathT: AsRef<Path>,
31    {
32        let path = path.as_ref();
33        let decoder = open_gif(path)?;
34        let stream = GifImageStream::new(path.into());
35        Ok(Self::new_stream(stream, ImageFormat::RGBA, (decoder.width(), decoder.height())))
36    }
37}
38
39//
40// GifImageStream
41//
42
43struct GifImageStream {
44    path: PathBuf,
45}
46
47impl GifImageStream {
48    fn new(path: PathBuf) -> Self {
49        Self { path }
50    }
51}
52
53impl ImageStream for GifImageStream {
54    fn open(&self) -> io::Result<(Box<dyn io::Read>, bool)> {
55        // We must load the entire file into memory to decode it
56        let (data, _size) = read_gif(&self.path, false)?;
57        Ok((Box::new(io::Cursor::new(data)), false))
58    }
59}
60
61// Utils
62
63fn read_gif<PathT>(path: PathT, size: bool) -> io::Result<(Vec<u8>, Vec2)>
64where
65    PathT: AsRef<Path>,
66{
67    let mut decoder = open_gif(path)?;
68    decoder.next_frame_info().map_err(io::Error::other)?.ok_or_else(|| io::Error::other("missing GIF frame"))?;
69    let mut data = vec![0; decoder.buffer_size()];
70    decoder.read_into_buffer(&mut data).map_err(io::Error::other)?;
71    let size = if size { (decoder.width(), decoder.height()).into() } else { Default::default() };
72    Ok((data, size))
73}
74
75fn open_gif<PathT>(path: PathT) -> io::Result<Decoder<File>>
76where
77    PathT: AsRef<Path>,
78{
79    let mut options = DecodeOptions::new();
80    options.set_color_output(ColorOutput::RGBA);
81    Ok(options.read_info(File::open(path)?).map_err(io::Error::other)?)
82}