Fast deinterlace for 8-bit+
This commit is contained in:
parent
a41d7de348
commit
15a9b4a3e7
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 {
|
||||
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_line = 8 + bits_per_pixel as usize * png.ihdr.width as usize;
|
||||
// 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
|
||||
current_y += pass_constants.y_step as usize;
|
||||
if current_y >= png.ihdr.height as usize {
|
||||
if current_pass == 7 {
|
||||
if !increment_pass(&mut current_pass, png.ihdr) {
|
||||
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);
|
||||
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());
|
||||
}
|
||||
PngImage {
|
||||
data: output,
|
||||
ihdr: IhdrData {
|
||||
interlaced: 0,
|
||||
..png.ihdr
|
||||
},
|
||||
aux_headers: png.aux_headers.clone(),
|
||||
palette: png.palette.clone(),
|
||||
transparency_pixel: png.transparency_pixel.clone(),
|
||||
output
|
||||
}
|
||||
|
||||
/// Deinterlace by bytes, for images with at least 8bpp
|
||||
fn deinterlace_bytes(png: &PngImage) -> Vec<u8> {
|
||||
let bytes_per_pixel = png.ihdr.bpp() / 8;
|
||||
let bytes_per_line = 1 + bytes_per_pixel as usize * png.ihdr.width as usize;
|
||||
// Initialize each output line with a starting filter byte of 0
|
||||
// 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)]
|
||||
|
|
|
|||
Loading…
Reference in a new issue