Support floating point predictor (predictor 3)
Based on work by @TomasKralCZ in #135
This commit is contained in:
1 parent
8a6e93f66e
commit
8e5c5b44c5
7 files changed
+86
-1
No files matched your search
+31
-1
@@ -4,8 +4,8 @@ use super::stream::{
|
||||
PackBitsReader,
|
||||
};
|
||||
use super::tag_reader::TagReader;
|
||||
use super::{fp_predict_f32, fp_predict_f64, DecodingBuffer, Limits};
|
||||
use super::{stream::SmartReader, ChunkType};
|
||||
use super::{DecodingBuffer, Limits};
|
||||
use crate::tags::{CompressionMethod, PhotometricInterpretation, Predictor, SampleFormat, Tag};
|
||||
use crate::{ColorType, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
@@ -406,6 +406,11 @@ impl Image {
|
||||
TiffUnsupportedError::HorizontalPredictor(color_type),
|
||||
))
|
||||
}
|
||||
Predictor::FloatingPoint => {
|
||||
return Err(TiffError::UnsupportedError(
|
||||
TiffUnsupportedError::FloatingPointPredictor(color_type),
|
||||
));
|
||||
}
|
||||
Predictor::__NonExhaustive => unreachable!(),
|
||||
},
|
||||
(type_, _) => {
|
||||
@@ -423,6 +428,13 @@ impl Image {
|
||||
TiffUnsupportedError::HorizontalPredictor(color_type),
|
||||
));
|
||||
}
|
||||
(Predictor::FloatingPoint, DecodingBuffer::F32(_))
|
||||
| (Predictor::FloatingPoint, DecodingBuffer::F64(_)) => {}
|
||||
(Predictor::FloatingPoint, _) => {
|
||||
return Err(TiffError::UnsupportedError(
|
||||
TiffUnsupportedError::FloatingPointPredictor(color_type),
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -471,6 +483,24 @@ impl Image {
|
||||
if photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
|
||||
super::invert_colors(&mut buffer.subrange(0..total_samples), color_type);
|
||||
}
|
||||
} else if padding.0 > 0 && self.predictor == Predictor::FloatingPoint {
|
||||
// The floating point predictor shuffles the padding bytes into the encoded output, so
|
||||
// this case is handled specially when needed.
|
||||
for row in 0..(chunk_dimensions.1 - padding.1) {
|
||||
let row_start = row * output_width * samples;
|
||||
let row_end = row_start + (chunk_dimensions.0 - padding.0) * samples;
|
||||
|
||||
let mut encoded = vec![0u8; chunk_dimensions.0 * samples * byte_len];
|
||||
reader.read_exact(&mut encoded)?;
|
||||
match buffer.subrange(row_start..row_end) {
|
||||
DecodingBuffer::F32(buf) => fp_predict_f32(&mut encoded, buf, samples),
|
||||
DecodingBuffer::F64(buf) => fp_predict_f64(&mut encoded, buf, samples),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
if photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
|
||||
super::invert_colors(&mut buffer.subrange(row_start..row_end), color_type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for row in 0..(chunk_dimensions.1 - padding.1) {
|
||||
let row_start = row * output_width * samples;
|
||||
|
||||
@@ -365,6 +365,36 @@ fn rev_hpredict_nsamp<T: Copy + Wrapping>(image: &mut [T], samples: usize) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fp_predict_f32(input: &mut [u8], output: &mut [f32], samples: usize) {
|
||||
rev_hpredict_nsamp(input, samples);
|
||||
for i in 0..output.len() {
|
||||
// TODO: use f32::from_be_bytes() when we can (version 1.40)
|
||||
output[i] = f32::from_bits(u32::from_be_bytes([
|
||||
input[input.len() / 4 * 0 + i],
|
||||
input[input.len() / 4 * 1 + i],
|
||||
input[input.len() / 4 * 2 + i],
|
||||
input[input.len() / 4 * 3 + i],
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fp_predict_f64(input: &mut [u8], output: &mut [f64], samples: usize) {
|
||||
rev_hpredict_nsamp(input, samples);
|
||||
for i in 0..output.len() {
|
||||
// TODO: use f64::from_be_bytes() when we can (version 1.40)
|
||||
output[i] = f64::from_bits(u64::from_be_bytes([
|
||||
input[input.len() / 8 * 0 + i],
|
||||
input[input.len() / 8 * 1 + i],
|
||||
input[input.len() / 8 * 2 + i],
|
||||
input[input.len() / 8 * 3 + i],
|
||||
input[input.len() / 8 * 4 + i],
|
||||
input[input.len() / 8 * 5 + i],
|
||||
input[input.len() / 8 * 6 + i],
|
||||
input[input.len() / 8 * 7 + i],
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
fn fix_endianness_and_predict(
|
||||
mut image: DecodingBuffer,
|
||||
samples: usize,
|
||||
@@ -389,6 +419,14 @@ fn fix_endianness_and_predict(
|
||||
DecodingBuffer::F32(_) | DecodingBuffer::F64(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
Predictor::FloatingPoint => {
|
||||
let mut buffer_copy = image.as_bytes_mut().to_vec();
|
||||
match image {
|
||||
DecodingBuffer::F32(buf) => fp_predict_f32(&mut buffer_copy, buf, samples),
|
||||
DecodingBuffer::F64(buf) => fp_predict_f64(&mut buffer_copy, buf, samples),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
Predictor::__NonExhaustive => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user