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!(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!(i32, i32_as_ne_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>),
/// A vector of 64 bit IEEE floats
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 {
@@ -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 {
match *self {
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::F32(ref mut buf) => DecodingBuffer::F32(&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]),
/// A slice of 64 bit IEEE floats
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> {
@@ -120,6 +146,8 @@ impl<'a> DecodingBuffer<'a> {
DecodingBuffer::U64(ref buf) => buf.len(),
DecodingBuffer::F32(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::F32(_) => 4,
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::F32(ref mut buf) => DecodingBuffer::F32(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<()>
where
T: Copy + Wrapping,
@@ -320,6 +364,12 @@ fn rev_hpredict(image: DecodingBuffer, size: (u32, u32), color_type: ColorType)
TiffUnsupportedError::HorizontalPredictor(color_type),
));
}
DecodingBuffer::I8(buf) => {
rev_hpredict_nsamp(buf, size, samples)?;
}
DecodingBuffer::I16(buf) => {
rev_hpredict_nsamp(buf, size, samples)?;
}
}
Ok(())
}
@@ -872,6 +922,19 @@ impl<R: Read + Seek> Decoder<R> {
reader.read_u64_into(&mut buffer[..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)) => {
reader.read_u64_into(&mut buffer[..bytes / 8])?;
if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
@@ -899,11 +962,31 @@ impl<R: Read + Seek> Decoder<R> {
}
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 => {
reader.read_exact(&mut buffer[..bytes])?;
if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
for byte in buffer[..bytes].iter_mut() {
*byte = 0xff - *byte
*byte = !*byte;
}
}
bytes
@@ -1017,7 +1100,6 @@ impl<R: Read + Seek> Decoder<R> {
pub fn read_strip_to_buffer(&mut self, mut buffer: DecodingBuffer) -> TiffResult<()> {
self.initialize_strip_decoder()?;
let index = self.strip_decoder.as_ref().unwrap().strip_index;
let offset = *self
.strip_decoder
@@ -1037,7 +1119,6 @@ impl<R: Read + Seek> Decoder<R> {
.ok_or(TiffError::FormatError(
TiffFormatError::InconsistentSizesEncountered,
))?;
let tag_rows = self.get_tag_u32(Tag::RowsPerStrip).unwrap_or(self.height);
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)?;
self.strip_decoder.as_mut().unwrap().strip_index += 1;
if u32::try_from(index)? == self.strip_count()? {
self.strip_decoder = None;
}
if units_read < buffer_size {
return Err(TiffError::FormatError(
TiffFormatError::InconsistentStripSamples {
@@ -1112,6 +1191,13 @@ impl<R: Read + Seek> Decoder<R> {
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 => {
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)?;
self.read_strip_to_buffer(result.as_buffer(0))?;
Ok(result)
@@ -1154,7 +1239,8 @@ impl<R: Read + Seek> Decoder<R> {
let mut result = self.result_buffer(usize::try_from(self.height)?)?;
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)
}
+47
View File
@@ -48,6 +48,35 @@ pub trait EndianReader: Read {
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
#[inline(always)]
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
#[inline(always)]
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_i8, I8, i64);
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_u64, U64, u64);
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]
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]
fn test_string_tags() {
// 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.