fix: clip border tile rows when discarding extra samples
Tiled images with a width that is not a multiple of the tile width wrote the border tiles' horizontal padding into the next output row. Fixes #400.
This commit is contained in:
4 files changed
+42
No files matched your search
@@ -1,5 +1,12 @@
|
|||||||
# Version 0.12.0 (unreleased)
|
# Version 0.12.0 (unreleased)
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
- Decoding a tiled image whose width is not a multiple of the tile width no
|
||||||
|
longer corrupts the columns below the right border tiles when extra samples
|
||||||
|
are discarded (e.g. RGB with an unspecified extra sample). The horizontal
|
||||||
|
tile padding was written past the end of the output row, spilling into the
|
||||||
|
leftmost columns of the following row.
|
||||||
|
|
||||||
Additions:
|
Additions:
|
||||||
- Added the `TiffHeader` type. It can be used to create a `Decoder` in a state
|
- Added the `TiffHeader` type. It can be used to create a `Decoder` in a state
|
||||||
before the first IFD and allows opening files at an arbitrary first IFD
|
before the first IFD and allows opening files at an arbitrary first IFD
|
||||||
|
|||||||
@@ -1308,6 +1308,10 @@ impl Image {
|
|||||||
let photo_range = photometric_bit_end / 8..bits_per_pixel / 8;
|
let photo_range = photometric_bit_end / 8..bits_per_pixel / 8;
|
||||||
let mut encoded = vec![0u8; chunk_row_bytes];
|
let mut encoded = vec![0u8; chunk_row_bytes];
|
||||||
for row in buf.chunks_mut(layout.row_stride).take(data_dims.1 as usize) {
|
for row in buf.chunks_mut(layout.row_stride).take(data_dims.1 as usize) {
|
||||||
|
// Clip to the chunk's data width: border chunks are stored at the full chunk
|
||||||
|
// width, and writing their horizontal padding would spill into the following
|
||||||
|
// output row (and predict/invert would run past the chunk's own columns).
|
||||||
|
let row = &mut row[..data_row_bytes];
|
||||||
reader.read_exact(&mut encoded)?;
|
reader.read_exact(&mut encoded)?;
|
||||||
|
|
||||||
Self::compact_photometric_bytes(&mut encoded, row, &photo_range);
|
Self::compact_photometric_bytes(&mut encoded, row, &photo_range);
|
||||||
|
|||||||
@@ -475,6 +475,37 @@ fn test_tiled_rect_rgb_u8() {
|
|||||||
test_image_sum_u8("tiled-rect-rgb-u8.tif", ColorType::RGB(8), 62081032);
|
test_image_sum_u8("tiled-rect-rgb-u8.tif", ColorType::RGB(8), 62081032);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tiled_extra_samples_border_u8() {
|
||||||
|
// Regression test for https://github.com/image-rs/image-tiff/issues/400
|
||||||
|
//
|
||||||
|
// A tiled image whose dimensions are not multiples of the tile size, with
|
||||||
|
// an extra sample that is discarded on decode. The horizontal padding of
|
||||||
|
// the right border tiles used to be written past the end of the output
|
||||||
|
// row, spilling into the leftmost columns of the following row. The
|
||||||
|
// fixture's tile padding is filled with 0xEE so any spill is visible.
|
||||||
|
let path = PathBuf::from(TEST_IMAGE_DIR).join("tiled-extra-samples-border-u8.tif");
|
||||||
|
let img_file = File::open(path).expect("Cannot find test image!");
|
||||||
|
let mut decoder = Decoder::open(img_file).expect("Cannot create decoder");
|
||||||
|
decoder.next_image().expect("Cannot read image IFD");
|
||||||
|
assert_eq!(decoder.dimensions().unwrap(), (40, 40));
|
||||||
|
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8));
|
||||||
|
|
||||||
|
let DecodingSampleBuffer::U8(data) = decoder.read_image().unwrap() else {
|
||||||
|
panic!("Wrong bit depth")
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut expected = Vec::with_capacity(40 * 40 * 3);
|
||||||
|
for y in 0..40u32 {
|
||||||
|
for x in 0..40u32 {
|
||||||
|
expected.push(((x * 3) % 251) as u8);
|
||||||
|
expected.push(((y * 7) % 251) as u8);
|
||||||
|
expected.push(((x + y) % 251) as u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_inner_access() {
|
fn test_inner_access() {
|
||||||
let path = PathBuf::from(TEST_IMAGE_DIR).join("tiled-rect-rgb-u8.tif");
|
let path = PathBuf::from(TEST_IMAGE_DIR).join("tiled-rect-rgb-u8.tif");
|
||||||
|
|||||||
Binary file not shown.
Reference in new issue
Block a user