Skip to content

Commit

Permalink
implemented paeth filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
kurtkuehnert committed Sep 14, 2022
1 parent 67ca8d8 commit be019ab
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 112 deletions.
2 changes: 1 addition & 1 deletion examples/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::time::Instant;
fn main() {
let input = ["tile", "bevy", "bevy_small", "hartenstein"];
// let input = ["tile", "bevy_small"];
// let input = ["bevy_small", "hartenstein"];
// let input = ["hartenstein"];
// let input = ["bevy_small"];
// let input = ["bevy"];

Expand Down
103 changes: 60 additions & 43 deletions src/decode.rs
Original file line number Diff line number Diff line change
@@ -1,57 +1,74 @@
use crate::{
CACHE, CACHE_END, DEFAULT, DOUBLE_DIFF, DOUBLE_DIFF_END, DOUBLE_DIFF_RANGE, MASK_3BIT,
paeth, CACHE, CACHE_END, DEFAULT, DOUBLE_DIFF, DOUBLE_DIFF_END, DOUBLE_DIFF_RANGE, MASK_3BIT,
MASK_6BIT, RUN_LENGTH, RUN_LENGTH_END, SINGLE_DIFF, SINGLE_DIFF_END, SINGLE_DIFF_RANGE,
};

pub fn decode(width: u32, height: u32, input: &[u8]) -> Vec<u16> {
let mut pixels = Vec::with_capacity(width as usize * height as usize);

let mut pixel_cache = [0; 64];

let mut index = 0;

while index != input.len() {
let byte = input[index];

match byte {
CACHE..=CACHE_END => {
pixels.push(pixel_cache[(MASK_6BIT & byte) as usize]);
index += 1;
}
SINGLE_DIFF..=SINGLE_DIFF_END => {
let reference_pixel = *pixels.last().unwrap_or(&0) as i32;
let diff = (MASK_6BIT & byte) as i32 - SINGLE_DIFF_RANGE;
pixels.push((reference_pixel + diff) as u16);
index += 1;
}
DOUBLE_DIFF..=DOUBLE_DIFF_END => {
let reference_pixel = *pixels.last().unwrap_or(&0);
let diff = (MASK_3BIT & (byte >> 3)) as i32 - DOUBLE_DIFF_RANGE;
pixels.push((reference_pixel as i32 + diff) as u16);

let previous_pixel = *pixels.last().unwrap_or(&0);
pixel_cache[(previous_pixel % 64) as usize] = previous_pixel;

let reference_pixel = previous_pixel;
let diff = (MASK_3BIT & byte) as i32 - DOUBLE_DIFF_RANGE;
pixels.push((reference_pixel as i32 + diff) as u16);
index += 1;
}
RUN_LENGTH..=RUN_LENGTH_END => {
let run_length = MASK_6BIT & byte + 1;
let previous_pixel = *pixels.last().unwrap_or(&0);
pixels.extend((0..run_length).map(|_| previous_pixel));
index += 1;
}
DEFAULT => {
pixels.push(((input[index + 1] as u16) << 8) + input[index + 2] as u16);
index += 3;
}
};

let previous_pixel = *pixels.last().unwrap_or(&0);
pixel_cache[(previous_pixel % 64) as usize] = previous_pixel;
index += decode_byte(input, &mut pixels, &mut pixel_cache, index, width as usize);
}

pixels
}

#[inline]
fn decode_byte(
input: &[u8],
mut pixels: &mut Vec<u16>,
pixel_cache: &mut [u16; 64],
index: usize,
width: usize,
) -> usize {
let byte = input[index];

match byte {
CACHE..=CACHE_END => {
let pixel = pixel_cache[(MASK_6BIT & byte) as usize];
pixels.push(pixel);

1
}
SINGLE_DIFF..=SINGLE_DIFF_END => {
let reference_pixel = paeth(&pixels, pixels.len(), width) as i32;
let diff = (MASK_6BIT & byte) as i32 - SINGLE_DIFF_RANGE;
let pixel = (reference_pixel + diff) as u16;
pixel_cache[pixel as usize % 64] = pixel;
pixels.push(pixel);

1
}
DOUBLE_DIFF..=DOUBLE_DIFF_END => {
let reference_pixel = paeth(&pixels, pixels.len(), width) as i32;
let diff = (MASK_3BIT & (byte >> 3)) as i32 - DOUBLE_DIFF_RANGE;
let pixel = (reference_pixel + diff) as u16;
pixel_cache[pixel as usize % 64] = pixel;
pixels.push(pixel);

let reference_pixel = paeth(&pixels, pixels.len(), width) as i32;
let diff = (MASK_3BIT & byte) as i32 - DOUBLE_DIFF_RANGE;
let pixel = (reference_pixel + diff) as u16;
pixel_cache[pixel as usize % 64] = pixel;
pixels.push(pixel);

1
}
RUN_LENGTH..=RUN_LENGTH_END => {
let run_length = MASK_6BIT & byte + 1;
let previous_pixel = *pixels.last().unwrap_or(&0);
pixels.extend((0..run_length).map(|_| previous_pixel));

1
}
DEFAULT => {
let pixel = ((input[index + 1] as u16) << 8) + input[index + 2] as u16;
pixel_cache[pixel as usize % 64] = pixel;
pixels.push(pixel);

3
}
}
}
151 changes: 83 additions & 68 deletions src/encode.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
CACHE, DEFAULT, DOUBLE_DIFF, DOUBLE_DIFF_RANGE, RUN_LENGTH, SINGLE_DIFF, SINGLE_DIFF_RANGE,
paeth, CACHE, DEFAULT, DOUBLE_DIFF, DOUBLE_DIFF_RANGE, RUN_LENGTH, SINGLE_DIFF,
SINGLE_DIFF_RANGE,
};

static mut C_CACHE: i32 = 0;
Expand All @@ -12,77 +13,25 @@ static mut C_DEFAULT: i32 = 0;
pub fn encode(width: u32, height: u32, pixels: &[u16]) -> Vec<u8> {
let size = width as usize * height as usize;
let mut output = Vec::with_capacity(size);

let mut pixel_cache = [0; 64];
let mut previous_pixel = 0;
let mut run_length: u8 = 0;
let mut outstanding_diff = None;
let mut pixel_cache = [0; 64];

unsafe {
C_DEFAULT = 0;
C_CACHE = 0;
C_SINGLE_DIFF = 0;
C_DOUBLE_DIFF = 0;
C_RUN_LENGTH = 0;
C_RUN_COUNT = 0;
};

for index in 0..pixels.len() {
let pixel = pixels[index];

if pixel == previous_pixel {
run_length += 1;

if run_length == 63 {
finish_run(
pixels,
&mut output,
&mut outstanding_diff,
&mut run_length,
index,
);
}
} else {
if run_length > 0 {
finish_run(
pixels,
&mut output,
&mut outstanding_diff,
&mut run_length,
index,
);
}

// let reference_pixel = if index <= width {
// previous_pixel
// } else {
// paeth(index, width, pixels)
// };
let reference_pixel = previous_pixel;
let diff = pixel as i32 - reference_pixel as i32;

if (-DOUBLE_DIFF_RANGE..DOUBLE_DIFF_RANGE).contains(&diff) {
if let Some(previous_diff) = outstanding_diff {
double_diff(&mut output, previous_diff, diff);
outstanding_diff = None;
} else {
outstanding_diff = Some(diff);
}
} else {
if let Some(previous_diff) = outstanding_diff {
single_diff(&mut output, previous_diff);
outstanding_diff = None;
}

if (-SINGLE_DIFF_RANGE..SINGLE_DIFF_RANGE).contains(&diff) {
single_diff(&mut output, diff);
} else if pixel == pixel_cache[(pixel % 64) as usize] {
cache(&mut output, pixel);
} else {
default(&mut output, pixel);
}
}
}
encode_pixel(
&mut output,
pixels,
&mut pixel_cache,
&mut outstanding_diff,
&mut run_length,
index,
previous_pixel,
pixel,
width as usize,
);

previous_pixel = pixel;
pixel_cache[(pixel % 64) as usize] = pixel;
Expand All @@ -95,6 +44,7 @@ pub fn encode(width: u32, height: u32, pixels: &[u16]) -> Vec<u8> {
&mut outstanding_diff,
&mut run_length,
pixels.len(),
width as usize,
);
}

Expand Down Expand Up @@ -134,29 +84,85 @@ pub fn encode(width: u32, height: u32, pixels: &[u16]) -> Vec<u8> {
C_CACHE + C_SINGLE_DIFF + C_DOUBLE_DIFF + C_RUN_LENGTH + C_DEFAULT,
size as i32
);

C_DEFAULT = 0;
C_CACHE = 0;
C_SINGLE_DIFF = 0;
C_DOUBLE_DIFF = 0;
C_RUN_LENGTH = 0;
C_RUN_COUNT = 0;
}

output
}

fn encode_pixel(
mut output: &mut Vec<u8>,
pixels: &[u16],
pixel_cache: &mut [u16; 64],
mut outstanding_diff: &mut Option<i32>,
mut run_length: &mut u8,
index: usize,
previous_pixel: u16,
pixel: u16,
width: usize,
) {
if pixel == previous_pixel {
*run_length += 1;

if *run_length == 63 {
finish_run(pixels, output, outstanding_diff, run_length, index, width);
}
} else {
if *run_length > 0 {
finish_run(pixels, output, outstanding_diff, run_length, index, width);
}

let reference_pixel = paeth(pixels, index, width);
let diff = pixel as i32 - reference_pixel as i32;

if (-DOUBLE_DIFF_RANGE..DOUBLE_DIFF_RANGE).contains(&diff) {
if let &mut Some(previous_diff) = outstanding_diff {
double_diff(output, previous_diff, diff);
*outstanding_diff = None;
} else {
*outstanding_diff = Some(diff);
}
} else {
if let &mut Some(previous_diff) = outstanding_diff {
single_diff(output, previous_diff);
*outstanding_diff = None;
}

if (-SINGLE_DIFF_RANGE..SINGLE_DIFF_RANGE).contains(&diff) {
single_diff(output, diff);
} else if pixel == pixel_cache[(pixel % 64) as usize] {
cache(output, pixel);
} else {
default(output, pixel);
}
}
}
}

fn finish_run(
pixels: &[u16],
output: &mut Vec<u8>,
outstanding_diff: &mut Option<i32>,
length: &mut u8,
index: usize,
width: usize,
) {
let mut run = true;

if let &mut Some(previous_diff) = outstanding_diff {
if *length == 1 {
let previous_pixel = pixels[index - 2];
let pixel = pixels[index - 1];
let reference_pixel = previous_pixel;
let reference_pixel = paeth(pixels, index - 1, width);
let diff = pixel as i32 - reference_pixel as i32;

if (-DOUBLE_DIFF_RANGE..DOUBLE_DIFF_RANGE).contains(&previous_diff)
|| (-DOUBLE_DIFF_RANGE..DOUBLE_DIFF_RANGE).contains(&diff)
&& (-DOUBLE_DIFF_RANGE..DOUBLE_DIFF_RANGE).contains(&diff)
{
double_diff(output, previous_diff, diff);
run = false;
Expand All @@ -177,14 +183,19 @@ fn finish_run(
*length = 0;
}

#[inline]
fn cache(output: &mut Vec<u8>, pixel: u16) {
output.push(CACHE | (pixel % 64) as u8);
unsafe { C_CACHE += 1 };
}

#[inline]
fn single_diff(output: &mut Vec<u8>, diff: i32) {
output.push(SINGLE_DIFF | (diff + SINGLE_DIFF_RANGE) as u8);
unsafe { C_SINGLE_DIFF += 1 };
}

#[inline]
fn double_diff(output: &mut Vec<u8>, previous_diff: i32, diff: i32) {
output.push(
DOUBLE_DIFF
Expand All @@ -194,11 +205,15 @@ fn double_diff(output: &mut Vec<u8>, previous_diff: i32, diff: i32) {

unsafe { C_DOUBLE_DIFF += 2 };
}

#[inline]
fn run_length(output: &mut Vec<u8>, length: u8) {
output.push(RUN_LENGTH | length - 1);
unsafe { C_RUN_LENGTH += length as i32 };
unsafe { C_RUN_COUNT += 1 };
}

#[inline]
fn default(output: &mut Vec<u8>, pixel: u16) {
output.extend_from_slice(&[DEFAULT, (pixel >> 8) as u8, pixel as u8]);
unsafe { C_DEFAULT += 1 };
Expand Down

0 comments on commit be019ab

Please sign in to comment.