Merge pull request #114 from HagaiHargil/int16_support

Int8/16 support
This commit is contained in:
HeroicKatora authored and GitHub committed 2020-12-14 00:21:51 +01:00
commit 4900c82871
8 files changed
+164 -9

No files matched your search

+2 -2
View File
@@ -23,9 +23,9 @@ macro_rules! integral_slice_as_bytes{($int:ty, $const:ident $(,$mut:ident)*) =>
})* })*
}} }}
integral_slice_as_bytes!(i8, i8_as_ne_bytes); integral_slice_as_bytes!(i8, i8_as_ne_bytes, i8_as_ne_mut_bytes);
integral_slice_as_bytes!(u16, u16_as_ne_bytes, u16_as_ne_mut_bytes); integral_slice_as_bytes!(u16, u16_as_ne_bytes, u16_as_ne_mut_bytes);
integral_slice_as_bytes!(i16, i16_as_ne_bytes); integral_slice_as_bytes!(i16, i16_as_ne_bytes, i16_as_ne_mut_bytes);
integral_slice_as_bytes!(u32, u32_as_ne_bytes, u32_as_ne_mut_bytes); integral_slice_as_bytes!(u32, u32_as_ne_bytes, u32_as_ne_mut_bytes);
integral_slice_as_bytes!(i32, i32_as_ne_bytes); integral_slice_as_bytes!(i32, i32_as_ne_bytes);
integral_slice_as_bytes!(u64, u64_as_ne_bytes, u64_as_ne_mut_bytes); integral_slice_as_bytes!(u64, u64_as_ne_bytes, u64_as_ne_mut_bytes);
+93 -7
View File
@@ -32,6 +32,10 @@ pub enum DecodingResult {
F32(Vec<f32>), F32(Vec<f32>),
/// A vector of 64 bit IEEE floats /// A vector of 64 bit IEEE floats
F64(Vec<f64>), F64(Vec<f64>),
/// A vector of 8 bit signed ints
I8(Vec<i8>),
/// A vector of 16 bit signed ints
I16(Vec<i16>),
} }
impl DecodingResult { impl DecodingResult {
@@ -83,6 +87,22 @@ impl DecodingResult {
} }
} }
fn new_i8(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
if size > limits.decoding_buffer_size / std::mem::size_of::<i8>() {
Err(TiffError::LimitsExceeded)
} else {
Ok(DecodingResult::I8(vec![0; size]))
}
}
fn new_i16(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
if size > limits.decoding_buffer_size / 2 {
Err(TiffError::LimitsExceeded)
} else {
Ok(DecodingResult::I16(vec![0; size]))
}
}
pub fn as_buffer(&mut self, start: usize) -> DecodingBuffer { pub fn as_buffer(&mut self, start: usize) -> DecodingBuffer {
match *self { match *self {
DecodingResult::U8(ref mut buf) => DecodingBuffer::U8(&mut buf[start..]), DecodingResult::U8(ref mut buf) => DecodingBuffer::U8(&mut buf[start..]),
@@ -91,6 +111,8 @@ impl DecodingResult {
DecodingResult::U64(ref mut buf) => DecodingBuffer::U64(&mut buf[start..]), DecodingResult::U64(ref mut buf) => DecodingBuffer::U64(&mut buf[start..]),
DecodingResult::F32(ref mut buf) => DecodingBuffer::F32(&mut buf[start..]), DecodingResult::F32(ref mut buf) => DecodingBuffer::F32(&mut buf[start..]),
DecodingResult::F64(ref mut buf) => DecodingBuffer::F64(&mut buf[start..]), DecodingResult::F64(ref mut buf) => DecodingBuffer::F64(&mut buf[start..]),
DecodingResult::I8(ref mut buf) => DecodingBuffer::I8(&mut buf[start..]),
DecodingResult::I16(ref mut buf) => DecodingBuffer::I16(&mut buf[start..]),
} }
} }
} }
@@ -109,6 +131,10 @@ pub enum DecodingBuffer<'a> {
F32(&'a mut [f32]), F32(&'a mut [f32]),
/// A slice of 64 bit IEEE floats /// A slice of 64 bit IEEE floats
F64(&'a mut [f64]), F64(&'a mut [f64]),
/// A slice of 8 bits signed ints
I8(&'a mut [i8]),
/// A slice of 16 bits signed ints
I16(&'a mut [i16]),
} }
impl<'a> DecodingBuffer<'a> { impl<'a> DecodingBuffer<'a> {
@@ -120,6 +146,8 @@ impl<'a> DecodingBuffer<'a> {
DecodingBuffer::U64(ref buf) => buf.len(), DecodingBuffer::U64(ref buf) => buf.len(),
DecodingBuffer::F32(ref buf) => buf.len(), DecodingBuffer::F32(ref buf) => buf.len(),
DecodingBuffer::F64(ref buf) => buf.len(), DecodingBuffer::F64(ref buf) => buf.len(),
DecodingBuffer::I8(ref buf) => buf.len(),
DecodingBuffer::I16(ref buf) => buf.len(),
} }
} }
@@ -131,6 +159,8 @@ impl<'a> DecodingBuffer<'a> {
DecodingBuffer::U64(_) => 8, DecodingBuffer::U64(_) => 8,
DecodingBuffer::F32(_) => 4, DecodingBuffer::F32(_) => 4,
DecodingBuffer::F64(_) => 8, DecodingBuffer::F64(_) => 8,
DecodingBuffer::I8(_) => 1,
DecodingBuffer::I16(_) => 2,
} }
} }
@@ -145,6 +175,8 @@ impl<'a> DecodingBuffer<'a> {
DecodingBuffer::U64(ref mut buf) => DecodingBuffer::U64(buf), DecodingBuffer::U64(ref mut buf) => DecodingBuffer::U64(buf),
DecodingBuffer::F32(ref mut buf) => DecodingBuffer::F32(buf), DecodingBuffer::F32(ref mut buf) => DecodingBuffer::F32(buf),
DecodingBuffer::F64(ref mut buf) => DecodingBuffer::F64(buf), DecodingBuffer::F64(ref mut buf) => DecodingBuffer::F64(buf),
DecodingBuffer::I8(ref mut buf) => DecodingBuffer::I8(buf),
DecodingBuffer::I16(ref mut buf) => DecodingBuffer::I16(buf),
} }
} }
} }
@@ -257,6 +289,18 @@ impl Wrapping for u64 {
} }
} }
impl Wrapping for i8 {
fn wrapping_add(&self, other: Self) -> Self {
i8::wrapping_add(*self, other)
}
}
impl Wrapping for i16 {
fn wrapping_add(&self, other: Self) -> Self {
i16::wrapping_add(*self, other)
}
}
fn rev_hpredict_nsamp<T>(image: &mut [T], size: (u32, u32), samples: usize) -> TiffResult<()> fn rev_hpredict_nsamp<T>(image: &mut [T], size: (u32, u32), samples: usize) -> TiffResult<()>
where where
T: Copy + Wrapping, T: Copy + Wrapping,
@@ -320,6 +364,12 @@ fn rev_hpredict(image: DecodingBuffer, size: (u32, u32), color_type: ColorType)
TiffUnsupportedError::HorizontalPredictor(color_type), TiffUnsupportedError::HorizontalPredictor(color_type),
)); ));
} }
DecodingBuffer::I8(buf) => {
rev_hpredict_nsamp(buf, size, samples)?;
}
DecodingBuffer::I16(buf) => {
rev_hpredict_nsamp(buf, size, samples)?;
}
} }
Ok(()) Ok(())
} }
@@ -872,6 +922,19 @@ impl<R: Read + Seek> Decoder<R> {
reader.read_u64_into(&mut buffer[..bytes / 8])?; reader.read_u64_into(&mut buffer[..bytes / 8])?;
bytes / 8 bytes / 8
} }
(ColorType::RGBA(8), DecodingBuffer::I8(ref mut buffer))
| (ColorType::RGB(8), DecodingBuffer::I8(ref mut buffer))
| (ColorType::CMYK(8), DecodingBuffer::I8(ref mut buffer)) => {
reader.read_i8_into(&mut buffer[..bytes])?;
bytes
}
(ColorType::RGBA(16), DecodingBuffer::I16(ref mut buffer))
| (ColorType::RGB(16), DecodingBuffer::I16(ref mut buffer))
| (ColorType::CMYK(16), DecodingBuffer::I16(ref mut buffer)) => {
reader.read_i16_into(&mut buffer[..bytes / 2])?;
bytes / 2
}
(ColorType::Gray(64), DecodingBuffer::U64(ref mut buffer)) => { (ColorType::Gray(64), DecodingBuffer::U64(ref mut buffer)) => {
reader.read_u64_into(&mut buffer[..bytes / 8])?; reader.read_u64_into(&mut buffer[..bytes / 8])?;
if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero { if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
@@ -899,11 +962,31 @@ impl<R: Read + Seek> Decoder<R> {
} }
bytes / 2 bytes / 2
} }
(ColorType::Gray(8), DecodingBuffer::I8(ref mut buffer)) => {
reader.read_i8_into(&mut buffer[..bytes])?;
if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
for datum in buffer[..bytes].iter_mut() {
*datum = !*datum;
}
}
bytes
}
// The following conversions interpret the image as in libtiff.
// In particular, MIN is white and MAX is black and not Zero as the name would imply.
(ColorType::Gray(16), DecodingBuffer::I16(ref mut buffer)) => {
reader.read_i16_into(&mut buffer[..bytes / 2])?;
if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
for datum in buffer[..bytes / 2].iter_mut() {
*datum = !*datum;
}
}
bytes / 2
}
(ColorType::Gray(n), DecodingBuffer::U8(ref mut buffer)) if n <= 8 => { (ColorType::Gray(n), DecodingBuffer::U8(ref mut buffer)) if n <= 8 => {
reader.read_exact(&mut buffer[..bytes])?; reader.read_exact(&mut buffer[..bytes])?;
if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero { if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
for byte in buffer[..bytes].iter_mut() { for byte in buffer[..bytes].iter_mut() {
*byte = 0xff - *byte *byte = !*byte;
} }
} }
bytes bytes
@@ -1017,7 +1100,6 @@ impl<R: Read + Seek> Decoder<R> {
pub fn read_strip_to_buffer(&mut self, mut buffer: DecodingBuffer) -> TiffResult<()> { pub fn read_strip_to_buffer(&mut self, mut buffer: DecodingBuffer) -> TiffResult<()> {
self.initialize_strip_decoder()?; self.initialize_strip_decoder()?;
let index = self.strip_decoder.as_ref().unwrap().strip_index; let index = self.strip_decoder.as_ref().unwrap().strip_index;
let offset = *self let offset = *self
.strip_decoder .strip_decoder
@@ -1037,7 +1119,6 @@ impl<R: Read + Seek> Decoder<R> {
.ok_or(TiffError::FormatError( .ok_or(TiffError::FormatError(
TiffFormatError::InconsistentSizesEncountered, TiffFormatError::InconsistentSizesEncountered,
))?; ))?;
let tag_rows = self.get_tag_u32(Tag::RowsPerStrip).unwrap_or(self.height); let tag_rows = self.get_tag_u32(Tag::RowsPerStrip).unwrap_or(self.height);
let rows_per_strip = usize::try_from(tag_rows)?; let rows_per_strip = usize::try_from(tag_rows)?;
@@ -1055,13 +1136,11 @@ impl<R: Read + Seek> Decoder<R> {
} }
let units_read = self.expand_strip(buffer.copy(), offset, byte_count, buffer_size)?; let units_read = self.expand_strip(buffer.copy(), offset, byte_count, buffer_size)?;
self.strip_decoder.as_mut().unwrap().strip_index += 1; self.strip_decoder.as_mut().unwrap().strip_index += 1;
if u32::try_from(index)? == self.strip_count()? { if u32::try_from(index)? == self.strip_count()? {
self.strip_decoder = None; self.strip_decoder = None;
} }
if units_read < buffer_size { if units_read < buffer_size {
return Err(TiffError::FormatError( return Err(TiffError::FormatError(
TiffFormatError::InconsistentStripSamples { TiffFormatError::InconsistentStripSamples {
@@ -1112,6 +1191,13 @@ impl<R: Read + Seek> Decoder<R> {
TiffUnsupportedError::UnsupportedBitsPerChannel(n), TiffUnsupportedError::UnsupportedBitsPerChannel(n),
)), )),
}, },
SampleFormat::Int => match max_sample_bits {
n if n <= 8 => DecodingResult::new_i8(buffer_size, &self.limits),
n if (n > 8) & (n <= 16) => DecodingResult::new_i16(buffer_size, &self.limits),
n => Err(TiffError::UnsupportedError(
TiffUnsupportedError::UnsupportedBitsPerChannel(n),
)),
},
format => { format => {
Err(TiffUnsupportedError::UnsupportedSampleFormat(vec![format.clone()]).into()) Err(TiffUnsupportedError::UnsupportedSampleFormat(vec![format.clone()]).into())
} }
@@ -1132,7 +1218,6 @@ impl<R: Read + Seek> Decoder<R> {
); );
let mut result = self.result_buffer(strip_height)?; let mut result = self.result_buffer(strip_height)?;
self.read_strip_to_buffer(result.as_buffer(0))?; self.read_strip_to_buffer(result.as_buffer(0))?;
Ok(result) Ok(result)
@@ -1154,7 +1239,8 @@ impl<R: Read + Seek> Decoder<R> {
let mut result = self.result_buffer(usize::try_from(self.height)?)?; let mut result = self.result_buffer(usize::try_from(self.height)?)?;
for i in 0..usize::try_from(self.strip_count()?)? { for i in 0..usize::try_from(self.strip_count()?)? {
self.read_strip_to_buffer(result.as_buffer(samples_per_strip * i))?; let r = result.as_buffer(samples_per_strip * i);
self.read_strip_to_buffer(r)?;
} }
Ok(result) Ok(result)
} }
+47
View File
@@ -48,6 +48,35 @@ pub trait EndianReader: Read {
Ok(()) Ok(())
} }
/// Reads an i8
#[inline(always)]
fn read_i8(&mut self) -> Result<i8, io::Error> {
let mut n = [0u8; 1];
self.read_exact(&mut n)?;
Ok(match self.byte_order() {
ByteOrder::LittleEndian => i8::from_le_bytes(n),
ByteOrder::BigEndian => i8::from_be_bytes(n),
})
}
#[inline(always)]
fn read_i8_into(&mut self, buffer: &mut [i8]) -> Result<(), io::Error> {
self.read_exact(bytecast::i8_as_ne_mut_bytes(buffer))?;
match self.byte_order() {
ByteOrder::LittleEndian => {
for n in buffer {
*n = i8::from_le(*n);
}
}
ByteOrder::BigEndian => {
for n in buffer {
*n = i8::from_be(*n);
}
}
}
Ok(())
}
/// Reads an i16 /// Reads an i16
#[inline(always)] #[inline(always)]
fn read_i16(&mut self) -> Result<i16, io::Error> { fn read_i16(&mut self) -> Result<i16, io::Error> {
@@ -59,6 +88,24 @@ pub trait EndianReader: Read {
}) })
} }
#[inline(always)]
fn read_i16_into(&mut self, buffer: &mut [i16]) -> Result<(), io::Error> {
self.read_exact(bytecast::i16_as_ne_mut_bytes(buffer))?;
match self.byte_order() {
ByteOrder::LittleEndian => {
for n in buffer {
*n = i16::from_le(*n);
}
}
ByteOrder::BigEndian => {
for n in buffer {
*n = i16::from_be(*n);
}
}
}
Ok(())
}
/// Reads an u32 /// Reads an u32
#[inline(always)] #[inline(always)]
fn read_u32(&mut self) -> Result<u32, io::Error> { fn read_u32(&mut self) -> Result<u32, io::Error> {
+22
View File
@@ -29,7 +29,9 @@ macro_rules! test_image_sum {
} }
test_image_sum!(test_image_sum_u8, U8, u64); test_image_sum!(test_image_sum_u8, U8, u64);
test_image_sum!(test_image_sum_i8, I8, i64);
test_image_sum!(test_image_sum_u16, U16, u64); test_image_sum!(test_image_sum_u16, U16, u64);
test_image_sum!(test_image_sum_i16, I16, i64);
test_image_sum!(test_image_sum_u32, U32, u64); test_image_sum!(test_image_sum_u32, U32, u64);
test_image_sum!(test_image_sum_u64, U64, u64); test_image_sum!(test_image_sum_u64, U64, u64);
test_image_sum!(test_image_sum_f32, F32, f32); test_image_sum!(test_image_sum_f32, F32, f32);
@@ -135,6 +137,26 @@ fn test_rgb_f32() {
test_image_sum_f32("gradient-3c-32b-float.tiff", ColorType::RGB(32), 472.8405); test_image_sum_f32("gradient-3c-32b-float.tiff", ColorType::RGB(32), 472.8405);
} }
#[test]
fn test_int8() {
test_image_sum_i8("int8.tif", ColorType::Gray(8), 3111)
}
#[test]
fn test_int8_rgb() {
test_image_sum_i8("int8_rgb.tif", ColorType::RGB(8), -10344)
}
#[test]
fn test_int16() {
test_image_sum_i16("int16.tif", ColorType::Gray(16), 354396);
}
#[test]
fn test_int16_rgb() {
test_image_sum_i16("int16_rgb.tif", ColorType::RGB(16), 1063188);
}
#[test] #[test]
fn test_string_tags() { fn test_string_tags() {
// these files have null-terminated strings for their Software tag. One has extra bytes after // these files have null-terminated strings for their Software tag. One has extra bytes after
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.