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:
parent
14867c7abc
commit
b6cc8e2414
2 changed files with 30 additions and 68 deletions
|
|
@ -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!(),
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue