Compare commits
6
Commits
96d37bb087
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c462915a61 | ||
|
|
caf8908fbf | ||
|
|
08492b5e16 | ||
|
|
563b2b11d7 | ||
|
|
a6e8ed772d | ||
|
|
9b452e93b7 |
No files matched your search
+11
-11
@@ -10,7 +10,7 @@ license = "MIT"
|
||||
description = "TIFF decoding and encoding library in pure Rust"
|
||||
authors = ["The image-rs Developers"]
|
||||
|
||||
repository = "https://github.com/image-rs/image-tiff"
|
||||
repository = "https://git.pomppervova.nl/wim/image-tiff"
|
||||
categories = ["multimedia::images", "multimedia::encoding"]
|
||||
|
||||
exclude = ["tests/images/*", "tests/fuzz_images/*", "tests/**/*.tif"]
|
||||
@@ -23,20 +23,20 @@ half = { version = "2.4.1" }
|
||||
quick-error = "2.0.1"
|
||||
|
||||
# Rename to avoid confusion with the feature name.
|
||||
fax34 = { package = "fax", version = "0.2.6", optional = true }
|
||||
flate2 = { version = "1.0.20", optional = true }
|
||||
weezl = { version = "0.2.1", optional = true }
|
||||
fax34 = { package = "fax", version = "0.3", optional = true }
|
||||
flate2 = { version = "1", optional = true }
|
||||
weezl = { version = "0.2", optional = true }
|
||||
zstd = { version = "0.14", optional = true }
|
||||
zrip-decode = { version = "0.8.2", features = ["paranoid"], optional = true }
|
||||
zune-jpeg = { version = "0.5.1", optional = true }
|
||||
image-webp = {version = "0.2.4", optional = true }
|
||||
zrip-decode = { version = "0.8", features = ["paranoid"], optional = true }
|
||||
zune-jpeg = { version = "0.5", optional = true }
|
||||
image-webp = {version = "0.2", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3.1"
|
||||
criterion = "0.3"
|
||||
# We may already depend on this via flate2
|
||||
crc32fast = "1.5"
|
||||
libtest-mimic = "0.8.1"
|
||||
walkdir = "2.5"
|
||||
crc32fast = "1"
|
||||
libtest-mimic = "0.8"
|
||||
walkdir = "2"
|
||||
|
||||
[features]
|
||||
default = ["deflate", "fax", "jpeg", "lzw"]
|
||||
|
||||
+12
-1
@@ -36,6 +36,9 @@ impl TileAttributes {
|
||||
pub fn tiles_down(&self) -> usize {
|
||||
self.image_height.div_ceil(self.tile_length)
|
||||
}
|
||||
pub fn tiles_per_plane(&self) -> usize {
|
||||
self.tiles_across() * self.tiles_down()
|
||||
}
|
||||
fn padding_right(&self) -> usize {
|
||||
(self.tile_width - self.image_width % self.tile_width) % self.tile_width
|
||||
}
|
||||
@@ -1016,7 +1019,15 @@ impl Image {
|
||||
}
|
||||
ChunkType::Tile => {
|
||||
let tile_attrs = self.tile_attributes.as_ref().unwrap();
|
||||
let (padding_right, padding_down) = tile_attrs.get_padding(chunk_index as usize);
|
||||
// The chunk index counts the tiles of all planes, but the tile grid repeats per
|
||||
// plane, so only the position within the plane decides the padding.
|
||||
let tiles_per_plane = tile_attrs.tiles_per_plane();
|
||||
let tile = if tiles_per_plane == 0 {
|
||||
0
|
||||
} else {
|
||||
chunk_index as usize % tiles_per_plane
|
||||
};
|
||||
let (padding_right, padding_down) = tile_attrs.get_padding(tile);
|
||||
|
||||
let tile_width = tile_attrs.tile_width - padding_right;
|
||||
let tile_length = tile_attrs.tile_length - padding_down;
|
||||
|
||||
+1
-1
@@ -1288,7 +1288,7 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
/// Utility to create a reader like [`Self::read_entry`], from the current IFD.
|
||||
///
|
||||
/// Returns an `Ok(None)` if the tag is not found in the current directory. See
|
||||
/// [`Self::read_entry´] of which this is a simple wrapper.
|
||||
/// [`Self::read_entry`] of which this is a simple wrapper.
|
||||
pub fn read_tag(&mut self, tag: Tag) -> TiffResult<Option<EntryBytesReader<'_, R>>> {
|
||||
match self.current_ifd().find_entry(tag) {
|
||||
None => Ok(None),
|
||||
|
||||
+12
-12
@@ -294,7 +294,7 @@ pub struct Group4Reader<R: Read> {
|
||||
decoder: fax34::decoder::Group4Decoder<FaxBytes<R>>,
|
||||
line_buf: io::Cursor<Vec<u8>>,
|
||||
height: u32,
|
||||
width: u16,
|
||||
width: u32,
|
||||
y: u32,
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ impl<R: Read> Group4Reader<R> {
|
||||
compressed_length: u64,
|
||||
fill_order: u16,
|
||||
) -> crate::TiffResult<Self> {
|
||||
let width = u16::try_from(dimensions.0)?;
|
||||
let width = dimensions.0;
|
||||
let height = dimensions.1;
|
||||
|
||||
Ok(Self {
|
||||
@@ -314,7 +314,7 @@ impl<R: Read> Group4Reader<R> {
|
||||
fax_byte_iter(reader, compressed_length, fill_order),
|
||||
width,
|
||||
)?,
|
||||
line_buf: io::Cursor::new(Vec::with_capacity(width.into())),
|
||||
line_buf: io::Cursor::new(Vec::with_capacity(width as usize)),
|
||||
width,
|
||||
height,
|
||||
y: 0,
|
||||
@@ -344,7 +344,7 @@ impl<R: Read> Read for Group4Reader<R> {
|
||||
let transitions = fax34::decoder::pels(self.decoder.transition(), self.width);
|
||||
|
||||
let buffer = self.line_buf.get_mut();
|
||||
buffer.resize(usize::from(self.width).div_ceil(8), 0u8);
|
||||
buffer.resize((self.width as usize).div_ceil(8), 0u8);
|
||||
|
||||
let target = &mut buffer[..];
|
||||
|
||||
@@ -409,7 +409,7 @@ pub struct Group3Reader {
|
||||
reader: OwnedBitReader,
|
||||
line_buf: io::Cursor<Vec<u8>>,
|
||||
height: u32,
|
||||
width: u16,
|
||||
width: u32,
|
||||
y: u32,
|
||||
}
|
||||
|
||||
@@ -421,7 +421,7 @@ impl Group3Reader {
|
||||
compressed_length: u64,
|
||||
fill_order: u16,
|
||||
) -> crate::TiffResult<Self> {
|
||||
let width = u16::try_from(dimensions.0)?;
|
||||
let width = dimensions.0;
|
||||
let height = dimensions.1;
|
||||
|
||||
// Buffer all compressed data and apply FillOrder bit reversal
|
||||
@@ -442,7 +442,7 @@ impl Group3Reader {
|
||||
|
||||
Ok(Self {
|
||||
reader: bit_reader,
|
||||
line_buf: io::Cursor::new(Vec::with_capacity(width.into())),
|
||||
line_buf: io::Cursor::new(Vec::with_capacity(width as usize)),
|
||||
width,
|
||||
height,
|
||||
y: 0,
|
||||
@@ -463,10 +463,10 @@ impl Group3Reader {
|
||||
fn with_markup<R: fax34::BitReader>(
|
||||
decoder: fn(&mut R) -> Option<u16>,
|
||||
reader: &mut R,
|
||||
) -> Option<u16> {
|
||||
let mut sum = 0u16;
|
||||
) -> Option<u32> {
|
||||
let mut sum = 0u32;
|
||||
while let Some(n) = decoder(reader) {
|
||||
sum = sum.checked_add(n)?;
|
||||
sum = sum.checked_add(n as u32)?;
|
||||
if n < 64 {
|
||||
return Some(sum);
|
||||
}
|
||||
@@ -483,7 +483,7 @@ impl Read for Group3Reader {
|
||||
{
|
||||
// Decode one line of alternating white/black run-lengths
|
||||
let mut transitions = Vec::new();
|
||||
let mut a0 = 0u16;
|
||||
let mut a0 = 0u32;
|
||||
let mut is_white = true;
|
||||
loop {
|
||||
let run = if is_white {
|
||||
@@ -507,7 +507,7 @@ impl Read for Group3Reader {
|
||||
self.y += 1;
|
||||
|
||||
// Convert transitions to packed bilevel output
|
||||
let bytes_per_line = usize::from(self.width).div_ceil(8);
|
||||
let bytes_per_line = (self.width as usize).div_ceil(8);
|
||||
let buffer = self.line_buf.get_mut();
|
||||
buffer.clear();
|
||||
buffer.resize(bytes_per_line, 0u8);
|
||||
|
||||
@@ -506,6 +506,47 @@ fn test_tiled_extra_samples_border_u8() {
|
||||
assert_eq!(data, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tiled_planar_border_u16() {
|
||||
// A planar (separate) tiled image whose dimensions are not multiples of the tile size.
|
||||
// The tile grid repeats for every plane, but the chunk (tile) index counts all planes, so
|
||||
// the border padding of the second plane used to be looked up with the wrong tile index.
|
||||
// The bottom-right tile of plane 1 then claimed a full tile height, and the decoder ran
|
||||
// past the end of the output buffer.
|
||||
//
|
||||
// Note that `read_image` only decodes the first plane, so this has to go through
|
||||
// `read_image_to_buffer` to reach the tiles that were mis-sized.
|
||||
let path = PathBuf::from(TEST_IMAGE_DIR).join("tiled-planar-2c-16b.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(), (30, 20));
|
||||
assert_eq!(
|
||||
decoder.colortype().unwrap(),
|
||||
ColorType::Multiband {
|
||||
bit_depth: 16,
|
||||
num_samples: 2
|
||||
}
|
||||
);
|
||||
|
||||
let mut buffer = DecodingSampleBuffer::U16(Vec::new());
|
||||
decoder.read_image_to_buffer(&mut buffer).unwrap();
|
||||
let DecodingSampleBuffer::U16(data) = buffer else {
|
||||
panic!("Wrong bit depth")
|
||||
};
|
||||
assert_eq!(data.len(), 2 * 20 * 30);
|
||||
|
||||
let mut expected = Vec::with_capacity(2 * 20 * 30);
|
||||
for plane in 0..2u16 {
|
||||
for y in 0..20u16 {
|
||||
for x in 0..30u16 {
|
||||
expected.push(1000 * plane + 10 * y + x);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert_eq!(data, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inner_access() {
|
||||
let path = PathBuf::from(TEST_IMAGE_DIR).join("tiled-rect-rgb-u8.tif");
|
||||
|
||||
Binary file not shown.
Reference in new issue
Block a user