From 4d7093c266bf9870648b9aaa4b9dd36561a69dcc Mon Sep 17 00:00:00 2001 From: gennyble Date: Tue, 2 Jan 2024 18:18:59 -0600 Subject: gif_build.rs renamed to videogif.rs also checking frame's are the right size now --- gifed/src/block/palette.rs | 5 +- gifed/src/gif_builder.rs | 102 -------------------------------------- gifed/src/lib.rs | 4 +- gifed/src/videogif.rs | 119 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 123 insertions(+), 107 deletions(-) delete mode 100644 gifed/src/gif_builder.rs create mode 100644 gifed/src/videogif.rs diff --git a/gifed/src/block/palette.rs b/gifed/src/block/palette.rs index 436e698..0dc1686 100644 --- a/gifed/src/block/palette.rs +++ b/gifed/src/block/palette.rs @@ -51,9 +51,8 @@ impl Palette { pub fn from_color(&self, color: Color) -> Option { self.table .iter() - .enumerate() - .find(|(_, c)| **c == color) - .map(|(i, _)| i as u8) + .position(|c| *c == color) + .map(|idx| idx as u8) } /// How many padding bytes we need to write. diff --git a/gifed/src/gif_builder.rs b/gifed/src/gif_builder.rs deleted file mode 100644 index 53b1929..0000000 --- a/gifed/src/gif_builder.rs +++ /dev/null @@ -1,102 +0,0 @@ -use crate::{block::Palette, writer::ImageBuilder, Color, EncodeError, Gif}; - -use color_quant::NeuQuant; -use rgb::{ComponentBytes, FromSlice}; - -use std::convert::TryFrom; - -pub struct VideoGif { - width: u16, - height: u16, - framerate: Option, - frames: Vec, -} - -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(100 / framerate); - } - - pub fn add_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 { - let Self { width, height, framerate, frames } = self; - - let mut gif = Gif::new(width, height); - - 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<&[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 indicies = 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]); - indicies[image_idx] = color_idx as u8; - } - - let palette = Palette::try_from(quant.color_map_rgb().as_slice()).unwrap(); - - Self { - image_indices: indicies, - 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); - } -} diff --git a/gifed/src/lib.rs b/gifed/src/lib.rs index 7d35dee..2ed3b9b 100644 --- a/gifed/src/lib.rs +++ b/gifed/src/lib.rs @@ -2,9 +2,9 @@ mod gif; mod lzw; pub mod block; -#[cfg(feature = "videoish")] -pub mod gif_builder; pub mod reader; +#[cfg(feature = "videoish")] +pub mod videogif; pub mod writer; pub use reader::DecodeError; diff --git a/gifed/src/videogif.rs b/gifed/src/videogif.rs new file mode 100644 index 0000000..27ec798 --- /dev/null +++ b/gifed/src/videogif.rs @@ -0,0 +1,119 @@ +use crate::{block::Palette, writer::ImageBuilder, Color, EncodeError, Gif}; + +use color_quant::NeuQuant; +use rgb::{ComponentBytes, FromSlice}; + +use std::convert::TryFrom; + +pub struct VideoGif { + width: u16, + height: u16, + framerate: Option, + frames: Vec, +} + +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(100 / framerate); + } + + /// 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 } = self; + + let mut gif = Gif::new(width, height); + + 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<&[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