use super::{
super::{format::*, image::*, stream::*},
zlib::*,
};
use {
cursive::*,
gif::*,
std::{fs::*, io, path::*},
};
impl Image {
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))
}
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())))
}
}
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)> {
let (data, _size) = read_gif(&self.path, false)?;
Ok((Box::new(io::Cursor::new(data)), false))
}
}
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)?)
}