Move some decoder fields into a new Image struct
This commit is contained in:
1 parent
6ba5553d20
commit
b385a6e752
2 files changed
+242
-177
No files matched your search
@@ -0,0 +1,96 @@
|
|||||||
|
use super::ChunkType;
|
||||||
|
use super::ifd::Directory;
|
||||||
|
use crate::tags::{
|
||||||
|
CompressionMethod, PhotometricInterpretation, Predictor, SampleFormat,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct StripDecodeState {
|
||||||
|
pub rows_per_strip: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// Computed values useful for tile decoding
|
||||||
|
pub(crate) struct TileAttributes {
|
||||||
|
pub image_width: usize,
|
||||||
|
pub image_height: usize,
|
||||||
|
pub samples_per_pixel: usize,
|
||||||
|
|
||||||
|
pub tile_width: usize,
|
||||||
|
pub tile_length: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TileAttributes {
|
||||||
|
pub fn tiles_across(&self) -> usize {
|
||||||
|
(self.image_width + self.tile_width - 1) / self.tile_width
|
||||||
|
}
|
||||||
|
pub fn tiles_down(&self) -> usize {
|
||||||
|
(self.image_height + self.tile_length - 1) / self.tile_length
|
||||||
|
}
|
||||||
|
fn padding_right(&self) -> usize {
|
||||||
|
self.tile_width - self.image_width % self.tile_width
|
||||||
|
}
|
||||||
|
fn padding_down(&self) -> usize {
|
||||||
|
self.tile_length - self.image_height % self.tile_length
|
||||||
|
}
|
||||||
|
pub fn row_samples(&self) -> usize {
|
||||||
|
self.tile_width * self.samples_per_pixel
|
||||||
|
}
|
||||||
|
pub fn tile_samples(&self) -> usize {
|
||||||
|
self.tile_length * self.tile_width * self.samples_per_pixel
|
||||||
|
}
|
||||||
|
fn tile_strip_samples(&self) -> usize {
|
||||||
|
(self.tile_samples() * self.tiles_across())
|
||||||
|
- (self.padding_right() * self.tile_length * self.samples_per_pixel)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the tile offset in the result buffer, counted in samples
|
||||||
|
pub fn get_offset(&self, tile: usize) -> usize {
|
||||||
|
let row = tile / self.tiles_across();
|
||||||
|
let column = tile % self.tiles_across();
|
||||||
|
|
||||||
|
(row * self.tile_strip_samples()) + (column * self.row_samples())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_padding(&self, tile: usize) -> (usize, usize) {
|
||||||
|
let row = tile / self.tiles_across();
|
||||||
|
let column = tile % self.tiles_across();
|
||||||
|
|
||||||
|
let padding_right = if column == self.tiles_across() - 1 {
|
||||||
|
self.padding_right()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
let padding_down = if row == self.tiles_down() - 1 {
|
||||||
|
self.padding_down()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
(padding_right, padding_down)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct Image {
|
||||||
|
pub ifd: Option<Directory>,
|
||||||
|
pub width: u32,
|
||||||
|
pub height: u32,
|
||||||
|
pub bits_per_sample: Vec<u8>,
|
||||||
|
pub samples: u8,
|
||||||
|
pub sample_format: Vec<SampleFormat>,
|
||||||
|
pub photometric_interpretation: PhotometricInterpretation,
|
||||||
|
pub compression_method: CompressionMethod,
|
||||||
|
pub predictor: Predictor,
|
||||||
|
pub jpeg_tables: Option<Vec<u8>>,
|
||||||
|
pub chunk_type: ChunkType,
|
||||||
|
pub strip_decoder: Option<StripDecodeState>,
|
||||||
|
pub tile_attributes: Option<TileAttributes>,
|
||||||
|
pub chunk_offsets: Vec<u64>,
|
||||||
|
pub chunk_bytes: Vec<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Image {
|
||||||
|
|
||||||
|
}
|
||||||
+146
-177
@@ -8,6 +8,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use self::ifd::Directory;
|
use self::ifd::Directory;
|
||||||
|
use self::image::{Image, StripDecodeState, TileAttributes};
|
||||||
use crate::tags::{
|
use crate::tags::{
|
||||||
CompressionMethod, PhotometricInterpretation, Predictor, SampleFormat, Tag, Type,
|
CompressionMethod, PhotometricInterpretation, Predictor, SampleFormat, Tag, Type,
|
||||||
};
|
};
|
||||||
@@ -17,6 +18,7 @@ use self::stream::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub mod ifd;
|
pub mod ifd;
|
||||||
|
mod image;
|
||||||
mod stream;
|
mod stream;
|
||||||
|
|
||||||
/// Result of a decoding process
|
/// Result of a decoding process
|
||||||
@@ -233,74 +235,6 @@ impl<'a> DecodingBuffer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct StripDecodeState {
|
|
||||||
rows_per_strip: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
/// Computed values useful for tile decoding
|
|
||||||
struct TileAttributes {
|
|
||||||
image_width: usize,
|
|
||||||
image_height: usize,
|
|
||||||
samples_per_pixel: usize,
|
|
||||||
|
|
||||||
tile_width: usize,
|
|
||||||
tile_length: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TileAttributes {
|
|
||||||
fn tiles_across(&self) -> usize {
|
|
||||||
(self.image_width + self.tile_width - 1) / self.tile_width
|
|
||||||
}
|
|
||||||
fn tiles_down(&self) -> usize {
|
|
||||||
(self.image_height + self.tile_length - 1) / self.tile_length
|
|
||||||
}
|
|
||||||
fn padding_right(&self) -> usize {
|
|
||||||
self.tile_width - self.image_width % self.tile_width
|
|
||||||
}
|
|
||||||
fn padding_down(&self) -> usize {
|
|
||||||
self.tile_length - self.image_height % self.tile_length
|
|
||||||
}
|
|
||||||
fn row_samples(&self) -> usize {
|
|
||||||
self.tile_width * self.samples_per_pixel
|
|
||||||
}
|
|
||||||
fn tile_samples(&self) -> usize {
|
|
||||||
self.tile_length * self.tile_width * self.samples_per_pixel
|
|
||||||
}
|
|
||||||
fn tile_strip_samples(&self) -> usize {
|
|
||||||
(self.tile_samples() * self.tiles_across())
|
|
||||||
- (self.padding_right() * self.tile_length * self.samples_per_pixel)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the tile offset in the result buffer, counted in samples
|
|
||||||
fn get_offset(&self, tile: usize) -> usize {
|
|
||||||
let row = tile / self.tiles_across();
|
|
||||||
let column = tile % self.tiles_across();
|
|
||||||
|
|
||||||
(row * self.tile_strip_samples()) + (column * self.row_samples())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_padding(&self, tile: usize) -> (usize, usize) {
|
|
||||||
let row = tile / self.tiles_across();
|
|
||||||
let column = tile % self.tiles_across();
|
|
||||||
|
|
||||||
let padding_right = if column == self.tiles_across() - 1 {
|
|
||||||
self.padding_right()
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
let padding_down = if row == self.tiles_down() - 1 {
|
|
||||||
self.padding_down()
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
(padding_right, padding_down)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
/// Chunk type of the internal representation
|
/// Chunk type of the internal representation
|
||||||
pub enum ChunkType {
|
pub enum ChunkType {
|
||||||
@@ -369,23 +303,9 @@ where
|
|||||||
bigtiff: bool,
|
bigtiff: bool,
|
||||||
limits: Limits,
|
limits: Limits,
|
||||||
next_ifd: Option<u64>,
|
next_ifd: Option<u64>,
|
||||||
ifd: Option<Directory>,
|
|
||||||
width: u32,
|
|
||||||
height: u32,
|
|
||||||
bits_per_sample: Vec<u8>,
|
|
||||||
samples: u8,
|
|
||||||
sample_format: Vec<SampleFormat>,
|
|
||||||
photometric_interpretation: PhotometricInterpretation,
|
|
||||||
compression_method: CompressionMethod,
|
|
||||||
predictor: Predictor,
|
|
||||||
jpeg_tables: Option<Vec<u8>>,
|
|
||||||
chunk_type: ChunkType,
|
|
||||||
strip_decoder: Option<StripDecodeState>,
|
|
||||||
tile_attributes: Option<TileAttributes>,
|
|
||||||
chunk_offsets: Vec<u64>,
|
|
||||||
chunk_bytes: Vec<u64>,
|
|
||||||
current_chunk: usize,
|
current_chunk: usize,
|
||||||
seen_ifds: HashSet<u64>,
|
seen_ifds: HashSet<u64>,
|
||||||
|
image: Image,
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Wrapping {
|
trait Wrapping {
|
||||||
@@ -584,6 +504,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
bigtiff,
|
bigtiff,
|
||||||
limits: Default::default(),
|
limits: Default::default(),
|
||||||
next_ifd,
|
next_ifd,
|
||||||
|
image: Image {
|
||||||
ifd: None,
|
ifd: None,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
@@ -599,6 +520,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
tile_attributes: None,
|
tile_attributes: None,
|
||||||
chunk_offsets: Vec::new(),
|
chunk_offsets: Vec::new(),
|
||||||
chunk_bytes: Vec::new(),
|
chunk_bytes: Vec::new(),
|
||||||
|
},
|
||||||
current_chunk: 0,
|
current_chunk: 0,
|
||||||
seen_ifds,
|
seen_ifds,
|
||||||
};
|
};
|
||||||
@@ -612,12 +534,12 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn dimensions(&mut self) -> TiffResult<(u32, u32)> {
|
pub fn dimensions(&mut self) -> TiffResult<(u32, u32)> {
|
||||||
Ok((self.width, self.height))
|
Ok((self.image().width, self.image().height))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn colortype(&mut self) -> TiffResult<ColorType> {
|
pub fn colortype(&mut self) -> TiffResult<ColorType> {
|
||||||
match self.photometric_interpretation {
|
match self.image().photometric_interpretation {
|
||||||
PhotometricInterpretation::RGB => match self.bits_per_sample[..] {
|
PhotometricInterpretation::RGB => match self.image().bits_per_sample[..] {
|
||||||
[r, g, b] if [r, r] == [g, b] => Ok(ColorType::RGB(r)),
|
[r, g, b] if [r, r] == [g, b] => Ok(ColorType::RGB(r)),
|
||||||
[r, g, b, a] if [r, r, r] == [g, b, a] => Ok(ColorType::RGBA(r)),
|
[r, g, b, a] if [r, r, r] == [g, b, a] => Ok(ColorType::RGBA(r)),
|
||||||
// FIXME: We should _ignore_ other components. In particular:
|
// FIXME: We should _ignore_ other components. In particular:
|
||||||
@@ -627,36 +549,40 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
// > -- TIFF 6.0 Specification, Section 7, Additional Baseline requirements.
|
// > -- TIFF 6.0 Specification, Section 7, Additional Baseline requirements.
|
||||||
_ => Err(TiffError::UnsupportedError(
|
_ => Err(TiffError::UnsupportedError(
|
||||||
TiffUnsupportedError::InterpretationWithBits(
|
TiffUnsupportedError::InterpretationWithBits(
|
||||||
self.photometric_interpretation,
|
self.image().photometric_interpretation,
|
||||||
self.bits_per_sample.clone(),
|
self.image().bits_per_sample.clone(),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
PhotometricInterpretation::CMYK => match self.bits_per_sample[..] {
|
PhotometricInterpretation::CMYK => match self.image().bits_per_sample[..] {
|
||||||
[c, m, y, k] if [c, c, c] == [m, y, k] => Ok(ColorType::CMYK(c)),
|
[c, m, y, k] if [c, c, c] == [m, y, k] => Ok(ColorType::CMYK(c)),
|
||||||
_ => Err(TiffError::UnsupportedError(
|
_ => Err(TiffError::UnsupportedError(
|
||||||
TiffUnsupportedError::InterpretationWithBits(
|
TiffUnsupportedError::InterpretationWithBits(
|
||||||
self.photometric_interpretation,
|
self.image().photometric_interpretation,
|
||||||
self.bits_per_sample.clone(),
|
self.image().bits_per_sample.clone(),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
PhotometricInterpretation::BlackIsZero | PhotometricInterpretation::WhiteIsZero
|
PhotometricInterpretation::BlackIsZero | PhotometricInterpretation::WhiteIsZero
|
||||||
if self.bits_per_sample.len() == 1 =>
|
if self.image().bits_per_sample.len() == 1 =>
|
||||||
{
|
{
|
||||||
Ok(ColorType::Gray(self.bits_per_sample[0]))
|
Ok(ColorType::Gray(self.image().bits_per_sample[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this is bad we should not fail at this point
|
// TODO: this is bad we should not fail at this point
|
||||||
_ => Err(TiffError::UnsupportedError(
|
_ => Err(TiffError::UnsupportedError(
|
||||||
TiffUnsupportedError::InterpretationWithBits(
|
TiffUnsupportedError::InterpretationWithBits(
|
||||||
self.photometric_interpretation,
|
self.image().photometric_interpretation,
|
||||||
self.bits_per_sample.clone(),
|
self.image().bits_per_sample.clone(),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn image(&self) -> &Image {
|
||||||
|
&self.image
|
||||||
|
}
|
||||||
|
|
||||||
/// Reset the decoder.
|
/// Reset the decoder.
|
||||||
#[deprecated = "Never should have been public. Only use Decoder::new()"]
|
#[deprecated = "Never should have been public. Only use Decoder::new()"]
|
||||||
pub fn init(self) -> TiffResult<Decoder<R>> {
|
pub fn init(self) -> TiffResult<Decoder<R>> {
|
||||||
@@ -668,30 +594,32 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
/// If there is no further image in the TIFF file a format error is returned.
|
/// If there is no further image in the TIFF file a format error is returned.
|
||||||
/// To determine whether there are more images call `TIFFDecoder::more_images` instead.
|
/// To determine whether there are more images call `TIFFDecoder::more_images` instead.
|
||||||
pub fn next_image(&mut self) -> TiffResult<()> {
|
pub fn next_image(&mut self) -> TiffResult<()> {
|
||||||
self.ifd = Some(self.read_ifd()?);
|
|
||||||
self.width = self.get_tag_u32(Tag::ImageWidth)?;
|
|
||||||
self.height = self.get_tag_u32(Tag::ImageLength)?;
|
|
||||||
self.strip_decoder = None;
|
|
||||||
self.tile_attributes = None;
|
|
||||||
self.chunk_offsets.clear();
|
|
||||||
self.chunk_bytes.clear();
|
|
||||||
self.current_chunk = 0;
|
self.current_chunk = 0;
|
||||||
|
|
||||||
self.photometric_interpretation = self
|
self.image.ifd = Some(self.read_ifd()?);
|
||||||
|
self.image.width = self.get_tag_u32(Tag::ImageWidth)?;
|
||||||
|
self.image.height = self.get_tag_u32(Tag::ImageLength)?;
|
||||||
|
self.image.strip_decoder = None;
|
||||||
|
self.image.tile_attributes = None;
|
||||||
|
self.image.chunk_offsets.clear();
|
||||||
|
self.image.chunk_bytes.clear();
|
||||||
|
self.image.jpeg_tables = None;
|
||||||
|
|
||||||
|
self.image.photometric_interpretation = self
|
||||||
.find_tag_unsigned(Tag::PhotometricInterpretation)?
|
.find_tag_unsigned(Tag::PhotometricInterpretation)?
|
||||||
.and_then(PhotometricInterpretation::from_u16)
|
.and_then(PhotometricInterpretation::from_u16)
|
||||||
.ok_or(TiffUnsupportedError::UnknownInterpretation)?;
|
.ok_or(TiffUnsupportedError::UnknownInterpretation)?;
|
||||||
|
|
||||||
// Try to parse both the compression method and the number, format, and bits of the included samples.
|
// Try to parse both the compression method and the number, format, and bits of the included samples.
|
||||||
// If they are not explicitly specified, those tags are reset to their default values and not carried from previous images.
|
// If they are not explicitly specified, those tags are reset to their default values and not carried from previous images.
|
||||||
self.compression_method = match self.find_tag_unsigned(Tag::Compression)? {
|
self.image.compression_method = match self.find_tag_unsigned(Tag::Compression)? {
|
||||||
Some(val) => CompressionMethod::from_u16(val)
|
Some(val) => CompressionMethod::from_u16(val)
|
||||||
.ok_or(TiffUnsupportedError::UnknownCompressionMethod)?,
|
.ok_or(TiffUnsupportedError::UnknownCompressionMethod)?,
|
||||||
None => CompressionMethod::None,
|
None => CompressionMethod::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.compression_method == CompressionMethod::ModernJPEG {
|
if self.image.compression_method == CompressionMethod::ModernJPEG {
|
||||||
self.jpeg_tables = self
|
self.image.jpeg_tables = self
|
||||||
.find_tag(Tag::JPEGTables)?
|
.find_tag(Tag::JPEGTables)?
|
||||||
.map(|_| {
|
.map(|_| {
|
||||||
let vec = self.get_tag_u8_vec(Tag::JPEGTables)?;
|
let vec = self.get_tag_u8_vec(Tag::JPEGTables)?;
|
||||||
@@ -705,9 +633,9 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
.transpose()?;
|
.transpose()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.samples = self.find_tag_unsigned(Tag::SamplesPerPixel)?.unwrap_or(1);
|
self.image.samples = self.find_tag_unsigned(Tag::SamplesPerPixel)?.unwrap_or(1);
|
||||||
|
|
||||||
self.sample_format = match self.find_tag_unsigned_vec(Tag::SampleFormat)? {
|
self.image.sample_format = match self.find_tag_unsigned_vec(Tag::SampleFormat)? {
|
||||||
Some(vals) => {
|
Some(vals) => {
|
||||||
let sample_format: Vec<_> = vals
|
let sample_format: Vec<_> = vals
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -717,7 +645,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
// TODO: for now, only homogenous formats across samples are supported.
|
// TODO: for now, only homogenous formats across samples are supported.
|
||||||
if !sample_format.windows(2).all(|s| s[0] == s[1]) {
|
if !sample_format.windows(2).all(|s| s[0] == s[1]) {
|
||||||
return Err(TiffUnsupportedError::UnsupportedSampleFormat(
|
return Err(TiffUnsupportedError::UnsupportedSampleFormat(
|
||||||
self.sample_format.clone(),
|
self.image.sample_format.clone(),
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
@@ -727,14 +655,14 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
None => vec![SampleFormat::Uint],
|
None => vec![SampleFormat::Uint],
|
||||||
};
|
};
|
||||||
|
|
||||||
self.bits_per_sample = match self.samples {
|
self.image.bits_per_sample = match self.image.samples {
|
||||||
1 | 3 | 4 => self
|
1 | 3 | 4 => self
|
||||||
.find_tag_unsigned_vec(Tag::BitsPerSample)?
|
.find_tag_unsigned_vec(Tag::BitsPerSample)?
|
||||||
.unwrap_or_else(|| vec![1]),
|
.unwrap_or_else(|| vec![1]),
|
||||||
_ => return Err(TiffUnsupportedError::UnsupportedSampleDepth(self.samples).into()),
|
_ => return Err(TiffUnsupportedError::UnsupportedSampleDepth(self.image.samples).into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.predictor = self
|
self.image.predictor = self
|
||||||
.find_tag_unsigned(Tag::Predictor)?
|
.find_tag_unsigned(Tag::Predictor)?
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
Predictor::from_u16(p)
|
Predictor::from_u16(p)
|
||||||
@@ -743,7 +671,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
.transpose()?
|
.transpose()?
|
||||||
.unwrap_or(Predictor::None);
|
.unwrap_or(Predictor::None);
|
||||||
|
|
||||||
let ifd = self.ifd.as_ref().unwrap();
|
let ifd = self.image.ifd.as_ref().unwrap();
|
||||||
match (
|
match (
|
||||||
ifd.contains_key(&Tag::StripByteCounts),
|
ifd.contains_key(&Tag::StripByteCounts),
|
||||||
ifd.contains_key(&Tag::StripOffsets),
|
ifd.contains_key(&Tag::StripOffsets),
|
||||||
@@ -751,18 +679,18 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
ifd.contains_key(&Tag::TileOffsets),
|
ifd.contains_key(&Tag::TileOffsets),
|
||||||
) {
|
) {
|
||||||
(true, true, false, false) => {
|
(true, true, false, false) => {
|
||||||
self.chunk_type = ChunkType::Strip;
|
self.image.chunk_type = ChunkType::Strip;
|
||||||
|
|
||||||
self.chunk_offsets = self.get_tag_u64_vec(Tag::StripOffsets)?;
|
self.image.chunk_offsets = self.get_tag_u64_vec(Tag::StripOffsets)?;
|
||||||
self.chunk_bytes = self.get_tag_u64_vec(Tag::StripByteCounts)?;
|
self.image.chunk_bytes = self.get_tag_u64_vec(Tag::StripByteCounts)?;
|
||||||
let rows_per_strip = self
|
let rows_per_strip = self
|
||||||
.find_tag(Tag::RowsPerStrip)?
|
.find_tag(Tag::RowsPerStrip)?
|
||||||
.unwrap_or(ifd::Value::Unsigned(self.height))
|
.unwrap_or(ifd::Value::Unsigned(self.image.height))
|
||||||
.into_u32()?;
|
.into_u32()?;
|
||||||
self.strip_decoder = Some(StripDecodeState { rows_per_strip });
|
self.image.strip_decoder = Some(StripDecodeState { rows_per_strip });
|
||||||
}
|
}
|
||||||
(false, false, true, true) => {
|
(false, false, true, true) => {
|
||||||
self.chunk_type = ChunkType::Tile;
|
self.image.chunk_type = ChunkType::Tile;
|
||||||
|
|
||||||
let tile_width = usize::try_from(self.get_tag_u32(Tag::TileWidth)?)?;
|
let tile_width = usize::try_from(self.get_tag_u32(Tag::TileWidth)?)?;
|
||||||
let tile_length = usize::try_from(self.get_tag_u32(Tag::TileLength)?)?;
|
let tile_length = usize::try_from(self.get_tag_u32(Tag::TileLength)?)?;
|
||||||
@@ -773,19 +701,19 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
return Err(TiffFormatError::InvalidTagValueType(Tag::TileLength).into());
|
return Err(TiffFormatError::InvalidTagValueType(Tag::TileLength).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tile_attributes = Some(TileAttributes {
|
self.image.tile_attributes = Some(TileAttributes {
|
||||||
image_width: usize::try_from(self.width)?,
|
image_width: usize::try_from(self.image.width)?,
|
||||||
image_height: usize::try_from(self.height)?,
|
image_height: usize::try_from(self.image.height)?,
|
||||||
samples_per_pixel: self.bits_per_sample.len(),
|
samples_per_pixel: self.image.bits_per_sample.len(),
|
||||||
tile_width,
|
tile_width,
|
||||||
tile_length,
|
tile_length,
|
||||||
});
|
});
|
||||||
self.chunk_offsets = self.get_tag_u64_vec(Tag::TileOffsets)?;
|
self.image.chunk_offsets = self.get_tag_u64_vec(Tag::TileOffsets)?;
|
||||||
self.chunk_bytes = self.get_tag_u64_vec(Tag::TileByteCounts)?;
|
self.image.chunk_bytes = self.get_tag_u64_vec(Tag::TileByteCounts)?;
|
||||||
|
|
||||||
let tile = self.tile_attributes.as_ref().unwrap();
|
let tile = self.image.tile_attributes.as_ref().unwrap();
|
||||||
if self.chunk_offsets.len() != self.chunk_bytes.len()
|
if self.image.chunk_offsets.len() != self.image.chunk_bytes.len()
|
||||||
|| self.chunk_offsets.len() != tile.tiles_down() * tile.tiles_across()
|
|| self.image.chunk_offsets.len() != tile.tiles_down() * tile.tiles_across()
|
||||||
{
|
{
|
||||||
return Err(TiffError::FormatError(
|
return Err(TiffError::FormatError(
|
||||||
TiffFormatError::InconsistentSizesEncountered,
|
TiffFormatError::InconsistentSizesEncountered,
|
||||||
@@ -984,7 +912,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
/// Tries to retrieve a tag.
|
/// Tries to retrieve a tag.
|
||||||
/// Return `Ok(None)` if the tag is not present.
|
/// Return `Ok(None)` if the tag is not present.
|
||||||
pub fn find_tag(&mut self, tag: Tag) -> TiffResult<Option<ifd::Value>> {
|
pub fn find_tag(&mut self, tag: Tag) -> TiffResult<Option<ifd::Value>> {
|
||||||
let entry = match self.ifd.as_ref().unwrap().get(&tag) {
|
let entry = match self.image().ifd.as_ref().unwrap().get(&tag) {
|
||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
Some(entry) => entry.clone(),
|
Some(entry) => entry.clone(),
|
||||||
};
|
};
|
||||||
@@ -1199,10 +1127,11 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
// Construct necessary reader to perform decompression.
|
// Construct necessary reader to perform decompression.
|
||||||
self.goto_offset_u64(offset)?;
|
self.goto_offset_u64(offset)?;
|
||||||
let byte_order = self.reader.byte_order;
|
let byte_order = self.reader.byte_order;
|
||||||
|
let compression_method = self.image().compression_method;
|
||||||
|
|
||||||
let reader = Self::create_reader(
|
let reader = Self::create_reader(
|
||||||
&mut self.reader,
|
&mut self.reader,
|
||||||
self.compression_method,
|
compression_method,
|
||||||
length,
|
length,
|
||||||
buffer.len(),
|
buffer.len(),
|
||||||
buffer.byte_len(),
|
buffer.byte_len(),
|
||||||
@@ -1235,7 +1164,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
|
|
||||||
Self::fix_endianness(&mut buffer, byte_order);
|
Self::fix_endianness(&mut buffer, byte_order);
|
||||||
|
|
||||||
if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
|
if self.image().photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
|
||||||
Self::invert_colors(&mut buffer, color_type);
|
Self::invert_colors(&mut buffer, color_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1255,20 +1184,22 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
let byte_len = buffer.byte_len();
|
let byte_len = buffer.byte_len();
|
||||||
let byte_order = self.reader.byte_order;
|
let byte_order = self.reader.byte_order;
|
||||||
|
|
||||||
let tile_attrs = self.tile_attributes.as_mut().unwrap();
|
let tile_attrs = self.image().tile_attributes.as_ref().unwrap();
|
||||||
let (padding_right, padding_down) = tile_attrs.get_padding(tile);
|
let (padding_right, padding_down) = tile_attrs.get_padding(tile);
|
||||||
let tile_samples = tile_attrs.tile_samples();
|
let tile_samples = tile_attrs.tile_samples();
|
||||||
let tile_length = tile_attrs.tile_length;
|
let tile_length = tile_attrs.tile_length;
|
||||||
let row_samples = tile_attrs.row_samples();
|
let row_samples = tile_attrs.row_samples();
|
||||||
let padding_right_samples = padding_right * self.bits_per_sample.len();
|
let padding_right_samples = padding_right * self.image().bits_per_sample.len();
|
||||||
|
|
||||||
self.goto_offset_u64(offset)?;
|
self.goto_offset_u64(offset)?;
|
||||||
|
|
||||||
let line_samples = output_width * self.bits_per_sample.len();
|
let line_samples = output_width * self.image().bits_per_sample.len();
|
||||||
|
let compression_method = self.image().compression_method;
|
||||||
|
let photometric_interpretation = self.image().photometric_interpretation;
|
||||||
|
|
||||||
let mut reader = Self::create_reader(
|
let mut reader = Self::create_reader(
|
||||||
&mut self.reader,
|
&mut self.reader,
|
||||||
self.compression_method,
|
compression_method,
|
||||||
compressed_length,
|
compressed_length,
|
||||||
tile_samples,
|
tile_samples,
|
||||||
byte_len,
|
byte_len,
|
||||||
@@ -1303,7 +1234,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
|
|
||||||
Self::fix_endianness(&mut buffer.subrange(row_start..row_end), byte_order);
|
Self::fix_endianness(&mut buffer.subrange(row_start..row_end), byte_order);
|
||||||
|
|
||||||
if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
|
if photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
|
||||||
Self::invert_colors(&mut buffer.subrange(row_start..row_end), color_type);
|
Self::invert_colors(&mut buffer.subrange(row_start..row_end), color_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1346,10 +1277,10 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_chunk_type(&self, expected: ChunkType) -> TiffResult<()> {
|
fn check_chunk_type(&self, expected: ChunkType) -> TiffResult<()> {
|
||||||
if expected != self.chunk_type {
|
if expected != self.image().chunk_type {
|
||||||
return Err(TiffError::UsageError(UsageError::InvalidChunkType(
|
return Err(TiffError::UsageError(UsageError::InvalidChunkType(
|
||||||
expected,
|
expected,
|
||||||
self.chunk_type,
|
self.image().chunk_type,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1358,20 +1289,20 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
|
|
||||||
/// The chunk type (Strips / Tiles) of the image
|
/// The chunk type (Strips / Tiles) of the image
|
||||||
pub fn get_chunk_type(&self) -> ChunkType {
|
pub fn get_chunk_type(&self) -> ChunkType {
|
||||||
self.chunk_type
|
self.image().chunk_type
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of strips in image
|
/// Number of strips in image
|
||||||
pub fn strip_count(&mut self) -> TiffResult<u32> {
|
pub fn strip_count(&mut self) -> TiffResult<u32> {
|
||||||
self.check_chunk_type(ChunkType::Strip)?;
|
self.check_chunk_type(ChunkType::Strip)?;
|
||||||
let rows_per_strip = self.strip_decoder.as_ref().unwrap().rows_per_strip;
|
let rows_per_strip = self.image().strip_decoder.as_ref().unwrap().rows_per_strip;
|
||||||
|
|
||||||
if rows_per_strip == 0 {
|
if rows_per_strip == 0 {
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// rows_per_strip - 1 can never fail since we know it's at least 1
|
// rows_per_strip - 1 can never fail since we know it's at least 1
|
||||||
let height = match self.height.checked_add(rows_per_strip - 1) {
|
let height = match self.image().height.checked_add(rows_per_strip - 1) {
|
||||||
Some(h) => h,
|
Some(h) => h,
|
||||||
None => return Err(TiffError::IntSizeError),
|
None => return Err(TiffError::IntSizeError),
|
||||||
};
|
};
|
||||||
@@ -1382,7 +1313,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
/// Number of tiles in image
|
/// Number of tiles in image
|
||||||
pub fn tile_count(&mut self) -> TiffResult<u32> {
|
pub fn tile_count(&mut self) -> TiffResult<u32> {
|
||||||
self.check_chunk_type(ChunkType::Tile)?;
|
self.check_chunk_type(ChunkType::Tile)?;
|
||||||
Ok(u32::try_from(self.chunk_offsets.len())?)
|
Ok(u32::try_from(self.image().chunk_offsets.len())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_jpeg(&mut self) -> TiffResult<DecodingResult> {
|
pub fn read_jpeg(&mut self) -> TiffResult<DecodingResult> {
|
||||||
@@ -1416,12 +1347,15 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
self.goto_offset(*offset)?;
|
self.goto_offset(*offset)?;
|
||||||
let length = bytes[idx];
|
let length = bytes[idx];
|
||||||
|
|
||||||
if self.jpeg_tables.is_some() && length < 2 {
|
if self.image().jpeg_tables.is_some() && length < 2 {
|
||||||
return Err(TiffError::FormatError(
|
return Err(TiffError::FormatError(
|
||||||
TiffFormatError::InvalidTagValueType(Tag::JPEGTables),
|
TiffFormatError::InvalidTagValueType(Tag::JPEGTables),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let jpeg_reader = JpegReader::new(&mut self.reader, length, &self.jpeg_tables)?;
|
// TODO: avoid this clone
|
||||||
|
let jpeg_tables = self.image().jpeg_tables.clone();
|
||||||
|
|
||||||
|
let jpeg_reader = JpegReader::new(&mut self.reader, length, &jpeg_tables)?;
|
||||||
let mut decoder = jpeg::Decoder::new(jpeg_reader);
|
let mut decoder = jpeg::Decoder::new(jpeg_reader);
|
||||||
|
|
||||||
match decoder.decode() {
|
match decoder.decode() {
|
||||||
@@ -1449,16 +1383,25 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
pub fn read_strip_to_buffer(&mut self, mut buffer: DecodingBuffer) -> TiffResult<()> {
|
pub fn read_strip_to_buffer(&mut self, mut buffer: DecodingBuffer) -> TiffResult<()> {
|
||||||
self.check_chunk_type(ChunkType::Strip)?;
|
self.check_chunk_type(ChunkType::Strip)?;
|
||||||
let index = self.current_chunk;
|
let index = self.current_chunk;
|
||||||
let offset = *self.chunk_offsets.get(index).ok_or(TiffError::FormatError(
|
let offset = *self
|
||||||
|
.image()
|
||||||
|
.chunk_offsets
|
||||||
|
.get(index)
|
||||||
|
.ok_or(TiffError::FormatError(
|
||||||
TiffFormatError::InconsistentSizesEncountered,
|
TiffFormatError::InconsistentSizesEncountered,
|
||||||
))?;
|
))?;
|
||||||
let byte_count = *self.chunk_bytes.get(index).ok_or(TiffError::FormatError(
|
let byte_count = *self
|
||||||
|
.image()
|
||||||
|
.chunk_bytes
|
||||||
|
.get(index)
|
||||||
|
.ok_or(TiffError::FormatError(
|
||||||
TiffFormatError::InconsistentSizesEncountered,
|
TiffFormatError::InconsistentSizesEncountered,
|
||||||
))?;
|
))?;
|
||||||
let rows_per_strip = usize::try_from(self.strip_decoder.as_ref().unwrap().rows_per_strip)?;
|
let rows_per_strip =
|
||||||
|
usize::try_from(self.image().strip_decoder.as_ref().unwrap().rows_per_strip)?;
|
||||||
|
|
||||||
let sized_width = usize::try_from(self.width)?;
|
let sized_width = usize::try_from(self.image().width)?;
|
||||||
let sized_height = usize::try_from(self.height)?;
|
let sized_height = usize::try_from(self.image().height)?;
|
||||||
|
|
||||||
let strip_height_without_padding = index
|
let strip_height_without_padding = index
|
||||||
.checked_mul(rows_per_strip)
|
.checked_mul(rows_per_strip)
|
||||||
@@ -1470,7 +1413,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
|
|
||||||
let buffer_size = sized_width
|
let buffer_size = sized_width
|
||||||
.checked_mul(strip_height)
|
.checked_mul(strip_height)
|
||||||
.and_then(|x| x.checked_mul(self.bits_per_sample.len()))
|
.and_then(|x| x.checked_mul(self.image().bits_per_sample.len()))
|
||||||
.ok_or(TiffError::LimitsExceeded)?;
|
.ok_or(TiffError::LimitsExceeded)?;
|
||||||
|
|
||||||
if buffer.len() < buffer_size {
|
if buffer.len() < buffer_size {
|
||||||
@@ -1482,16 +1425,13 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
self.expand_strip(buffer.subrange(0..buffer_size), offset, byte_count)?;
|
self.expand_strip(buffer.subrange(0..buffer_size), offset, byte_count)?;
|
||||||
self.current_chunk += 1;
|
self.current_chunk += 1;
|
||||||
|
|
||||||
if u32::try_from(index)? == self.strip_count()? {
|
match self.image().predictor {
|
||||||
self.strip_decoder = None;
|
|
||||||
}
|
|
||||||
match self.predictor {
|
|
||||||
Predictor::None => {}
|
Predictor::None => {}
|
||||||
Predictor::Horizontal => {
|
Predictor::Horizontal => {
|
||||||
rev_hpredict(
|
rev_hpredict(
|
||||||
buffer.copy(),
|
buffer.copy(),
|
||||||
(self.width, u32::try_from(strip_height)?),
|
(self.image().width, u32::try_from(strip_height)?),
|
||||||
usize::try_from(self.width)?,
|
usize::try_from(self.image().width)?,
|
||||||
self.colortype()?,
|
self.colortype()?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@@ -1506,15 +1446,24 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
tile: usize,
|
tile: usize,
|
||||||
output_width: usize,
|
output_width: usize,
|
||||||
) -> TiffResult<()> {
|
) -> TiffResult<()> {
|
||||||
let file_offset = *self.chunk_offsets.get(tile).ok_or(TiffError::FormatError(
|
let file_offset = *self
|
||||||
|
.image()
|
||||||
|
.chunk_offsets
|
||||||
|
.get(tile)
|
||||||
|
.ok_or(TiffError::FormatError(
|
||||||
TiffFormatError::InconsistentSizesEncountered,
|
TiffFormatError::InconsistentSizesEncountered,
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
let compressed_bytes = *self.chunk_bytes.get(tile).ok_or(TiffError::FormatError(
|
let compressed_bytes =
|
||||||
|
*self
|
||||||
|
.image()
|
||||||
|
.chunk_bytes
|
||||||
|
.get(tile)
|
||||||
|
.ok_or(TiffError::FormatError(
|
||||||
TiffFormatError::InconsistentSizesEncountered,
|
TiffFormatError::InconsistentSizesEncountered,
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
let tile_attrs = self.tile_attributes.as_ref().unwrap();
|
let tile_attrs = self.image().tile_attributes.as_ref().unwrap();
|
||||||
let tile_width = tile_attrs.tile_width;
|
let tile_width = tile_attrs.tile_width;
|
||||||
let tile_length = tile_attrs.tile_length;
|
let tile_length = tile_attrs.tile_length;
|
||||||
|
|
||||||
@@ -1528,7 +1477,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
output_width,
|
output_width,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
match self.predictor {
|
match self.image().predictor {
|
||||||
Predictor::None => {}
|
Predictor::None => {}
|
||||||
Predictor::Horizontal => {
|
Predictor::Horizontal => {
|
||||||
rev_hpredict(
|
rev_hpredict(
|
||||||
@@ -1549,14 +1498,25 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
fn result_buffer(&self, width: usize, height: usize) -> TiffResult<DecodingResult> {
|
fn result_buffer(&self, width: usize, height: usize) -> TiffResult<DecodingResult> {
|
||||||
let buffer_size = match width
|
let buffer_size = match width
|
||||||
.checked_mul(height)
|
.checked_mul(height)
|
||||||
.and_then(|x| x.checked_mul(self.bits_per_sample.len()))
|
.and_then(|x| x.checked_mul(self.image().bits_per_sample.len()))
|
||||||
{
|
{
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return Err(TiffError::LimitsExceeded),
|
None => return Err(TiffError::LimitsExceeded),
|
||||||
};
|
};
|
||||||
|
|
||||||
let max_sample_bits = self.bits_per_sample.iter().cloned().max().unwrap_or(8);
|
let max_sample_bits = self
|
||||||
match self.sample_format.first().unwrap_or(&SampleFormat::Uint) {
|
.image()
|
||||||
|
.bits_per_sample
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.max()
|
||||||
|
.unwrap_or(8);
|
||||||
|
match self
|
||||||
|
.image()
|
||||||
|
.sample_format
|
||||||
|
.first()
|
||||||
|
.unwrap_or(&SampleFormat::Uint)
|
||||||
|
{
|
||||||
SampleFormat::Uint => match max_sample_bits {
|
SampleFormat::Uint => match max_sample_bits {
|
||||||
n if n <= 8 => DecodingResult::new_u8(buffer_size, &self.limits),
|
n if n <= 8 => DecodingResult::new_u8(buffer_size, &self.limits),
|
||||||
n if n <= 16 => DecodingResult::new_u16(buffer_size, &self.limits),
|
n if n <= 16 => DecodingResult::new_u16(buffer_size, &self.limits),
|
||||||
@@ -1593,14 +1553,15 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
self.check_chunk_type(ChunkType::Strip)?;
|
self.check_chunk_type(ChunkType::Strip)?;
|
||||||
let index = self.current_chunk;
|
let index = self.current_chunk;
|
||||||
|
|
||||||
let rows_per_strip = usize::try_from(self.strip_decoder.as_ref().unwrap().rows_per_strip)?;
|
let rows_per_strip =
|
||||||
|
usize::try_from(self.image().strip_decoder.as_ref().unwrap().rows_per_strip)?;
|
||||||
|
|
||||||
let strip_height = cmp::min(
|
let strip_height = cmp::min(
|
||||||
rows_per_strip,
|
rows_per_strip,
|
||||||
usize::try_from(self.height)? - index * rows_per_strip,
|
usize::try_from(self.image().height)? - index * rows_per_strip,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut result = self.result_buffer(usize::try_from(self.width)?, strip_height)?;
|
let mut result = self.result_buffer(usize::try_from(self.image().width)?, strip_height)?;
|
||||||
self.read_strip_to_buffer(result.as_buffer(0))?;
|
self.read_strip_to_buffer(result.as_buffer(0))?;
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
@@ -1612,7 +1573,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
|
|
||||||
let tile = self.current_chunk;
|
let tile = self.current_chunk;
|
||||||
|
|
||||||
let tile_attrs = self.tile_attributes.as_ref().unwrap();
|
let tile_attrs = self.image().tile_attributes.as_ref().unwrap();
|
||||||
let (padding_right, padding_down) = tile_attrs.get_padding(tile);
|
let (padding_right, padding_down) = tile_attrs.get_padding(tile);
|
||||||
|
|
||||||
let tile_width = tile_attrs.tile_width - padding_right;
|
let tile_width = tile_attrs.tile_width - padding_right;
|
||||||
@@ -1628,11 +1589,16 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_tiled_image(&mut self) -> TiffResult<DecodingResult> {
|
fn read_tiled_image(&mut self) -> TiffResult<DecodingResult> {
|
||||||
let width = usize::try_from(self.width)?;
|
let width = usize::try_from(self.image().width)?;
|
||||||
let mut result = self.result_buffer(width, usize::try_from(self.height)?)?;
|
let mut result = self.result_buffer(width, usize::try_from(self.image().height)?)?;
|
||||||
|
|
||||||
for tile in 0..self.chunk_offsets.len() {
|
for tile in 0..self.image().chunk_offsets.len() {
|
||||||
let buffer_offset = self.tile_attributes.as_ref().unwrap().get_offset(tile);
|
let buffer_offset = self
|
||||||
|
.image()
|
||||||
|
.tile_attributes
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.get_offset(tile);
|
||||||
self.read_tile_to_buffer(&mut result.as_buffer(buffer_offset), tile, width)?;
|
self.read_tile_to_buffer(&mut result.as_buffer(buffer_offset), tile, width)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1640,18 +1606,21 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_stripped_image(&mut self) -> TiffResult<DecodingResult> {
|
fn read_stripped_image(&mut self) -> TiffResult<DecodingResult> {
|
||||||
let rows_per_strip = usize::try_from(self.strip_decoder.as_ref().unwrap().rows_per_strip)?;
|
let rows_per_strip =
|
||||||
|
usize::try_from(self.image().strip_decoder.as_ref().unwrap().rows_per_strip)?;
|
||||||
|
|
||||||
let samples_per_strip = match usize::try_from(self.width)?
|
let samples_per_strip = match usize::try_from(self.image().width)?
|
||||||
.checked_mul(rows_per_strip)
|
.checked_mul(rows_per_strip)
|
||||||
.and_then(|x| x.checked_mul(self.bits_per_sample.len()))
|
.and_then(|x| x.checked_mul(self.image().bits_per_sample.len()))
|
||||||
{
|
{
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return Err(TiffError::LimitsExceeded),
|
None => return Err(TiffError::LimitsExceeded),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut result =
|
let mut result = self.result_buffer(
|
||||||
self.result_buffer(usize::try_from(self.width)?, usize::try_from(self.height)?)?;
|
usize::try_from(self.image().width)?,
|
||||||
|
usize::try_from(self.image().height)?,
|
||||||
|
)?;
|
||||||
|
|
||||||
for i in 0..usize::try_from(self.strip_count()?)? {
|
for i in 0..usize::try_from(self.strip_count()?)? {
|
||||||
let r = result.as_buffer(samples_per_strip * i);
|
let r = result.as_buffer(samples_per_strip * i);
|
||||||
@@ -1662,7 +1631,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
|
|
||||||
/// Decodes the entire image and return it as a Vector
|
/// Decodes the entire image and return it as a Vector
|
||||||
pub fn read_image(&mut self) -> TiffResult<DecodingResult> {
|
pub fn read_image(&mut self) -> TiffResult<DecodingResult> {
|
||||||
let result = match (self.chunk_type, self.compression_method) {
|
let result = match (self.image().chunk_type, self.image().compression_method) {
|
||||||
(_, CompressionMethod::ModernJPEG) => self.read_jpeg()?,
|
(_, CompressionMethod::ModernJPEG) => self.read_jpeg()?,
|
||||||
(ChunkType::Strip, _) => self.read_stripped_image()?,
|
(ChunkType::Strip, _) => self.read_stripped_image()?,
|
||||||
(ChunkType::Tile, _) => self.read_tiled_image()?,
|
(ChunkType::Tile, _) => self.read_tiled_image()?,
|
||||||
|
|||||||
Reference in new issue
Block a user