Optimize unfiltering (#400)

* Clippy lints

* Fewer pushes

* Remove special case for empty last line

* Zip with last line

* Combine bound checks
This commit is contained in:
Kornel 2021-05-19 20:16:14 +01:00 committed by GitHub
parent 14867c7abc
commit b6cc8e2414
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 68 deletions

View file

@ -65,88 +65,49 @@ pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf: &
pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf: &mut Vec<u8>) { pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf: &mut Vec<u8>) {
buf.clear(); buf.clear();
buf.reserve(data.len()); buf.reserve(data.len());
assert_eq!(data.len(), last_line.len());
match filter { match filter {
0 => { 0 => {
buf.extend_from_slice(data); buf.extend_from_slice(data);
} }
1 => { 1 => {
for (i, byte) in data.iter().enumerate() { for (i, &cur) in data.iter().enumerate() {
match i.checked_sub(bpp) { let prev_byte = i.checked_sub(bpp).and_then(|x| buf.get(x).copied());
Some(x) => { buf.push(match prev_byte {
let b = buf[x]; Some(b) => cur.wrapping_add(b),
buf.push(byte.wrapping_add(b)); None => cur,
} });
None => {
buf.push(*byte);
}
};
} }
} }
2 => { 2 => {
if last_line.is_empty() { buf.extend(
buf.extend_from_slice(data); data.iter()
} else { .zip(last_line)
buf.extend( .map(|(&cur, &last)| cur.wrapping_add(last)),
data.iter() );
.zip(last_line.iter())
.map(|(cur, last)| cur.wrapping_add(*last)),
);
};
} }
3 => { 3 => {
for (i, byte) in data.iter().enumerate() { for (i, (&cur, &last)) in data.iter().zip(last_line).enumerate() {
if last_line.is_empty() { let prev_byte = i.checked_sub(bpp).and_then(|x| buf.get(x).copied());
match i.checked_sub(bpp) { buf.push(match prev_byte {
Some(x) => { Some(b) => cur.wrapping_add(((u16::from(b) + u16::from(last)) >> 1) as u8),
let b = buf[x]; None => cur.wrapping_add(last >> 1),
buf.push(byte.wrapping_add(b >> 1)); });
}
None => {
buf.push(*byte);
}
};
} else {
match i.checked_sub(bpp) {
Some(x) => {
let b = buf[x];
buf.push(byte.wrapping_add(
((u16::from(b) + u16::from(last_line[i])) >> 1) as u8,
));
}
None => {
buf.push(byte.wrapping_add(last_line[i] >> 1));
}
};
};
} }
} }
4 => { 4 => {
for (i, byte) in data.iter().enumerate() { for (i, (&cur, &up)) in data.iter().zip(last_line).enumerate() {
if last_line.is_empty() { buf.push(
match i.checked_sub(bpp) { match i
Some(x) => { .checked_sub(bpp)
let b = buf[x]; .map(|x| (buf.get(x).copied(), last_line.get(x).copied()))
buf.push(byte.wrapping_add(b)); {
Some((Some(left), Some(left_up))) => {
cur.wrapping_add(paeth_predictor(left, up, left_up))
} }
None => { _ => cur.wrapping_add(up),
buf.push(*byte); },
} );
};
} else {
match i.checked_sub(bpp) {
Some(x) => {
let b = buf[x];
buf.push(byte.wrapping_add(paeth_predictor(
b,
last_line[i],
last_line[x],
)));
}
None => {
buf.push(byte.wrapping_add(last_line[i]));
}
};
};
} }
} }
_ => unreachable!(), _ => unreachable!(),

View file

@ -294,6 +294,7 @@ impl PngImage {
last_pass = pass; last_pass = pass;
} }
} }
last_line.resize(line.data.len(), 0);
unfilter_line( unfilter_line(
line.filter, line.filter,
bpp, bpp,