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,
|
PackBitsReader,
|
||||||
};
|
};
|
||||||
use super::tag_reader::TagReader;
|
use super::tag_reader::TagReader;
|
||||||
|
use super::{fp_predict_f32, fp_predict_f64, DecodingBuffer, Limits};
|
||||||
use super::{stream::SmartReader, ChunkType};
|
use super::{stream::SmartReader, ChunkType};
|
||||||
use super::{DecodingBuffer, Limits};
|
|
||||||
use crate::tags::{CompressionMethod, PhotometricInterpretation, Predictor, SampleFormat, Tag};
|
use crate::tags::{CompressionMethod, PhotometricInterpretation, Predictor, SampleFormat, Tag};
|
||||||
use crate::{ColorType, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
|
use crate::{ColorType, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
@@ -406,6 +406,11 @@ impl Image {
|
|||||||
TiffUnsupportedError::HorizontalPredictor(color_type),
|
TiffUnsupportedError::HorizontalPredictor(color_type),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
Predictor::FloatingPoint => {
|
||||||
|
return Err(TiffError::UnsupportedError(
|
||||||
|
TiffUnsupportedError::FloatingPointPredictor(color_type),
|
||||||
|
));
|
||||||
|
}
|
||||||
Predictor::__NonExhaustive => unreachable!(),
|
Predictor::__NonExhaustive => unreachable!(),
|
||||||
},
|
},
|
||||||
(type_, _) => {
|
(type_, _) => {
|
||||||
@@ -423,6 +428,13 @@ impl Image {
|
|||||||
TiffUnsupportedError::HorizontalPredictor(color_type),
|
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 {
|
if photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
|
||||||
super::invert_colors(&mut buffer.subrange(0..total_samples), color_type);
|
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 {
|
} else {
|
||||||
for row in 0..(chunk_dimensions.1 - padding.1) {
|
for row in 0..(chunk_dimensions.1 - padding.1) {
|
||||||
let row_start = row * output_width * samples;
|
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(
|
fn fix_endianness_and_predict(
|
||||||
mut image: DecodingBuffer,
|
mut image: DecodingBuffer,
|
||||||
samples: usize,
|
samples: usize,
|
||||||
@@ -389,6 +419,14 @@ fn fix_endianness_and_predict(
|
|||||||
DecodingBuffer::F32(_) | DecodingBuffer::F64(_) => unreachable!(),
|
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!(),
|
Predictor::__NonExhaustive => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ impl fmt::Display for TiffFormatError {
|
|||||||
/// stability guarantees.
|
/// stability guarantees.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum TiffUnsupportedError {
|
pub enum TiffUnsupportedError {
|
||||||
|
FloatingPointPredictor(ColorType),
|
||||||
HorizontalPredictor(ColorType),
|
HorizontalPredictor(ColorType),
|
||||||
InterpretationWithBits(PhotometricInterpretation, Vec<u8>),
|
InterpretationWithBits(PhotometricInterpretation, Vec<u8>),
|
||||||
UnknownInterpretation,
|
UnknownInterpretation,
|
||||||
@@ -154,6 +155,11 @@ impl fmt::Display for TiffUnsupportedError {
|
|||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
use self::TiffUnsupportedError::*;
|
use self::TiffUnsupportedError::*;
|
||||||
match *self {
|
match *self {
|
||||||
|
FloatingPointPredictor(color_type) => write!(
|
||||||
|
fmt,
|
||||||
|
"Floating point predictor for {:?} is unsupported.",
|
||||||
|
color_type
|
||||||
|
),
|
||||||
HorizontalPredictor(color_type) => write!(
|
HorizontalPredictor(color_type) => write!(
|
||||||
fmt,
|
fmt,
|
||||||
"Horizontal predictor for {:?} is unsupported.",
|
"Horizontal predictor for {:?} is unsupported.",
|
||||||
|
|||||||
@@ -214,6 +214,7 @@ tags! {
|
|||||||
pub enum Predictor(u16) {
|
pub enum Predictor(u16) {
|
||||||
None = 1,
|
None = 1,
|
||||||
Horizontal = 2,
|
Horizontal = 2,
|
||||||
|
FloatingPoint = 3,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -494,3 +494,13 @@ fn timeout() {
|
|||||||
fn test_no_rows_per_strip() {
|
fn test_no_rows_per_strip() {
|
||||||
test_image_sum_u8("no_rows_per_strip.tiff", ColorType::RGB(8), 99448840);
|
test_image_sum_u8("no_rows_per_strip.tiff", ColorType::RGB(8), 99448840);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_predictor_3_rgb_f32() {
|
||||||
|
test_image_sum_f32("predictor-3-rgb-f32.tif", ColorType::RGB(32), 54004.33);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_predictor_3_gray_f32() {
|
||||||
|
test_image_sum_f32("predictor-3-gray-f32.tif", ColorType::Gray(32), 20008.275);
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Reference in new issue
Block a user