Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] transformation-redux #51

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions flif-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ fn decode(identify: bool, input: &str, output: Option<String>) -> Result<()> {
let mut writer = encoder.write_header().unwrap();

// Get the raw pixel array of the FLIF image
let data = image.get_raw_pixels();
let data = image.raw();
// Save as PNG
writer.write_image_data(&data).unwrap();
} else {
std::io::stdout().write_all(&image.get_raw_pixels())?;
std::io::stdout().write_all(&image.raw())?;
}
}
Ok(())
Expand All @@ -111,14 +111,17 @@ fn id_file(info: &FlifInfo) {
println!("channels: {:?}", info.header.channels);
println!("dimensions: {} x {}", info.header.width, info.header.height);

let len = info.second_header.transformations.len();
let len = info.second_header.transformations.set.len();
if len != 0 {
println!("transformations:");

for transformation in info.second_header.transformations[..len - 1].iter() {
for transformation in info.second_header.transformations.set[..len - 1].iter() {
println!("├── {}", transformation);
}
println!("└── {}", info.second_header.transformations[len - 1]);
println!(
"└── {}",
info.second_header.transformations.set[len - 1]
);
}
}

Expand Down
10 changes: 8 additions & 2 deletions flif/examples/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@ use flif::Flif;
use png::HasParameters;

fn main() {
decode_and_write("resources/flif_logo.flif", "examples/flif_logo_out.png");
decode_and_write("resources/sea_snail.flif", "examples/sea_snail_out.png");
// decode_and_write(
// "resources/flif_logo.flif",
// "flif/examples/flif_logo_out.png",
// );
decode_and_write(
"resources/sea_snail_cutout.flif",
"flif/examples/sea_snail.png",
);
}

fn decode_and_write(input: &str, output: &str) {
Expand Down
Binary file modified flif/examples/sea_snail_out.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
63 changes: 33 additions & 30 deletions flif/src/components/header.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use components::transformations::TransformationSet;
use pixels::Greyscale;
use pixels::Rgb;
use pixels::Rgba;
use std::io::Read;

use super::transformations;
use super::transformations::{Transform, Transformation};
use pixels::ColorSpace;
use error::*;
use numbers::chances::UpdateTable;
use numbers::rac::RacRead;
use numbers::symbol::UniformSymbolCoder;
use numbers::FlifReadExt;
use pixels::ColorSpace;
use Limits;

#[derive(Eq, PartialEq, Debug, Clone, Copy)]
Expand Down Expand Up @@ -116,7 +118,7 @@ impl Header {
}
}

#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug)]
pub struct SecondHeader {
pub bits_per_pixel: Vec<u8>,
pub alpha_zero: bool,
Expand All @@ -126,22 +128,18 @@ pub struct SecondHeader {
pub cutoff: u8,
pub alpha_divisor: u8,
pub custom_bitchance: bool,
pub transformations: Vec<Transformation>, // Placeholder until transformations are implemented
pub transformations: TransformationSet, // Placeholder until transformations are implemented
pub invis_pixel_predictor: Option<u8>,
}

impl SecondHeader {
pub(crate) fn from_rac<R: RacRead>(
main_header: &Header,
rac: &mut R,
) -> Result<(Self, Box<Transform>)> {
pub(crate) fn from_rac<R: RacRead>(main_header: &Header, rac: &mut R) -> Result<Self> {
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 => rac.read_val(1, 16),
})
.collect::<Result<Vec<_>>>()?;
}).collect::<Result<Vec<_>>>()?;

let alpha_zero = if main_header.channels == ColorSpace::RGBA {
rac.read_bool()?
Expand Down Expand Up @@ -179,30 +177,35 @@ impl SecondHeader {
};
let update_table = UpdateTable::new(alpha_divisor, cutoff);

let (transformations, transform) =
transformations::load_transformations(rac, main_header.channels, &update_table)?;

let transformations = match main_header.channels {
ColorSpace::Monochrome => ::components::transformations::load_transformations::<
_,
Greyscale,
>(rac, &update_table)?,
ColorSpace::RGB => {
::components::transformations::load_transformations::<_, Rgb>(rac, &update_table)?
}
ColorSpace::RGBA => {
::components::transformations::load_transformations::<_, Rgba>(rac, &update_table)?
}
};
let invis_pixel_predictor = if alpha_zero && main_header.interlaced {
Some(rac.read_val(0, 2)?)
} else {
// Garbage value
None
};

Ok((
SecondHeader {
bits_per_pixel,
alpha_zero,
loops,
frame_delay,
custom_cutoff,
cutoff,
alpha_divisor,
custom_bitchance,
transformations,
invis_pixel_predictor,
},
transform,
))
Ok(SecondHeader {
bits_per_pixel,
alpha_zero,
loops,
frame_delay,
custom_cutoff,
cutoff,
alpha_divisor,
custom_bitchance,
transformations,
invis_pixel_predictor,
})
}
}
47 changes: 25 additions & 22 deletions flif/src/components/transformations/bounds.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
use super::Transform;
use pixels::{Rgba, RgbaChannels, ColorSpace};
use components::transformations::ColorRange;
use error::*;
use numbers::chances::{ChanceTable, UpdateTable};
use numbers::near_zero::NearZeroCoder;
use numbers::rac::RacRead;
use pixels::Pixel;
use pixels::{ChannelsTrait, RgbaChannels};

#[derive(Debug)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Bounds {
ranges: [ColorRange; 4],
previous_transformation: Box<Transform>,
}

impl Bounds {
pub fn new<R: RacRead>(
pub fn new<T: Transform, R: RacRead, P: Pixel>(
rac: &mut R,
trans: Box<Transform>,
channels: ColorSpace,
trans: &T,
update_table: &UpdateTable,
) -> Result<Bounds> {
let mut context = ChanceTable::new(update_table);
let mut ranges = [ColorRange::default(); 4];
for &c in &RgbaChannels::ORDER[..channels as usize] {
let t_range = trans.range(c);
let c = c as usize;
for c in P::get_channels().as_ref() {
let t_range = trans.range::<P>(*c);
let c = c.as_channel() as usize;
ranges[c].min = rac.read_near_zero(t_range.min, t_range.max, &mut context)?;
ranges[c].max = rac.read_near_zero(ranges[c].min, t_range.max, &mut context)?;

Expand All @@ -32,29 +31,33 @@ impl Bounds {
ranges[c].max = ::std::cmp::min(ranges[c].max, t_range.max);
}

Ok(Bounds {
ranges,
previous_transformation: trans,
})
Ok(Bounds { ranges })
}
}

impl Transform for Bounds {
fn undo(&self, pixel: Rgba) -> Rgba {
self.previous_transformation.undo(pixel)
fn undo<P: Pixel>(&self, pixel: P) -> P {
pixel
}

fn range(&self, channel: RgbaChannels) -> ColorRange {
self.ranges[channel as usize]
fn range<P: Pixel>(&self, channel: P::Channels) -> ColorRange {
self.ranges[channel.as_channel() as usize]
}

fn crange(&self, channel: RgbaChannels, values: Rgba) -> ColorRange {
if channel == RgbaChannels::Red || channel == RgbaChannels::Alpha {
return self.ranges[channel as usize];
fn crange<T: Transform, P: Pixel>(
&self,
channel: P::Channels,
values: P,
previous: &[T],
) -> ColorRange {
let rgba_channel = channel.as_channel();
if rgba_channel == RgbaChannels::Red || rgba_channel == RgbaChannels::Alpha {
return self.ranges[rgba_channel as usize];
}

let mut range = self.previous_transformation.crange(channel, values);
let channel = channel as usize;
let (last, rest) = previous.split_last().unwrap();
let mut range = last.crange(channel, values, rest);
let channel = rgba_channel as usize;
range.min = range.min.max(self.ranges[channel].min);
range.max = range.max.min(self.ranges[channel].max);

Expand Down
42 changes: 24 additions & 18 deletions flif/src/components/transformations/channel_compact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,29 @@ use error::*;
use numbers::chances::{ChanceTable, UpdateTable};
use numbers::near_zero::NearZeroCoder;
use numbers::rac::RacRead;
use pixels::{ColorSpace, Rgba, RgbaChannels};
use pixels::ChannelsTrait;
use pixels::Pixel;

#[derive(Debug)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ChannelCompact {
ranges: [ColorRange; 4],
decompacted: [Vec<i16>; 4],
channels: ColorSpace,
}
impl ChannelCompact {
pub fn new<R: RacRead, T: Transform>(
pub fn new<R: RacRead, T: Transform, P: Pixel>(
rac: &mut R,
transformation: T,
channels: ColorSpace,
transformation: &T,
update_table: &UpdateTable,
) -> Result<ChannelCompact> {
let mut context = ChanceTable::new(update_table);
let mut t = ChannelCompact {
ranges: Default::default(),
decompacted: Default::default(),
channels,
};

for &c in &RgbaChannels::ORDER[..channels as usize] {
let t_range = transformation.range(c);
let c = c as usize;
for c in P::get_channels().as_ref() {
let t_range = transformation.range::<P>(*c);
let c = c.as_channel() as usize;
t.ranges[c].max = rac.read_near_zero(0, t_range.max - t_range.min, &mut context)?;
let mut min = t_range.min;
for i in 0..t.ranges[c].max + 1 {
Expand All @@ -48,20 +46,28 @@ impl ChannelCompact {
}

impl Transform for ChannelCompact {
fn undo(&self, mut pixel: Rgba) -> Rgba {
for c in self.channels {
let c = c as usize;
pixel.0[c] = self.decompacted[c][pixel.0[c] as usize];
fn undo<P: Pixel>(&self, mut pixel: P) -> P {
for c in P::get_channels().as_ref() {
let previous = pixel.get_value(*c);
pixel.set_value(
self.decompacted[c.as_channel() as usize][previous as usize],
*c,
);
}

pixel
}

fn range(&self, channel: RgbaChannels) -> ColorRange {
self.ranges[channel as usize]
fn range<P: Pixel>(&self, channel: P::Channels) -> ColorRange {
self.ranges[channel.as_channel() as usize]
}

fn crange(&self, channel: RgbaChannels, _values: Rgba) -> ColorRange {
self.ranges[channel as usize]
fn crange<T: Transform, P: Pixel>(
&self,
channel: P::Channels,
_values: P,
_previous: &[T],
) -> ColorRange {
self.ranges[channel.as_channel() as usize]
}
}
Loading