1use binrw::{BinWrite, BinWriterExt, Endian};
7use std::io::{Seek, SeekFrom, Write};
8
9use crate::error::RawResult;
10use crate::tiff::TiffTag;
11use crate::tiff::types::{ByteOrder, TiffType};
12
13#[derive(Debug, Clone)]
15pub struct IfdEntry {
16 pub tag: u16,
18 pub typ: TiffType,
20 pub count: u32,
22 pub value_bytes: Vec<u8>,
24}
25
26#[derive(Debug, Clone, BinWrite)]
28pub struct RawIfdEntry {
29 pub tag: u16,
30 pub typ: u16,
31 pub count: u32,
32 pub value_offset: [u8; 4],
33}
34
35impl IfdEntry {
36 pub fn short(tag: TiffTag, value: u16) -> Self {
38 Self {
39 tag: tag.as_u16(),
40 typ: TiffType::Short,
41 count: 1,
42 value_bytes: value.to_le_bytes().to_vec(),
43 }
44 }
45
46 pub fn shorts(tag: TiffTag, values: &[u16]) -> Self {
48 let mut bytes = Vec::with_capacity(values.len() * 2);
49 for v in values {
50 bytes.extend_from_slice(&v.to_le_bytes());
51 }
52 Self {
53 tag: tag.as_u16(),
54 typ: TiffType::Short,
55 count: values.len() as u32,
56 value_bytes: bytes,
57 }
58 }
59
60 pub fn long(tag: TiffTag, value: u32) -> Self {
62 Self {
63 tag: tag.as_u16(),
64 typ: TiffType::Long,
65 count: 1,
66 value_bytes: value.to_le_bytes().to_vec(),
67 }
68 }
69
70 pub fn longs(tag: TiffTag, values: &[u32]) -> Self {
72 let mut bytes = Vec::with_capacity(values.len() * 4);
73 for v in values {
74 bytes.extend_from_slice(&v.to_le_bytes());
75 }
76 Self {
77 tag: tag.as_u16(),
78 typ: TiffType::Long,
79 count: values.len() as u32,
80 value_bytes: bytes,
81 }
82 }
83
84 pub fn rational(tag: TiffTag, num: u32, den: u32) -> Self {
86 let mut bytes = Vec::with_capacity(8);
87 bytes.extend_from_slice(&num.to_le_bytes());
88 bytes.extend_from_slice(&den.to_le_bytes());
89 Self {
90 tag: tag.as_u16(),
91 typ: TiffType::Rational,
92 count: 1,
93 value_bytes: bytes,
94 }
95 }
96
97 pub fn rationals(tag: TiffTag, values: &[(u32, u32)]) -> Self {
99 let mut bytes = Vec::with_capacity(values.len() * 8);
100 for (num, den) in values {
101 bytes.extend_from_slice(&num.to_le_bytes());
102 bytes.extend_from_slice(&den.to_le_bytes());
103 }
104 Self {
105 tag: tag.as_u16(),
106 typ: TiffType::Rational,
107 count: values.len() as u32,
108 value_bytes: bytes,
109 }
110 }
111
112 pub fn srational(tag: TiffTag, num: i32, den: i32) -> Self {
114 let mut bytes = Vec::with_capacity(8);
115 bytes.extend_from_slice(&num.to_le_bytes());
116 bytes.extend_from_slice(&den.to_le_bytes());
117 Self {
118 tag: tag.as_u16(),
119 typ: TiffType::SRational,
120 count: 1,
121 value_bytes: bytes,
122 }
123 }
124
125 pub fn srationals(tag: TiffTag, values: &[(i32, i32)]) -> Self {
127 let mut bytes = Vec::with_capacity(values.len() * 8);
128 for (num, den) in values {
129 bytes.extend_from_slice(&num.to_le_bytes());
130 bytes.extend_from_slice(&den.to_le_bytes());
131 }
132 Self {
133 tag: tag.as_u16(),
134 typ: TiffType::SRational,
135 count: values.len() as u32,
136 value_bytes: bytes,
137 }
138 }
139
140 pub fn ascii(tag: TiffTag, s: &str) -> Self {
142 let mut bytes = s.as_bytes().to_vec();
143 bytes.push(0); Self {
145 tag: tag.as_u16(),
146 typ: TiffType::Ascii,
147 count: bytes.len() as u32,
148 value_bytes: bytes,
149 }
150 }
151
152 pub fn bytes(tag: TiffTag, data: &[u8]) -> Self {
154 Self {
155 tag: tag.as_u16(),
156 typ: TiffType::Byte,
157 count: data.len() as u32,
158 value_bytes: data.to_vec(),
159 }
160 }
161
162 pub fn undefined(tag: TiffTag, data: &[u8]) -> Self {
164 Self {
165 tag: tag.as_u16(),
166 typ: TiffType::Undefined,
167 count: data.len() as u32,
168 value_bytes: data.to_vec(),
169 }
170 }
171
172 pub fn doubles(tag: TiffTag, values: &[f64]) -> Self {
174 let mut bytes = Vec::with_capacity(values.len() * 8);
175 for v in values {
176 bytes.extend_from_slice(&v.to_le_bytes());
177 }
178 Self {
179 tag: tag.as_u16(),
180 typ: TiffType::Double,
181 count: values.len() as u32,
182 value_bytes: bytes,
183 }
184 }
185
186 fn value_size(&self) -> usize {
188 self.value_bytes.len()
189 }
190
191 fn fits_inline(&self) -> bool {
193 self.value_size() <= 4
194 }
195}
196
197pub struct TiffWriter<W> {
199 writer: W,
200 byte_order: ByteOrder,
201 position: u64,
202}
203
204impl<W: Write + Seek> TiffWriter<W> {
205 pub fn new(writer: W, byte_order: ByteOrder) -> Self {
207 Self {
208 writer,
209 byte_order,
210 position: 0,
211 }
212 }
213
214 fn endian(&self) -> Endian {
216 match self.byte_order {
217 ByteOrder::LittleEndian => Endian::Little,
218 ByteOrder::BigEndian => Endian::Big,
219 }
220 }
221
222 pub fn write_header(&mut self) -> RawResult<()> {
224 let endian = self.endian();
225
226 self.writer.write_type(&self.byte_order, endian)?;
228 self.position += 2;
229
230 self.writer.write_type(&42u16, endian)?;
232 self.position += 2;
233
234 self.writer.write_type(&8u32, endian)?;
237 self.position += 4;
238
239 Ok(())
240 }
241
242 pub fn write_ifd(&mut self, entries: &mut [IfdEntry], next_ifd_offset: u32) -> RawResult<u64> {
246 let endian = self.endian();
247
248 entries.sort_by_key(|e| e.tag);
250
251 let ifd_start = self.position;
252 let entry_count = entries.len() as u16;
253
254 self.writer.write_type(&entry_count, endian)?;
256 self.position += 2;
257
258 let overflow_start = ifd_start + 2 + (12 * entries.len() as u64) + 4;
261 let mut overflow_offset = overflow_start;
262
263 let mut offsets: Vec<Option<u64>> = Vec::with_capacity(entries.len());
265 for entry in entries.iter() {
266 if entry.fits_inline() {
267 offsets.push(None);
268 } else {
269 offsets.push(Some(overflow_offset));
270 overflow_offset += entry.value_size() as u64;
271 if !overflow_offset.is_multiple_of(2) {
273 overflow_offset += 1;
274 }
275 }
276 }
277
278 for (entry, offset) in entries.iter().zip(offsets.iter()) {
280 let val_field: [u8; 4] = if let Some(off) = offset {
282 let off_u32 = *off as u32;
284 match endian {
285 Endian::Little => off_u32.to_le_bytes(),
286 Endian::Big => off_u32.to_be_bytes(),
287 }
288 } else {
289 let mut inline = [0u8; 4];
309 let len = entry.value_bytes.len().min(4);
310 inline[..len].copy_from_slice(&entry.value_bytes[..len]);
311 inline
312 };
313
314 let raw_entry = RawIfdEntry {
315 tag: entry.tag,
316 typ: entry.typ as u16,
317 count: entry.count,
318 value_offset: val_field,
319 };
320
321 self.writer.write_type(&raw_entry, endian)?;
322 self.position += 12;
323 }
324
325 self.writer.write_type(&next_ifd_offset, endian)?;
327 self.position += 4;
328
329 for (entry, offset) in entries.iter().zip(offsets.iter()) {
331 if offset.is_some() {
332 self.write_bytes(&entry.value_bytes)?;
333 if entry.value_bytes.len() % 2 != 0 {
335 self.write_bytes(&[0])?;
336 }
337 }
338 }
339
340 Ok(ifd_start)
341 }
342
343 pub fn write_image_strip_rgb16(&mut self, data: &[u16]) -> RawResult<(u64, u64)> {
346 let offset = self.position;
347 let endian = self.endian();
348
349 for &pixel in data {
353 self.writer.write_type(&pixel, endian)?;
354 }
355 self.position += data.len() as u64 * 2;
356
357 let byte_count = data.len() as u64 * 2;
358 Ok((offset, byte_count))
359 }
360
361 pub fn position(&self) -> u64 {
363 self.position
364 }
365
366 pub fn seek_to(&mut self, offset: u64) -> RawResult<()> {
368 self.writer.seek(SeekFrom::Start(offset))?;
369 self.position = offset;
370 Ok(())
371 }
372
373 pub fn update_ifd0_offset(&mut self, offset: u32) -> RawResult<()> {
375 let current = self.position;
376 self.seek_to(4)?;
377 let endian = self.endian();
378 self.writer.write_type(&offset, endian)?;
379 self.seek_to(current)?;
380 Ok(())
381 }
382
383 pub fn finish(self) -> W {
385 self.writer
386 }
387
388 fn write_bytes(&mut self, data: &[u8]) -> RawResult<()> {
391 self.writer.write_all(data)?;
392 self.position += data.len() as u64;
393 Ok(())
394 }
395}
396
397#[cfg(test)]
398mod tests {
399 use super::*;
400 use std::io::Cursor;
401
402 #[test]
403 fn test_ifd_entry_short() {
404 let entry = IfdEntry::short(TiffTag::ImageWidth, 1024);
405 assert_eq!(entry.tag, 0x0100);
406 assert_eq!(entry.count, 1);
407 assert!(entry.fits_inline());
408 }
409
410 #[test]
411 fn test_ifd_entry_ascii() {
412 let entry = IfdEntry::ascii(TiffTag::Make, "SONY");
413 assert_eq!(entry.tag, 0x010F);
414 assert_eq!(entry.count, 5); assert!(!entry.fits_inline()); }
417
418 #[test]
419 fn test_tiff_writer_header() {
420 let mut buffer = Cursor::new(Vec::new());
421 let mut writer = TiffWriter::new(&mut buffer, ByteOrder::LittleEndian);
422 writer.write_header().unwrap();
423
424 let data = buffer.into_inner();
425 assert_eq!(&data[0..2], b"II"); assert_eq!(&data[2..4], &[42, 0]); assert_eq!(&data[4..8], &[8, 0, 0, 0]); }
429
430 #[test]
431 fn test_write_ifd() {
432 let mut buffer = Cursor::new(Vec::new());
433 let mut writer = TiffWriter::new(&mut buffer, ByteOrder::LittleEndian);
434 writer.write_header().unwrap();
435
436 let mut entries = vec![
437 IfdEntry::short(TiffTag::ImageWidth, 100),
438 IfdEntry::short(TiffTag::ImageLength, 50),
439 ];
440 let ifd_offset = writer.write_ifd(&mut entries, 0).unwrap();
441 assert_eq!(ifd_offset, 8);
442 }
443}