Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96d37bb087 | ||
|
|
12f16dbfdd | ||
|
|
a8abdd2484 | ||
|
|
934fde185a | ||
|
|
3302936b08 | ||
|
|
a5b9a57e09 |
No files matched your search
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
/target/
|
/target/
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
tests/benches/corpus/
|
tests/benches/corpus/
|
||||||
|
.idea
|
||||||
|
.agentbridge
|
||||||
+5
-3
@@ -1,8 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tiff"
|
name = "ndbioimage-tiff"
|
||||||
version = "0.11.3"
|
version = "0.11.3"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
resolver = "2"
|
|
||||||
|
|
||||||
# note: when changed, also update test runner in `.github/workflows/rust.yml`
|
# note: when changed, also update test runner in `.github/workflows/rust.yml`
|
||||||
rust-version = "1.88.0"
|
rust-version = "1.88.0"
|
||||||
@@ -16,6 +15,9 @@ categories = ["multimedia::images", "multimedia::encoding"]
|
|||||||
|
|
||||||
exclude = ["tests/images/*", "tests/fuzz_images/*", "tests/**/*.tif"]
|
exclude = ["tests/images/*", "tests/fuzz_images/*", "tests/**/*.tif"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "tiff"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
half = { version = "2.4.1" }
|
half = { version = "2.4.1" }
|
||||||
quick-error = "2.0.1"
|
quick-error = "2.0.1"
|
||||||
@@ -24,7 +26,7 @@ quick-error = "2.0.1"
|
|||||||
fax34 = { package = "fax", version = "0.2.6", optional = true }
|
fax34 = { package = "fax", version = "0.2.6", optional = true }
|
||||||
flate2 = { version = "1.0.20", optional = true }
|
flate2 = { version = "1.0.20", optional = true }
|
||||||
weezl = { version = "0.2.1", optional = true }
|
weezl = { version = "0.2.1", optional = true }
|
||||||
zstd = { version = "0.13", optional = true }
|
zstd = { version = "0.14", optional = true }
|
||||||
zrip-decode = { version = "0.8.2", features = ["paranoid"], optional = true }
|
zrip-decode = { version = "0.8.2", features = ["paranoid"], optional = true }
|
||||||
zune-jpeg = { version = "0.5.1", optional = true }
|
zune-jpeg = { version = "0.5.1", optional = true }
|
||||||
image-webp = {version = "0.2.4", optional = true }
|
image-webp = {version = "0.2.4", optional = true }
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
TIFF decoding and encoding library in pure Rust
|
TIFF decoding and encoding library in pure Rust
|
||||||
|
|
||||||
|
Forked from https://github.com/image-rs/image-tiff. Changes: read images containing RGBPalette frames, ignoring colormaps.
|
||||||
|
|
||||||
## Supported
|
## Supported
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
+42
-22
@@ -599,8 +599,10 @@ impl Entry {
|
|||||||
self.decode_values(self.count, self.type_, reader, |bytes| {
|
self.decode_values(self.count, self.type_, reader, |bytes| {
|
||||||
v.extend(
|
v.extend(
|
||||||
bytes
|
bytes
|
||||||
.chunks_exact(2)
|
.as_chunks::<2>()
|
||||||
.map(|ch| Short(u16::from_ne_bytes(ch.try_into().unwrap()))),
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|&ch| Short(u16::from_ne_bytes(ch))),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -609,8 +611,10 @@ impl Entry {
|
|||||||
self.decode_values(self.count, self.type_, reader, |bytes| {
|
self.decode_values(self.count, self.type_, reader, |bytes| {
|
||||||
v.extend(
|
v.extend(
|
||||||
bytes
|
bytes
|
||||||
.chunks_exact(2)
|
.as_chunks::<2>()
|
||||||
.map(|ch| SignedShort(i16::from_ne_bytes(ch.try_into().unwrap()))),
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|&ch| SignedShort(i16::from_ne_bytes(ch))),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -619,8 +623,10 @@ impl Entry {
|
|||||||
self.decode_values(self.count, self.type_, reader, |bytes| {
|
self.decode_values(self.count, self.type_, reader, |bytes| {
|
||||||
v.extend(
|
v.extend(
|
||||||
bytes
|
bytes
|
||||||
.chunks_exact(4)
|
.as_chunks::<4>()
|
||||||
.map(|ch| Unsigned(u32::from_ne_bytes(ch.try_into().unwrap()))),
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|&ch| Unsigned(u32::from_ne_bytes(ch))),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -629,8 +635,10 @@ impl Entry {
|
|||||||
self.decode_values(self.count, self.type_, reader, |bytes| {
|
self.decode_values(self.count, self.type_, reader, |bytes| {
|
||||||
v.extend(
|
v.extend(
|
||||||
bytes
|
bytes
|
||||||
.chunks_exact(4)
|
.as_chunks::<4>()
|
||||||
.map(|ch| Signed(i32::from_ne_bytes(ch.try_into().unwrap()))),
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|&ch| Signed(i32::from_ne_bytes(ch))),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -639,8 +647,10 @@ impl Entry {
|
|||||||
self.decode_values(self.count, self.type_, reader, |bytes| {
|
self.decode_values(self.count, self.type_, reader, |bytes| {
|
||||||
v.extend(
|
v.extend(
|
||||||
bytes
|
bytes
|
||||||
.chunks_exact(4)
|
.as_chunks::<4>()
|
||||||
.map(|ch| Float(f32::from_ne_bytes(ch.try_into().unwrap()))),
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|&ch| Float(f32::from_ne_bytes(ch))),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -649,15 +659,17 @@ impl Entry {
|
|||||||
self.decode_values(self.count, self.type_, reader, |bytes| {
|
self.decode_values(self.count, self.type_, reader, |bytes| {
|
||||||
v.extend(
|
v.extend(
|
||||||
bytes
|
bytes
|
||||||
.chunks_exact(8)
|
.as_chunks::<8>()
|
||||||
.map(|ch| Double(f64::from_ne_bytes(ch.try_into().unwrap()))),
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|&ch| Double(f64::from_ne_bytes(ch))),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Type::RATIONAL => {
|
Type::RATIONAL => {
|
||||||
v = Self::vec_with_capacity(self.count, self.type_, limits)?;
|
v = Self::vec_with_capacity(self.count, self.type_, limits)?;
|
||||||
self.decode_values(self.count, self.type_, reader, |bytes| {
|
self.decode_values(self.count, self.type_, reader, |bytes| {
|
||||||
v.extend(bytes.chunks_exact(8).map(|ch| {
|
v.extend(bytes.as_chunks::<8>().0.iter().map(|ch| {
|
||||||
Rational(
|
Rational(
|
||||||
u32::from_ne_bytes(ch[..4].try_into().unwrap()),
|
u32::from_ne_bytes(ch[..4].try_into().unwrap()),
|
||||||
u32::from_ne_bytes(ch[4..].try_into().unwrap()),
|
u32::from_ne_bytes(ch[4..].try_into().unwrap()),
|
||||||
@@ -668,7 +680,7 @@ impl Entry {
|
|||||||
Type::SRATIONAL => {
|
Type::SRATIONAL => {
|
||||||
v = Self::vec_with_capacity(self.count, self.type_, limits)?;
|
v = Self::vec_with_capacity(self.count, self.type_, limits)?;
|
||||||
self.decode_values(self.count, self.type_, reader, |bytes| {
|
self.decode_values(self.count, self.type_, reader, |bytes| {
|
||||||
v.extend(bytes.chunks_exact(8).map(|ch| {
|
v.extend(bytes.as_chunks::<8>().0.iter().map(|ch| {
|
||||||
SRational(
|
SRational(
|
||||||
i32::from_ne_bytes(ch[..4].try_into().unwrap()),
|
i32::from_ne_bytes(ch[..4].try_into().unwrap()),
|
||||||
i32::from_ne_bytes(ch[4..].try_into().unwrap()),
|
i32::from_ne_bytes(ch[4..].try_into().unwrap()),
|
||||||
@@ -681,8 +693,10 @@ impl Entry {
|
|||||||
self.decode_values(self.count, self.type_, reader, |bytes| {
|
self.decode_values(self.count, self.type_, reader, |bytes| {
|
||||||
v.extend(
|
v.extend(
|
||||||
bytes
|
bytes
|
||||||
.chunks_exact(8)
|
.as_chunks::<8>()
|
||||||
.map(|ch| UnsignedBig(u64::from_ne_bytes(ch.try_into().unwrap()))),
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|&ch| UnsignedBig(u64::from_ne_bytes(ch))),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -691,8 +705,10 @@ impl Entry {
|
|||||||
self.decode_values(self.count, self.type_, reader, |bytes| {
|
self.decode_values(self.count, self.type_, reader, |bytes| {
|
||||||
v.extend(
|
v.extend(
|
||||||
bytes
|
bytes
|
||||||
.chunks_exact(8)
|
.as_chunks::<8>()
|
||||||
.map(|ch| SignedBig(i64::from_ne_bytes(ch.try_into().unwrap()))),
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|&ch| SignedBig(i64::from_ne_bytes(ch))),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -701,8 +717,10 @@ impl Entry {
|
|||||||
self.decode_values(self.count, self.type_, reader, |bytes| {
|
self.decode_values(self.count, self.type_, reader, |bytes| {
|
||||||
v.extend(
|
v.extend(
|
||||||
bytes
|
bytes
|
||||||
.chunks_exact(4)
|
.as_chunks::<4>()
|
||||||
.map(|ch| Ifd(u32::from_ne_bytes(ch.try_into().unwrap()))),
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|&ch| Ifd(u32::from_ne_bytes(ch))),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -711,8 +729,10 @@ impl Entry {
|
|||||||
self.decode_values(self.count, self.type_, reader, |bytes| {
|
self.decode_values(self.count, self.type_, reader, |bytes| {
|
||||||
v.extend(
|
v.extend(
|
||||||
bytes
|
bytes
|
||||||
.chunks_exact(8)
|
.as_chunks::<8>()
|
||||||
.map(|ch| IfdBig(u64::from_ne_bytes(ch.try_into().unwrap()))),
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|&ch| IfdBig(u64::from_ne_bytes(ch))),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ impl Image {
|
|||||||
.map(Value::into_u16)
|
.map(Value::into_u16)
|
||||||
.transpose()?
|
.transpose()?
|
||||||
.and_then(PhotometricInterpretation::from_u16)
|
.and_then(PhotometricInterpretation::from_u16)
|
||||||
.ok_or(TiffUnsupportedError::UnknownInterpretation)?;
|
.unwrap_or(PhotometricInterpretation::BlackIsZero);
|
||||||
|
|
||||||
// Try to parse both the compression method and the number, format, and bits of the included samples.
|
// Try to parse both the compression method and the number, format, and bits of the included samples.
|
||||||
// If they are not explicitly specified, those tags are reset to their default values and not carried from previous images.
|
// If they are not explicitly specified, those tags are reset to their default values and not carried from previous images.
|
||||||
@@ -467,11 +467,11 @@ impl Image {
|
|||||||
}
|
}
|
||||||
Some(map)
|
Some(map)
|
||||||
}
|
}
|
||||||
None => {
|
// A missing palette is not an error. The pixel values of an indexed image are just
|
||||||
return Err(TiffError::FormatError(
|
// indices into the palette, and the palette itself is only display information, so
|
||||||
TiffFormatError::RequiredTagNotFound(Tag::ColorMap),
|
// the image still decodes. Callers observe the absence as `None` from
|
||||||
));
|
// `Decoder::color_map`.
|
||||||
}
|
None => None,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|||||||
+3
-3
@@ -294,8 +294,8 @@ fn one_byte_predict<const N: usize>(buf: &mut [u8]) {
|
|||||||
acc.copy_from_slice(&buf[..N]);
|
acc.copy_from_slice(&buf[..N]);
|
||||||
|
|
||||||
// Process N bytes per iteration. Each channel's prefix sum is independent.
|
// Process N bytes per iteration. Each channel's prefix sum is independent.
|
||||||
let mut chunks = buf[N..].chunks_exact_mut(N);
|
let chunks = buf[N..].as_chunks_mut::<N>();
|
||||||
for chunk in &mut chunks {
|
for chunk in &mut chunks.0.iter_mut() {
|
||||||
for c in 0..N {
|
for c in 0..N {
|
||||||
acc[c] = chunk[c].wrapping_add(acc[c]);
|
acc[c] = chunk[c].wrapping_add(acc[c]);
|
||||||
chunk[c] = acc[c];
|
chunk[c] = acc[c];
|
||||||
@@ -303,7 +303,7 @@ fn one_byte_predict<const N: usize>(buf: &mut [u8]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle trailing bytes (when buf.len() - N is not a multiple of N).
|
// Handle trailing bytes (when buf.len() - N is not a multiple of N).
|
||||||
for (c, byte) in chunks.into_remainder().iter_mut().enumerate() {
|
for (c, byte) in chunks.1.iter_mut().enumerate() {
|
||||||
*byte = byte.wrapping_add(acc[c]);
|
*byte = byte.wrapping_add(acc[c]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -171,7 +171,7 @@ mod tests {
|
|||||||
dir.get(Tag::Unknown(1))
|
dir.get(Tag::Unknown(1))
|
||||||
.expect("tag 1 should be present after this chain")
|
.expect("tag 1 should be present after this chain")
|
||||||
.count(),
|
.count(),
|
||||||
u16::MAX.into()
|
u64::from(u16::MAX)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-7
@@ -617,26 +617,22 @@ impl ByteOrder {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: at MSRV 1.89 or higher use `slice::as_chunks_mut`.
|
|
||||||
match cls {
|
match cls {
|
||||||
EndianBytes::One => {
|
EndianBytes::One => {
|
||||||
// No change needed
|
// No change needed
|
||||||
}
|
}
|
||||||
EndianBytes::Two => {
|
EndianBytes::Two => {
|
||||||
for chunk in buffer.chunks_exact_mut(2) {
|
for chunk in buffer.as_chunks_mut::<2>().0 {
|
||||||
let chunk: &mut [u8; 2] = chunk.try_into().unwrap();
|
|
||||||
*chunk = u16::from_be_bytes(*chunk).to_le_bytes();
|
*chunk = u16::from_be_bytes(*chunk).to_le_bytes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EndianBytes::Four => {
|
EndianBytes::Four => {
|
||||||
for chunk in buffer.chunks_exact_mut(4) {
|
for chunk in buffer.as_chunks_mut::<4>().0 {
|
||||||
let chunk: &mut [u8; 4] = chunk.try_into().unwrap();
|
|
||||||
*chunk = u32::from_be_bytes(*chunk).to_le_bytes();
|
*chunk = u32::from_be_bytes(*chunk).to_le_bytes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EndianBytes::Eight => {
|
EndianBytes::Eight => {
|
||||||
for chunk in buffer.chunks_exact_mut(8) {
|
for chunk in buffer.as_chunks_mut::<8>().0 {
|
||||||
let chunk: &mut [u8; 8] = chunk.try_into().unwrap();
|
|
||||||
*chunk = u64::from_be_bytes(*chunk).to_le_bytes();
|
*chunk = u64::from_be_bytes(*chunk).to_le_bytes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -898,22 +898,22 @@ fn test_image_bytes(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn byte_order_u16(bytes: &mut [u8]) {
|
fn byte_order_u16(bytes: &mut [u8]) {
|
||||||
for chunk in bytes.chunks_exact_mut(2) {
|
for chunk in bytes.as_chunks_mut::<2>().0 {
|
||||||
let n = u16::from_ne_bytes(chunk.try_into().unwrap());
|
let n = u16::from_ne_bytes(*chunk);
|
||||||
chunk.copy_from_slice(&n.to_le_bytes());
|
chunk.copy_from_slice(&n.to_le_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn byte_order_u32(bytes: &mut [u8]) {
|
fn byte_order_u32(bytes: &mut [u8]) {
|
||||||
for chunk in bytes.chunks_exact_mut(4) {
|
for chunk in bytes.as_chunks_mut::<4>().0 {
|
||||||
let n = u32::from_ne_bytes(chunk.try_into().unwrap());
|
let n = u32::from_ne_bytes(*chunk);
|
||||||
chunk.copy_from_slice(&n.to_le_bytes());
|
chunk.copy_from_slice(&n.to_le_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn byte_order_u64(bytes: &mut [u8]) {
|
fn byte_order_u64(bytes: &mut [u8]) {
|
||||||
for chunk in bytes.chunks_exact_mut(8) {
|
for chunk in bytes.as_chunks_mut::<8>().0 {
|
||||||
let n = u64::from_ne_bytes(chunk.try_into().unwrap());
|
let n = u64::from_ne_bytes(*chunk);
|
||||||
chunk.copy_from_slice(&n.to_le_bytes());
|
chunk.copy_from_slice(&n.to_le_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user