Removed unwrap and set colour transform with Jpeg compressed tiffs

This commit is contained in:
Alan Race committed 2022-11-22 14:31:33 +01:00
1 parent 9333d99c92
commit 7307e96782
3 files changed
+62 -71

No files matched your search

+35 -19
View File
@@ -1,8 +1,5 @@
use super::ifd::{Directory, Value};
use super::stream::{
add_app14segment, ByteOrder, DeflateReader, JpegReader, JpegTagApp14Transform, LZWReader,
PackBitsReader,
};
use super::stream::{ByteOrder, DeflateReader, JpegReader, LZWReader, PackBitsReader};
use super::tag_reader::TagReader;
use super::{fp_predict_f32, fp_predict_f64, DecodingBuffer, Limits};
use super::{stream::SmartReader, ChunkType};
@@ -121,7 +118,7 @@ impl Image {
let jpeg_tables = if compression_method == CompressionMethod::ModernJPEG
&& ifd.contains_key(&Tag::JPEGTables)
{
let mut vec = tag_reader
let vec = tag_reader
.find_tag(Tag::JPEGTables)?
.unwrap()
.into_u8_vec()?;
@@ -131,11 +128,6 @@ impl Image {
));
}
// TODO: Can we avoid this somehow?
if photometric_interpretation == PhotometricInterpretation::RGB {
add_app14segment(&mut vec, JpegTagApp14Transform::App14TransformUnknown)
}
Some(Arc::new(vec))
} else {
None
@@ -332,6 +324,7 @@ impl Image {
fn create_reader<'r, R: 'r + Read>(
reader: R,
photometric_interpretation: PhotometricInterpretation,
compression_method: CompressionMethod,
compressed_length: u64,
jpeg_tables: Option<Arc<Vec<u8>>>,
@@ -354,14 +347,32 @@ impl Image {
let jpeg_reader = JpegReader::new(reader, compressed_length, jpeg_tables)?;
let mut decoder = jpeg::Decoder::new(jpeg_reader);
let data = match decoder.decode() {
Ok(data) => data,
Err(e) => {
return Err(TiffError::FormatError(TiffFormatError::Format(
e.to_string(),
)))
match photometric_interpretation {
PhotometricInterpretation::RGB => {
decoder.set_color_transform(jpeg::ColorTransform::RGB)
}
};
PhotometricInterpretation::WhiteIsZero => {
decoder.set_color_transform(jpeg::ColorTransform::None)
}
PhotometricInterpretation::BlackIsZero => {
decoder.set_color_transform(jpeg::ColorTransform::None)
}
PhotometricInterpretation::RGBPalette => todo!(),
PhotometricInterpretation::TransparencyMask => {
decoder.set_color_transform(jpeg::ColorTransform::None)
}
PhotometricInterpretation::CMYK => {
decoder.set_color_transform(jpeg::ColorTransform::CMYK)
}
PhotometricInterpretation::YCbCr => {
decoder.set_color_transform(jpeg::ColorTransform::YCbCr)
}
PhotometricInterpretation::CIELab => todo!(),
_ => todo!(),
}
let data = decoder.decode()?;
Box::new(Cursor::new(data))
}
@@ -509,8 +520,13 @@ impl Image {
let padding_right = chunk_dims.0 - data_dims.0;
let jpeg_tables = self.jpeg_tables.clone();
let mut reader =
Self::create_reader(reader, compression_method, *compressed_bytes, jpeg_tables)?;
let mut reader = Self::create_reader(
reader,
photometric_interpretation,
compression_method,
*compressed_bytes,
jpeg_tables,
)?;
if output_width == data_dims.0 as usize && padding_right == 0 {
let total_samples = data_dims.0 as usize * data_dims.1 as usize * samples;
-52
View File
@@ -250,58 +250,6 @@ impl JpegReader {
}
}
#[repr(u8)]
pub(crate) enum JpegTagApp14Transform {
// App14TransformYCCK = 2,
// App14TransformYCbCr = 1,
App14TransformUnknown = 0,
}
pub(crate) fn add_app14segment(jpeg_tables: &mut Vec<u8>, transform: JpegTagApp14Transform) {
// Add JPEG Tag APP14 Adobe segment to jpeg_tables.
// This segment stores image encoding information for DCT filters.
// When `transform` value is 0 which is defined as Unknown, jpeg-decoder interpret the
// color-space of image as RGB(3 channels) or CMYK(4).
let mut app14_offset = None;
let mut dht_offset = None;
for (offset, window) in jpeg_tables.windows(2).enumerate() {
if window == [0xff, 0xee] {
app14_offset = Some(offset);
break;
}
if window == [0xff, 0xc4] {
dht_offset = Some(offset);
}
}
match (app14_offset, dht_offset) {
(Some(i), _) => {
jpeg_tables[i + 16] = transform as u8;
}
(None, Some(sos_offset)) => {
let app14segment: [u8; 16] = [
0xff,
0xee,
0x00,
0x0e,
0x41,
0x64,
0x6f,
0x62,
0x65,
0x00,
0x64,
0x00,
0x00,
0x00,
0x00,
transform as u8,
];
jpeg_tables.splice(sos_offset..sos_offset, app14segment.iter().copied());
}
(None, None) => {}
}
}
impl Read for JpegReader {
// #[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+27
View File
@@ -4,6 +4,8 @@ use std::io;
use std::str;
use std::string;
use jpeg::UnsupportedFeature;
use crate::decoder::{ifd::Value, ChunkType};
use crate::tags::{
CompressionMethod, PhotometricInterpretation, PlanarConfiguration, SampleFormat, Tag,
@@ -146,6 +148,10 @@ pub enum TiffUnsupportedError {
UnsupportedBitsPerChannel(u8),
UnsupportedPlanarConfig(Option<PlanarConfiguration>),
UnsupportedDataType,
UnsupportedJpegFeature(UnsupportedFeature),
#[doc(hidden)]
/// Do not match against this variant. It may get removed.
__NonExhaustive,
}
impl fmt::Display for TiffUnsupportedError {
@@ -191,6 +197,10 @@ impl fmt::Display for TiffUnsupportedError {
write!(fmt, "Unsupported planar configuration “{:?}”.", config)
}
UnsupportedDataType => write!(fmt, "Unsupported data type."),
UnsupportedJpegFeature(ref unsupported_feature) => {
write!(fmt, "Unsupported JPEG feature {:?}", unsupported_feature)
}
__NonExhaustive => unreachable!(),
}
}
}
@@ -310,5 +320,22 @@ impl From<LzwError> for TiffError {
}
}
impl From<jpeg::Error> for TiffError {
fn from(error: jpeg::Error) -> Self {
match error {
jpeg::Error::Format(format) => {
TiffError::FormatError(TiffFormatError::Format(format!("JPEG format: {}", format)))
}
jpeg::Error::Unsupported(unsupported) => TiffError::UnsupportedError(
TiffUnsupportedError::UnsupportedJpegFeature(unsupported),
),
jpeg::Error::Io(io_error) => TiffError::IoError(io_error),
jpeg::Error::Internal(internal) => {
panic!("According to jpeg create, this is not used, so this shouldn't be reached..")
}
}
}
}
/// Result of an image decoding/encoding process
pub type TiffResult<T> = Result<T, TiffError>;