1 extern crate tiff;
2 
3 use tiff::decoder::{ifd, Decoder, DecodingResult};
4 use tiff::encoder::{colortype, SRational, TiffEncoder};
5 use tiff::tags::Tag;
6 use tiff::ColorType;
7 
8 use std::fs::File;
9 use std::io::{Cursor, Seek, SeekFrom};
10 use std::path::PathBuf;
11 
12 #[test]
encode_decode()13 fn encode_decode() {
14     let mut image_data = Vec::new();
15     for x in 0..100 {
16         for y in 0..100u8 {
17             let val = x + y;
18             image_data.push(val);
19             image_data.push(val);
20             image_data.push(val);
21         }
22     }
23     let mut file = Cursor::new(Vec::new());
24     {
25         let mut tiff = TiffEncoder::new(&mut file).unwrap();
26 
27         let mut image = tiff.new_image::<colortype::RGB8>(100, 100).unwrap();
28         image
29             .encoder()
30             .write_tag(Tag::Artist, "Image-tiff")
31             .unwrap();
32         image.write_data(&image_data).unwrap();
33     }
34     {
35         file.seek(SeekFrom::Start(0)).unwrap();
36         let mut decoder = Decoder::new(&mut file).unwrap();
37         assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8));
38         assert_eq!(decoder.dimensions().unwrap(), (100, 100));
39         assert_eq!(
40             decoder.get_tag(Tag::Artist).unwrap(),
41             ifd::Value::Ascii("Image-tiff".into())
42         );
43         if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() {
44             assert_eq!(image_data, img_res);
45         } else {
46             panic!("Wrong data type");
47         }
48     }
49 }
50 
51 #[test]
52 /// Test that attempting to encode when the input buffer is undersized returns
53 /// an error rather than panicking.
54 /// See: https://github.com/PistonDevelopers/image-tiff/issues/35
test_encode_undersized_buffer()55 fn test_encode_undersized_buffer() {
56     let input_data = vec![1, 2, 3];
57     let output = Vec::new();
58     let mut output_stream = Cursor::new(output);
59     if let Ok(mut tiff) = TiffEncoder::new(&mut output_stream) {
60         let res = tiff.write_image::<colortype::RGB8>(50, 50, &input_data);
61         assert!(res.is_err());
62     }
63 }
64 
65 const TEST_IMAGE_DIR: &str = "./tests/images/";
66 
67 macro_rules! test_roundtrip {
68     ($name:ident, $buffer:ident, $buffer_ty:ty) => {
69         fn $name<C: colortype::ColorType<Inner = $buffer_ty>>(
70             file: &str,
71             expected_type: ColorType,
72         ) {
73             let path = PathBuf::from(TEST_IMAGE_DIR).join(file);
74             let img_file = File::open(path).expect("Cannot find test image!");
75             let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
76             assert_eq!(decoder.colortype().unwrap(), expected_type);
77 
78             let image_data = match decoder.read_image().unwrap() {
79                 DecodingResult::$buffer(res) => res,
80                 _ => panic!("Wrong data type"),
81             };
82 
83             let mut file = Cursor::new(Vec::new());
84             {
85                 let mut tiff = TiffEncoder::new(&mut file).unwrap();
86 
87                 let (width, height) = decoder.dimensions().unwrap();
88                 tiff.write_image::<C>(width, height, &image_data).unwrap();
89             }
90             file.seek(SeekFrom::Start(0)).unwrap();
91             {
92                 let mut decoder = Decoder::new(&mut file).unwrap();
93                 if let DecodingResult::$buffer(img_res) = decoder.read_image().unwrap() {
94                     assert_eq!(image_data, img_res);
95                 } else {
96                     panic!("Wrong data type");
97                 }
98             }
99         }
100     };
101 }
102 
103 test_roundtrip!(test_u8_roundtrip, U8, u8);
104 test_roundtrip!(test_u16_roundtrip, U16, u16);
105 test_roundtrip!(test_u32_roundtrip, U32, u32);
106 test_roundtrip!(test_u64_roundtrip, U64, u64);
107 test_roundtrip!(test_f32_roundtrip, F32, f32);
108 test_roundtrip!(test_f64_roundtrip, F64, f64);
109 
110 #[test]
test_gray_u8_roundtrip()111 fn test_gray_u8_roundtrip() {
112     test_u8_roundtrip::<colortype::Gray8>("minisblack-1c-8b.tiff", ColorType::Gray(8));
113 }
114 
115 #[test]
test_rgb_u8_roundtrip()116 fn test_rgb_u8_roundtrip() {
117     test_u8_roundtrip::<colortype::RGB8>("rgb-3c-8b.tiff", ColorType::RGB(8));
118 }
119 
120 #[test]
test_cmyk_u8_roundtrip()121 fn test_cmyk_u8_roundtrip() {
122     test_u8_roundtrip::<colortype::CMYK8>("cmyk-3c-8b.tiff", ColorType::CMYK(8));
123 }
124 
125 #[test]
test_gray_u16_roundtrip()126 fn test_gray_u16_roundtrip() {
127     test_u16_roundtrip::<colortype::Gray16>("minisblack-1c-16b.tiff", ColorType::Gray(16));
128 }
129 
130 #[test]
test_rgb_u16_roundtrip()131 fn test_rgb_u16_roundtrip() {
132     test_u16_roundtrip::<colortype::RGB16>("rgb-3c-16b.tiff", ColorType::RGB(16));
133 }
134 
135 #[test]
test_cmyk_u16_roundtrip()136 fn test_cmyk_u16_roundtrip() {
137     test_u16_roundtrip::<colortype::CMYK16>("cmyk-3c-16b.tiff", ColorType::CMYK(16));
138 }
139 
140 #[test]
test_gray_u32_roundtrip()141 fn test_gray_u32_roundtrip() {
142     test_u32_roundtrip::<colortype::Gray32>("gradient-1c-32b.tiff", ColorType::Gray(32));
143 }
144 
145 #[test]
test_rgb_u32_roundtrip()146 fn test_rgb_u32_roundtrip() {
147     test_u32_roundtrip::<colortype::RGB32>("gradient-3c-32b.tiff", ColorType::RGB(32));
148 }
149 
150 #[test]
test_gray_u64_roundtrip()151 fn test_gray_u64_roundtrip() {
152     test_u64_roundtrip::<colortype::Gray64>("gradient-1c-64b.tiff", ColorType::Gray(64));
153 }
154 
155 #[test]
test_rgb_u64_roundtrip()156 fn test_rgb_u64_roundtrip() {
157     test_u64_roundtrip::<colortype::RGB64>("gradient-3c-64b.tiff", ColorType::RGB(64));
158 }
159 
160 #[test]
test_gray_f32_roundtrip()161 fn test_gray_f32_roundtrip() {
162     test_f32_roundtrip::<colortype::Gray32Float>("gradient-1c-32b-float.tiff", ColorType::Gray(32));
163 }
164 
165 #[test]
test_rgb_f32_roundtrip()166 fn test_rgb_f32_roundtrip() {
167     test_f32_roundtrip::<colortype::RGB32Float>("gradient-3c-32b-float.tiff", ColorType::RGB(32));
168 }
169 
170 #[test]
test_cmyk_f32_roundtrip()171 fn test_cmyk_f32_roundtrip() {
172     test_f32_roundtrip::<colortype::CMYK32Float>("cmyk-3c-32b-float.tiff", ColorType::CMYK(32));
173 }
174 
175 #[test]
test_gray_f64_roundtrip()176 fn test_gray_f64_roundtrip() {
177     test_f64_roundtrip::<colortype::Gray64Float>("gradient-1c-64b-float.tiff", ColorType::Gray(64));
178 }
179 
180 trait AssertDecode {
assert_tag_u32(&mut self, tag: u16) -> u32181     fn assert_tag_u32(&mut self, tag: u16) -> u32;
assert_tag_u32_vec(&mut self, tag: u16) -> Vec<u32>182     fn assert_tag_u32_vec(&mut self, tag: u16) -> Vec<u32>;
assert_tag_i32(&mut self, tag: u16) -> i32183     fn assert_tag_i32(&mut self, tag: u16) -> i32;
assert_tag_i32_vec(&mut self, tag: u16) -> Vec<i32>184     fn assert_tag_i32_vec(&mut self, tag: u16) -> Vec<i32>;
185 }
186 
187 impl<R: std::io::Read + std::io::Seek> AssertDecode for Decoder<R> {
assert_tag_u32(&mut self, tag: u16) -> u32188     fn assert_tag_u32(&mut self, tag: u16) -> u32 {
189         self.get_tag(Tag::Unknown(tag)).unwrap().into_u32().unwrap()
190     }
assert_tag_u32_vec(&mut self, tag: u16) -> Vec<u32>191     fn assert_tag_u32_vec(&mut self, tag: u16) -> Vec<u32> {
192         self.get_tag(Tag::Unknown(tag))
193             .unwrap()
194             .into_u32_vec()
195             .unwrap()
196     }
assert_tag_i32(&mut self, tag: u16) -> i32197     fn assert_tag_i32(&mut self, tag: u16) -> i32 {
198         self.get_tag(Tag::Unknown(tag)).unwrap().into_i32().unwrap()
199     }
assert_tag_i32_vec(&mut self, tag: u16) -> Vec<i32>200     fn assert_tag_i32_vec(&mut self, tag: u16) -> Vec<i32> {
201         self.get_tag(Tag::Unknown(tag))
202             .unwrap()
203             .into_i32_vec()
204             .unwrap()
205     }
206 }
207 
208 #[test]
test_multiple_byte()209 fn test_multiple_byte() {
210     let mut data = Cursor::new(Vec::new());
211 
212     {
213         let mut tiff = TiffEncoder::new(&mut data).unwrap();
214         let mut image_encoder = tiff.new_image::<colortype::Gray8>(1, 1).unwrap();
215         let encoder = image_encoder.encoder();
216 
217         encoder.write_tag(Tag::Unknown(65000), &[1_u8][..]).unwrap();
218         encoder
219             .write_tag(Tag::Unknown(65001), &[1_u8, 2][..])
220             .unwrap();
221         encoder
222             .write_tag(Tag::Unknown(65002), &[1_u8, 2, 3][..])
223             .unwrap();
224         encoder
225             .write_tag(Tag::Unknown(65003), &[1_u8, 2, 3, 4][..])
226             .unwrap();
227         encoder
228             .write_tag(Tag::Unknown(65004), &[1_u8, 2, 3, 4, 5][..])
229             .unwrap();
230     }
231 
232     data.set_position(0);
233     {
234         let mut decoder = Decoder::new(&mut data).unwrap();
235 
236         assert_eq!(decoder.assert_tag_u32_vec(65000), [1]);
237         assert_eq!(decoder.assert_tag_u32_vec(65001), [1, 2]);
238         assert_eq!(decoder.assert_tag_u32_vec(65002), [1, 2, 3]);
239         assert_eq!(decoder.assert_tag_u32_vec(65003), [1, 2, 3, 4]);
240         assert_eq!(decoder.assert_tag_u32_vec(65004), [1, 2, 3, 4, 5]);
241     }
242 }
243 
244 #[test]
245 /// Test writing signed tags from TIFF 6.0
test_signed()246 fn test_signed() {
247     let mut data = Cursor::new(Vec::new());
248     fn make_srational(i: i32) -> SRational {
249         SRational { n: i, d: 100 }
250     }
251 
252     {
253         let mut tiff = TiffEncoder::new(&mut data).unwrap();
254         let mut image_encoder = tiff.new_image::<colortype::Gray8>(1, 1).unwrap();
255         let encoder = image_encoder.encoder();
256 
257         //Use the "reusable" tags section as per the TIFF6 spec
258         encoder.write_tag(Tag::Unknown(65000), -1_i8).unwrap();
259         encoder
260             .write_tag(Tag::Unknown(65001), &[-1_i8][..])
261             .unwrap();
262         encoder
263             .write_tag(Tag::Unknown(65002), &[-1_i8, 2][..])
264             .unwrap();
265         encoder
266             .write_tag(Tag::Unknown(65003), &[-1_i8, 2, -3][..])
267             .unwrap();
268         encoder
269             .write_tag(Tag::Unknown(65004), &[-1_i8, 2, -3, 4][..])
270             .unwrap();
271         encoder
272             .write_tag(Tag::Unknown(65005), &[-1_i8, 2, -3, 4, -5][..])
273             .unwrap();
274 
275         encoder.write_tag(Tag::Unknown(65010), -1_i16).unwrap();
276         encoder.write_tag(Tag::Unknown(65011), -1_i16).unwrap();
277         encoder
278             .write_tag(Tag::Unknown(65012), &[-1_i16, 2][..])
279             .unwrap();
280         encoder
281             .write_tag(Tag::Unknown(65013), &[-1_i16, 2, -3][..])
282             .unwrap();
283 
284         encoder.write_tag(Tag::Unknown(65020), -1_i32).unwrap();
285         encoder
286             .write_tag(Tag::Unknown(65021), &[-1_i32][..])
287             .unwrap();
288         encoder
289             .write_tag(Tag::Unknown(65022), &[-1_i32, 2][..])
290             .unwrap();
291 
292         encoder
293             .write_tag(Tag::Unknown(65030), make_srational(-1))
294             .unwrap();
295         encoder
296             .write_tag(
297                 Tag::Unknown(65031),
298                 &[make_srational(-1), make_srational(2)][..],
299             )
300             .unwrap();
301     }
302 
303     //Rewind the cursor for reading
304     data.set_position(0);
305     {
306         let mut decoder = Decoder::new(&mut data).unwrap();
307 
308         assert_eq!(decoder.assert_tag_i32(65000), -1);
309         assert_eq!(decoder.assert_tag_i32_vec(65001), [-1]);
310         assert_eq!(decoder.assert_tag_i32_vec(65002), [-1, 2]);
311         assert_eq!(decoder.assert_tag_i32_vec(65003), [-1, 2, -3]);
312         assert_eq!(decoder.assert_tag_i32_vec(65004), [-1, 2, -3, 4]);
313         assert_eq!(decoder.assert_tag_i32_vec(65005), [-1, 2, -3, 4, -5],);
314 
315         assert_eq!(decoder.assert_tag_i32(65010), -1);
316         assert_eq!(decoder.assert_tag_i32_vec(65011), [-1]);
317         assert_eq!(decoder.assert_tag_i32_vec(65012), [-1, 2]);
318         assert_eq!(decoder.assert_tag_i32_vec(65013), [-1, 2, -3]);
319 
320         assert_eq!(decoder.assert_tag_i32(65020), -1);
321         assert_eq!(decoder.assert_tag_i32_vec(65021), [-1]);
322         assert_eq!(decoder.assert_tag_i32_vec(65022), [-1, 2]);
323 
324         assert_eq!(decoder.assert_tag_i32_vec(65030), [-1, 100]);
325         assert_eq!(decoder.assert_tag_i32_vec(65031), [-1_i32, 100, 2, 100]);
326     }
327 }
328 
329 #[test]
330 /// check multipage image handling
test_multipage_image()331 fn test_multipage_image() {
332     let mut img_file = Cursor::new(Vec::new());
333 
334     {
335         // first create a multipage image with 2 images
336         let mut img_encoder = TiffEncoder::new(&mut img_file).unwrap();
337 
338         // write first grayscale image (2x2 16-bit)
339         let img1: Vec<u16> = [1, 2, 3, 4].to_vec();
340         img_encoder
341             .write_image::<colortype::Gray16>(2, 2, &img1[..])
342             .unwrap();
343         // write second grayscale image (3x3 8-bit)
344         let img2: Vec<u8> = [9, 8, 7, 6, 5, 4, 3, 2, 1].to_vec();
345         img_encoder
346             .write_image::<colortype::Gray8>(3, 3, &img2[..])
347             .unwrap();
348     }
349 
350     // seek to the beginning of the file, so that it can be decoded
351     img_file.seek(SeekFrom::Start(0)).unwrap();
352 
353     {
354         let mut img_decoder = Decoder::new(&mut img_file).unwrap();
355 
356         // check the dimensions of the image in the first page
357         assert_eq!(img_decoder.dimensions().unwrap(), (2, 2));
358         img_decoder.next_image().unwrap();
359         // check the dimensions of the image in the second page
360         assert_eq!(img_decoder.dimensions().unwrap(), (3, 3));
361     }
362 }
363 
364 #[test]
365 /// verify rows per strip setting
test_rows_per_strip()366 fn test_rows_per_strip() {
367     let mut file = Cursor::new(Vec::new());
368     {
369         let mut img_encoder = TiffEncoder::new(&mut file).unwrap();
370 
371         let mut image = img_encoder.new_image::<colortype::Gray8>(100, 100).unwrap();
372         assert_eq!(image.next_strip_sample_count(), 100 * 100);
373         image.rows_per_strip(2).unwrap();
374         assert_eq!(image.next_strip_sample_count(), 2 * 100);
375 
376         let img2: Vec<u8> = vec![0; 2 * 100];
377         image.write_strip(&img2[..]).unwrap();
378         assert!(image.rows_per_strip(5).is_err());
379         for i in 1..50 {
380             let img2: Vec<u8> = vec![i; 2 * 100];
381             image.write_strip(&img2[..]).unwrap();
382         }
383         assert!(image.write_strip(&img2[..]).is_err());
384         image.finish().unwrap();
385     }
386 
387     file.seek(SeekFrom::Start(0)).unwrap();
388     {
389         let mut decoder = Decoder::new(&mut file).unwrap();
390         assert_eq!(decoder.get_tag_u64(Tag::RowsPerStrip).unwrap(), 2);
391         assert_eq!(decoder.strip_count().unwrap(), 50);
392 
393         for i in 0..50 {
394             let img2 = [i; 2 * 100];
395             match decoder.read_strip().unwrap() {
396                 DecodingResult::U8(data) => assert_eq!(&img2[..], &data[..]),
397                 other => panic!("Incorrect strip type {:?}", other),
398             }
399         }
400     }
401 }
402