Skip to content

Commit

Permalink
Merge pull request TeXitoi#5 from dgriffen/transformations
Browse files Browse the repository at this point in the history
early transformation decoding
ZoeyR authored Oct 22, 2017
2 parents 8550b0f + 31328f8 commit 2359bc7
Showing 12 changed files with 365 additions and 86 deletions.
18 changes: 14 additions & 4 deletions examples/decode.rs
Original file line number Diff line number Diff line change
@@ -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);
}
Binary file added examples/flif_large.flif
Binary file not shown.
File renamed without changes.
56 changes: 32 additions & 24 deletions src/flif/components/header.rs
Original file line number Diff line number Diff line change
@@ -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<Box<Transformation>>, // Placeholder until transformations are implemented
pub invis_pixel_predictor: Option<u8>,
}

impl SecondHeader {
pub fn from_rac<R: Read>(main_header: &Header, rac: &mut Rac<R>) -> Result<Self> {
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::<Result<Vec<_>>>()?;

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::<Result<Vec<_>>>()?)
} 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)
}
}
1 change: 1 addition & 0 deletions src/flif/components/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod header;
pub mod metadata;
pub mod transformations;
58 changes: 58 additions & 0 deletions src/flif/components/transformations/bounds.rs
Original file line number Diff line number Diff line change
@@ -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<R: Read, T: ?Sized + Transformation>(
rac: &mut Rac<R>,
trans: &T,
(ref header, ref second): (&Header, &SecondHeader),
) -> Result<Bounds> {
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!()
}
}
70 changes: 70 additions & 0 deletions src/flif/components/transformations/channel_compact.rs
Original file line number Diff line number Diff line change
@@ -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<i16>; 4],
}
impl ChannelCompact {
pub fn new<R: Read, T: ?Sized + Transformation>(
rac: &mut Rac<R>,
transformation: &T,
(ref header, ref second): (&Header, &SecondHeader),
) -> Result<ChannelCompact> {
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]
}
}
80 changes: 80 additions & 0 deletions src/flif/components/transformations/mod.rs
Original file line number Diff line number Diff line change
@@ -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<R: Read>(
rac: &mut Rac<R>,
(ref header, ref second): (&Header, &SecondHeader),
) -> Result<Vec<Box<Transformation>>> {
let mut transforms: Vec<Box<Transformation>> = 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<Transformation>,
4 => Box::new(Bounds::new(
rac,
transforms[transforms.len() - 1].as_ref(),
(header, second),
)?),
_ => {
break;
}
};
transforms.push(t);
}

Ok(transforms)
}
Loading

0 comments on commit 2359bc7

Please sign in to comment.