Merge pull request #66 from aschampion/features/32-bit

Support 32- and 64-bit integer sample grayscale and RGB(A) images
This commit is contained in:
Andrew Champion authored and GitHub committed 2019-12-19 13:19:35 +00:00
commit 57783ba43f
13 files changed
+431 -18

No files matched your search

+2
View File
@@ -122,6 +122,8 @@ pub enum Type(u16) {
SSHORT = 8, SSHORT = 8,
SLONG = 9, SLONG = 9,
SRATIONAL = 10, SRATIONAL = 10,
/// BigTIFF 64-bit unsigned integer
LONG8 = 16,
} }
} }
+97 -16
View File
@@ -19,6 +19,10 @@ pub enum DecodingResult {
U8(Vec<u8>), U8(Vec<u8>),
/// A vector of unsigned words /// A vector of unsigned words
U16(Vec<u16>), U16(Vec<u16>),
/// A vector of 32 bit unsigned ints
U32(Vec<u32>),
/// A vector of 64 bit unsigned ints
U64(Vec<u64>),
} }
impl DecodingResult { impl DecodingResult {
@@ -38,10 +42,28 @@ impl DecodingResult {
} }
} }
fn new_u32(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
if size > limits.decoding_buffer_size / 4 {
Err(TiffError::LimitsExceeded)
} else {
Ok(DecodingResult::U32(vec![0; size]))
}
}
fn new_u64(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
if size > limits.decoding_buffer_size / 8 {
Err(TiffError::LimitsExceeded)
} else {
Ok(DecodingResult::U64(vec![0; size]))
}
}
pub fn as_buffer(&mut self, start: usize) -> DecodingBuffer { pub fn as_buffer(&mut self, start: usize) -> DecodingBuffer {
match *self { match *self {
DecodingResult::U8(ref mut buf) => DecodingBuffer::U8(&mut buf[start..]), DecodingResult::U8(ref mut buf) => DecodingBuffer::U8(&mut buf[start..]),
DecodingResult::U16(ref mut buf) => DecodingBuffer::U16(&mut buf[start..]), DecodingResult::U16(ref mut buf) => DecodingBuffer::U16(&mut buf[start..]),
DecodingResult::U32(ref mut buf) => DecodingBuffer::U32(&mut buf[start..]),
DecodingResult::U64(ref mut buf) => DecodingBuffer::U64(&mut buf[start..]),
} }
} }
} }
@@ -52,6 +74,10 @@ pub enum DecodingBuffer<'a> {
U8(&'a mut [u8]), U8(&'a mut [u8]),
/// A slice of unsigned words /// A slice of unsigned words
U16(&'a mut [u16]), U16(&'a mut [u16]),
/// A slice of 32 bit unsigned ints
U32(&'a mut [u32]),
/// A slice of 64 bit unsigned ints
U64(&'a mut [u64]),
} }
impl<'a> DecodingBuffer<'a> { impl<'a> DecodingBuffer<'a> {
@@ -59,6 +85,8 @@ impl<'a> DecodingBuffer<'a> {
match *self { match *self {
DecodingBuffer::U8(ref buf) => buf.len(), DecodingBuffer::U8(ref buf) => buf.len(),
DecodingBuffer::U16(ref buf) => buf.len(), DecodingBuffer::U16(ref buf) => buf.len(),
DecodingBuffer::U32(ref buf) => buf.len(),
DecodingBuffer::U64(ref buf) => buf.len(),
} }
} }
@@ -66,6 +94,8 @@ impl<'a> DecodingBuffer<'a> {
match *self { match *self {
DecodingBuffer::U8(_) => 1, DecodingBuffer::U8(_) => 1,
DecodingBuffer::U16(_) => 2, DecodingBuffer::U16(_) => 2,
DecodingBuffer::U32(_) => 4,
DecodingBuffer::U64(_) => 8,
} }
} }
@@ -76,6 +106,8 @@ impl<'a> DecodingBuffer<'a> {
match *self { match *self {
DecodingBuffer::U8(ref mut buf) => DecodingBuffer::U8(buf), DecodingBuffer::U8(ref mut buf) => DecodingBuffer::U8(buf),
DecodingBuffer::U16(ref mut buf) => DecodingBuffer::U16(buf), DecodingBuffer::U16(ref mut buf) => DecodingBuffer::U16(buf),
DecodingBuffer::U32(ref mut buf) => DecodingBuffer::U32(buf),
DecodingBuffer::U64(ref mut buf) => DecodingBuffer::U64(buf),
} }
} }
} }
@@ -233,6 +265,18 @@ impl Wrapping for u16 {
} }
} }
impl Wrapping for u32 {
fn wrapping_add(&self, other: Self) -> Self {
u32::wrapping_add(*self, other)
}
}
impl Wrapping for u64 {
fn wrapping_add(&self, other: Self) -> Self {
u64::wrapping_add(*self, other)
}
}
fn rev_hpredict_nsamp<T>(image: &mut [T], size: (u32, u32), samples: usize) fn rev_hpredict_nsamp<T>(image: &mut [T], size: (u32, u32), samples: usize)
where where
T: Copy + Wrapping, T: Copy + Wrapping,
@@ -250,9 +294,9 @@ where
fn rev_hpredict(image: DecodingBuffer, size: (u32, u32), color_type: ColorType) -> TiffResult<()> { fn rev_hpredict(image: DecodingBuffer, size: (u32, u32), color_type: ColorType) -> TiffResult<()> {
let samples = match color_type { let samples = match color_type {
ColorType::Gray(8) | ColorType::Gray(16) => 1, ColorType::Gray(8) | ColorType::Gray(16) | ColorType::Gray(32) | ColorType::Gray(64) => 1,
ColorType::RGB(8) | ColorType::RGB(16) => 3, ColorType::RGB(8) | ColorType::RGB(16) | ColorType::RGB(32) | ColorType::RGB(64) => 3,
ColorType::RGBA(8) | ColorType::RGBA(16) | ColorType::CMYK(8) => 4, ColorType::RGBA(8) | ColorType::RGBA(16) | ColorType::RGBA(32) | ColorType::RGBA(64) | ColorType::CMYK(8) => 4,
_ => { _ => {
return Err(TiffError::UnsupportedError( return Err(TiffError::UnsupportedError(
TiffUnsupportedError::HorizontalPredictor(color_type), TiffUnsupportedError::HorizontalPredictor(color_type),
@@ -266,6 +310,12 @@ fn rev_hpredict(image: DecodingBuffer, size: (u32, u32), color_type: ColorType)
DecodingBuffer::U16(buf) => { DecodingBuffer::U16(buf) => {
rev_hpredict_nsamp(buf, size, samples); rev_hpredict_nsamp(buf, size, samples);
} }
DecodingBuffer::U32(buf) => {
rev_hpredict_nsamp(buf, size, samples);
}
DecodingBuffer::U64(buf) => {
rev_hpredict_nsamp(buf, size, samples);
}
} }
Ok(()) Ok(())
} }
@@ -301,19 +351,18 @@ impl<R: Read + Seek> Decoder<R> {
pub fn colortype(&mut self) -> TiffResult<ColorType> { pub fn colortype(&mut self) -> TiffResult<ColorType> {
match self.photometric_interpretation { match self.photometric_interpretation {
// TODO: catch also [ 8, 8, 8, _] this does not work due to a bug in rust atm PhotometricInterpretation::RGB => {
PhotometricInterpretation::RGB if self.bits_per_sample == [8, 8, 8, 8] => { match self.bits_per_sample[..] {
Ok(ColorType::RGBA(8)) [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)),
PhotometricInterpretation::RGB if self.bits_per_sample == [8, 8, 8] => { _ => Err(TiffError::UnsupportedError(
Ok(ColorType::RGB(8)) TiffUnsupportedError::InterpretationWithBits(
} self.photometric_interpretation,
PhotometricInterpretation::RGB if self.bits_per_sample == [16, 16, 16, 16] => { self.bits_per_sample.clone(),
Ok(ColorType::RGBA(16)) ),
} )),
PhotometricInterpretation::RGB if self.bits_per_sample == [16, 16, 16] => { }
Ok(ColorType::RGB(16)) },
}
PhotometricInterpretation::CMYK if self.bits_per_sample == [8, 8, 8, 8] => { PhotometricInterpretation::CMYK if self.bits_per_sample == [8, 8, 8, 8] => {
Ok(ColorType::CMYK(8)) Ok(ColorType::CMYK(8))
} }
@@ -659,6 +708,34 @@ impl<R: Read + Seek> Decoder<R> {
reader.read_u16_into(&mut buffer[..bytes / 2])?; reader.read_u16_into(&mut buffer[..bytes / 2])?;
bytes / 2 bytes / 2
} }
(ColorType::RGBA(32), DecodingBuffer::U32(ref mut buffer))
| (ColorType::RGB(32), DecodingBuffer::U32(ref mut buffer)) => {
reader.read_u32_into(&mut buffer[..bytes / 4])?;
bytes / 4
}
(ColorType::RGBA(64), DecodingBuffer::U64(ref mut buffer))
| (ColorType::RGB(64), DecodingBuffer::U64(ref mut buffer)) => {
reader.read_u64_into(&mut buffer[..bytes / 8])?;
bytes / 8
}
(ColorType::Gray(64), DecodingBuffer::U64(ref mut buffer)) => {
reader.read_u64_into(&mut buffer[..bytes / 8])?;
if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
for datum in buffer[..bytes / 8].iter_mut() {
*datum = 0xffff_ffff_ffff_ffff - *datum
}
}
bytes / 8
}
(ColorType::Gray(32), DecodingBuffer::U32(ref mut buffer)) => {
reader.read_u32_into(&mut buffer[..bytes / 4])?;
if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
for datum in buffer[..bytes / 4].iter_mut() {
*datum = 0xffff_ffff - *datum
}
}
bytes / 4
}
(ColorType::Gray(16), DecodingBuffer::U16(ref mut buffer)) => { (ColorType::Gray(16), DecodingBuffer::U16(ref mut buffer)) => {
reader.read_u16_into(&mut buffer[..bytes / 2])?; reader.read_u16_into(&mut buffer[..bytes / 2])?;
if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero { if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
@@ -806,6 +883,8 @@ impl<R: Read + Seek> Decoder<R> {
let mut result = match self.bits_per_sample.iter().cloned().max().unwrap_or(8) { let mut result = match self.bits_per_sample.iter().cloned().max().unwrap_or(8) {
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)?,
n if n <= 32 => DecodingResult::new_u32(buffer_size, &self.limits)?,
n if n <= 64 => DecodingResult::new_u64(buffer_size, &self.limits)?,
n => { n => {
return Err(TiffError::UnsupportedError( return Err(TiffError::UnsupportedError(
TiffUnsupportedError::UnsupportedBitsPerChannel(n), TiffUnsupportedError::UnsupportedBitsPerChannel(n),
@@ -834,6 +913,8 @@ impl<R: Read + Seek> Decoder<R> {
let mut result = match self.bits_per_sample.iter().cloned().max().unwrap_or(8) { let mut result = match self.bits_per_sample.iter().cloned().max().unwrap_or(8) {
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)?,
n if n <= 32 => DecodingResult::new_u32(buffer_size, &self.limits)?,
n if n <= 64 => DecodingResult::new_u64(buffer_size, &self.limits)?,
n => { n => {
return Err(TiffError::UnsupportedError( return Err(TiffError::UnsupportedError(
TiffUnsupportedError::UnsupportedBitsPerChannel(n), TiffUnsupportedError::UnsupportedBitsPerChannel(n),
+33
View File
@@ -59,6 +59,39 @@ pub trait EndianReader: Read {
} }
} }
#[inline(always)]
fn read_u32_into(&mut self, buffer: &mut [u32]) -> Result<(), io::Error> {
match self.byte_order() {
ByteOrder::LittleEndian => {
<Self as ReadBytesExt>::read_u32_into::<LittleEndian>(self, buffer)
}
ByteOrder::BigEndian => {
<Self as ReadBytesExt>::read_u32_into::<BigEndian>(self, buffer)
}
}
}
/// Reads an u64
#[inline(always)]
fn read_u64(&mut self) -> Result<u64, io::Error> {
match self.byte_order() {
ByteOrder::LittleEndian => <Self as ReadBytesExt>::read_u64::<LittleEndian>(self),
ByteOrder::BigEndian => <Self as ReadBytesExt>::read_u64::<BigEndian>(self),
}
}
#[inline(always)]
fn read_u64_into(&mut self, buffer: &mut [u64]) -> Result<(), io::Error> {
match self.byte_order() {
ByteOrder::LittleEndian => {
<Self as ReadBytesExt>::read_u64_into::<LittleEndian>(self, buffer)
}
ByteOrder::BigEndian => {
<Self as ReadBytesExt>::read_u64_into::<BigEndian>(self, buffer)
}
}
}
/// Reads an i32 /// Reads an i32
#[inline(always)] #[inline(always)]
fn read_i32(&mut self) -> Result<i32, io::Error> { fn read_i32(&mut self) -> Result<i32, io::Error> {
+42
View File
@@ -24,6 +24,20 @@ impl ColorType for Gray16 {
const BITS_PER_SAMPLE: &'static [u16] = &[16]; const BITS_PER_SAMPLE: &'static [u16] = &[16];
} }
pub struct Gray32;
impl ColorType for Gray32 {
type Inner = u32;
const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::BlackIsZero;
const BITS_PER_SAMPLE: &'static [u16] = &[32];
}
pub struct Gray64;
impl ColorType for Gray64 {
type Inner = u64;
const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::BlackIsZero;
const BITS_PER_SAMPLE: &'static [u16] = &[64];
}
pub struct RGB8; pub struct RGB8;
impl ColorType for RGB8 { impl ColorType for RGB8 {
type Inner = u8; type Inner = u8;
@@ -38,6 +52,20 @@ impl ColorType for RGB16 {
const BITS_PER_SAMPLE: &'static [u16] = &[16, 16, 16]; const BITS_PER_SAMPLE: &'static [u16] = &[16, 16, 16];
} }
pub struct RGB32;
impl ColorType for RGB32 {
type Inner = u32;
const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
const BITS_PER_SAMPLE: &'static [u16] = &[32, 32, 32];
}
pub struct RGB64;
impl ColorType for RGB64 {
type Inner = u64;
const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
const BITS_PER_SAMPLE: &'static [u16] = &[64, 64, 64];
}
pub struct RGBA8; pub struct RGBA8;
impl ColorType for RGBA8 { impl ColorType for RGBA8 {
type Inner = u8; type Inner = u8;
@@ -52,6 +80,20 @@ impl ColorType for RGBA16 {
const BITS_PER_SAMPLE: &'static [u16] = &[16, 16, 16, 16]; const BITS_PER_SAMPLE: &'static [u16] = &[16, 16, 16, 16];
} }
pub struct RGBA32;
impl ColorType for RGBA32 {
type Inner = u16;
const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
const BITS_PER_SAMPLE: &'static [u16] = &[32, 32, 32, 32];
}
pub struct RGBA64;
impl ColorType for RGBA64 {
type Inner = u16;
const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
const BITS_PER_SAMPLE: &'static [u16] = &[64, 64, 64, 64];
}
pub struct CMYK8; pub struct CMYK8;
impl ColorType for CMYK8 { impl ColorType for CMYK8 {
type Inner = u8; type Inner = u8;
+31
View File
@@ -142,6 +142,23 @@ impl TiffValue for [i32] {
} }
} }
impl TiffValue for [u64] {
const BYTE_LEN: u32 = 8;
const FIELD_TYPE: ifd::Type = ifd::Type::LONG8;
fn count(&self) -> u32 {
self.len() as u32
}
fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
// We write using nativeedian so this sould be safe
let slice =
unsafe { ::std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len() * 8) };
writer.write_bytes(slice)?;
Ok(())
}
}
impl TiffValue for [Rational] { impl TiffValue for [Rational] {
const BYTE_LEN: u32 = 8; const BYTE_LEN: u32 = 8;
const FIELD_TYPE: ifd::Type = ifd::Type::RATIONAL; const FIELD_TYPE: ifd::Type = ifd::Type::RATIONAL;
@@ -258,6 +275,20 @@ impl TiffValue for i32 {
} }
} }
impl TiffValue for u64 {
const BYTE_LEN: u32 = 8;
const FIELD_TYPE: ifd::Type = ifd::Type::LONG8;
fn count(&self) -> u32 {
1
}
fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
writer.write_u64(*self)?;
Ok(())
}
}
impl TiffValue for Rational { impl TiffValue for Rational {
const BYTE_LEN: u32 = 8; const BYTE_LEN: u32 = 8;
const FIELD_TYPE: ifd::Type = ifd::Type::RATIONAL; const FIELD_TYPE: ifd::Type = ifd::Type::RATIONAL;
+102
View File
@@ -44,6 +44,18 @@ fn test_rgb_u8() {
} }
} }
#[test]
fn test_gray_u12() {
let img_file =
File::open("./tests/images/12bit.cropped.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(12));
assert!(match decoder.read_image() {
Err(tiff::TiffError::UnsupportedError(tiff::TiffUnsupportedError::UnsupportedColorType(_))) => true,
_ => false,
});
}
#[test] #[test]
fn test_gray_u16() { fn test_gray_u16() {
let img_file = let img_file =
@@ -64,6 +76,58 @@ fn test_gray_u16() {
} }
} }
#[test]
fn test_gray_u32() {
let img_file =
File::open("./tests/images/gradient-1c-32b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(32));
let img_res = decoder.read_image().unwrap();
if let DecodingResult::U32(res) = img_res {
let mut res_sum: u64 = 0;
for x in res {
res_sum += x as u64;
}
assert_eq!(res_sum, 549892913787);
}
else {
panic!("Wrong bit depth")
}
}
#[test]
fn test_gray_u64() {
let img_file =
File::open("./tests/images/gradient-1c-64b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(64));
let img_res = decoder.read_image().unwrap();
if let DecodingResult::U64(res) = img_res {
let mut res_sum: u64 = 0;
for x in res {
res_sum += x as u64;
}
assert_eq!(res_sum, 549892913787);
}
else {
panic!("Wrong bit depth")
}
}
#[test]
fn test_rgb_u12() {
let img_file =
File::open("./tests/images/12bit.cropped.rgb.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(12));
assert!(match decoder.read_image() {
Err(tiff::TiffError::UnsupportedError(tiff::TiffUnsupportedError::UnsupportedColorType(_))) => true,
_ => false,
});
}
#[test] #[test]
fn test_rgb_u16() { fn test_rgb_u16() {
let img_file = File::open("./tests/images/rgb-3c-16b.tiff").expect("Cannot find test image!"); let img_file = File::open("./tests/images/rgb-3c-16b.tiff").expect("Cannot find test image!");
@@ -83,6 +147,44 @@ fn test_rgb_u16() {
} }
} }
#[test]
fn test_rgb_u32() {
let img_file = File::open("./tests/images/gradient-3c-32b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(32));
let img_res = decoder.read_image().unwrap();
if let DecodingResult::U32(res) = img_res {
let mut res_sum: u64 = 0;
for x in res {
res_sum += x as u64;
}
assert_eq!(res_sum, 2030834111716);
}
else {
panic!("Wrong bit depth")
}
}
#[test]
fn test_rgb_u64() {
let img_file = File::open("./tests/images/gradient-3c-64b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(64));
let img_res = decoder.read_image().unwrap();
if let DecodingResult::U64(res) = img_res {
let mut res_sum: u64 = 0;
for x in res {
res_sum += x as u64;
}
assert_eq!(res_sum, 2030834111716);
}
else {
panic!("Wrong bit depth")
}
}
#[test] #[test]
fn test_string_tags() { fn test_string_tags() {
// these files have null-terminated strings for their Software tag. One has extra bytes after // these files have null-terminated strings for their Software tag. One has extra bytes after
+124 -2
View File
@@ -177,6 +177,128 @@ fn test_rgb_u16_roundtrip() {
} }
} }
#[test]
fn test_gray_u32_roundtrip() {
let img_file =
File::open("./tests/images/gradient-1c-32b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(32));
let image_data = match decoder.read_image().unwrap() {
DecodingResult::U32(res) => res,
_ => panic!("Wrong data type"),
};
let mut file = tempfile::tempfile().unwrap();
{
let mut tiff = TiffEncoder::new(&mut file).unwrap();
let (width, height) = decoder.dimensions().unwrap();
tiff.write_image::<colortype::Gray32>(width, height, &image_data)
.unwrap();
}
file.seek(SeekFrom::Start(0)).unwrap();
{
let mut decoder = Decoder::new(&mut file).unwrap();
if let DecodingResult::U32(img_res) = decoder.read_image().unwrap() {
assert_eq!(image_data, img_res);
} else {
panic!("Wrong data type");
}
}
}
#[test]
fn test_rgb_u32_roundtrip() {
let img_file = File::open("./tests/images/gradient-3c-32b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(32));
let image_data = match decoder.read_image().unwrap() {
DecodingResult::U32(res) => res,
_ => panic!("Wrong data type"),
};
let mut file = tempfile::tempfile().unwrap();
{
let mut tiff = TiffEncoder::new(&mut file).unwrap();
let (width, height) = decoder.dimensions().unwrap();
tiff.write_image::<colortype::RGB32>(width, height, &image_data)
.unwrap();
}
file.seek(SeekFrom::Start(0)).unwrap();
{
let mut decoder = Decoder::new(&mut file).unwrap();
if let DecodingResult::U32(img_res) = decoder.read_image().unwrap() {
assert_eq!(image_data, img_res);
} else {
panic!("Wrong data type");
}
}
}
#[test]
fn test_gray_u64_roundtrip() {
let img_file =
File::open("./tests/images/gradient-1c-64b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(64));
let image_data = match decoder.read_image().unwrap() {
DecodingResult::U64(res) => res,
_ => panic!("Wrong data type"),
};
let mut file = tempfile::tempfile().unwrap();
{
let mut tiff = TiffEncoder::new(&mut file).unwrap();
let (width, height) = decoder.dimensions().unwrap();
tiff.write_image::<colortype::Gray64>(width, height, &image_data)
.unwrap();
}
file.seek(SeekFrom::Start(0)).unwrap();
{
let mut decoder = Decoder::new(&mut file).unwrap();
if let DecodingResult::U64(img_res) = decoder.read_image().unwrap() {
assert_eq!(image_data, img_res);
} else {
panic!("Wrong data type");
}
}
}
#[test]
fn test_rgb_u64_roundtrip() {
let img_file = File::open("./tests/images/gradient-3c-64b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(64));
let image_data = match decoder.read_image().unwrap() {
DecodingResult::U64(res) => res,
_ => panic!("Wrong data type"),
};
let mut file = tempfile::tempfile().unwrap();
{
let mut tiff = TiffEncoder::new(&mut file).unwrap();
let (width, height) = decoder.dimensions().unwrap();
tiff.write_image::<colortype::RGB64>(width, height, &image_data)
.unwrap();
}
file.seek(SeekFrom::Start(0)).unwrap();
{
let mut decoder = Decoder::new(&mut file).unwrap();
if let DecodingResult::U64(img_res) = decoder.read_image().unwrap() {
assert_eq!(image_data, img_res);
} else {
panic!("Wrong data type");
}
}
}
#[test] #[test]
fn test_multiple_byte() { fn test_multiple_byte() {
let mut data = Cursor::new(Vec::new()); let mut data = Cursor::new(Vec::new());
@@ -273,10 +395,10 @@ fn test_multipage_image() {
// write first grayscale image (2x2 16-bit) // write first grayscale image (2x2 16-bit)
let img1: Vec<u16> = [1, 2, 3, 4].to_vec(); let img1: Vec<u16> = [1, 2, 3, 4].to_vec();
img_encoder.write_image::<colortype::Gray16>(2, 2, &img1[..]); img_encoder.write_image::<colortype::Gray16>(2, 2, &img1[..]).unwrap();
// write second grayscale image (3x3 8-bit) // write second grayscale image (3x3 8-bit)
let img2: Vec<u8> = [9, 8, 7, 6, 5, 4, 3, 2, 1].to_vec(); let img2: Vec<u8> = [9, 8, 7, 6, 5, 4, 3, 2, 1].to_vec();
img_encoder.write_image::<colortype::Gray8>(3, 3, &img2[..]); img_encoder.write_image::<colortype::Gray8>(3, 3, &img2[..]).unwrap();
} }
// seek to the beginning of the file, so that it can be decoded // seek to the beginning of the file, so that it can be decoded
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.