Fast deinterlace for 8-bit+
This commit is contained in:
parent
a41d7de348
commit
937a653dd5
1 changed files with 75 additions and 30 deletions
105
src/interlace.rs
105
src/interlace.rs
|
|
@ -95,6 +95,23 @@ pub fn interlace_image(png: &PngImage) -> PngImage {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinterlace_image(png: &PngImage) -> PngImage {
|
pub fn deinterlace_image(png: &PngImage) -> PngImage {
|
||||||
|
PngImage {
|
||||||
|
data: match png.ihdr.bpp() {
|
||||||
|
8.. => deinterlace_bytes(png),
|
||||||
|
_ => deinterlace_bits(png),
|
||||||
|
},
|
||||||
|
ihdr: IhdrData {
|
||||||
|
interlaced: 0,
|
||||||
|
..png.ihdr
|
||||||
|
},
|
||||||
|
aux_headers: png.aux_headers.clone(),
|
||||||
|
palette: png.palette.clone(),
|
||||||
|
transparency_pixel: png.transparency_pixel.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deinterlace by bits, for images with less than 8bpp
|
||||||
|
fn deinterlace_bits(png: &PngImage) -> Vec<u8> {
|
||||||
let bits_per_pixel = png.ihdr.bpp();
|
let bits_per_pixel = png.ihdr.bpp();
|
||||||
let bits_per_line = 8 + bits_per_pixel as usize * png.ihdr.width as usize;
|
let bits_per_line = 8 + bits_per_pixel as usize * png.ihdr.width as usize;
|
||||||
// Initialize each output line with a starting filter byte of 0
|
// Initialize each output line with a starting filter byte of 0
|
||||||
|
|
@ -125,29 +142,9 @@ pub fn deinterlace_image(png: &PngImage) -> PngImage {
|
||||||
// Calculate the next line and move to next pass if necessary
|
// Calculate the next line and move to next pass if necessary
|
||||||
current_y += pass_constants.y_step as usize;
|
current_y += pass_constants.y_step as usize;
|
||||||
if current_y >= png.ihdr.height as usize {
|
if current_y >= png.ihdr.height as usize {
|
||||||
if current_pass == 7 {
|
if !increment_pass(&mut current_pass, png.ihdr) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
current_pass += 1;
|
|
||||||
if current_pass == 2 && png.ihdr.width <= 4 {
|
|
||||||
current_pass += 1;
|
|
||||||
}
|
|
||||||
if current_pass == 3 && png.ihdr.height <= 4 {
|
|
||||||
current_pass += 1;
|
|
||||||
}
|
|
||||||
if current_pass == 4 && png.ihdr.width <= 2 {
|
|
||||||
current_pass += 1;
|
|
||||||
}
|
|
||||||
if current_pass == 5 && png.ihdr.height <= 2 {
|
|
||||||
current_pass += 1;
|
|
||||||
}
|
|
||||||
if current_pass == 6 && png.ihdr.width == 1 {
|
|
||||||
current_pass += 1;
|
|
||||||
}
|
|
||||||
if current_pass == 7 && png.ihdr.height == 1 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pass_constants = interlaced_constants(current_pass);
|
pass_constants = interlaced_constants(current_pass);
|
||||||
current_y = pass_constants.y_shift as usize;
|
current_y = pass_constants.y_shift as usize;
|
||||||
}
|
}
|
||||||
|
|
@ -159,16 +156,64 @@ pub fn deinterlace_image(png: &PngImage) -> PngImage {
|
||||||
}
|
}
|
||||||
output.extend_from_slice(line.as_raw_slice());
|
output.extend_from_slice(line.as_raw_slice());
|
||||||
}
|
}
|
||||||
PngImage {
|
output
|
||||||
data: output,
|
}
|
||||||
ihdr: IhdrData {
|
|
||||||
interlaced: 0,
|
/// Deinterlace by bytes, for images with at least 8bpp
|
||||||
..png.ihdr
|
fn deinterlace_bytes(png: &PngImage) -> Vec<u8> {
|
||||||
},
|
let bytes_per_pixel = png.ihdr.bpp() / 8;
|
||||||
aux_headers: png.aux_headers.clone(),
|
let bytes_per_line = 1 + bytes_per_pixel as usize * png.ihdr.width as usize;
|
||||||
palette: png.palette.clone(),
|
// Initialize each output line with a starting filter byte of 0
|
||||||
transparency_pixel: png.transparency_pixel.clone(),
|
// as well as some blank data
|
||||||
|
let mut lines: Vec<Vec<u8>> = vec![vec![0; bytes_per_line]; png.ihdr.height as usize];
|
||||||
|
let mut current_pass = 1;
|
||||||
|
let mut pass_constants = interlaced_constants(current_pass);
|
||||||
|
let mut current_y: usize = pass_constants.y_shift as usize;
|
||||||
|
for line in png.scan_lines() {
|
||||||
|
for (i, byte) in line.data.iter().enumerate() {
|
||||||
|
let current_x: usize = pass_constants.x_shift as usize
|
||||||
|
+ (i / bytes_per_pixel as usize) * pass_constants.x_step as usize;
|
||||||
|
// Copy this byte into the output line, offset by 1 because of filter byte
|
||||||
|
let index = 1 + (i % bytes_per_pixel as usize) + current_x * bytes_per_pixel as usize;
|
||||||
|
lines[current_y][index] = *byte;
|
||||||
|
}
|
||||||
|
// Calculate the next line and move to next pass if necessary
|
||||||
|
current_y += pass_constants.y_step as usize;
|
||||||
|
if current_y >= png.ihdr.height as usize {
|
||||||
|
if !increment_pass(&mut current_pass, png.ihdr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pass_constants = interlaced_constants(current_pass);
|
||||||
|
current_y = pass_constants.y_shift as usize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
lines.concat()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn increment_pass(current_pass: &mut u8, ihdr: IhdrData) -> bool {
|
||||||
|
if *current_pass == 7 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*current_pass += 1;
|
||||||
|
if *current_pass == 2 && ihdr.width <= 4 {
|
||||||
|
*current_pass += 1;
|
||||||
|
}
|
||||||
|
if *current_pass == 3 && ihdr.height <= 4 {
|
||||||
|
*current_pass += 1;
|
||||||
|
}
|
||||||
|
if *current_pass == 4 && ihdr.width <= 2 {
|
||||||
|
*current_pass += 1;
|
||||||
|
}
|
||||||
|
if *current_pass == 5 && ihdr.height <= 2 {
|
||||||
|
*current_pass += 1;
|
||||||
|
}
|
||||||
|
if *current_pass == 6 && ihdr.width == 1 {
|
||||||
|
*current_pass += 1;
|
||||||
|
}
|
||||||
|
if *current_pass == 7 && ihdr.height == 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue