diff options
author | Genny <gen@nyble.dev> | 2022-11-24 22:15:20 -0600 |
---|---|---|
committer | Genny <gen@nyble.dev> | 2022-11-24 22:15:20 -0600 |
commit | ac8578823b9ef467dc58a6afd5f7f4adfdb4c8bd (patch) | |
tree | 62e6c61feaf1fd63eb09f04d74dd179611aac991 | |
parent | 8d0ed482d292e0a8fe8ea7c0c83b0fdb2d786729 (diff) | |
download | gifed-ac8578823b9ef467dc58a6afd5f7f4adfdb4c8bd.tar.gz gifed-ac8578823b9ef467dc58a6afd5f7f4adfdb4c8bd.zip |
Add write example, remove bad read example
-rw-r--r-- | gifed/examples/read.rs | 30 | ||||
-rw-r--r-- | gifed/examples/write.rs | 43 | ||||
-rw-r--r-- | gifed/src/block/indexedimage.rs | 8 | ||||
-rw-r--r-- | gifed/src/block/mod.rs | 10 | ||||
-rw-r--r-- | gifed/src/block/palette.rs | 4 | ||||
-rw-r--r-- | gifed/src/block/screendescriptor.rs | 16 | ||||
-rw-r--r-- | gifed/src/block/version.rs | 6 | ||||
-rw-r--r-- | gifed/src/gif.rs | 18 | ||||
-rw-r--r-- | gifed/src/writer/gifbuilder.rs | 12 |
9 files changed, 89 insertions, 58 deletions
diff --git a/gifed/examples/read.rs b/gifed/examples/read.rs deleted file mode 100644 index 2c8b08d..0000000 --- a/gifed/examples/read.rs +++ /dev/null @@ -1,30 +0,0 @@ -use std::fs::File; - -use gifed::{ - reader::{self, GifReader}, - writer::ImageBuilder, - Gif, -}; - -fn main() { - let reader = GifReader::file("/home/gen/Downloads/emilia_bar.gif").unwrap(); - - // Create the directory we're we'll dump all the PNGs - std::fs::create_dir_all("examples/read/").unwrap(); - - for (frame_number, image) in reader.images().enumerate() { - let filename = format!("examples/read/simulation_{}.png", frame_number); - let file = File::create(filename).unwrap(); - - let mut encoder = png::Encoder::new(file, image.width as u32, image.height as u32); - encoder.set_color(png::ColorType::Indexed); - encoder.set_palette(image.palette.as_bytes()); - - if let Some(trns) = image.png_trns() { - encoder.set_trns(trns); - } - - let mut writer = encoder.write_header().unwrap(); - writer.write_image_data(&image.indicies).unwrap(); - } -} diff --git a/gifed/examples/write.rs b/gifed/examples/write.rs new file mode 100644 index 0000000..ff8809f --- /dev/null +++ b/gifed/examples/write.rs @@ -0,0 +1,43 @@ +use gifed::{ + block::{LoopCount, Palette}, + writer::ImageBuilder, + Color, Gif, +}; + +fn main() { + let gif_path = match std::env::args().nth(1) { + None => { + eprintln!("Expected a path to output the gif to"); + std::process::exit(-1); + } + Some(path) => path, + }; + + let mut palette = Palette::new(); + + // Fill the palette with every gray + for gray in 0..=255 { + palette.push(Color::new(gray, gray, gray)); + } + + let mut image = vec![0; 128 * 128]; + + let mut builder = Gif::builder(128, 128).palette(palette); + for idx in 0..=255 { + image.fill(idx); + + builder = builder.image( + ImageBuilder::new(128, 128) + .delay(3) + .build(image.clone()) + .unwrap(), + ); + } + + builder + .repeat(LoopCount::Forever) + .build() + .unwrap() + .save(gif_path) + .unwrap(); +} diff --git a/gifed/src/block/indexedimage.rs b/gifed/src/block/indexedimage.rs index 25eadbe..d27d463 100644 --- a/gifed/src/block/indexedimage.rs +++ b/gifed/src/block/indexedimage.rs @@ -33,9 +33,13 @@ impl IndexedImage { /// LZW Minimum Code Size here. It is equal to the value of [Palette::packed_len], but /// must also be at least 2. pub fn compress(self, lzw_code_size: Option<u8>) -> Result<CompressedImage, EncodeError> { - //TODO: gen- The old code had a +1 here. Why? + // gen- The old code had a +1 here. Why? + // In the spec, under the section for the Logical Screen Descriptor, it + // mentions that the size in the packed field is calculated with + // 2 ^ (packed + 1) and the code size is supposed to be the "number + // of color bits", which I guess is the exponent? let mcs = match self.local_color_table.as_ref() { - Some(palette) => palette.packed_len(), + Some(palette) => palette.lzw_code_size(), None => match lzw_code_size { None => return Err(EncodeError::InvalidCodeSize { lzw_code_size: 0 }), Some(mcs) => mcs, diff --git a/gifed/src/block/mod.rs b/gifed/src/block/mod.rs index 99075cf..5eb8a78 100644 --- a/gifed/src/block/mod.rs +++ b/gifed/src/block/mod.rs @@ -38,7 +38,15 @@ pub enum LoopCount { Number(u16), } -pub(crate) fn encode_block(mcs: u8, block: &Block) -> Vec<u8> { +impl LoopCount { + /// Set a fixed loop count. A value of 0 means forever, which you should + /// probably use [LoopCount::Forever] for. + pub fn count(count: u16) -> Self { + Self::Number(count) + } +} + +pub(crate) fn encode_block(block: &Block) -> Vec<u8> { match block { Block::CompressedImage(img) => img.as_bytes(), Block::GraphicControlExtension(_) => encode_extension(block), diff --git a/gifed/src/block/palette.rs b/gifed/src/block/palette.rs index 8f58b40..f2f4de3 100644 --- a/gifed/src/block/palette.rs +++ b/gifed/src/block/palette.rs @@ -25,6 +25,10 @@ impl Palette { ((self.table.len() as f32).log2().ceil() - 1f32) as u8 } + pub fn lzw_code_size(&self) -> u8 { + self.packed_len() + 1 + } + /// Returns the number of items in the table pub fn len(&self) -> usize { self.table.len() diff --git a/gifed/src/block/screendescriptor.rs b/gifed/src/block/screendescriptor.rs index 766ad66..aaeea53 100644 --- a/gifed/src/block/screendescriptor.rs +++ b/gifed/src/block/screendescriptor.rs @@ -42,18 +42,16 @@ impl ScreenDescriptor { pub fn color_table_len(&self) -> usize { crate::packed_to_color_table_length(self.packed.color_table_size()) } -} -impl From<&ScreenDescriptor> for Box<[u8]> { - fn from(lsd: &ScreenDescriptor) -> Self { + pub fn as_bytes(&self) -> Vec<u8> { let mut vec = vec![]; - vec.extend_from_slice(&lsd.width.to_le_bytes()); - vec.extend_from_slice(&lsd.height.to_le_bytes()); - vec.push(lsd.packed.raw); - vec.push(lsd.background_color_index); - vec.push(lsd.pixel_aspect_ratio); + vec.extend_from_slice(&self.width.to_le_bytes()); + vec.extend_from_slice(&self.height.to_le_bytes()); + vec.push(self.packed.raw); + vec.push(self.background_color_index); + vec.push(self.pixel_aspect_ratio); - vec.into_boxed_slice() + vec } } diff --git a/gifed/src/block/version.rs b/gifed/src/block/version.rs index 0171ad4..c26ebb5 100644 --- a/gifed/src/block/version.rs +++ b/gifed/src/block/version.rs @@ -6,6 +6,12 @@ pub enum Version { Gif89a, } +impl Version { + pub fn as_bytes(&self) -> &[u8] { + self.into() + } +} + impl From<&Version> for &[u8] { fn from(version: &Version) -> Self { match version { diff --git a/gifed/src/gif.rs b/gifed/src/gif.rs index 5ee6906..fd3a322 100644 --- a/gifed/src/gif.rs +++ b/gifed/src/gif.rs @@ -24,23 +24,15 @@ impl Gif { pub fn as_bytes(&self) -> Vec<u8> { let mut out = vec![]; - out.extend_from_slice((&self.header).into()); + out.extend_from_slice(&self.header.as_bytes()); + out.extend_from_slice(&self.screen_descriptor.as_bytes()); - let mut boxed: Box<[u8]> = (&self.screen_descriptor).into(); - out.extend_from_slice(&*boxed); - - // While we output the color table, grab it's length to use when - // outputting the image, or 0 if we don't have a GCT - let mcs = if let Some(gct) = &self.global_color_table { + if let Some(gct) = &self.global_color_table { out.extend_from_slice(&gct.as_bytes()); - - gct.packed_len() - } else { - 0 - }; + } for block in self.blocks.iter() { - out.extend_from_slice(&encode_block(mcs, block)); + out.extend_from_slice(&encode_block(block)); } // Write Trailer diff --git a/gifed/src/writer/gifbuilder.rs b/gifed/src/writer/gifbuilder.rs index 3e26c24..4ea88ec 100644 --- a/gifed/src/writer/gifbuilder.rs +++ b/gifed/src/writer/gifbuilder.rs @@ -2,8 +2,8 @@ use std::io::Write; use crate::{ block::{ - packed::ScreenPacked, Block, CompressedImage, IndexedImage, Palette, ScreenDescriptor, - Version, + packed::ScreenPacked, Block, CompressedImage, IndexedImage, LoopCount, Palette, + ScreenDescriptor, Version, }, EncodeError, Gif, }; @@ -48,6 +48,12 @@ impl GifBuilder { self } + pub fn repeat(mut self, count: LoopCount) -> Self { + self.blocks + .push(BuildBlock::Block(Block::LoopingExtension(count))); + self + } + pub fn image<I: Into<EncodeImage>>(mut self, img: I) -> Self { match img.into() { EncodeImage::CompressedImage(ci) => self @@ -87,7 +93,7 @@ impl GifBuilder { blocks: vec![], }; - let lzw_gct_size = gif.global_color_table.as_ref().map(|ct| ct.packed_len()); + let lzw_gct_size = gif.global_color_table.as_ref().map(|ct| ct.lzw_code_size()); for block in self.blocks { match block { |