diff options
Diffstat (limited to 'src/writer')
-rw-r--r-- | src/writer/gifbuilder.rs | 44 | ||||
-rw-r--r-- | src/writer/imagebuilder.rs | 92 | ||||
-rw-r--r-- | src/writer/mod.rs | 2 |
3 files changed, 106 insertions, 32 deletions
diff --git a/src/writer/gifbuilder.rs b/src/writer/gifbuilder.rs index d16be56..ec3c304 100644 --- a/src/writer/gifbuilder.rs +++ b/src/writer/gifbuilder.rs @@ -1,6 +1,8 @@ +use std::convert::TryInto; + use crate::block::{extension::Extension, Block, ColorTable, ScreenDescriptor, Version}; use crate::writer::ImageBuilder; -use crate::Gif; +use crate::{EncodingError, Gif}; pub struct GifBuilder { version: Version, @@ -12,9 +14,9 @@ pub struct GifBuilder { } impl GifBuilder { - pub fn new(version: Version, width: u16, height: u16) -> Self { + pub fn new(width: u16, height: u16) -> Self { Self { - version, + version: Version::Gif87a, width, height, background_color_index: 0, @@ -23,30 +25,40 @@ impl GifBuilder { } } - pub fn global_color_table(mut self, table: ColorTable) -> Self { - self.global_color_table = Some(table); - + pub fn palette(mut self, palette: ColorTable) -> Self { + self.global_color_table = Some(palette); self } - pub fn background_color_index(mut self, ind: u8) -> Self { + pub fn background_index(mut self, ind: u8) -> Result<Self, EncodingError> { if self.global_color_table.is_none() { - //TODO: Throw error or let it go by, who knows - panic!("Setting background color index with noGCT!"); + Err(EncodingError::NoColorTable) + } else { + self.background_color_index = ind; + Ok(self) } - - self.background_color_index = ind; - self } - pub fn image(mut self, ib: ImageBuilder) -> Self { - self.blocks.push(Block::IndexedImage(ib.build())); - self + pub fn image(mut self, ib: ImageBuilder) -> Result<Self, EncodingError> { + if ib.required_version() == Version::Gif89a { + self.version = Version::Gif89a; + } + + if let Some(gce) = ib.get_graphic_control() { + self.blocks.push(Block::Extension(gce.into())); + } + + self.blocks.push(Block::IndexedImage(ib.build()?)); + Ok(self) } - pub fn extension(mut self, ext: Extension) -> Self { + /*pub fn extension(mut self, ext: Extension) -> Self { self.blocks.push(Block::Extension(ext)); self + }*/ + + pub fn repeat(&mut self, count: u16) { + self.blocks.push(Block::Extension(Extension::Looping(count))) } pub fn build(self) -> Gif { diff --git a/src/writer/imagebuilder.rs b/src/writer/imagebuilder.rs index d38687e..1486f16 100644 --- a/src/writer/imagebuilder.rs +++ b/src/writer/imagebuilder.rs @@ -1,4 +1,10 @@ -use crate::block::{ColorTable, ImageDescriptor, IndexedImage}; +use crate::{ + block::{ + extension::{DisposalMethod, GraphicControl}, + ColorTable, ImageDescriptor, IndexedImage, Version, + }, + EncodingError, +}; pub struct ImageBuilder { left_offset: u16, @@ -6,6 +12,11 @@ pub struct ImageBuilder { width: u16, height: u16, color_table: Option<ColorTable>, + + delay: u16, + disposal_method: DisposalMethod, + transparent_index: Option<u8>, + indicies: Vec<u8>, } @@ -17,38 +28,89 @@ impl ImageBuilder { width, height, color_table: None, + delay: 0, + disposal_method: DisposalMethod::NoAction, + transparent_index: None, indicies: vec![], } } - pub fn offsets(mut self, left_offset: u16, top_offset: u16) -> Self { - self.left_offset = left_offset; - self.top_offset = top_offset; + pub fn offset(mut self, left: u16, top: u16) -> Self { + self.left_offset = left; + self.top_offset = top; self } - pub fn left_offset(mut self, offset: u16) -> Self { - self.left_offset = offset; + pub fn palette(mut self, table: ColorTable) -> Self { + self.color_table = Some(table); self } - pub fn top_offset(mut self, offset: u16) -> Self { - self.top_offset = offset; + /// Time to wait, in hundreths of a second, before this image is drawn + pub fn delay(mut self, hundreths: u16) -> Self { + self.delay = hundreths; self } - pub fn color_table(mut self, table: ColorTable) -> Self { - self.color_table = Some(table); + pub fn disposal_method(mut self, method: DisposalMethod) -> Self { + self.disposal_method = method; + self + } + pub fn transparent_index(mut self, index: Option<u8>) -> Self { + self.transparent_index = index; self } - pub fn indicies(mut self, vec: Vec<u8>) -> Self { - self.indicies = vec; + pub fn required_version(&self) -> Version { + if self.delay > 0 + || self.disposal_method != DisposalMethod::NoAction + || self.transparent_index.is_some() + { + Version::Gif89a + } else { + Version::Gif87a + } + } + + pub fn get_graphic_control(&self) -> Option<GraphicControl> { + if self.required_version() == Version::Gif89a { + if let Some(transindex) = self.transparent_index { + Some(GraphicControl::new( + self.disposal_method, + false, + true, + self.delay, + transindex, + )) + } else { + Some(GraphicControl::new( + self.disposal_method, + false, + false, + self.delay, + 0, + )) + } + } else { + None + } + } + + pub fn indicies(mut self, indicies: Vec<u8>) -> Self { + self.indicies = indicies; self } - pub fn build(self) -> IndexedImage { + pub fn build(self) -> Result<IndexedImage, EncodingError> { + let expected_len = self.width as usize * self.height as usize; + if self.indicies.len() != expected_len { + return Err(EncodingError::IndicieSizeMismatch { + expected: expected_len, + got: self.indicies.len(), + }); + } + let mut imgdesc = ImageDescriptor { left: self.left_offset, top: self.top_offset, @@ -62,10 +124,10 @@ impl ImageBuilder { imgdesc.set_color_table_size(lct.packed_len()); } - IndexedImage { + Ok(IndexedImage { image_descriptor: imgdesc, local_color_table: self.color_table, indicies: self.indicies, - } + }) } } diff --git a/src/writer/mod.rs b/src/writer/mod.rs index b801a3a..88311fc 100644 --- a/src/writer/mod.rs +++ b/src/writer/mod.rs @@ -2,4 +2,4 @@ mod gifbuilder; mod imagebuilder; pub use gifbuilder::GifBuilder; -pub use imagebuilder::ImageBuilder; \ No newline at end of file +pub use imagebuilder::ImageBuilder; |