Skip to content

Commit ca05d99

Browse files
authored
Assume None if the line is all zeros (#650)
#648 may have been a bit hasty - I realised afterward that there's a simpler way to achieve the same thing, and include the Brute filter as well. This reverts #648 and instead just picks None up front if the line is all zeros. This is guaranteed to be the chosen filter for MinSum, Entropy, Bigrams and BigEnt. It's almost certainly true for Brute as well but this is harder to prove. I've tested this across hundreds of images and found no change in output.
1 parent 1efacac commit ca05d99

1 file changed

Lines changed: 13 additions & 28 deletions

File tree

src/png/mod.rs

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -341,17 +341,9 @@ impl PngImage {
341341
let mut prev_line = Vec::new();
342342
let mut prev_pass: Option<u8> = None;
343343
let mut f_buf = Vec::new();
344-
let mut best_possible = 0;
345344
for line in self.scan_lines(false) {
346345
if prev_pass != line.pass || line.data.len() != prev_line.len() {
347346
prev_line = vec![0; line.data.len()];
348-
// Calculate the best possible result for this pass
349-
best_possible = match filter {
350-
RowFilter::Entropy => ilog2i(line.data.len() as u32 + 1) as i32,
351-
RowFilter::Bigrams => 1,
352-
RowFilter::BigEnt => ilog2i(line.data.len() as u32) as i32,
353-
_ => 0,
354-
}
355347
}
356348
// Alpha optimisation may alter the line data, so we need a mutable copy of it
357349
let mut line_data = line.data.to_vec();
@@ -368,6 +360,15 @@ impl PngImage {
368360
prev_line = line_data;
369361
} else {
370362
// Heuristic filter selection strategies
363+
364+
if line_data.iter().all(|&x| x == 0) {
365+
// Assume None if the line is all zeros
366+
filtered.push(RowFilter::None as u8);
367+
filtered.extend_from_slice(&line_data);
368+
prev_line = line_data;
369+
continue;
370+
}
371+
371372
let mut best_line = Vec::new();
372373
let mut best_line_raw = Vec::new();
373374
// Avoid vertical filtering on first line of each interlacing pass
@@ -380,21 +381,17 @@ impl PngImage {
380381
RowFilter::MinSum => {
381382
// MSAD algorithm mentioned in libpng reference docs
382383
// http://www.libpng.org/pub/png/book/chapter09.html
383-
let mut best_size = i32::MAX;
384+
let mut best_size = usize::MAX;
384385
for f in try_filters {
385386
f.filter_line(bpp, &mut line_data, &prev_line, &mut f_buf, alpha_bytes);
386387
let size = f_buf.iter().fold(0, |acc, &x| {
387388
let signed = x as i8;
388-
acc + signed.unsigned_abs() as i32
389+
acc + signed.unsigned_abs() as usize
389390
});
390391
if size < best_size {
391392
best_size = size;
392393
std::mem::swap(&mut best_line, &mut f_buf);
393394
best_line_raw.clone_from(&line_data);
394-
if size == best_possible {
395-
// Best possible result
396-
break;
397-
}
398395
}
399396
}
400397
}
@@ -418,33 +415,25 @@ impl PngImage {
418415
best_size = size;
419416
std::mem::swap(&mut best_line, &mut f_buf);
420417
best_line_raw.clone_from(&line_data);
421-
if size == best_possible {
422-
// Best possible result
423-
break;
424-
}
425418
}
426419
}
427420
}
428421
RowFilter::Bigrams => {
429422
// Count distinct bigrams, from pngwolf
430423
// https://bjoern.hoehrmann.de/pngwolf/
431-
let mut best_size = i32::MAX;
424+
let mut best_size = usize::MAX;
432425
for f in try_filters {
433426
f.filter_line(bpp, &mut line_data, &prev_line, &mut f_buf, alpha_bytes);
434427
let mut set = bitarr![0; 0x10000];
435428
for pair in f_buf.windows(2) {
436429
let bigram = (pair[0] as usize) << 8 | pair[1] as usize;
437430
set.set(bigram, true);
438431
}
439-
let size = set.count_ones() as i32;
432+
let size = set.count_ones();
440433
if size < best_size {
441434
best_size = size;
442435
std::mem::swap(&mut best_line, &mut f_buf);
443436
best_line_raw.clone_from(&line_data);
444-
if size == best_possible {
445-
// Best possible result
446-
break;
447-
}
448437
}
449438
}
450439
}
@@ -465,10 +454,6 @@ impl PngImage {
465454
best_size = size;
466455
std::mem::swap(&mut best_line, &mut f_buf);
467456
best_line_raw.clone_from(&line_data);
468-
if size == best_possible {
469-
// Best possible result
470-
break;
471-
}
472457
}
473458
}
474459
}

0 commit comments

Comments
 (0)