1use std::io;
28use std::io::{Seek, SeekFrom, Write};
29
30use crate::endian::{Endian, BigEndian, LittleEndian};
31use crate::error::Error;
32use crate::tag::{Context, Tag};
33use crate::tiff::{Field, In, TIFF_BE_SIG, TIFF_LE_SIG};
34use crate::value::Value;
35
36#[derive(Debug)]
62pub struct Writer<'a> {
63 ifd_list: Vec<Ifd<'a>>,
64}
65
66#[derive(Debug, Default)]
67struct Ifd<'a> {
68 tiff_fields: Vec<&'a Field>,
69 exif_fields: Vec<&'a Field>,
70 gps_fields: Vec<&'a Field>,
71 interop_fields: Vec<&'a Field>,
72 strips: Option<&'a [&'a [u8]]>,
73 tiles: Option<&'a [&'a [u8]]>,
74 jpeg: Option<&'a [u8]>,
75}
76
77impl<'a> Ifd<'a> {
78 fn is_empty(&self) -> bool {
79 self.tiff_fields.is_empty() &&
80 self.exif_fields.is_empty() &&
81 self.gps_fields.is_empty() &&
82 self.interop_fields.is_empty() &&
83 self.strips.is_none() &&
84 self.tiles.is_none() &&
85 self.jpeg.is_none()
86 }
87}
88
89struct WriterState<'a> {
90 tiff_fields: Vec<&'a Field>,
91 exif_fields: Vec<&'a Field>,
92 gps_fields: Vec<&'a Field>,
93 interop_fields: Vec<&'a Field>,
94 tiff_ifd_offset: u32,
95 exif_ifd_offset: u32,
96 gps_ifd_offset: u32,
97 interop_ifd_offset: u32,
98}
99
100impl<'a> Writer<'a> {
101 pub fn new() -> Writer<'a> {
103 Writer {
104 ifd_list: Vec::new(),
105 }
106 }
107
108 pub fn push_field(&mut self, field: &'a Field) {
118 match *field {
119 Field { tag: Tag::ExifIFDPointer, .. } |
121 Field { tag: Tag::GPSInfoIFDPointer, .. } |
122 Field { tag: Tag::InteropIFDPointer, .. } => {},
123 Field { tag: Tag::StripOffsets, .. } |
125 Field { tag: Tag::StripByteCounts, .. } |
126 Field { tag: Tag::TileOffsets, .. } |
127 Field { tag: Tag::TileByteCounts, .. } => {},
128 Field { tag: Tag::JPEGInterchangeFormat, .. } |
130 Field { tag: Tag::JPEGInterchangeFormatLength, .. } => {},
131 Field { tag: Tag(ctx, _), ifd_num, .. } => {
133 let ifd = self.pick_ifd(ifd_num);
134 match ctx {
135 Context::Tiff => ifd.tiff_fields.push(field),
136 Context::Exif => ifd.exif_fields.push(field),
137 Context::Gps => ifd.gps_fields.push(field),
138 Context::Interop => ifd.interop_fields.push(field),
139 }
140 },
141 }
142 }
143
144 pub fn set_strips(&mut self, strips: &'a [&'a [u8]], ifd_num: In) {
147 self.pick_ifd(ifd_num).strips = Some(strips);
148 }
149
150 pub fn set_tiles(&mut self, tiles: &'a [&'a [u8]], ifd_num: In) {
153 self.pick_ifd(ifd_num).tiles = Some(tiles);
154 }
155
156 pub fn set_jpeg(&mut self, jpeg: &'a [u8], ifd_num: In) {
159 self.pick_ifd(ifd_num).jpeg = Some(jpeg);
160 }
161
162 pub fn write<W>(&mut self, w: &mut W, little_endian: bool)
167 -> Result<(), Error> where W: Write + Seek {
168 if little_endian {
170 w.write_all(&TIFF_LE_SIG)?;
171 LittleEndian::writeu32(w, 8)?;
172 } else {
173 w.write_all(&TIFF_BE_SIG)?;
174 BigEndian::writeu32(w, 8)?;
175 }
176
177 if self.ifd_list.is_empty() {
180 return Err(Error::InvalidFormat("At least one IFD must exist"));
181 }
182 let mut ifd_num_ck = Some(0);
183 let mut next_ifd_offset_offset = 4;
184 for ifd in &self.ifd_list {
185 if ifd.is_empty() {
188 return Err(Error::InvalidFormat("IFD must not be empty"));
189 }
190 let ifd_num =
191 ifd_num_ck.ok_or(Error::InvalidFormat("Too many IFDs"))?;
192 if ifd_num > 0 {
193 let next_ifd_offset = pad_and_get_offset(w)?;
194 let origpos = w.seek(SeekFrom::Current(0))?;
195 w.seek(SeekFrom::Start(next_ifd_offset_offset as u64))?;
196 match little_endian {
197 false => BigEndian::writeu32(w, next_ifd_offset)?,
198 true => LittleEndian::writeu32(w, next_ifd_offset)?,
199 }
200 w.seek(SeekFrom::Start(origpos))?;
201 }
202 next_ifd_offset_offset =
203 synthesize_fields(w, ifd, In(ifd_num), little_endian)?;
204 ifd_num_ck = ifd_num.checked_add(1);
205 }
206 w.flush()?;
207 Ok(())
208 }
209
210 fn pick_ifd(&mut self, ifd_num: In) -> &mut Ifd<'a> {
211 let ifd_num = ifd_num.index() as usize;
212 if self.ifd_list.len() <= ifd_num {
213 self.ifd_list.resize_with(ifd_num + 1, Default::default);
214 }
215 &mut self.ifd_list[ifd_num]
216 }
217}
218
219fn synthesize_fields<W>(w: &mut W, ifd: &Ifd, ifd_num: In,
222 little_endian: bool)
223 -> Result<u32, Error> where W: Write + Seek {
224 let exif_in_tiff;
225 let gps_in_tiff;
226 let interop_in_exif;
227 let strip_offsets;
228 let strip_byte_counts;
229 let tile_offsets;
230 let tile_byte_counts;
231 let jpeg_offset;
232 let jpeg_length;
233 let mut ws = WriterState {
234 tiff_fields: ifd.tiff_fields.clone(),
235 exif_fields: ifd.exif_fields.clone(),
236 gps_fields: ifd.gps_fields.clone(),
237 interop_fields: ifd.interop_fields.clone(),
238 tiff_ifd_offset: 0,
239 exif_ifd_offset: 0,
240 gps_ifd_offset: 0,
241 interop_ifd_offset: 0,
242 };
243
244 if let Some(strips) = ifd.strips {
245 strip_offsets = Field {
246 tag: Tag::StripOffsets,
247 ifd_num: ifd_num,
248 value: Value::Long(vec![0; strips.len()]),
249 };
250 ws.tiff_fields.push(&strip_offsets);
251 strip_byte_counts = Field {
252 tag: Tag::StripByteCounts,
253 ifd_num: ifd_num,
254 value: Value::Long(
255 strips.iter().map(|s| s.len() as u32).collect()),
256 };
257 ws.tiff_fields.push(&strip_byte_counts);
258 }
259 if let Some(tiles) = ifd.tiles {
260 tile_offsets = Field {
261 tag: Tag::TileOffsets,
262 ifd_num: ifd_num,
263 value: Value::Long(vec![0; tiles.len()]),
264 };
265 ws.tiff_fields.push(&tile_offsets);
266 tile_byte_counts = Field {
267 tag: Tag::TileByteCounts,
268 ifd_num: ifd_num,
269 value: Value::Long(
270 tiles.iter().map(|s| s.len() as u32).collect()),
271 };
272 ws.tiff_fields.push(&tile_byte_counts);
273 }
274 if let Some(jpeg) = ifd.jpeg {
275 jpeg_offset = Field {
276 tag: Tag::JPEGInterchangeFormat,
277 ifd_num: ifd_num,
278 value: Value::Long(vec![0]),
279 };
280 ws.tiff_fields.push(&jpeg_offset);
281 jpeg_length = Field {
282 tag: Tag::JPEGInterchangeFormatLength,
283 ifd_num: ifd_num,
284 value: Value::Long(vec![jpeg.len() as u32]),
285 };
286 ws.tiff_fields.push(&jpeg_length);
287 }
288
289 let interop_fields_len = ws.interop_fields.len();
290 let gps_fields_len = ws.gps_fields.len();
291 let exif_fields_len = ws.exif_fields.len() +
292 match interop_fields_len { 0 => 0, _ => 1 };
293 let tiff_fields_len = ws.tiff_fields.len() +
294 match gps_fields_len { 0 => 0, _ => 1 } +
295 match exif_fields_len { 0 => 0, _ => 1 };
296 assert_ne!(tiff_fields_len, 0);
297
298 ws.tiff_ifd_offset = reserve_ifd(w, tiff_fields_len)?;
299 if exif_fields_len > 0 {
300 ws.exif_ifd_offset = reserve_ifd(w, exif_fields_len)?;
301 exif_in_tiff = Field {
302 tag: Tag::ExifIFDPointer,
303 ifd_num: ifd_num,
304 value: Value::Long(vec![ws.exif_ifd_offset]),
305 };
306 ws.tiff_fields.push(&exif_in_tiff);
307 }
308 if gps_fields_len > 0 {
309 ws.gps_ifd_offset = reserve_ifd(w, gps_fields_len)?;
310 gps_in_tiff = Field {
311 tag: Tag::GPSInfoIFDPointer,
312 ifd_num: ifd_num,
313 value: Value::Long(vec![ws.gps_ifd_offset]),
314 };
315 ws.tiff_fields.push(&gps_in_tiff);
316 }
317 if interop_fields_len > 0 {
318 ws.interop_ifd_offset = reserve_ifd(w, interop_fields_len)?;
319 interop_in_exif = Field {
320 tag: Tag::InteropIFDPointer,
321 ifd_num: ifd_num,
322 value: Value::Long(vec![ws.interop_ifd_offset]),
323 };
324 ws.exif_fields.push(&interop_in_exif);
325 }
326
327 ws.tiff_fields.sort_by_key(|f| f.tag.number());
328 ws.exif_fields.sort_by_key(|f| f.tag.number());
329 ws.gps_fields.sort_by_key(|f| f.tag.number());
330 ws.interop_fields.sort_by_key(|f| f.tag.number());
331
332 match little_endian {
333 false => write_image::<_, BigEndian>(w, &ws, ifd),
334 true => write_image::<_, LittleEndian>(w, &ws, ifd),
335 }
336}
337
338fn write_image<W, E>(w: &mut W, ws: &WriterState, ifd: &Ifd)
340 -> Result<u32, Error> where W: Write + Seek, E: Endian {
341 let (next_ifd_offset_offset,
342 strip_offsets_offset, tile_offsets_offset, jpeg_offset) =
343 write_ifd_and_fields::<_, E>(
344 w, &ws.tiff_fields, ws.tiff_ifd_offset)?;
345 if ws.exif_fields.len() > 0 {
346 write_ifd_and_fields::<_, E>(
347 w, &ws.exif_fields, ws.exif_ifd_offset)?;
348 }
349 if ws.gps_fields.len() > 0 {
350 write_ifd_and_fields::<_, E>(
351 w, &ws.gps_fields, ws.gps_ifd_offset)?;
352 }
353 if ws.interop_fields.len() > 0 {
354 write_ifd_and_fields::<_, E>(
355 w, &ws.interop_fields, ws.interop_ifd_offset)?;
356 }
357
358 if let Some(strips) = ifd.strips {
359 let mut strip_offsets = Vec::new();
360 for strip in strips {
361 strip_offsets.push(get_offset(w)?);
362 w.write_all(strip)?;
363 }
364 let origpos = w.seek(SeekFrom::Current(0))?;
365 w.seek(SeekFrom::Start(strip_offsets_offset as u64))?;
366 for ofs in strip_offsets {
367 E::writeu32(w, ofs)?;
368 }
369 w.seek(SeekFrom::Start(origpos))?;
370 }
371 if let Some(tiles) = ifd.tiles {
372 let mut tile_offsets = Vec::new();
373 for tile in tiles {
374 tile_offsets.push(get_offset(w)?);
375 w.write_all(tile)?;
376 }
377 let origpos = w.seek(SeekFrom::Current(0))?;
378 w.seek(SeekFrom::Start(tile_offsets_offset as u64))?;
379 for ofs in tile_offsets {
380 E::writeu32(w, ofs)?;
381 }
382 w.seek(SeekFrom::Start(origpos))?;
383 }
384 if let Some(jpeg) = ifd.jpeg {
385 let offset = get_offset(w)?;
386 w.write_all(jpeg)?;
387 let origpos = w.seek(SeekFrom::Current(0))?;
388 w.seek(SeekFrom::Start(jpeg_offset as u64))?;
389 E::writeu32(w, offset)?;
390 w.seek(SeekFrom::Start(origpos))?;
391 }
392
393 Ok(next_ifd_offset_offset)
394}
395
396fn reserve_ifd<W>(w: &mut W, count: usize)
399 -> Result<u32, Error> where W: Write + Seek {
400 let ifdpos = get_offset(w)?;
401 assert!(ifdpos % 2 == 0);
402 w.seek(SeekFrom::Current(2 + count as i64 * 12 + 4))?;
405 Ok(ifdpos)
406}
407
408fn write_ifd_and_fields<W, E>(
412 w: &mut W, fields: &Vec<&Field>, ifd_offset: u32)
413 -> Result<(u32, u32, u32, u32), Error> where W: Write + Seek, E: Endian
414{
415 let mut strip_offsets_offset = 0;
416 let mut tile_offsets_offset = 0;
417 let mut jpeg_offset = 0;
418 let mut ifd = Vec::new();
419
420 E::writeu16(&mut ifd, fields.len() as u16)?;
422 for f in fields {
424 let (typ, cnt, mut valbuf) = compose_value::<E>(&f.value)?;
425 if cnt as u32 as usize != cnt {
426 return Err(Error::TooBig("Too long array"));
427 }
428 E::writeu16(&mut ifd, f.tag.number())?;
429 E::writeu16(&mut ifd, typ)?;
430 E::writeu32(&mut ifd, cnt as u32)?;
431 if valbuf.len() <= 4 {
434 valbuf.resize(4, 0);
435 ifd.write_all(&valbuf)?;
436 } else {
437 let valofs = pad_and_get_offset(w)?;
440 E::writeu32(&mut ifd, valofs)?;
441 w.write_all(&valbuf)?;
442 }
443 if f.tag == Tag::StripOffsets {
444 strip_offsets_offset = match valbuf.len() {
445 0..=4 => ifd_offset + ifd.len() as u32 - 4,
446 _ => get_offset(w)? - valbuf.len() as u32,
447 };
448 }
449 if f.tag == Tag::TileOffsets {
450 tile_offsets_offset = match valbuf.len() {
451 0..=4 => ifd_offset + ifd.len() as u32 - 4,
452 _ => get_offset(w)? - valbuf.len() as u32,
453 };
454 }
455 if f.tag == Tag::JPEGInterchangeFormat {
456 jpeg_offset = ifd_offset + ifd.len() as u32 - 4;
457 }
458 }
459 let next_ifd_offset_offset = ifd_offset + ifd.len() as u32;
461 E::writeu32(&mut ifd, 0)?;
462
463 write_at(w, &ifd, ifd_offset)?;
465
466 Ok((next_ifd_offset_offset,
467 strip_offsets_offset, tile_offsets_offset, jpeg_offset))
468}
469
470fn compose_value<E>(value: &Value)
472 -> Result<(u16, usize, Vec<u8>), Error> where E: Endian {
473 match *value {
474 Value::Byte(ref vec) =>
475 Ok((1, vec.len(), vec.clone())),
476 Value::Ascii(ref vec) => {
477 let mut buf = Vec::new();
478 for x in vec {
479 buf.extend_from_slice(x);
480 buf.push(0);
481 }
482 Ok((2, buf.len(), buf))
483 },
484 Value::Short(ref vec) => {
485 let mut buf = Vec::new();
486 for &v in vec {
487 E::writeu16(&mut buf, v)?;
488 }
489 Ok((3, vec.len(), buf))
490 },
491 Value::Long(ref vec) => {
492 let mut buf = Vec::new();
493 for &v in vec {
494 E::writeu32(&mut buf, v)?;
495 }
496 Ok((4, vec.len(), buf))
497 },
498 Value::Rational(ref vec) => {
499 let mut buf = Vec::new();
500 for v in vec {
501 E::writeu32(&mut buf, v.num)?;
502 E::writeu32(&mut buf, v.denom)?;
503 }
504 Ok((5, vec.len(), buf))
505 },
506 Value::SByte(ref vec) => {
507 let bytes = vec.iter().map(|x| *x as u8).collect();
508 Ok((6, vec.len(), bytes))
509 },
510 Value::Undefined(ref s, _) =>
511 Ok((7, s.len(), s.to_vec())),
512 Value::SShort(ref vec) => {
513 let mut buf = Vec::new();
514 for &v in vec {
515 E::writeu16(&mut buf, v as u16)?;
516 }
517 Ok((8, vec.len(), buf))
518 },
519 Value::SLong(ref vec) => {
520 let mut buf = Vec::new();
521 for &v in vec {
522 E::writeu32(&mut buf, v as u32)?;
523 }
524 Ok((9, vec.len(), buf))
525 },
526 Value::SRational(ref vec) => {
527 let mut buf = Vec::new();
528 for v in vec {
529 E::writeu32(&mut buf, v.num as u32)?;
530 E::writeu32(&mut buf, v.denom as u32)?;
531 }
532 Ok((10, vec.len(), buf))
533 },
534 Value::Float(ref vec) => {
535 let mut buf = Vec::new();
536 for &v in vec {
537 E::writeu32(&mut buf, v.to_bits())?;
538 }
539 Ok((11, vec.len(), buf))
540 },
541 Value::Double(ref vec) => {
542 let mut buf = Vec::new();
543 for &v in vec {
544 E::writeu64(&mut buf, v.to_bits())?;
545 }
546 Ok((12, vec.len(), buf))
547 },
548 Value::Unknown(_, _, _) =>
549 Err(Error::NotSupported("Cannot write unknown field types")),
550 }
551}
552
553fn write_at<W>(w: &mut W, buf: &[u8], offset: u32)
554 -> io::Result<()> where W: Write + Seek {
555 let orig = w.seek(SeekFrom::Current(0))?;
556 w.seek(SeekFrom::Start(offset as u64))?;
557 w.write_all(buf)?;
558 w.seek(SeekFrom::Start(orig))?;
559 Ok(())
560}
561
562fn pad_and_get_offset<W>(w: &mut W)
564 -> Result<u32, Error> where W: Write + Seek {
565 let mut pos = w.seek(SeekFrom::Current(0))?;
566 if pos >= (1 << 32) - 1 {
567 return Err(Error::TooBig("Offset too large"));
568 }
569 if pos % 2 != 0 {
570 w.write_all(&[0])?;
571 pos += 1;
572 }
573 Ok(pos as u32)
574}
575
576fn get_offset<W>(w: &mut W)
577 -> Result<u32, Error> where W: Write + Seek {
578 let pos = w.seek(SeekFrom::Current(0))?;
579 if pos as u32 as u64 != pos {
580 return Err(Error::TooBig("Offset too large"));
581 }
582 Ok(pos as u32)
583}
584
585#[cfg(test)]
586mod tests {
587 use std::io::Cursor;
588 use super::*;
589
590 #[test]
591 fn primary() {
592 let image_desc = Field {
593 tag: Tag::ImageDescription,
594 ifd_num: In::PRIMARY,
595 value: Value::Ascii(vec![b"Sample".to_vec()]),
596 };
597 let mut writer = Writer::new();
598 let mut buf = Cursor::new(Vec::new());
599 writer.push_field(&image_desc);
600 writer.write(&mut buf, false).unwrap();
601 let expected: &[u8] =
602 b"\x4d\x4d\x00\x2a\x00\x00\x00\x08\
603 \x00\x01\x01\x0e\x00\x02\x00\x00\x00\x07\x00\x00\x00\x1a\
604 \x00\x00\x00\x00\
605 Sample\0";
606 assert_eq!(buf.into_inner(), expected);
607 }
608
609 #[test]
610 fn primary_exif_only() {
611 let exif_ver = Field {
612 tag: Tag::ExifVersion,
613 ifd_num: In::PRIMARY,
614 value: Value::Undefined(b"0231".to_vec(), 0),
615 };
616 let mut writer = Writer::new();
617 let mut buf = Cursor::new(Vec::new());
618 writer.push_field(&exif_ver);
619 writer.write(&mut buf, false).unwrap();
620 let expected: &[u8] =
621 b"\x4d\x4d\x00\x2a\x00\x00\x00\x08\
622 \x00\x01\x87\x69\x00\x04\x00\x00\x00\x01\x00\x00\x00\x1a\
623 \x00\x00\x00\x00\
624 \x00\x01\x90\x00\x00\x07\x00\x00\x00\x040231\
625 \x00\x00\x00\x00";
626 assert_eq!(buf.into_inner(), expected);
627 }
628
629 #[test]
630 fn primary_tiff_tiled() {
631 let tiles: &[&[u8]] = &[b"TILE"];
633 let mut writer = Writer::new();
634 let mut buf = Cursor::new(Vec::new());
635 writer.set_tiles(tiles, In::PRIMARY);
636 writer.write(&mut buf, false).unwrap();
637 let expected: &[u8] =
638 b"\x4d\x4d\x00\x2a\x00\x00\x00\x08\
639 \x00\x02\x01\x44\x00\x04\x00\x00\x00\x01\x00\x00\x00\x26\
640 \x01\x45\x00\x04\x00\x00\x00\x01\x00\x00\x00\x04\
641 \x00\x00\x00\x00\
642 TILE";
643 assert_eq!(buf.into_inner(), expected);
644 }
645
646 #[test]
647 fn thumbnail_jpeg() {
648 let jpeg = b"JPEG";
650 let desc = Field {
651 tag: Tag::ImageDescription,
652 ifd_num: In::PRIMARY,
653 value: Value::Ascii(vec![b"jpg".to_vec()]),
654 };
655 let mut writer = Writer::new();
656 let mut buf = Cursor::new(Vec::new());
657 writer.push_field(&desc);
658 writer.set_jpeg(jpeg, In::THUMBNAIL);
659 writer.write(&mut buf, false).unwrap();
660 let expected: &[u8] =
661 b"\x4d\x4d\x00\x2a\x00\x00\x00\x08\
662 \x00\x01\x01\x0e\x00\x02\x00\x00\x00\x04jpg\x00\
663 \x00\x00\x00\x1a\
664 \x00\x02\x02\x01\x00\x04\x00\x00\x00\x01\x00\x00\x00\x38\
665 \x02\x02\x00\x04\x00\x00\x00\x01\x00\x00\x00\x04\
666 \x00\x00\x00\x00\
667 JPEG";
668 assert_eq!(buf.into_inner(), expected);
669 }
670
671 #[test]
672 fn thumbnail_tiff() {
673 let desc = Field {
675 tag: Tag::ImageDescription,
676 ifd_num: In::PRIMARY,
677 value: Value::Ascii(vec![b"tif".to_vec()]),
678 };
679 let strips: &[&[u8]] = &[b"STRIP"];
680 let mut writer = Writer::new();
681 let mut buf = Cursor::new(Vec::new());
682 writer.push_field(&desc);
683 writer.set_strips(strips, In::THUMBNAIL);
684 writer.write(&mut buf, false).unwrap();
685 let expected: &[u8] =
686 b"\x4d\x4d\x00\x2a\x00\x00\x00\x08\
687 \x00\x01\x01\x0e\x00\x02\x00\x00\x00\x04tif\x00\
688 \x00\x00\x00\x1a\
689 \x00\x02\x01\x11\x00\x04\x00\x00\x00\x01\x00\x00\x00\x38\
690 \x01\x17\x00\x04\x00\x00\x00\x01\x00\x00\x00\x05\
691 \x00\x00\x00\x00\
692 STRIP";
693 assert_eq!(buf.into_inner(), expected);
694 }
695
696 #[test]
697 fn primary_and_thumbnail() {
698 let image_desc = Field {
699 tag: Tag::ImageDescription,
700 ifd_num: In::PRIMARY,
701 value: Value::Ascii(vec![b"Sample".to_vec()]),
702 };
703 let exif_ver = Field {
704 tag: Tag::ExifVersion,
705 ifd_num: In::PRIMARY,
706 value: Value::Undefined(b"0231".to_vec(), 0),
707 };
708 let gps_ver = Field {
709 tag: Tag::GPSVersionID,
710 ifd_num: In::PRIMARY,
711 value: Value::Byte(vec![2, 3, 0, 0]),
712 };
713 let interop_index = Field {
714 tag: Tag::InteroperabilityIndex,
715 ifd_num: In::PRIMARY,
716 value: Value::Ascii(vec![b"ABC".to_vec()]),
717 };
718 let jpeg = b"JPEG";
719 let mut writer = Writer::new();
720 let mut buf = Cursor::new(Vec::new());
721 writer.push_field(&image_desc);
722 writer.push_field(&exif_ver);
723 writer.push_field(&gps_ver);
724 writer.push_field(&interop_index);
725 writer.set_jpeg(jpeg, In::THUMBNAIL);
726 writer.write(&mut buf, false).unwrap();
727 let expected: &[u8] =
728 b"\x4d\x4d\x00\x2a\x00\x00\x00\x08\
729 \x00\x03\x01\x0e\x00\x02\x00\x00\x00\x07\x00\x00\x00\x74\
730 \x87\x69\x00\x04\x00\x00\x00\x01\x00\x00\x00\x32\
731 \x88\x25\x00\x04\x00\x00\x00\x01\x00\x00\x00\x50\
732 \x00\x00\x00\x7c\
733 \x00\x02\x90\x00\x00\x07\x00\x00\x00\x040231\
734 \xa0\x05\x00\x04\x00\x00\x00\x01\x00\x00\x00\x62\
735 \x00\x00\x00\x00\
736 \x00\x01\x00\x00\x00\x01\x00\x00\x00\x04\x02\x03\x00\x00\
737 \x00\x00\x00\x00\
738 \x00\x01\x00\x01\x00\x02\x00\x00\x00\x04ABC\0\
739 \x00\x00\x00\x00\
740 Sample\0\0\
741 \x00\x02\x02\x01\x00\x04\x00\x00\x00\x01\x00\x00\x00\x9a\
742 \x02\x02\x00\x04\x00\x00\x00\x01\x00\x00\x00\x04\
743 \x00\x00\x00\x00\
744 JPEG";
745 assert_eq!(buf.into_inner(), expected);
746 }
747
748 #[test]
749 fn primary_thumbnail_and_2nd() {
750 let desc0 = Field {
751 tag: Tag::ImageDescription,
752 ifd_num: In::PRIMARY,
753 value: Value::Ascii(vec![b"p".to_vec()]),
754 };
755 let desc1 = Field {
756 tag: Tag::ImageDescription,
757 ifd_num: In::THUMBNAIL,
758 value: Value::Ascii(vec![b"t".to_vec()]),
759 };
760 let desc2 = Field {
761 tag: Tag::ImageDescription,
762 ifd_num: In(2),
763 value: Value::Ascii(vec![b"2".to_vec()]),
764 };
765 let mut writer = Writer::new();
766 let mut buf = Cursor::new(Vec::new());
767 writer.push_field(&desc0);
768 writer.push_field(&desc1);
769 writer.push_field(&desc2);
770 writer.write(&mut buf, false).unwrap();
771 let expected: &[u8] =
772 b"\x4d\x4d\x00\x2a\x00\x00\x00\x08\
773 \x00\x01\x01\x0e\x00\x02\x00\x00\x00\x02p\x00\x00\x00\
774 \x00\x00\x00\x1a\
775 \x00\x01\x01\x0e\x00\x02\x00\x00\x00\x02t\x00\x00\x00\
776 \x00\x00\x00\x2c\
777 \x00\x01\x01\x0e\x00\x02\x00\x00\x00\x022\x00\x00\x00\
778 \x00\x00\x00\x00";
779 assert_eq!(buf.into_inner(), expected);
780 }
781
782 #[test]
783 fn empty_file() {
784 let mut writer = Writer::new();
785 let mut buf = Cursor::new(Vec::new());
786 assert_pat!(writer.write(&mut buf, false),
787 Err(Error::InvalidFormat("At least one IFD must exist")));
788 }
789
790 #[test]
791 fn missing_primary() {
792 let jpeg = b"JPEG";
793 let mut writer = Writer::new();
794 let mut buf = Cursor::new(Vec::new());
795 writer.set_jpeg(jpeg, In::THUMBNAIL);
796 assert_pat!(writer.write(&mut buf, false),
797 Err(Error::InvalidFormat("IFD must not be empty")));
798 }
799
800 #[test]
801 fn write_twice() {
802 let image_desc = Field {
803 tag: Tag::ImageDescription,
804 ifd_num: In::PRIMARY,
805 value: Value::Ascii(vec![b"Sample".to_vec()]),
806 };
807 let mut writer = Writer::new();
808 writer.push_field(&image_desc);
809 let mut buf1 = Cursor::new(Vec::new());
810 writer.write(&mut buf1, false).unwrap();
811 let mut buf2 = Cursor::new(Vec::new());
812 writer.write(&mut buf2, false).unwrap();
813 assert_eq!(buf1.into_inner(), buf2.into_inner());
814 }
815
816 #[test]
817 fn compose_field_value() {
818 let patterns = vec![
819 (Value::Byte(vec![1, 2]),
820 (1, 2, vec![1, 2]),
821 (1, 2, vec![1, 2])),
822 (Value::Ascii(vec![b"a".to_vec(), b"b".to_vec()]),
823 (2, 4, b"a\0b\0".to_vec()),
824 (2, 4, b"a\0b\0".to_vec())),
825 (Value::Short(vec![0x0102, 0x0304]),
826 (3, 2, b"\x01\x02\x03\x04".to_vec()),
827 (3, 2, b"\x02\x01\x04\x03".to_vec())),
828 (Value::Long(vec![0x01020304, 0x05060708]),
829 (4, 2, b"\x01\x02\x03\x04\x05\x06\x07\x08".to_vec()),
830 (4, 2, b"\x04\x03\x02\x01\x08\x07\x06\x05".to_vec())),
831 (Value::Rational(vec![(1, 2).into(), (3, 4).into()]),
832 (5, 2, b"\0\0\0\x01\0\0\0\x02\0\0\0\x03\0\0\0\x04".to_vec()),
833 (5, 2, b"\x01\0\0\0\x02\0\0\0\x03\0\0\0\x04\0\0\0".to_vec())),
834 (Value::SByte(vec![-2, -128]),
835 (6, 2, b"\xfe\x80".to_vec()),
836 (6, 2, b"\xfe\x80".to_vec())),
837 (Value::Undefined(b"abc".to_vec(), 0),
838 (7, 3, b"abc".to_vec()),
839 (7, 3, b"abc".to_vec())),
840 (Value::SShort(vec![-2, -0x8000]),
841 (8, 2, b"\xff\xfe\x80\x00".to_vec()),
842 (8, 2, b"\xfe\xff\x00\x80".to_vec())),
843 (Value::SLong(vec![-2, -0x80000000]),
844 (9, 2, b"\xff\xff\xff\xfe\x80\x00\x00\x00".to_vec()),
845 (9, 2, b"\xfe\xff\xff\xff\x00\x00\x00\x80".to_vec())),
846 (Value::SRational(vec![(-1, -2).into(), (-3, -4).into()]),
847 (10, 2, b"\xff\xff\xff\xff\xff\xff\xff\xfe\
848 \xff\xff\xff\xfd\xff\xff\xff\xfc".to_vec()),
849 (10, 2, b"\xff\xff\xff\xff\xfe\xff\xff\xff\
850 \xfd\xff\xff\xff\xfc\xff\xff\xff".to_vec())),
851 (Value::Float(vec![2.5, -0.5]),
852 (11, 2, b"\x40\x20\x00\x00\xbf\x00\x00\x00".to_vec()),
853 (11, 2, b"\x00\x00\x20\x40\x00\x00\x00\xbf".to_vec())),
854 (Value::Double(vec![2.5, -0.5]),
855 (12, 2, b"\x40\x04\x00\x00\x00\x00\x00\x00\
856 \xbf\xe0\x00\x00\x00\x00\x00\x00".to_vec()),
857 (12, 2, b"\x00\x00\x00\x00\x00\x00\x04\x40\
858 \x00\x00\x00\x00\x00\x00\xe0\xbf".to_vec())),
859 ];
860 for (val, be, le) in patterns {
861 assert_eq!(compose_value::<BigEndian>(&val).unwrap(), be);
862 assert_eq!(compose_value::<LittleEndian>(&val).unwrap(), le);
863 }
864 }
865}