diff --git a/examples/decode.rs b/examples/decode.rs index 039b134e..21059802 100644 --- a/examples/decode.rs +++ b/examples/decode.rs @@ -3,11 +3,21 @@ extern crate flif; use flif::Decoder; fn main() { - let file = std::fs::File::open("examples/flif.flif").unwrap(); + let file = std::fs::File::open("examples/flif_small.flif").unwrap(); let mut decoder = Decoder::new(file); let flif = decoder.decode().unwrap(); - println!("{:?}", flif.header); - println!("{:?}", flif.metadata); - println!("{:?}", flif.second_header); + println!("Compact Flif Info:"); + println!("├───{:?}", flif.header); + println!("├───{:?}", flif.metadata); + println!("└───{:?}", flif.second_header); + + let file = std::fs::File::open("examples/flif_large.flif").unwrap(); + + let mut decoder = Decoder::new(file); + let flif = decoder.decode().unwrap(); + println!("Large Flif Info:"); + println!("├───{:?}", flif.header); + println!("├───{:?}", flif.metadata); + println!("└───{:?}", flif.second_header); } \ No newline at end of file diff --git a/examples/flif_large.flif b/examples/flif_large.flif new file mode 100644 index 00000000..23da1427 Binary files /dev/null and b/examples/flif_large.flif differ diff --git a/examples/flif.flif b/examples/flif_small.flif similarity index 100% rename from examples/flif.flif rename to examples/flif_small.flif diff --git a/src/flif/components/header.rs b/src/flif/components/header.rs index 817f6522..7da18a40 100644 --- a/src/flif/components/header.rs +++ b/src/flif/components/header.rs @@ -2,7 +2,9 @@ use std::io::Read; use error::*; use numbers::FlifReadExt; use numbers::rac::Rac; -use numbers::symbol::UniformSymbolDecoder; +use numbers::symbol::UniformSymbolCoder; +use super::transformations; +use super::transformations::Transformation; #[derive(PartialEq, Eq, Debug, Clone, Copy)] pub enum Channels { @@ -105,49 +107,47 @@ pub struct SecondHeader { pub cutoff: u8, pub alpha_divisor: u8, pub custom_bitchance: bool, - pub transformations: Vec<()>, // Placeholder until transformations are implemented - pub invis_pixel_predictor: u8, + pub transformations: Vec>, // Placeholder until transformations are implemented + pub invis_pixel_predictor: Option, } impl SecondHeader { pub fn from_rac(main_header: &Header, rac: &mut Rac) -> Result { - let mut uni_decoder = UniformSymbolDecoder::new(rac); - let bits_per_pixel = (0..main_header.channels as u8) .map(|_| match main_header.bytes_per_channel { BytesPerChannel::One => Ok(8), BytesPerChannel::Two => Ok(16), - BytesPerChannel::Custom => uni_decoder.read_val(1, 16), + BytesPerChannel::Custom => rac.read_val(1, 16), }) .collect::>>()?; let alpha_zero = if main_header.channels == Channels::RGBA { - uni_decoder.read_bool()? + rac.read_bool()? } else { false }; let loops = if main_header.animated { - Some(uni_decoder.read_val(0, 100)?) + Some(rac.read_val(0, 100)?) } else { None }; let frame_delay = if main_header.animated { Some((0..main_header.num_frames) - .map(|_| uni_decoder.read_val(0, 60_000)) + .map(|_| rac.read_val(0, 60_000)) .collect::>>()?) } else { None }; - let custom_cutoff = uni_decoder.read_bool()?; + let custom_cutoff = rac.read_bool()?; let (cutoff, alpha_divisor, custom_bitchance) = if custom_cutoff { ( - uni_decoder.read_val(1, 128)?, - uni_decoder.read_val(2, 128)?, - uni_decoder.read_bool()?, + rac.read_val(1, 128)?, + rac.read_val(2, 128)?, + rac.read_bool()?, ) } else { (2, 19, false) @@ -160,14 +160,7 @@ impl SecondHeader { )); } - // TODO: read transformations - let invis_pixel_predictor = if uni_decoder.read_bool()? { - 255 // placeholder - } else { - uni_decoder.read_val(0, 2)? - }; - - Ok(SecondHeader { + let mut second = SecondHeader { bits_per_pixel, alpha_zero, loops, @@ -176,8 +169,23 @@ impl SecondHeader { cutoff, alpha_divisor, custom_bitchance, - transformations: vec![], - invis_pixel_predictor, - }) + transformations: Vec::new(), + invis_pixel_predictor: None, + }; + + let transformations = + transformations::load_transformations(rac, (&main_header, &second))?; + + let invis_pixel_predictor = if alpha_zero && main_header.interlaced { + Some(rac.read_val(0, 2)?) + } else { + // Garbage value + None + }; + + second.transformations = transformations; + second.invis_pixel_predictor = invis_pixel_predictor; + + Ok(second) } } diff --git a/src/flif/components/mod.rs b/src/flif/components/mod.rs index 2ac29d12..c079a4b2 100644 --- a/src/flif/components/mod.rs +++ b/src/flif/components/mod.rs @@ -1,2 +1,3 @@ pub mod header; pub mod metadata; +pub mod transformations; diff --git a/src/flif/components/transformations/bounds.rs b/src/flif/components/transformations/bounds.rs new file mode 100644 index 00000000..ee119b97 --- /dev/null +++ b/src/flif/components/transformations/bounds.rs @@ -0,0 +1,58 @@ +use std::io::Read; +use components::header::{Header, SecondHeader}; +use error::*; +use numbers::near_zero::NearZeroCoder; +use numbers::rac::ChanceTable; +use numbers::rac::Rac; +use super::Transformation; + +#[derive(Debug)] +pub struct Bounds { + min: [i16; 4], + max: [i16; 4], +} + +impl Bounds { + pub fn new( + rac: &mut Rac, + trans: &T, + (ref header, ref second): (&Header, &SecondHeader), + ) -> Result { + let mut context = ChanceTable::new(second.alpha_divisor, second.cutoff); + let mut min = [0; 4]; + let mut max = [0; 4]; + for c in 0..header.channels as usize { + min[c] = rac.read_near_zero(0, trans.max(c as u8) - trans.min(c as u8), &mut context)? + + trans.min(c as u8); + max[c] = rac.read_near_zero(0, trans.max(c as u8) - min[c], &mut context)? + min[c]; + + // set real min and max + min[c] = ::std::cmp::max(min[c], trans.min(c as u8)); + max[c] = ::std::cmp::min(max[c], trans.max(c as u8)); + } + + Ok(Bounds { min, max }) + } +} + +impl Transformation for Bounds { + fn snap(&self, _channel: u8, _values: i16, _pixel: i16) -> i16 { + unimplemented!() + } + + fn min(&self, channel: u8) -> i16 { + self.min[channel as usize] + } + + fn max(&self, channel: u8) -> i16 { + self.max[channel as usize] + } + + fn cmin(&self, _channel: u8, _values: i16) -> i16 { + unimplemented!() + } + + fn cmax(&self, _channel: u8, _values: i16) -> i16 { + unimplemented!() + } +} diff --git a/src/flif/components/transformations/channel_compact.rs b/src/flif/components/transformations/channel_compact.rs new file mode 100644 index 00000000..a17ffa64 --- /dev/null +++ b/src/flif/components/transformations/channel_compact.rs @@ -0,0 +1,70 @@ +use std::io::Read; +use components::header::{Header, SecondHeader}; +use error::*; +use numbers::near_zero::NearZeroCoder; +use numbers::rac::ChanceTable; +use numbers::rac::Rac; +use super::Transformation; + +#[derive(Debug)] +pub struct ChannelCompact { + max: [i16; 4], + decompacted: [Vec; 4], +} +impl ChannelCompact { + pub fn new( + rac: &mut Rac, + transformation: &T, + (ref header, ref second): (&Header, &SecondHeader), + ) -> Result { + let mut context = ChanceTable::new(second.alpha_divisor, second.cutoff); + let mut t = ChannelCompact { + max: [0; 4], + decompacted: [Vec::new(), Vec::new(), Vec::new(), Vec::new()], + }; + + for c in 0..header.channels as usize { + t.max[c] = rac.read_near_zero( + 0, + transformation.max(c as u8) - transformation.min(c as u8), + &mut context, + )?; + let mut min = transformation.min(c as u8); + for i in 0..t.max[c] { + t.decompacted[c].push( + min + + rac.read_near_zero( + 0, + transformation.max(c as u8) - (min + (t.max[c] - i)), + &mut context, + )?, + ); + min = t.decompacted[c][i as usize]; + } + } + + Ok(t) + } +} + +impl Transformation for ChannelCompact { + fn snap(&self, _channel: u8, _values: i16, _pixel: i16) -> i16 { + unimplemented!() + } + + fn min(&self, _channel: u8) -> i16 { + 0 + } + + fn max(&self, channel: u8) -> i16 { + self.max[channel as usize] + } + + fn cmin(&self, _channel: u8, _values: i16) -> i16 { + 0 + } + + fn cmax(&self, channel: u8, _values: i16) -> i16 { + self.max[channel as usize] + } +} diff --git a/src/flif/components/transformations/mod.rs b/src/flif/components/transformations/mod.rs new file mode 100644 index 00000000..9e026f95 --- /dev/null +++ b/src/flif/components/transformations/mod.rs @@ -0,0 +1,80 @@ +use std::io::Read; +use components::header::{Header, SecondHeader}; +use error::*; +use numbers::rac::Rac; +use numbers::symbol::UniformSymbolCoder; +use self::channel_compact::ChannelCompact; +use self::bounds::Bounds; +use self::ycocg::YCoGg; + +mod bounds; +mod channel_compact; +mod ycocg; + +pub trait Transformation: ::std::fmt::Debug { + fn snap(&self, channel: u8, values: i16, pixel: i16) -> i16; + + fn min(&self, channel: u8) -> i16; + + fn max(&self, channel: u8) -> i16; + + fn cmin(&self, channel: u8, values: i16) -> i16; + + fn cmax(&self, channel: u8, values: i16) -> i16; +} + +#[derive(Debug)] +struct Orig; + +impl Transformation for Orig { + fn snap(&self, _channel: u8, _values: i16, pixel: i16) -> i16 { + pixel + } + + fn min(&self, _channel: u8) -> i16 { + 0 + } + + fn max(&self, _channel: u8) -> i16 { + 255 + } + + fn cmin(&self, _channel: u8, _values: i16) -> i16 { + 0 + } + + fn cmax(&self, _channel: u8, _values: i16) -> i16 { + 255 + } +} + +pub fn load_transformations( + rac: &mut Rac, + (ref header, ref second): (&Header, &SecondHeader), +) -> Result>> { + let mut transforms: Vec> = Vec::new(); + transforms.push(Box::new(Orig)); + while rac.read_bit()? { + let id = rac.read_val(0, 13)?; + let t = match id { + 0 => Box::new(ChannelCompact::new( + rac, + transforms[transforms.len() - 1].as_ref(), + (header, second), + )?), + 1 => Box::new(YCoGg::new(transforms[transforms.len() - 1].as_ref())) + as Box, + 4 => Box::new(Bounds::new( + rac, + transforms[transforms.len() - 1].as_ref(), + (header, second), + )?), + _ => { + break; + } + }; + transforms.push(t); + } + + Ok(transforms) +} diff --git a/src/flif/components/transformations/ycocg.rs b/src/flif/components/transformations/ycocg.rs new file mode 100644 index 00000000..1c712aba --- /dev/null +++ b/src/flif/components/transformations/ycocg.rs @@ -0,0 +1,45 @@ +use super::Transformation; + +#[derive(Debug)] +pub struct YCoGg { + max: i16, +} + +impl YCoGg { + pub fn new(transformation: &T) -> YCoGg { + let max_iter = [ + transformation.max(0), + transformation.max(1), + transformation.max(2), + ]; + + let old_max = max_iter.iter().max().unwrap(); + let new_max = (((old_max / 4) + 1) * 4) - 1; + YCoGg { max: new_max } + } +} + +impl Transformation for YCoGg { + fn snap(&self, _channel: u8, _values: i16, _pixel: i16) -> i16 { + unimplemented!() + } + + fn min(&self, channel: u8) -> i16 { + match channel { + 0 => 0, + _ => -self.max, + } + } + + fn max(&self, _channel: u8) -> i16 { + self.max + } + + fn cmin(&self, _channel: u8, _values: i16) -> i16 { + unimplemented!() + } + + fn cmax(&self, _channel: u8, _values: i16) -> i16 { + unimplemented!() + } +} diff --git a/src/flif/numbers/near_zero.rs b/src/flif/numbers/near_zero.rs index 7156c57b..bb399f3d 100644 --- a/src/flif/numbers/near_zero.rs +++ b/src/flif/numbers/near_zero.rs @@ -5,75 +5,85 @@ use numbers::rac::ChanceTable; use numbers::rac::ChanceTableEntry; use numbers::rac::Rac; -pub fn read_near_zero( - min: i32, - max: i32, - rac: &mut Rac, - context: &mut ChanceTable, -) -> Result { - assert!(min < max); +pub trait NearZeroCoder { + fn read_near_zero( + &mut self, + min: I, + max: I, + context: &mut ChanceTable, + ) -> Result; +} - if min == max { - return Ok(min); - } +impl NearZeroCoder for Rac { + fn read_near_zero( + &mut self, + min: I, + max: I, + context: &mut ChanceTable, + ) -> Result { + if min > max { + return Err(Error::Unimplemented("something")); + } - if rac.read(context, ChanceTableEntry::Zero)? { - return Ok(0); - } + if min == max { + return Ok(min); + } - let sign = if min < 0 && max > 0 { - rac.read(context, ChanceTableEntry::Sign)? - } else if min < 0 && max < 0 { - false - } else { - true - }; + if self.read(context, ChanceTableEntry::Zero)? { + return Ok(I::zero()); + } - let absolute_max = ::std::cmp::max(max, -min); - let largest_exponent = - (::std::mem::size_of::() * 8) - absolute_max.leading_zeros() as usize - 1; + let sign = if min < I::zero() && max > I::zero() { + self.read(context, ChanceTableEntry::Sign)? + } else { + min >= I::zero() + }; - let mut exponent = 0; - loop { - if exponent as usize == largest_exponent || rac.read(context, ChanceTableEntry::Exp(exponent, sign))? { - break; + let absolute_max = ::std::cmp::max(max, -min); + let largest_exponent = + (::std::mem::size_of::() * 8) - absolute_max.leading_zeros() as usize - 1; + + let mut exponent = 0; + loop { + if exponent as usize == largest_exponent + || self.read(context, ChanceTableEntry::Exp(exponent, sign))? + { + break; + } + + exponent += 1; } - exponent += 1; - } + // the first mantissa bit is always 1 + let mut have = 1 << exponent; - // the first mantissa bit is always 1 - let mut have = 1 << exponent; - - // if all other mantissa bits are 1, then the total is have+left - let mut left = have-1; + // if all other mantissa bits are 1, then the total is have+left + let mut left = have - 1; // read mantissa bits from most-significant to least-significant - for pos in (exponent - 1)..0 { - left >>= 1; + for pos in (0..exponent).rev() { + left >>= 1; // if the bit is 1, then the value will be at least minabs1 - let minabs1 = have | (1< absolute_max { + if I::from(minabs1).unwrap() > absolute_max { // 1-bit is impossible (would bump value above maximum), // so assume the bit is 0 without reading it } else if maxabs0 >= 1 { // 0-bit and 1-bit are both possible, // so we read the bit and adjust what we have if it is a 1 - if rac.read(context, ChanceTableEntry::Mant(pos))? { + if self.read(context, ChanceTableEntry::Mant(pos))? { have = minabs1; - } + } } else { // 0-bit is impossible (would make the value zero), // so assume the bit is 1 without reading it have = minabs1; } } - Ok(if sign { - have - } else { - -have - }) + let have = I::from(have).unwrap(); + Ok(if sign { have } else { -have }) + } } diff --git a/src/flif/numbers/rac.rs b/src/flif/numbers/rac.rs index 8b954ce5..4f9adcc3 100644 --- a/src/flif/numbers/rac.rs +++ b/src/flif/numbers/rac.rs @@ -1,7 +1,7 @@ -use std::io::Write; use std::collections::HashMap; -use std::io::Read; use std::io; +use std::io::Read; +use std::io::Write; use error::*; use super::FlifReadExt; diff --git a/src/flif/numbers/symbol.rs b/src/flif/numbers/symbol.rs index 7184be6c..71a10c24 100644 --- a/src/flif/numbers/symbol.rs +++ b/src/flif/numbers/symbol.rs @@ -3,19 +3,16 @@ use error::*; use num_traits::PrimInt; use super::rac::Rac; -pub struct UniformSymbolDecoder<'rac, R: 'rac> { - rac: &'rac mut Rac, +pub trait UniformSymbolCoder { + fn read_val(&mut self, min: T, max: T) -> Result; + fn read_bool(&mut self) -> Result; } -impl<'rac, R: Read> UniformSymbolDecoder<'rac, R> { - pub fn new(rac: &'rac mut Rac) -> Self { - UniformSymbolDecoder { rac } - } - - pub fn read_val(&mut self, mut min: T, mut max: T) -> Result { +impl UniformSymbolCoder for Rac { + fn read_val(&mut self, mut min: T, mut max: T) -> Result { while max != min { let mid = min + ((max - min) >> 1); - if self.rac.read_bit()? { + if self.read_bit()? { min = mid + T::one(); } else { max = mid; @@ -25,7 +22,7 @@ impl<'rac, R: Read> UniformSymbolDecoder<'rac, R> { Ok(min) } - pub fn read_bool(&mut self) -> Result { - Ok(self.rac.read_bit()?) + fn read_bool(&mut self) -> Result { + Ok(self.read_bit()?) } }