diff options
Diffstat (limited to 'src/writer/gifbuilder.rs')
-rw-r--r-- | src/writer/gifbuilder.rs | 208 |
1 files changed, 21 insertions, 187 deletions
diff --git a/src/writer/gifbuilder.rs b/src/writer/gifbuilder.rs index ff98ba7..6ae55d5 100644 --- a/src/writer/gifbuilder.rs +++ b/src/writer/gifbuilder.rs @@ -1,12 +1,11 @@ -use crate::common::{Color, Version}; -use super::OutVec; +use crate::components::{ColorTable, Gif, LogicalScreenDescriptor, Version}; use super::ImageBuilder; pub struct GifBuilder { version: Version, width: u16, height: u16, - global_color_table: Option<Vec<Color>>, + global_color_table: Option<ColorTable>, background_color_index: u8, imagebuilders: Vec<ImageBuilder> } @@ -23,13 +22,8 @@ impl GifBuilder { } } - pub fn global_color_table(mut self, vec: Vec<Color>) -> Self { - if vec.len() == 0 || vec.len() > 256 { - //TODO: Throw error instead of panic - panic!("GCT has to be less than or 256 colors in size, and at least one"); - } - - self.global_color_table = Some(vec); + pub fn global_color_table(mut self, table: ColorTable) -> Self { + self.global_color_table = Some(table); self } @@ -49,190 +43,30 @@ impl GifBuilder { self } - pub fn write_to_vec(&self) -> Vec<u8> { - let mut out = OutVec::new(); - - self - .write_header(&mut out) - .write_logical_screen_descriptor(&mut out) - .write_global_color_table(&mut out) - .write_images(&mut out) - .write_trailer(&mut out); - - out.vec() - } - - fn write_header(&self, out: &mut OutVec) -> &Self { - out.push_slice(b"GIF"); - - //TODO: Automatically detect version - match self.version { - Version::Gif87a => out.push_slice(b"87a"), - Version::Gif89a => out.push_slice(b"89a") + pub fn build(self) -> Gif { + let mut lsd = LogicalScreenDescriptor { + width: self.width, + height: self.height, + packed: 0, // Set later + background_color_index: self.background_color_index, + pixel_aspect_ratio: 0 //TODO: Allow configuring }; - self - } - - fn write_logical_screen_descriptor(&self, out: &mut OutVec) -> &Self { - out.push_u16(self.width).push_u16(self.height); - - let mut packed: u8 = 0; - if let Some(gct) = &self.global_color_table { - packed |= 0b1000_0000; // Set the GCT flag - - // GCT size is calulated by raising two to this number plus one, - // so we have to work backwards. - let size = (gct.len() as f32).log2().ceil() - 1f32; - - packed |= size as u8; + lsd.color_table_present(true); + lsd.color_table_size(gct.len() as u8); } - //TODO: Color Resolution and Sort Flag fields in packed. - out.push_u8(packed); - - out.push_u8(self.background_color_index) - .push_u8(0x00); //TOOD: Allow setting pixel aspect ratio - self - } - - fn write_global_color_table(&self, out: &mut OutVec) -> &Self { - if let Some(gct) = &self.global_color_table { - out.push_colors(&gct); + let mut images = vec![]; + for builder in self.imagebuilders.into_iter() { + images.push(builder.build()); } - self - } - - fn write_images(&self, out: &mut OutVec) -> &Self { - //TODO: Deduplicate color table size code - let mcs = if let Some(gct) = &self.global_color_table { - ((gct.len() as f32).log2().ceil() - 1f32) as u8 - } else { - 0 - }; - - for ib in &self.imagebuilders { - let image = ib.write_to_vec(mcs); - out.push_slice(&image); + Gif { + header: self.version, + logical_screen_descriptor: lsd, + global_color_table: self.global_color_table, + images } - - self - } - - fn write_trailer(&self, out: &mut OutVec) { - /* - "This block is a single-field block indicating the end of the GIF Data Stream. - It contains the fixed value 0x3B." - */ - out.push_u8(0x3B); - } -} - -#[cfg(test)] -pub mod gifbuilder_test { - use super::*; - - #[test] - pub fn writer_header() { - let mut out = OutVec::new(); - GifBuilder::new(Version::Gif87a, 0, 0).write_header(&mut out); - - assert_eq!(out.vec(), b"GIF87a"); - } - - #[test] - pub fn write_logical_screen_descriptor() { - let mut out = OutVec::new(); - GifBuilder::new(Version::Gif87a, 4, 4).write_logical_screen_descriptor(&mut out); - - assert_eq!(out.vec(), vec![0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00]); - - let mut out = OutVec::new(); - let gct = vec![ - Color::new(0, 0, 0), Color::new(0, 0, 0), Color::new(0, 0, 0), - Color::new(0, 0, 0), Color::new(0, 0, 0) - ]; - GifBuilder::new(Version::Gif87a, 4, 4).global_color_table(gct).write_logical_screen_descriptor(&mut out); - - assert_eq!(out.vec(), vec![0x04, 0x00, 0x04, 0x00, 0b1000_0010, 0x00, 0x00]); - } - - #[test] - pub fn write_global_color_table() { - let mut out = OutVec::new(); - let gct = vec![ - Color::new(1, 2, 3), Color::new(253, 254, 255) - ]; - GifBuilder::new(Version::Gif87a, 4, 4).global_color_table(gct).write_global_color_table(&mut out); - - assert_eq!(out.vec(), vec![1, 2, 3, 253, 254, 255]); - } - - #[test] - fn write_images() { - let gct = vec![ - Color::new(1, 2, 3), Color::new(253, 254, 255) - ]; - let colortable = vec![ - Color::new(0, 0, 0), Color::new(128, 0, 255) - ]; - let indicies = vec![0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0]; - - let expected_out = vec![ - 0x2C, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0b1000_0000, // Image Descriptor 1 - 0, 0, 0, 128, 0, 255, // Color Table - 0x02, 0x05, 0x84, 0x1D, 0x81, 0x7A, 0x50, 0x00, // Image Data 1 - 0x2C, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0b0000_0000, // Image Descriptor 2 - 0x02, 0x05, 0x84, 0x1D, 0x81, 0x7A, 0x50, 0x00 // Image Data 2 - ]; - - let mut out = OutVec::new(); - GifBuilder::new(Version::Gif87a, 4, 4) - .global_color_table(gct) - .image(ImageBuilder::new(4, 4) - .color_table(colortable) - .indicies(indicies.clone()) - ).image(ImageBuilder::new(4, 4) - .indicies(indicies) - ).write_images(&mut out); - - assert_eq!(out.vec(), expected_out); - } - - #[test] - fn write_to_vec() { - let gct = vec![ - Color::new(1, 2, 3), Color::new(253, 254, 255) - ]; - let colortable = vec![ - Color::new(0, 0, 0), Color::new(128, 0, 255) - ]; - let indicies = vec![0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0]; - - let expected_out = vec![ - 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, // Version - GIF87a - 0x04, 0x00, 0x04, 0x00, 0b1000_0000, 0x00, 0x00, // Logical Screen Descriptor - 1, 2, 3, 253, 254, 255, // Global Color Table - 0x2C, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0b1000_0000, // Image Descriptor 1 - 0, 0, 0, 128, 0, 255, // Color Table - 0x02, 0x05, 0x84, 0x1D, 0x81, 0x7A, 0x50, 0x00, // Image Data 1 - 0x2C, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0b0000_0000, // Image Descriptor 2 - 0x02, 0x05, 0x84, 0x1D, 0x81, 0x7A, 0x50, 0x00, // Image Data 2 - 0x3B // Trailer - ]; - - let mut out = OutVec::new(); - let actual_out = GifBuilder::new(Version::Gif87a, 4, 4) - .global_color_table(gct) - .image(ImageBuilder::new(4, 4) - .color_table(colortable) - .indicies(indicies.clone()) - ).image(ImageBuilder::new(4, 4) - .indicies(indicies) - ).write_to_vec(); - - assert_eq!(actual_out, expected_out); } } \ No newline at end of file |