Add FP16 support (#257)
This commit is contained in:
1 parent
d42e6be507
commit
3bfb43e83e
14 files changed
+239
-6
No files matched your search
@@ -1,7 +1,7 @@
|
||||
use super::ifd::{Directory, Value};
|
||||
use super::stream::{ByteOrder, DeflateReader, LZWReader, PackBitsReader};
|
||||
use super::tag_reader::TagReader;
|
||||
use super::{predict_f32, predict_f64, Limits};
|
||||
use super::{predict_f16, predict_f32, predict_f64, Limits};
|
||||
use super::{stream::SmartReader, ChunkType};
|
||||
use crate::tags::{
|
||||
CompressionMethod, PhotometricInterpretation, PlanarConfiguration, Predictor, SampleFormat, Tag,
|
||||
@@ -592,7 +592,10 @@ impl Image {
|
||||
|
||||
// Validate that the predictor is supported for the sample type.
|
||||
match (self.predictor, self.sample_format) {
|
||||
(Predictor::Horizontal, SampleFormat::Int | SampleFormat::Uint) => {}
|
||||
(
|
||||
Predictor::Horizontal,
|
||||
SampleFormat::Int | SampleFormat::Uint | SampleFormat::IEEEFP,
|
||||
) => {}
|
||||
(Predictor::Horizontal, _) => {
|
||||
return Err(TiffError::UnsupportedError(
|
||||
TiffUnsupportedError::HorizontalPredictor(color_type),
|
||||
@@ -672,6 +675,7 @@ impl Image {
|
||||
|
||||
let row = &mut row[..data_row_bytes];
|
||||
match color_type.bit_depth() {
|
||||
16 => predict_f16(&mut encoded, row, samples),
|
||||
32 => predict_f32(&mut encoded, row, samples),
|
||||
64 => predict_f64(&mut encoded, row, samples),
|
||||
_ => unreachable!(),
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::tags::{
|
||||
use crate::{
|
||||
bytecast, ColorType, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError, UsageError,
|
||||
};
|
||||
use half::f16;
|
||||
|
||||
use self::ifd::Directory;
|
||||
use self::image::Image;
|
||||
@@ -29,6 +30,8 @@ pub enum DecodingResult {
|
||||
U32(Vec<u32>),
|
||||
/// A vector of 64 bit unsigned ints
|
||||
U64(Vec<u64>),
|
||||
/// A vector of 16 bit IEEE floats (held in u16)
|
||||
F16(Vec<f16>),
|
||||
/// A vector of 32 bit IEEE floats
|
||||
F32(Vec<f32>),
|
||||
/// A vector of 64 bit IEEE floats
|
||||
@@ -92,6 +95,14 @@ impl DecodingResult {
|
||||
}
|
||||
}
|
||||
|
||||
fn new_f16(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
|
||||
if size > limits.decoding_buffer_size / std::mem::size_of::<u16>() {
|
||||
Err(TiffError::LimitsExceeded)
|
||||
} else {
|
||||
Ok(DecodingResult::F16(vec![f16::ZERO; size]))
|
||||
}
|
||||
}
|
||||
|
||||
fn new_i8(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
|
||||
if size > limits.decoding_buffer_size / std::mem::size_of::<i8>() {
|
||||
Err(TiffError::LimitsExceeded)
|
||||
@@ -130,6 +141,7 @@ impl DecodingResult {
|
||||
DecodingResult::U16(ref mut buf) => DecodingBuffer::U16(&mut buf[start..]),
|
||||
DecodingResult::U32(ref mut buf) => DecodingBuffer::U32(&mut buf[start..]),
|
||||
DecodingResult::U64(ref mut buf) => DecodingBuffer::U64(&mut buf[start..]),
|
||||
DecodingResult::F16(ref mut buf) => DecodingBuffer::F16(&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..]),
|
||||
@@ -150,6 +162,8 @@ pub enum DecodingBuffer<'a> {
|
||||
U32(&'a mut [u32]),
|
||||
/// A slice of 64 bit unsigned ints
|
||||
U64(&'a mut [u64]),
|
||||
/// A slice of 16 bit IEEE floats
|
||||
F16(&'a mut [f16]),
|
||||
/// A slice of 32 bit IEEE floats
|
||||
F32(&'a mut [f32]),
|
||||
/// A slice of 64 bit IEEE floats
|
||||
@@ -175,6 +189,7 @@ impl<'a> DecodingBuffer<'a> {
|
||||
DecodingBuffer::I32(buf) => bytecast::i32_as_ne_mut_bytes(buf),
|
||||
DecodingBuffer::U64(buf) => bytecast::u64_as_ne_mut_bytes(buf),
|
||||
DecodingBuffer::I64(buf) => bytecast::i64_as_ne_mut_bytes(buf),
|
||||
DecodingBuffer::F16(buf) => bytecast::f16_as_ne_mut_bytes(buf),
|
||||
DecodingBuffer::F32(buf) => bytecast::f32_as_ne_mut_bytes(buf),
|
||||
DecodingBuffer::F64(buf) => bytecast::f64_as_ne_mut_bytes(buf),
|
||||
}
|
||||
@@ -303,6 +318,19 @@ fn predict_f32(input: &mut [u8], output: &mut [u8], samples: usize) {
|
||||
}
|
||||
}
|
||||
|
||||
fn predict_f16(input: &mut [u8], output: &mut [u8], samples: usize) {
|
||||
for i in samples..input.len() {
|
||||
input[i] = input[i].wrapping_add(input[i - samples]);
|
||||
}
|
||||
|
||||
for (i, chunk) in output.chunks_mut(2).enumerate() {
|
||||
chunk.copy_from_slice(&u16::to_ne_bytes(u16::from_be_bytes([
|
||||
input[i],
|
||||
input[input.len() / 2 + i],
|
||||
])));
|
||||
}
|
||||
}
|
||||
|
||||
fn predict_f64(input: &mut [u8], output: &mut [u8], samples: usize) {
|
||||
for i in samples..input.len() {
|
||||
input[i] = input[i].wrapping_add(input[i - samples]);
|
||||
@@ -340,6 +368,7 @@ fn fix_endianness_and_predict(
|
||||
Predictor::FloatingPoint => {
|
||||
let mut buffer_copy = buf.to_vec();
|
||||
match bit_depth {
|
||||
16 => predict_f16(&mut buffer_copy, buf, samples),
|
||||
32 => predict_f32(&mut buffer_copy, buf, samples),
|
||||
64 => predict_f64(&mut buffer_copy, buf, samples),
|
||||
_ => unreachable!("Caller should have validated arguments. Please file a bug."),
|
||||
@@ -1004,6 +1033,7 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
)),
|
||||
},
|
||||
SampleFormat::IEEEFP => match max_sample_bits {
|
||||
16 => DecodingResult::new_f16(buffer_size, &self.limits),
|
||||
32 => DecodingResult::new_f32(buffer_size, &self.limits),
|
||||
64 => DecodingResult::new_f64(buffer_size, &self.limits),
|
||||
n => Err(TiffError::UnsupportedError(
|
||||
|
||||
Reference in new issue
Block a user