From a49b9ab5ca5ee6c0a92195beacf96f468f0756ea Mon Sep 17 00:00:00 2001 From: gennyble Date: Wed, 29 Jan 2025 21:57:38 -0600 Subject: rename videogif to standardgif --- gifed/Cargo.toml | 5 +- gifed/src/lib.rs | 6 +-- gifed/src/standard.rs | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++ gifed/src/videogif.rs | 143 -------------------------------------------------- 4 files changed, 148 insertions(+), 149 deletions(-) create mode 100644 gifed/src/standard.rs delete mode 100644 gifed/src/videogif.rs diff --git a/gifed/Cargo.toml b/gifed/Cargo.toml index b4d6322..aded3e2 100644 --- a/gifed/Cargo.toml +++ b/gifed/Cargo.toml @@ -9,14 +9,13 @@ repository = "https://github.com/genuinebyte/gifed" [dependencies] bitvec = "1.0.1" -weezl = "0.1.5" +weezl = "0.1.8" color_quant = { version = "1.1.0", optional = true } rgb = { version = "0.8", optional = true } [features] -weezl-encode = [] -videoish = ["color_quant", "rgb"] +standard = ["color_quant", "rgb"] default = [] [dev-dependencies] diff --git a/gifed/src/lib.rs b/gifed/src/lib.rs index 2ed3b9b..96ffb1b 100644 --- a/gifed/src/lib.rs +++ b/gifed/src/lib.rs @@ -1,10 +1,10 @@ mod gif; -mod lzw; +pub mod lzw; pub mod block; pub mod reader; -#[cfg(feature = "videoish")] -pub mod videogif; +#[cfg(feature = "standard")] +pub mod standard; pub mod writer; pub use reader::DecodeError; diff --git a/gifed/src/standard.rs b/gifed/src/standard.rs new file mode 100644 index 0000000..bc296cb --- /dev/null +++ b/gifed/src/standard.rs @@ -0,0 +1,143 @@ +use crate::{ + block::{LoopCount, Palette}, + writer::ImageBuilder, + Color, EncodeError, Gif, +}; + +use color_quant::NeuQuant; +use rgb::{ComponentBytes, FromSlice}; + +use std::convert::TryFrom; + +/// A constant framerate gif animation. Every frame must be the same size +/// and entirely fill the gif. +pub struct StandardGif { + width: u16, + height: u16, + framerate: Option, + frames: Vec, + looping: LoopCount, +} + +impl StandardGif { + pub fn new(width: u16, height: u16) -> Self { + Self { + width, + height, + framerate: None, + frames: vec![], + looping: LoopCount::Forever, + } + } + + /// 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(100 / framerate); + } + + /// Set the number of times this gif should loop. Defaults to forever. + /// + /// See [LoopCount] + pub fn set_looping(&mut self, count: LoopCount) { + self.looping = count; + } + + /// Adds a frame to the gif. + /// + /// # Panic + /// Panics if the provided [Frame]'s length is not the same as the gif's + /// width * height. + pub fn add_frame>(&mut self, frame: F) { + let frame = frame.into(); + let frame_area = frame.image_indices.len(); + let gif_area = self.width as usize * self.height as usize; + + if frame_area != gif_area { + //TODO: gen- Result instead of panic? + panic!( + "frame has a length of {frame_area} but VideoGif expected {gif_area} ({} * {})", + self.width, self.height + ); + } + + self.frames.push(frame) + } + + #[rustfmt::skip] // it was doing things i did not like + pub fn build(self) -> Result { + let Self { width, height, framerate, frames, looping } = self; + + let mut gif = Gif::new(width, height); + + gif.push(looping); + + 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) + } +} + +pub struct Frame { + /// indices into the palette + image_indices: Vec, + /// in hundredths of a second + interval: Option, + palette: Palette, +} + +impl From> for Frame { + fn from(flat: Vec) -> Self { + flat.as_slice().into() + } +} + +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 mut indices = vec![0; flat.len()]; + for (image_idx, px) in flat.iter().enumerate() { + let color_idx = quant.index_of(&[px.r, px.g, px.b, 255]); + indices[image_idx] = color_idx as u8; + } + + let palette = Palette::try_from(quant.color_map_rgb().as_slice()).unwrap(); + + Self { + image_indices: indices, + interval: None, + palette, + } + } +} + +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 { + self.interval = Some(interval_hundredths); + self + } +} diff --git a/gifed/src/videogif.rs b/gifed/src/videogif.rs deleted file mode 100644 index d066019..0000000 --- a/gifed/src/videogif.rs +++ /dev/null @@ -1,143 +0,0 @@ -use crate::{ - block::{LoopCount, Palette}, - writer::ImageBuilder, - Color, EncodeError, Gif, -}; - -use color_quant::NeuQuant; -use rgb::{ComponentBytes, FromSlice}; - -use std::convert::TryFrom; - -/// A Video-like GIF. -/// -/// All images must have the same dimensions. -pub struct VideoGif { - width: u16, - height: u16, - framerate: Option, - frames: Vec, - looping: LoopCount, -} - -impl VideoGif { - pub fn new(width: u16, height: u16) -> Self { - Self { - width, - height, - framerate: None, - frames: vec![], - looping: LoopCount::Forever, - } - } - - /// 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(100 / framerate); - } - - /// Set the number of times this gif should loop. Defaults to forever. - /// - /// See [LoopCount] - pub fn set_looping(&mut self, count: LoopCount) { - self.looping = count; - } - - /// Adds a frame to the gif. - /// - /// # Panic - /// Panics if the provided [Frame]'s length is not the same as the gif's - /// width * height. - pub fn add_frame>(&mut self, frame: F) { - let frame = frame.into(); - let frame_area = frame.image_indices.len(); - let gif_area = self.width as usize * self.height as usize; - - if frame_area != gif_area { - //TODO: gen- Result instead of panic? - panic!( - "frame has a length of {frame_area} but VideoGif expected {gif_area} ({} * {})", - self.width, self.height - ); - } - - self.frames.push(frame) - } - - #[rustfmt::skip] // it was doing things i did not like - pub fn build(self) -> Result { - let Self { width, height, framerate, frames, looping } = self; - - let mut gif = Gif::new(width, height); - - gif.push(looping); - - 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) - } -} - -pub struct Frame { - /// indices into the palette - image_indices: Vec, - /// in hundredths of a second - interval: Option, - palette: Palette, -} - -impl From> for Frame { - fn from(flat: Vec) -> Self { - flat.as_slice().into() - } -} - -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 mut indices = vec![0; flat.len()]; - for (image_idx, px) in flat.iter().enumerate() { - let color_idx = quant.index_of(&[px.r, px.g, px.b, 255]); - indices[image_idx] = color_idx as u8; - } - - let palette = Palette::try_from(quant.color_map_rgb().as_slice()).unwrap(); - - Self { - image_indices: indices, - interval: None, - palette, - } - } -} - -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); - } -} -- cgit 1.4.1-3-g733a5