cursive-image 0.0.6

Image view for the Cursive TUI library
Documentation
use super::{
    super::{format::*, image::*, stream::*},
    zlib::*,
};

use {
    cursive::*,
    gif::*,
    std::{fs::*, io, path::*},
};

impl Image {
    /// Constructor.
    ///
    /// The implementation only supports [RGBA](ImageFormat::RGBA).
    pub fn new_owned_from_gif_file<PathT>(path: PathT, compress: bool) -> io::Result<Self>
    where
        PathT: AsRef<Path>,
    {
        let (data, size) = read_gif(path, true)?;
        let data = if compress { zlib(&data)? } else { data };
        Ok(Self::new_owned(data, compress, ImageFormat::RGBA, size))
    }

    /// Constructor.
    ///
    /// The implementation only supports [RGBA](ImageFormat::RGBA).
    pub fn new_stream_from_gif_file<PathT>(path: PathT) -> io::Result<Self>
    where
        PathT: AsRef<Path>,
    {
        let path = path.as_ref();
        let decoder = open_gif(path)?;
        let stream = GifImageStream::new(path.into());
        Ok(Self::new_stream(stream, ImageFormat::RGBA, (decoder.width(), decoder.height())))
    }
}

//
// GifImageStream
//

struct GifImageStream {
    path: PathBuf,
}

impl GifImageStream {
    fn new(path: PathBuf) -> Self {
        Self { path }
    }
}

impl ImageStream for GifImageStream {
    fn open(&self) -> io::Result<(Box<dyn io::Read>, bool)> {
        // We must load the entire file into memory to decode it
        let (data, _size) = read_gif(&self.path, false)?;
        Ok((Box::new(io::Cursor::new(data)), false))
    }
}

// Utils

fn read_gif<PathT>(path: PathT, size: bool) -> io::Result<(Vec<u8>, Vec2)>
where
    PathT: AsRef<Path>,
{
    let mut decoder = open_gif(path)?;
    decoder.next_frame_info().map_err(io::Error::other)?.ok_or_else(|| io::Error::other("missing GIF frame"))?;
    let mut data = vec![0; decoder.buffer_size()];
    decoder.read_into_buffer(&mut data).map_err(io::Error::other)?;
    let size = if size { (decoder.width(), decoder.height()).into() } else { Default::default() };
    Ok((data, size))
}

fn open_gif<PathT>(path: PathT) -> io::Result<Decoder<File>>
where
    PathT: AsRef<Path>,
{
    let mut options = DecodeOptions::new();
    options.set_color_output(ColorOutput::RGBA);
    Ok(options.read_info(File::open(path)?).map_err(io::Error::other)?)
}