Handle files with invalid filters (#410)
The bad filter case is reachable, and can happen when the PNG file is corrupted.
This commit is contained in:
parent
286aaffa31
commit
ea75f6ccc1
2 changed files with 15 additions and 6 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::error::PngError;
|
||||||
|
|
||||||
pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf: &mut Vec<u8>) {
|
pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf: &mut Vec<u8>) {
|
||||||
assert!(data.len() >= bpp);
|
assert!(data.len() >= bpp);
|
||||||
assert!(last_line.is_empty() || data.len() == last_line.len());
|
assert!(last_line.is_empty() || data.len() == last_line.len());
|
||||||
|
|
@ -65,7 +67,13 @@ 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>,
|
||||||
|
) -> Result<(), PngError> {
|
||||||
buf.clear();
|
buf.clear();
|
||||||
buf.reserve(data.len());
|
buf.reserve(data.len());
|
||||||
assert!(data.len() >= bpp);
|
assert!(data.len() >= bpp);
|
||||||
|
|
@ -114,8 +122,9 @@ pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf:
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => return Err(PngError::InvalidData),
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paeth_predictor(a: u8, b: u8, c: u8) -> u8 {
|
fn paeth_predictor(a: u8, b: u8, c: u8) -> u8 {
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ impl PngData {
|
||||||
transparency_pixel,
|
transparency_pixel,
|
||||||
aux_headers,
|
aux_headers,
|
||||||
};
|
};
|
||||||
raw.data = raw.unfilter_image();
|
raw.data = raw.unfilter_image()?;
|
||||||
// Return the PngData
|
// Return the PngData
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
idat_data: idat_headers,
|
idat_data: idat_headers,
|
||||||
|
|
@ -281,7 +281,7 @@ impl PngImage {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reverse all filters applied on the image, returning an unfiltered IDAT bytestream
|
/// Reverse all filters applied on the image, returning an unfiltered IDAT bytestream
|
||||||
fn unfilter_image(&self) -> Vec<u8> {
|
fn unfilter_image(&self) -> Result<Vec<u8>, PngError> {
|
||||||
let mut unfiltered = Vec::with_capacity(self.data.len());
|
let mut unfiltered = Vec::with_capacity(self.data.len());
|
||||||
let bpp = ((self.ihdr.bit_depth.as_u8() * self.channels_per_pixel() + 7) / 8) as usize;
|
let bpp = ((self.ihdr.bit_depth.as_u8() * self.channels_per_pixel() + 7) / 8) as usize;
|
||||||
let mut last_line: Vec<u8> = Vec::new();
|
let mut last_line: Vec<u8> = Vec::new();
|
||||||
|
|
@ -293,13 +293,13 @@ impl PngImage {
|
||||||
last_pass = line.pass;
|
last_pass = line.pass;
|
||||||
}
|
}
|
||||||
last_line.resize(line.data.len(), 0);
|
last_line.resize(line.data.len(), 0);
|
||||||
unfilter_line(line.filter, bpp, line.data, &last_line, &mut unfiltered_buf);
|
unfilter_line(line.filter, bpp, line.data, &last_line, &mut unfiltered_buf)?;
|
||||||
unfiltered.push(0);
|
unfiltered.push(0);
|
||||||
unfiltered.extend_from_slice(&unfiltered_buf);
|
unfiltered.extend_from_slice(&unfiltered_buf);
|
||||||
std::mem::swap(&mut last_line, &mut unfiltered_buf);
|
std::mem::swap(&mut last_line, &mut unfiltered_buf);
|
||||||
unfiltered_buf.clear();
|
unfiltered_buf.clear();
|
||||||
}
|
}
|
||||||
unfiltered
|
Ok(unfiltered)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply the specified filter type to all rows in the image
|
/// Apply the specified filter type to all rows in the image
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue