diff options
-rw-r--r-- | gifed/Cargo.toml | 2 | ||||
-rw-r--r-- | gifed/src/block/extension/application.rs | 4 | ||||
-rw-r--r-- | gifed/src/block/extension/graphiccontrol.rs | 84 | ||||
-rw-r--r-- | gifed/src/block/indexedimage.rs | 2 | ||||
-rw-r--r-- | gifed/src/block/mod.rs | 3 | ||||
-rw-r--r-- | gifed/src/colorimage.rs | 2 | ||||
-rw-r--r-- | gifed/src/gif.rs | 39 | ||||
-rw-r--r-- | gifed/src/lzw.rs | 5 | ||||
-rw-r--r-- | gifed/src/reader/mod.rs | 2 | ||||
-rw-r--r-- | gifprobe/Cargo.toml | 2 | ||||
-rw-r--r-- | gifprobe/src/main.rs | 6 |
11 files changed, 94 insertions, 57 deletions
diff --git a/gifed/Cargo.toml b/gifed/Cargo.toml index 08974f5..bf02547 100644 --- a/gifed/Cargo.toml +++ b/gifed/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "gifed" version = "0.1.0" -authors = ["Genevive Alfirevic <gen@nyble.dev>"] +authors = ["Genevive <gen@nyble.dev>"] edition = "2018" license = "CC0-1.0" description = "Gif encoding and decoding with fine control" diff --git a/gifed/src/block/extension/application.rs b/gifed/src/block/extension/application.rs index 9ec1814..3d46277 100644 --- a/gifed/src/block/extension/application.rs +++ b/gifed/src/block/extension/application.rs @@ -1,11 +1,11 @@ pub struct Application { - pub(crate) identifier: String, // max len 8 + pub(crate) identifier: [u8; 8], pub(crate) authentication_code: [u8; 3], pub(crate) data: Vec<u8>, } impl Application { - pub fn identifier(&self) -> &str { + pub fn identifier(&self) -> &[u8] { &self.identifier } diff --git a/gifed/src/block/extension/graphiccontrol.rs b/gifed/src/block/extension/graphiccontrol.rs index 8b62160..a6abbdc 100644 --- a/gifed/src/block/extension/graphiccontrol.rs +++ b/gifed/src/block/extension/graphiccontrol.rs @@ -1,9 +1,9 @@ -use std::{convert::TryInto, fmt}; +use std::{convert::TryInto, fmt, time::Duration}; #[derive(Clone, Debug)] pub struct GraphicControl { pub(crate) packed: u8, - pub(crate) delay_time: u16, + pub(crate) delay: u16, pub(crate) transparency_index: u8, } @@ -12,22 +12,27 @@ impl GraphicControl { disposal_method: DisposalMethod, user_input_flag: bool, transparency_flag: bool, - delay_time: u16, + delay: u16, transparency_index: u8, ) -> Self { let mut ret = Self { packed: 0, - delay_time, + delay, transparency_index, }; ret.set_disposal_method(disposal_method); ret.set_user_input(user_input_flag); - ret.transparency(transparency_flag); + ret.set_transparent(transparency_flag); ret } + /// Get the disposal method that should be used for the associated image. + /// + /// # Returns + /// This method will return `Some([DisposalMethod])` if the disposal method + /// is recognized, or None if it was set to a reserved value. pub fn disposal_method(&self) -> Option<DisposalMethod> { match self.packed & 0b000_111_00 { 0b000_000_00 => Some(DisposalMethod::NoAction), @@ -38,6 +43,7 @@ impl GraphicControl { } } + /// Set the disposal method that shoudl be used for the associated image. pub fn set_disposal_method(&mut self, method: DisposalMethod) { match method { DisposalMethod::NoAction => self.packed &= 0b111_000_1_1, @@ -47,10 +53,48 @@ impl GraphicControl { }; } - pub fn transparency_index(&self) -> u8 { + /// Returns the index that should be replaced by a fully transparent pixel + /// if the transparency flag is set, or None if it's not set. + pub fn transparent_index(&self) -> Option<u8> { + if self.transparent() { + Some(self.transparency_index) + } else { + None + } + } + + /// Returns the transparency index regardless if the transparency flag is set. + /// You probably want [GraphicControl::transparency_index] instead.s + pub fn transparent_index_unchecked(&self) -> u8 { self.transparency_index } + /// Sets the transparent index flag to the value provided. This will change + /// the index value in any way and should be used with caution. You probably + /// want [GraphicControl::set_transparent_index] instead. + pub fn set_transparent(&mut self, flag: bool) { + if flag { + self.packed |= 0b000_000_0_1; + } else { + self.packed &= 0b111_111_1_0; + } + } + + /// Sets the transparent index and flips the flag to indicate a transparent + /// index is present. + pub fn set_transparent_index(&mut self, index: Option<u8>) { + self.set_transparent(index.is_some()); + + if let Some(index) = index { + self.transparency_index = index; + } + } + + /// Get the value of the transparency flag + pub fn transparent(&self) -> bool { + self.packed & 0b000_000_0_1 > 0 + } + pub fn user_input(&self) -> bool { self.packed & 0b000_000_1_0 > 0 } @@ -63,36 +107,36 @@ impl GraphicControl { } } - pub fn transparency(&mut self, flag: bool) { - if flag { - self.packed |= 0b000_000_0_1; - } else { - self.packed &= 0b111_111_1_0; - } + pub fn delay(&self) -> u16 { + self.delay } - pub fn delay_time(&self) -> u16 { - self.delay_time + pub fn delay_duration(&self) -> Duration { + Duration::from_millis(self.delay as u64 * 10) } - pub fn delay_time_mut(&mut self) -> &mut u16 { - &mut self.delay_time + pub fn delay_mut(&mut self) -> &mut u16 { + &mut self.delay } - pub fn is_transparent(&self) -> bool { - self.packed & 0b000_000_0_1 > 0 + pub fn packed(&self) -> u8 { + self.packed + } + + pub fn packed_mut(&mut self) -> &mut u8 { + &mut self.packed } } impl From<[u8; 4]> for GraphicControl { fn from(arr: [u8; 4]) -> Self { let packed = arr[0]; - let delay_time = u16::from_le_bytes(arr[1..3].try_into().unwrap()); + let delay = u16::from_le_bytes(arr[1..3].try_into().unwrap()); let transparency_index = arr[3]; Self { packed, - delay_time, + delay, transparency_index, } } diff --git a/gifed/src/block/indexedimage.rs b/gifed/src/block/indexedimage.rs index 8ed0319..8834d33 100644 --- a/gifed/src/block/indexedimage.rs +++ b/gifed/src/block/indexedimage.rs @@ -37,7 +37,7 @@ impl IndexedImage { boxed = lct.into(); out.extend_from_slice(&*boxed); - lct.packed_len() + lct.packed_len() + 1 } else { minimum_code_size + 1 }; diff --git a/gifed/src/block/mod.rs b/gifed/src/block/mod.rs index a101600..623b346 100644 --- a/gifed/src/block/mod.rs +++ b/gifed/src/block/mod.rs @@ -2,6 +2,7 @@ mod colortable; pub mod extension; mod imagedescriptor; mod indexedimage; +pub mod packed; mod screendescriptor; mod version; @@ -57,7 +58,7 @@ fn encode_extension(block: &Block) -> Box<[u8]> { vec.push(0xF9); // Graphic control label vec.push(0x04); // Block size for this extension is always 4 vec.push(gce.packed); - vec.extend_from_slice(&gce.delay_time.to_le_bytes()); + vec.extend_from_slice(&gce.delay.to_le_bytes()); vec.push(gce.transparency_index); } Block::CommentExtension(comment) => todo!(), diff --git a/gifed/src/colorimage.rs b/gifed/src/colorimage.rs index 69dac1e..93314ff 100644 --- a/gifed/src/colorimage.rs +++ b/gifed/src/colorimage.rs @@ -49,7 +49,7 @@ impl<'a> TryFrom<Image<'a>> for ColorImage { img.height, img.indicies, img.palette, - img.transparent_index, + img.trans_index(), ) } } diff --git a/gifed/src/gif.rs b/gifed/src/gif.rs index 5f1bd7a..e8d6150 100644 --- a/gifed/src/gif.rs +++ b/gifed/src/gif.rs @@ -71,18 +71,14 @@ impl<'a> Iterator for ImageIterator<'a> { type Item = Image<'a>; fn next(&mut self) -> Option<Self::Item> { - let mut transparent = None; + let mut graphic_control = None; let img = loop { match self.veciter.next() { Some(block) => match block { Block::IndexedImage(img) => break img, Block::GraphicControlExtension(gce) => { - if gce.is_transparent() { - transparent = Some(gce.transparency_index()); - } else { - transparent = None; - } + graphic_control = Some(gce.clone()); } _ => (), }, @@ -97,8 +93,8 @@ impl<'a> Iterator for ImageIterator<'a> { left_offset: img.image_descriptor.left, top_offset: img.image_descriptor.top, palette: &img.local_color_table.as_ref().unwrap(), - transparent_index: transparent, indicies: &img.indicies, + graphic_control, }) } else { Some(Image { @@ -107,8 +103,8 @@ impl<'a> Iterator for ImageIterator<'a> { left_offset: img.image_descriptor.left, top_offset: img.image_descriptor.top, palette: self.gif.global_color_table.as_ref().unwrap(), - transparent_index: transparent, indicies: &img.indicies, + graphic_control, }) } } @@ -120,8 +116,8 @@ pub struct Image<'a> { pub left_offset: u16, pub top_offset: u16, pub palette: &'a ColorTable, - pub transparent_index: Option<u8>, pub indicies: &'a [u8], + pub graphic_control: Option<GraphicControl>, } impl<'a> Image<'a> { @@ -129,7 +125,7 @@ impl<'a> Image<'a> { let mut rgba = vec![0; self.indicies.len() * 4]; for (image_index, &color_index) in self.indicies.iter().enumerate() { - match self.transparent_index { + match self.trans_index() { Some(trans) if trans == color_index => { rgba[image_index as usize * 4] = 0; rgba[image_index * 4 + 1] = 0; @@ -156,7 +152,7 @@ impl<'a> Image<'a> { let mut rgb = vec![0; self.indicies.len() * 3]; for (image_index, &color_index) in self.indicies.iter().enumerate() { - match self.transparent_index { + match self.trans_index() { Some(trans) if trans == color_index => { rgb[image_index as usize * 4] = transparent_replace.r; rgb[image_index * 3 + 1] = transparent_replace.g; @@ -176,22 +172,13 @@ impl<'a> Image<'a> { Some(rgb) } -} - -pub struct FrameIterator<'a> { - gif: &'a Gif, - veciter: std::slice::Iter<'a, Block>, - buffer: Vec<u8>, -} -pub struct Frame { - pub width: u16, - pub height: u16, - pub palette: ColorTable, - pub transparent_index: Option<u8>, - pub indicies: Vec<u8>, - pub delay_after_draw: u16, - pub user_input_flag: bool, + pub fn trans_index(&self) -> Option<u8> { + self.graphic_control + .as_ref() + .map(|gce| gce.transparent_index()) + .flatten() + } } #[cfg(test)] diff --git a/gifed/src/lzw.rs b/gifed/src/lzw.rs index dce6a5d..9fdfcdd 100644 --- a/gifed/src/lzw.rs +++ b/gifed/src/lzw.rs @@ -8,6 +8,8 @@ impl LZW { let cc = 2u16.pow(minimum_size as u32); let eoi = cc + 1; + println!("mcs {} | cc {}", minimum_size, cc); + // Fill dictionary with self-descriptive values for value in 0..cc { dictionary.insert(vec![value as u8], value); @@ -44,6 +46,9 @@ impl LZW { buffer.clear(); buffer.push(indicie); } else { + println!("indicie is: {}", indicie); + println!("buffer is: {:?}", buffer); + println!("dictionary: {:?}", dictionary); unreachable!() } } diff --git a/gifed/src/reader/mod.rs b/gifed/src/reader/mod.rs index 966ebde..1b2e34a 100644 --- a/gifed/src/reader/mod.rs +++ b/gifed/src/reader/mod.rs @@ -113,7 +113,7 @@ impl GifReader { 0xFF => { //TODO: error instead of unwraps assert_eq!(Some(11), reader.u8()); - let identifier = reader.take_lossy_utf8(8).unwrap().to_string(); + let identifier = TryInto::try_into(reader.take(8).unwrap()).unwrap(); let authentication_code: [u8; 3] = TryInto::try_into(reader.take(3).unwrap()).unwrap(); let data = reader.take_and_collapse_subblocks(); diff --git a/gifprobe/Cargo.toml b/gifprobe/Cargo.toml index 75047b8..96e76a5 100644 --- a/gifprobe/Cargo.toml +++ b/gifprobe/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "gifprobe" version = "0.1.0" -authors = ["Genevive Alfirevic <gen@nyble.dev"] +authors = ["Genevive <gen@nyble.dev"] edition = "2018" license = "CC0-1.0" description = "Print the details of a gif to stdout; ffprobe for gif" diff --git a/gifprobe/src/main.rs b/gifprobe/src/main.rs index 35a137f..a8e3cfd 100644 --- a/gifprobe/src/main.rs +++ b/gifprobe/src/main.rs @@ -49,11 +49,11 @@ fn main() { img_count += 1; } Block::GraphicControlExtension(gce) => { - hundreths += gce.delay_time() as usize; + hundreths += gce.delay() as usize; println!( "Graphic Control Extension\n\tDelay Time {}\n\tDispose {}", - format!("{}s", gce.delay_time() as f32 / 100.0).yellow(), + format!("{}s", gce.delay() as f32 / 100.0).yellow(), gce.disposal_method().unwrap().yellow() ) } @@ -65,7 +65,7 @@ fn main() { let auth = app.authentication_code(); println!( "Application Extension\n\tIdentifier {}\n\tAuthentication {:02X} {:02X} {:02X}", - app.identifier().yellow(), + String::from_utf8_lossy(app.identifier()).yellow(), auth[0].yellow(), auth[1].yellow(), auth[2].yellow() |