Merge branch 'master' of github.com:Farkal/image-tiff into features/32-bit-float-samples
This commit is contained in:
commit
5f48444fa0
11 files changed
+77
-29
No files matched your search
@@ -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
@@ -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>",
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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.
Reference in new issue
Block a user