diff options
-rw-r--r-- | gifed/Cargo.toml | 8 | ||||
-rw-r--r-- | gifed/src/gif.rs | 10 | ||||
-rw-r--r-- | gifed/src/gif_builder.rs | 124 | ||||
-rw-r--r-- | gifed/src/lib.rs | 2 |
4 files changed, 65 insertions, 79 deletions
diff --git a/gifed/Cargo.toml b/gifed/Cargo.toml index ce49947..b4d6322 100644 --- a/gifed/Cargo.toml +++ b/gifed/Cargo.toml @@ -9,13 +9,15 @@ repository = "https://github.com/genuinebyte/gifed" [dependencies] bitvec = "1.0.1" -color_quant = "1.1.0" -rgb = { version = "0.8", optional = true } weezl = "0.1.5" +color_quant = { version = "1.1.0", optional = true } +rgb = { version = "0.8", optional = true } + [features] weezl-encode = [] -default = ["rgb"] +videoish = ["color_quant", "rgb"] +default = [] [dev-dependencies] rand = "0.8.5" diff --git a/gifed/src/gif.rs b/gifed/src/gif.rs index 87a310f..f11694a 100644 --- a/gifed/src/gif.rs +++ b/gifed/src/gif.rs @@ -20,6 +20,16 @@ pub struct Gif { } impl Gif { + pub fn new(width: u16, height: u16) -> Self { + Self { + //TODO: gen- select lower when possible + version: Version::Gif89a, + descriptor: ScreenDescriptor::new(width, height), + palette: None, + blocks: vec![], + } + } + pub fn set_width(&mut self, width: u16) { self.descriptor.width = width; } diff --git a/gifed/src/gif_builder.rs b/gifed/src/gif_builder.rs index 9d039bf..53b1929 100644 --- a/gifed/src/gif_builder.rs +++ b/gifed/src/gif_builder.rs @@ -1,90 +1,59 @@ -use crate::{ - block::{Palette, ScreenDescriptor, Version}, - writer::ImageBuilder, - EncodeError, Gif, -}; +use crate::{block::Palette, writer::ImageBuilder, Color, EncodeError, Gif}; use color_quant::NeuQuant; -use rgb::{ComponentBytes, FromSlice, RGB8}; +use rgb::{ComponentBytes, FromSlice}; use std::convert::TryFrom; -pub struct GifBuilder { +pub struct VideoGif { width: u16, height: u16, framerate: Option<u16>, - global_palette: Option<Palette>, frames: Vec<Frame>, } -impl GifBuilder { - pub fn set_resolution(&mut self, width: u16, height: u16) { - self.width = width; - self.height = height; +impl VideoGif { + pub fn new(width: u16, height: u16) -> Self { + Self { + width, + height, + framerate: None, + frames: vec![], + } } + + /// Set the approximate frames per second. + /// + /// This struct uses a constant framerate and is only precise to hundreths + /// of a second, so you might not get exactly what you want. pub fn set_framerate(&mut self, framerate: u16) { - self.framerate = Some(framerate) + self.framerate = Some(100 / framerate); } - pub fn add_frame(&mut self, frame: Frame) { - self.frames.push(frame) - } - pub fn add_global_palette(&mut self, palette: Palette) { - self.global_palette = Some(palette) + + pub fn add_frame<F: Into<Frame>>(&mut self, frame: F) { + self.frames.push(frame.into()) } + + #[rustfmt::skip] // it was doing things i did not like pub fn build(self) -> Result<Gif, EncodeError> { - let Self { - width, - height, - framerate, - frames, - global_palette, - } = self; - - let descriptor = ScreenDescriptor::new(width, height); - let mut gif = Gif { - version: Version::Gif89a, - descriptor, - palette: global_palette, - blocks: vec![], - }; - - let images = frames.into_iter().map(|frame| { - let Frame { - interval, - image_indices, - palette, - } = frame; - - let delay = interval - .map(|interval| interval) - .or(framerate.map(|fr| 100 / fr)) - .unwrap_or(10); - ImageBuilder::new(width, height) - .delay(delay) - .palette(palette) - .build(image_indices) - }); - - for compressed_image in images { - match compressed_image { - Ok(img) => gif.push(img), - Err(e) => return Err(e), - } - } + let Self { width, height, framerate, frames } = self; - Ok(gif) - } -} + let mut gif = Gif::new(width, height); -impl Default for GifBuilder { - fn default() -> Self { - Self { - width: 256, - height: 256, - framerate: Some(15), - frames: vec![], - global_palette: None, + for Frame { image_indices, interval, palette } in frames { + //TODO: return error instead of defaulting to 10? or print warning? + // printing in a library is bad but perhaps so is assuming 10 fps? + let delay = interval.or(framerate).unwrap_or(10); + + gif.push( + ImageBuilder::new(width, height) + .delay(delay) + .palette(palette) + .build(image_indices)?, + ) } + + Ok(gif) } } @@ -96,13 +65,10 @@ pub struct Frame { palette: Palette, } -impl From<Vec<Vec<RGB8>>> for Frame { - /// image: row-major ordering - fn from(image: Vec<Vec<RGB8>>) -> Self { - let flat = image.concat(); - +impl From<&[Color]> for Frame { + fn from(flat: &[Color]) -> Self { let flat_rgba = flat.as_rgba(); - let quant = NeuQuant::new(1, 256, &flat_rgba.as_bytes()); + let quant = NeuQuant::new(1, 256, flat_rgba.as_bytes()); let mut indicies = vec![0; flat.len()]; for (image_idx, px) in flat.iter().enumerate() { @@ -120,8 +86,16 @@ impl From<Vec<Vec<RGB8>>> for Frame { } } +impl From<(&[Color], u16)> for Frame { + fn from(image_delay: (&[Color], u16)) -> Self { + let (flat, delay) = image_delay; + let mut this: Frame = flat.into(); + this.interval = Some(delay); + this + } +} + impl Frame { - /// pub fn set_interval(&mut self, interval_hundredths: u16) { self.interval = Some(interval_hundredths); } diff --git a/gifed/src/lib.rs b/gifed/src/lib.rs index 3990e33..7d35dee 100644 --- a/gifed/src/lib.rs +++ b/gifed/src/lib.rs @@ -2,7 +2,7 @@ mod gif; mod lzw; pub mod block; -#[cfg(all(feature = "rgb"))] +#[cfg(feature = "videoish")] pub mod gif_builder; pub mod reader; pub mod writer; |