Improve up and left alpha reductions
This commit is contained in:
parent
446c788eb3
commit
28ffd174d0
1 changed files with 63 additions and 38 deletions
|
|
@ -2,7 +2,6 @@ use crate::colors::AlphaOptim;
|
||||||
use crate::colors::ColorType;
|
use crate::colors::ColorType;
|
||||||
use crate::evaluate::Evaluator;
|
use crate::evaluate::Evaluator;
|
||||||
use crate::headers::IhdrData;
|
use crate::headers::IhdrData;
|
||||||
use crate::png::scan_lines::ScanLine;
|
|
||||||
use crate::png::PngImage;
|
use crate::png::PngImage;
|
||||||
#[cfg(not(feature = "parallel"))]
|
#[cfg(not(feature = "parallel"))]
|
||||||
use crate::rayon::prelude::*;
|
use crate::rayon::prelude::*;
|
||||||
|
|
@ -90,50 +89,69 @@ fn reduced_alpha_to_white(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reduced_alpha_to_up(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
|
fn reduced_alpha_to_up(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
|
||||||
let mut scan_lines = png.scan_lines().collect::<Vec<ScanLine<'_>>>();
|
let mut reduced = Vec::with_capacity(png.data.len());
|
||||||
scan_lines.reverse();
|
let mut prev_line = Vec::new();
|
||||||
let mut lines = Vec::with_capacity(scan_lines.len());
|
let mut transparent = Vec::new();
|
||||||
let mut last_line = Vec::new();
|
for line in png.scan_lines() {
|
||||||
let mut current_line = Vec::with_capacity(scan_lines[0].data.len() + 1); // filter size + pixels
|
if line.data.len() != prev_line.len() {
|
||||||
for line in scan_lines {
|
prev_line = vec![0; line.data.len()];
|
||||||
if line.data.len() != last_line.len() {
|
transparent = vec![0; line.data.len()];
|
||||||
last_line = vec![0; line.data.len()];
|
|
||||||
}
|
}
|
||||||
current_line.push(line.filter);
|
reduced.push(line.filter);
|
||||||
for (pixel, last_pixel) in line.data.chunks(bpp).zip(last_line.chunks(bpp)) {
|
let line_start = reduced.len();
|
||||||
|
let mut line_transparent = true;
|
||||||
|
for (col, (pixel, prev_pixel)) in
|
||||||
|
line.data.chunks(bpp).zip(prev_line.chunks(bpp)).enumerate()
|
||||||
|
{
|
||||||
if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
|
if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
|
||||||
current_line.extend_from_slice(&last_pixel[0..(bpp - bpc)]);
|
// Copy the color values from the previous line
|
||||||
current_line.resize(current_line.len() + bpc, 0);
|
reduced.extend_from_slice(&prev_pixel[0..(bpp - bpc)]);
|
||||||
|
reduced.resize(reduced.len() + bpc, 0);
|
||||||
|
transparent[col] += 1;
|
||||||
} else {
|
} else {
|
||||||
current_line.extend_from_slice(pixel);
|
if transparent[col] > 0 {
|
||||||
|
// Copy the current color values upwards in this column
|
||||||
|
let mut offset = line_start + col * bpp;
|
||||||
|
for _ in 0..transparent[col] {
|
||||||
|
offset -= prev_line.len() + 1;
|
||||||
|
reduced[offset..(offset + bpp - bpc)]
|
||||||
|
.copy_from_slice(&pixel[..(bpp - bpc)]);
|
||||||
|
}
|
||||||
|
transparent[col] = 0;
|
||||||
|
}
|
||||||
|
reduced.extend_from_slice(pixel);
|
||||||
|
line_transparent = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
last_line = current_line[1..current_line.len()].to_vec();
|
if line_transparent {
|
||||||
lines.push(current_line.clone());
|
// Zero out the line if it's fully transparent
|
||||||
current_line.clear();
|
reduced.truncate(line_start);
|
||||||
|
reduced.resize(line_start + prev_line.len(), 0);
|
||||||
|
transparent = vec![0; prev_line.len()];
|
||||||
}
|
}
|
||||||
lines.into_iter().rev().flatten().collect()
|
prev_line = reduced[line_start..].to_vec();
|
||||||
|
}
|
||||||
|
reduced
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reduced_alpha_to_down(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
|
fn reduced_alpha_to_down(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
|
||||||
let mut reduced = Vec::with_capacity(png.data.len());
|
let mut reduced = Vec::with_capacity(png.data.len());
|
||||||
let mut last_line = Vec::new();
|
let mut prev_line = Vec::new();
|
||||||
let mut pos = 0;
|
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines() {
|
||||||
if line.data.len() != last_line.len() {
|
if line.data.len() != prev_line.len() {
|
||||||
last_line = vec![0; line.data.len()];
|
prev_line = vec![0; line.data.len()];
|
||||||
}
|
}
|
||||||
reduced.push(line.filter);
|
reduced.push(line.filter);
|
||||||
for (pixel, last_pixel) in line.data.chunks(bpp).zip(last_line.chunks(bpp)) {
|
let line_start = reduced.len();
|
||||||
|
for (pixel, prev_pixel) in line.data.chunks(bpp).zip(prev_line.chunks(bpp)) {
|
||||||
if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
|
if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
|
||||||
reduced.extend_from_slice(&last_pixel[0..(bpp - bpc)]);
|
reduced.extend_from_slice(&prev_pixel[0..(bpp - bpc)]);
|
||||||
reduced.resize(reduced.len() + bpc, 0);
|
reduced.resize(reduced.len() + bpc, 0);
|
||||||
} else {
|
} else {
|
||||||
reduced.extend_from_slice(pixel);
|
reduced.extend_from_slice(pixel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
last_line = reduced[(pos + 1)..reduced.len()].to_vec();
|
prev_line = reduced[line_start..].to_vec();
|
||||||
pos = reduced.len();
|
|
||||||
}
|
}
|
||||||
reduced
|
reduced
|
||||||
}
|
}
|
||||||
|
|
@ -141,19 +159,26 @@ fn reduced_alpha_to_down(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
|
||||||
fn reduced_alpha_to_left(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
|
fn reduced_alpha_to_left(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
|
||||||
let mut reduced = Vec::with_capacity(png.data.len());
|
let mut reduced = Vec::with_capacity(png.data.len());
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines() {
|
||||||
let mut line_bytes = Vec::with_capacity(line.data.len());
|
|
||||||
let mut last_pixel = vec![0; bpp];
|
|
||||||
for pixel in line.data.chunks(bpp).rev() {
|
|
||||||
if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
|
|
||||||
line_bytes.extend_from_slice(&last_pixel[0..(bpp - bpc)]);
|
|
||||||
line_bytes.resize(line_bytes.len() + bpc, 0);
|
|
||||||
} else {
|
|
||||||
line_bytes.extend_from_slice(pixel);
|
|
||||||
last_pixel = pixel.to_owned();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reduced.push(line.filter);
|
reduced.push(line.filter);
|
||||||
reduced.extend(line_bytes.chunks(bpp).rev().flatten());
|
let mut prev_pixel = vec![0; bpp];
|
||||||
|
let mut transparent = 0;
|
||||||
|
for pixel in line.data.chunks(bpp) {
|
||||||
|
if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
|
||||||
|
// Count number of consecutive transparent pixel bytes
|
||||||
|
transparent += bpp;
|
||||||
|
} else {
|
||||||
|
prev_pixel[..(bpp - bpc)].copy_from_slice(&pixel[..(bpp - bpc)]);
|
||||||
|
if transparent > 0 {
|
||||||
|
// Copy the current color values to preceding transparent pixels
|
||||||
|
reduced.extend(prev_pixel.iter().cycle().take(transparent));
|
||||||
|
transparent = 0;
|
||||||
|
}
|
||||||
|
reduced.extend_from_slice(pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if transparent > 0 {
|
||||||
|
reduced.extend(prev_pixel.iter().cycle().take(transparent));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
reduced
|
reduced
|
||||||
}
|
}
|
||||||
|
|
@ -162,14 +187,14 @@ fn reduced_alpha_to_right(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
|
||||||
let mut reduced = Vec::with_capacity(png.data.len());
|
let mut reduced = Vec::with_capacity(png.data.len());
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines() {
|
||||||
reduced.push(line.filter);
|
reduced.push(line.filter);
|
||||||
let mut last_pixel = vec![0; bpp];
|
let mut prev_pixel = vec![0; bpp];
|
||||||
for pixel in line.data.chunks(bpp) {
|
for pixel in line.data.chunks(bpp) {
|
||||||
if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
|
if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
|
||||||
reduced.extend_from_slice(&last_pixel[0..(bpp - bpc)]);
|
reduced.extend_from_slice(&prev_pixel[0..(bpp - bpc)]);
|
||||||
reduced.resize(reduced.len() + bpc, 0);
|
reduced.resize(reduced.len() + bpc, 0);
|
||||||
} else {
|
} else {
|
||||||
|
prev_pixel[..(bpp - bpc)].copy_from_slice(&pixel[..(bpp - bpc)]);
|
||||||
reduced.extend_from_slice(pixel);
|
reduced.extend_from_slice(pixel);
|
||||||
last_pixel = pixel.to_owned();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue