diff options
author | Genny <gen@nyble.dev> | 2021-03-08 21:02:50 -0600 |
---|---|---|
committer | Genny <gen@nyble.dev> | 2021-03-08 21:02:50 -0600 |
commit | a368be4dfb3c1f75f6bcfdc297fe0372fb5f6092 (patch) | |
tree | 73c85d0abc2b065d827beea5f69f28a93d74816a /src/block | |
parent | c54872f011c135bbbc963f4a2b6b1d8ee4fa92bc (diff) | |
download | gifed-a368be4dfb3c1f75f6bcfdc297fe0372fb5f6092.tar.gz gifed-a368be4dfb3c1f75f6bcfdc297fe0372fb5f6092.zip |
Rename a few things
Diffstat (limited to 'src/block')
-rw-r--r-- | src/block/block.rs | 9 | ||||
-rw-r--r-- | src/block/colortable.rs | 67 | ||||
-rw-r--r-- | src/block/image.rs | 47 | ||||
-rw-r--r-- | src/block/imagedescriptor.rs | 45 | ||||
-rw-r--r-- | src/block/mod.rs | 13 | ||||
-rw-r--r-- | src/block/screendescriptor.rs | 40 | ||||
-rw-r--r-- | src/block/version.rs | 13 |
7 files changed, 234 insertions, 0 deletions
diff --git a/src/block/block.rs b/src/block/block.rs new file mode 100644 index 0000000..95ff12e --- /dev/null +++ b/src/block/block.rs @@ -0,0 +1,9 @@ +use crate::block::Version; + +use super::ScreenDescriptor; + + +pub enum Block { + Version(Version), + LogicalScreenDescriptor(ScreenDescriptor) +} \ No newline at end of file diff --git a/src/block/colortable.rs b/src/block/colortable.rs new file mode 100644 index 0000000..97b428f --- /dev/null +++ b/src/block/colortable.rs @@ -0,0 +1,67 @@ +use std::ops::Deref; +pub use crate::Color; + +pub struct ColorTable { + table: Vec<Color> +} + +impl ColorTable { + pub fn new() -> Self { + Self { + table: vec![] + } + } + + /// Returns the number of colors in the color table as used by the packed + /// fields in the Logical Screen Descriptor and Image Descriptor. You can + /// get the actual size with the [`len`](struct.ColorTable.html#method.len) method. + pub fn packed_len(&self) -> u8 { + ((self.table.len() as f32).log2().ceil() - 1f32) as u8 + } + + /// Returns the number of items in the table + pub fn len(&self) -> usize { + self.table.len() + } + + /// Pushes a color on to the end of the table + pub fn push(&mut self, color: Color) { + self.table.push(color); + } +} + +impl Deref for ColorTable { + type Target = [Color]; + + fn deref(&self) -> &Self::Target { + &self.table + } +} + +impl From<Vec<Color>> for ColorTable { + fn from(table: Vec<Color>) -> Self{ + ColorTable { + table + } + } +} + +impl From<&ColorTable> for Box<[u8]> { + fn from(table: &ColorTable) -> Self { + let mut vec = vec![]; + + for color in table.iter() { + vec.extend_from_slice(&[color.r, color.g, color.b]); + } + + let packed_len = 2u8.pow(table.packed_len() as u32 + 1); + let padding = (packed_len as usize - table.len()) * 3; + if padding > 0 { + vec.extend_from_slice(&vec![0; padding]); + } + + vec.into_boxed_slice() + } +} + +//TODO: TryFrom Vec<u8> (must be multiple of 3 len) and From Vec<Color> \ No newline at end of file diff --git a/src/block/image.rs b/src/block/image.rs new file mode 100644 index 0000000..07f9555 --- /dev/null +++ b/src/block/image.rs @@ -0,0 +1,47 @@ +use crate::LZW; +use super::{ColorTable, ImageDescriptor}; + +pub struct Image { + pub image_descriptor: ImageDescriptor, + pub local_color_table: Option<ColorTable>, + pub indicies: Vec<u8> +} + +impl Image { + pub fn as_boxed_slice(&self, minimum_code_size: u8) -> Box<[u8]> { + let mut out = vec![]; + + let mut boxed: Box<[u8]> = (&self.image_descriptor).into(); + out.extend_from_slice(&*boxed); + + // Table based image data // + + // Get the mcs while we write out the color table + let mut mcs = if let Some(lct) = &self.local_color_table { + boxed = lct.into(); + out.extend_from_slice(&*boxed); + + lct.packed_len() + } else { + minimum_code_size + }; + + if mcs < 2 { + mcs = 2; // Must be true: 0 <= mcs <= 8 + } + + // First write out the MCS + out.push(mcs); + + let compressed = LZW::encode(mcs, &self.indicies); + + for chunk in compressed.chunks(255) { + out.push(chunk.len() as u8); + out.extend_from_slice(chunk); + } + // Data block length 0 to indicate an end + out.push(0x00); + + out.into_boxed_slice() + } +} \ No newline at end of file diff --git a/src/block/imagedescriptor.rs b/src/block/imagedescriptor.rs new file mode 100644 index 0000000..c911baa --- /dev/null +++ b/src/block/imagedescriptor.rs @@ -0,0 +1,45 @@ +pub struct ImageDescriptor { + // Image Seperator 0x2C is the first byte // + pub left: u16, + pub top: u16, + pub width: u16, + pub height: u16, + pub packed: u8 +} + +impl ImageDescriptor { + pub fn color_table_present(&mut self, is_present: bool) { + if is_present { + self.packed |= 0b1000_0000; + } else { + self.packed &= 0b0111_1111; + } + } + + pub fn color_table_size(&mut self, size: u8) { + // GCT size is calulated by raising two to this number plus one, + // so we have to work backwards. + let size = (size as f32).log2().ceil() - 1f32; + self.packed |= size as u8; + } + + //TODO: Setter for sort flag in packed field + //TODO: Setter for interlace flag in packed field +} + +impl From<&ImageDescriptor> for Box<[u8]> { + fn from(desc: &ImageDescriptor) -> Self { + let mut vec = vec![]; + + vec.push(0x2C); // Image Seperator + vec.extend_from_slice(&desc.left.to_le_bytes()); + vec.extend_from_slice(&desc.top.to_le_bytes()); + vec.extend_from_slice(&desc.width.to_le_bytes()); + vec.extend_from_slice(&desc.height.to_le_bytes()); + vec.push(desc.packed); + + vec.into_boxed_slice() + } +} + +//TODO: Impl to allow changing the packed field easier \ No newline at end of file diff --git a/src/block/mod.rs b/src/block/mod.rs new file mode 100644 index 0000000..049b39a --- /dev/null +++ b/src/block/mod.rs @@ -0,0 +1,13 @@ +mod block; +mod colortable; +mod image; +mod imagedescriptor; +mod screendescriptor; +mod version; + +pub use block::Block; +pub use colortable::ColorTable; +pub use image::Image; +pub use imagedescriptor::ImageDescriptor; +pub use screendescriptor::ScreenDescriptor; +pub use version::Version; \ No newline at end of file diff --git a/src/block/screendescriptor.rs b/src/block/screendescriptor.rs new file mode 100644 index 0000000..d53d252 --- /dev/null +++ b/src/block/screendescriptor.rs @@ -0,0 +1,40 @@ +pub struct ScreenDescriptor { + pub width: u16, + pub height: u16, + pub packed: u8, + pub background_color_index: u8, + pub pixel_aspect_ratio: u8 +} + +impl ScreenDescriptor { + pub fn color_table_present(&mut self, is_present: bool) { + if is_present { + self.packed |= 0b1000_0000; + } else { + self.packed &= 0b0111_1111; + } + } + + pub fn color_table_size(&mut self, size: u8) { + // GCT size is calulated by raising two to this number plus one, + // so we have to work backwards. + let size = (size as f32).log2().ceil() - 1f32; + self.packed |= size as u8; + } + + //TODO: Setter for sort flag in packed field + //TODO: Setter for color resolution in packed field +} + +impl From<&ScreenDescriptor> for Box<[u8]> { + fn from(lsd: &ScreenDescriptor) -> Self { + 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); + vec.push(lsd.background_color_index); + vec.push(lsd.pixel_aspect_ratio); + + vec.into_boxed_slice() + } +} \ No newline at end of file diff --git a/src/block/version.rs b/src/block/version.rs new file mode 100644 index 0000000..a5d688d --- /dev/null +++ b/src/block/version.rs @@ -0,0 +1,13 @@ +pub enum Version { + Gif87a, + Gif89a +} + +impl From<&Version> for &[u8] { + fn from(version: &Version) -> Self { + match version { + Version::Gif87a => b"GIF87a", + Version::Gif89a => b"GIF89a" + } + } +} \ No newline at end of file |