Merge branch 'master' of github.com:Farkal/image-tiff into features/32-bit-float-samples

This commit is contained in:
Etienne Prothon committed 2020-08-04 16:43:01 +02:00
commit 5f48444fa0
11 files changed
+77 -29

No files matched your search

+9
View File
@@ -1,3 +1,12 @@
# Version 0.5.0
* Added support for 32-bit and 64-bit decoded values.
* Added CMYK(16|32|64) color type support.
* Check many internal integer conversions to increase stability. This should
only lead to images being reported as faulty that would previously silently
break platform limits. If there are any false positives, please report them.
* Remove an erroneous check of decoded length in lzw compressed images.
# Version 0.4.0 # Version 0.4.0
* Several enumerations are now non_exhaustive for future extensions. * Several enumerations are now non_exhaustive for future extensions.
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "tiff" name = "tiff"
version = "0.4.0" version = "0.5.0"
authors = [ authors = [
"ccgn", "ccgn",
"bvssvni <bvssvni@gmail.com>", "bvssvni <bvssvni@gmail.com>",
+8
View File
@@ -198,10 +198,18 @@ impl Entry {
if n > limits.decoding_buffer_size { if n > limits.decoding_buffer_size {
return Err(TiffError::LimitsExceeded); return Err(TiffError::LimitsExceeded);
} }
if n <= 4 {
let mut buf = vec![0; n];
self.r(bo).read_exact(&mut buf )?;
let v = String::from_utf8(buf)?;
let v = v.trim_matches(char::from(0));
Ok(Ascii(v.into()))
} else {
decoder.goto_offset(self.r(bo).read_u32()?)?; decoder.goto_offset(self.r(bo).read_u32()?)?;
let string = decoder.read_string(n)?; let string = decoder.read_string(n)?;
Ok(Ascii(string)) Ok(Ascii(string))
} }
}
_ => Err(TiffError::UnsupportedError( _ => Err(TiffError::UnsupportedError(
TiffUnsupportedError::UnsupportedDataType, TiffUnsupportedError::UnsupportedDataType,
)), )),
+8 -6
View File
@@ -486,11 +486,13 @@ impl<R: Read + Seek> Decoder<R> {
/// Reads a string /// Reads a string
#[inline] #[inline]
pub fn read_string(&mut self, length: usize) -> TiffResult<String> { pub fn read_string(&mut self, length: usize) -> TiffResult<String> {
let mut out = String::with_capacity(length); let mut out = vec![0; length];
self.reader.read_to_string(&mut out)?; self.reader.read_exact(&mut out)?;
// Strings may be null-terminated, so we trim anything downstream of the null byte // Strings may be null-terminated, so we trim anything downstream of the null byte
let trimmed = out.bytes().take_while(|&n| n != 0).collect::<Vec<u8>>(); if let Some(first) = out.iter().position(|&b| b == 0) {
Ok(String::from_utf8(trimmed)?) out.truncate(first);
}
Ok(String::from_utf8(out)?)
} }
/// Reads a TIFF IFA offset/value field /// Reads a TIFF IFA offset/value field
@@ -646,7 +648,7 @@ impl<R: Read + Seek> Decoder<R> {
let (bytes, reader) = LZWReader::new( let (bytes, reader) = LZWReader::new(
&mut self.reader, &mut self.reader,
usize::try_from(length)?, usize::try_from(length)?,
max_uncompressed_length max_uncompressed_length * buffer.byte_len()
)?; )?;
(bytes, Box::new(reader)) (bytes, Box::new(reader))
} }
@@ -838,7 +840,7 @@ impl<R: Read + Seek> Decoder<R> {
let buffer_size = usize::try_from(self.width)? * strip_height * self.bits_per_sample.len(); let buffer_size = usize::try_from(self.width)? * strip_height * self.bits_per_sample.len();
if buffer.len() < buffer_size || usize::try_from(byte_count)? / buffer.byte_len() > buffer_size { if buffer.len() < buffer_size {
return Err(TiffError::FormatError( return Err(TiffError::FormatError(
TiffFormatError::InconsistentSizesEncountered, TiffFormatError::InconsistentSizesEncountered,
)); ));
+33 -19
View File
@@ -469,26 +469,9 @@ impl<W: Write + Seek> TiffEncoder<W> {
where where
[C::Inner]: TiffValue, [C::Inner]: TiffValue,
{ {
let num_pix = usize::try_from(width)?.checked_mul(usize::try_from(height)?)
.ok_or_else(|| ::std::io::Error::new(
::std::io::ErrorKind::InvalidInput,
"Image width * height exceeds usize"))?;
if data.len() < num_pix {
return Err(::std::io::Error::new(
::std::io::ErrorKind::InvalidData,
"Input data slice is undersized for provided dimensions").into());
}
let encoder = DirectoryEncoder::new(&mut self.writer)?; let encoder = DirectoryEncoder::new(&mut self.writer)?;
let mut image: ImageEncoder<W, C> = ImageEncoder::new(encoder, width, height)?; let image: ImageEncoder<W, C> = ImageEncoder::new(encoder, width, height)?;
image.write_data(data)
let mut idx = 0;
while image.next_strip_sample_count() > 0 {
let sample_count = usize::try_from(image.next_strip_sample_count())?;
image.write_strip(&data[idx..idx + sample_count])?;
idx += sample_count;
}
image.finish()
} }
} }
@@ -610,10 +593,14 @@ impl<'a, W: Write + Seek> Drop for DirectoryEncoder<'a, W> {
/// # let mut file = std::io::Cursor::new(Vec::new()); /// # let mut file = std::io::Cursor::new(Vec::new());
/// # let image_data = vec![0; 100*100*3]; /// # let image_data = vec![0; 100*100*3];
/// use tiff::encoder::*; /// use tiff::encoder::*;
/// use tiff::tags::Tag;
/// ///
/// let mut tiff = TiffEncoder::new(&mut file).unwrap(); /// let mut tiff = TiffEncoder::new(&mut file).unwrap();
/// let mut image = tiff.new_image::<colortype::RGB8>(100, 100).unwrap(); /// let mut image = tiff.new_image::<colortype::RGB8>(100, 100).unwrap();
/// ///
/// // You can encode tags here
/// image.encoder().write_tag(Tag::Artist, "Image-tiff").unwrap();
///
/// let mut idx = 0; /// let mut idx = 0;
/// while image.next_strip_sample_count() > 0 { /// while image.next_strip_sample_count() > 0 {
/// let sample_count = image.next_strip_sample_count() as usize; /// let sample_count = image.next_strip_sample_count() as usize;
@@ -623,11 +610,13 @@ impl<'a, W: Write + Seek> Drop for DirectoryEncoder<'a, W> {
/// image.finish().unwrap(); /// image.finish().unwrap();
/// # } /// # }
/// ``` /// ```
/// You can also call write_data function wich will encode by strip and finish
pub struct ImageEncoder<'a, W: 'a + Write + Seek, C: ColorType> { pub struct ImageEncoder<'a, W: 'a + Write + Seek, C: ColorType> {
encoder: DirectoryEncoder<'a, W>, encoder: DirectoryEncoder<'a, W>,
strip_idx: u64, strip_idx: u64,
strip_count: u64, strip_count: u64,
row_samples: u64, row_samples: u64,
width: u32,
height: u32, height: u32,
rows_per_strip: u64, rows_per_strip: u64,
strip_offsets: Vec<u32>, strip_offsets: Vec<u32>,
@@ -672,6 +661,7 @@ impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> {
strip_idx: 0, strip_idx: 0,
row_samples, row_samples,
rows_per_strip, rows_per_strip,
width,
height, height,
strip_offsets: Vec::new(), strip_offsets: Vec::new(),
strip_byte_count: Vec::new(), strip_byte_count: Vec::new(),
@@ -716,6 +706,30 @@ impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> {
Ok(()) Ok(())
} }
/// Write strips from data
pub fn write_data(mut self, data: &[T::Inner]) -> TiffResult<()>
where
[T::Inner]: TiffValue,
{
let num_pix = usize::try_from(self.width)?.checked_mul(usize::try_from(self.height)?)
.ok_or_else(|| ::std::io::Error::new(
::std::io::ErrorKind::InvalidInput,
"Image width * height exceeds usize"))?;
if data.len() < num_pix {
return Err(::std::io::Error::new(
::std::io::ErrorKind::InvalidData,
"Input data slice is undersized for provided dimensions").into());
}
let mut idx = 0;
while self.next_strip_sample_count() > 0 {
let sample_count = usize::try_from(self.next_strip_sample_count())?;
self.write_strip(&data[idx..idx + sample_count])?;
idx += sample_count;
}
self.finish()?;
Ok(())
}
/// Set image resolution /// Set image resolution
pub fn resolution(&mut self, unit: ResolutionUnit, value: Rational) { pub fn resolution(&mut self, unit: ResolutionUnit, value: Rational) {
self.encoder.write_tag(Tag::ResolutionUnit, unit.to_u16()).unwrap(); self.encoder.write_tag(Tag::ResolutionUnit, unit.to_u16()).unwrap();
+1 -1
View File
@@ -4,7 +4,7 @@
//! lossless and lossy compression. //! lossless and lossy compression.
//! //!
//! # Related Links //! # Related Links
//! * <http://partners.adobe.com/public/developer/tiff/index.html> - The TIFF specification //! * <https://www.adobe.io/open/standards/TIFF.html> - The TIFF specification
extern crate byteorder; extern crate byteorder;
extern crate lzw; extern crate lzw;
+5
View File
@@ -114,6 +114,11 @@ pub enum Tag(u16) unknown("A private or extension tag") {
YResolution = 283, YResolution = 283,
// Advanced tags // Advanced tags
Predictor = 317, Predictor = 317,
TileWidth = 322,
TileLength = 323,
TileOffsets = 324,
TileByteCounts = 325,
SampleFormat = 339,
} }
} }
+6
View File
@@ -171,6 +171,12 @@ fn test_decode_data() {
} }
} }
#[test]
fn issue_69() {
test_image_sum_u16("issue_69_lzw.tiff", ColorType::Gray(16), 1015486);
test_image_sum_u16("issue_69_packbits.tiff", ColorType::Gray(16), 1015486);
}
// TODO: GrayA support // TODO: GrayA support
//#[test] //#[test]
//fn test_gray_alpha_u8() //fn test_gray_alpha_u8()
+6 -2
View File
@@ -1,6 +1,6 @@
extern crate tiff; extern crate tiff;
use tiff::decoder::{Decoder, DecodingResult}; use tiff::decoder::{Decoder, DecodingResult, ifd};
use tiff::encoder::{colortype, TiffEncoder, SRational}; use tiff::encoder::{colortype, TiffEncoder, SRational};
use tiff::ColorType; use tiff::ColorType;
use tiff::tags::Tag; use tiff::tags::Tag;
@@ -24,14 +24,18 @@ fn encode_decode() {
{ {
let mut tiff = TiffEncoder::new(&mut file).unwrap(); let mut tiff = TiffEncoder::new(&mut file).unwrap();
tiff.write_image::<colortype::RGB8>(100, 100, &image_data) let mut image = tiff.new_image::<colortype::RGB8>(100, 100)
.unwrap(); .unwrap();
image.encoder().write_tag(Tag::Artist, "Image-tiff").unwrap();
image.write_data(&image_data).unwrap();
} }
{ {
file.seek(SeekFrom::Start(0)).unwrap(); file.seek(SeekFrom::Start(0)).unwrap();
let mut decoder = Decoder::new(&mut file).unwrap(); let mut decoder = Decoder::new(&mut file).unwrap();
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8)); assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8));
assert_eq!(decoder.dimensions().unwrap(), (100, 100)); assert_eq!(decoder.dimensions().unwrap(), (100, 100));
assert_eq!(decoder.get_tag(Tag::Artist).unwrap(), ifd::Value::Ascii("Image-tiff".into()));
if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() { if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() {
assert_eq!(image_data, img_res); assert_eq!(image_data, img_res);
} else { } else {
Binary file not shown.
Binary file not shown.