Add brute filter
This commit is contained in:
parent
48453db292
commit
19030b8c6a
2 changed files with 34 additions and 1 deletions
|
|
@ -16,6 +16,7 @@ pub enum RowFilter {
|
|||
Entropy,
|
||||
Bigrams,
|
||||
BigEnt,
|
||||
Brute,
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for RowFilter {
|
||||
|
|
@ -44,13 +45,14 @@ impl Display for RowFilter {
|
|||
Self::Entropy => "Entropy",
|
||||
Self::Bigrams => "Bigrams",
|
||||
Self::BigEnt => "BigEnt",
|
||||
Self::Brute => "Brute",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl RowFilter {
|
||||
pub const LAST: u8 = Self::BigEnt as u8;
|
||||
pub const LAST: u8 = Self::Brute as u8;
|
||||
pub const STANDARD: [Self; 5] = [Self::None, Self::Sub, Self::Up, Self::Average, Self::Paeth];
|
||||
pub const SINGLE_LINE: [Self; 2] = [Self::None, Self::Sub];
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use crate::headers::*;
|
|||
use crate::interlace::{deinterlace_image, interlace_image};
|
||||
use bitvec::bitarr;
|
||||
use indexmap::IndexMap;
|
||||
use libdeflater::{CompressionLvl, Compressor};
|
||||
use rgb::ComponentSlice;
|
||||
use rgb::RGBA8;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
|
@ -19,6 +20,11 @@ pub(crate) mod scan_lines;
|
|||
|
||||
use self::scan_lines::{ScanLines, ScanLinesMut};
|
||||
|
||||
/// Compression level to use for the Brute filter strategy
|
||||
const BRUTE_LEVEL: i32 = 1; // 1 is fastest, 2-4 are not useful, 5 is slower but more effective
|
||||
/// Number of lines to compress with the Brute filter strategy
|
||||
const BRUTE_LINES: usize = 4; // Values over 8 are generally not useful
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PngImage {
|
||||
/// The headers stored in the IHDR chunk
|
||||
|
|
@ -406,6 +412,31 @@ impl PngImage {
|
|||
}
|
||||
}
|
||||
}
|
||||
RowFilter::Brute => {
|
||||
// Brute force by compressing each filter attempt
|
||||
// Similar to that of LodePNG but includes some previous lines for context
|
||||
let mut best_size = usize::MAX;
|
||||
let line_start = filtered.len();
|
||||
filtered.resize(filtered.len() + line.data.len() + 1, 0);
|
||||
let mut compressor =
|
||||
Compressor::new(CompressionLvl::new(BRUTE_LEVEL).unwrap());
|
||||
let limit = filtered.len().min((line.data.len() + 1) * BRUTE_LINES);
|
||||
let capacity = compressor.zlib_compress_bound(limit);
|
||||
let mut dest = vec![0; capacity];
|
||||
|
||||
for try_filter in try_filters {
|
||||
try_filter.filter_line(bpp, line.data, last_line, &mut f_buf);
|
||||
filtered[line_start..].copy_from_slice(&f_buf);
|
||||
let size = compressor
|
||||
.zlib_compress(&filtered[filtered.len() - limit..], &mut dest)
|
||||
.unwrap_or(usize::MAX);
|
||||
if size < best_size {
|
||||
best_size = size;
|
||||
std::mem::swap(&mut best_line, &mut f_buf);
|
||||
}
|
||||
}
|
||||
filtered.resize(line_start, 0);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
filtered.extend_from_slice(&best_line);
|
||||
|
|
|
|||
Loading…
Reference in a new issue