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