about summary refs log tree commit diff
path: root/src/writer
diff options
context:
space:
mode:
Diffstat (limited to 'src/writer')
-rw-r--r--src/writer/gifbuilder.rs44
-rw-r--r--src/writer/imagebuilder.rs92
-rw-r--r--src/writer/mod.rs2
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;