Skip to main content

fax/
tiff.rs

1#[derive(Copy, Clone)]
2enum Value {
3    Short(u16),
4    Long(u32),
5    Rational(u32, u32),
6    DataOffset,
7}
8
9pub fn wrap(data: &[u8], width: u32, height: u32) -> Vec<u8> {
10    use Value::*;
11    let header_data = [
12        (256, Long(width)),             // ImageWidth
13        (257, Long(height)),            // ImageLength
14        (259, Short(4)),                // Compression
15        (262, Short(0)),                // PhotometricInterpretation
16        (273, DataOffset),              // StripOffsets
17        (274, Short(1)),                // Orientation
18        (278, Long(height)),            // RowsPerStrip
19        (279, Long(data.len() as u32)), // StripByteCounts
20        (282, Rational(200, 1)),        // XResolution
21        (283, Rational(200, 1)),        // YResolution
22        (296, Short(2)),                // ResolutionUnit
23    ];
24    let rat_data_len = 2 * 8; // number of rationals * 8
25    let ifd_end = 4 + // magic
26        4 + // IFD offset
27        2 + // IFD entry count
28        12 * header_data.len() + // IFD enties
29        4; // null pointer at end of IFD
30    let header_size = ifd_end + rat_data_len;
31
32    let mut out = Vec::with_capacity(header_size + data.len());
33
34    out.extend_from_slice(&[73, 73, 42, 0]);
35    let ifd_offset: u32 = 8;
36    out.extend_from_slice(&ifd_offset.to_le_bytes());
37
38    out.extend_from_slice(&u16::to_le_bytes(header_data.len() as u16));
39
40    let mut num_rat = 0;
41    for &(tag, val) in header_data.iter() {
42        let (typ_num, val) = match val {
43            Short(n) => (3, n as u32),
44            Long(n) => (4, n),
45            Rational(_, _) => {
46                let o = ifd_end + 8 * num_rat;
47                num_rat += 1;
48                (5, o as u32)
49            }
50            DataOffset => (4, header_size as u32),
51        };
52        let count = 1;
53        out.extend_from_slice(&u16::to_le_bytes(tag));
54        out.extend_from_slice(&u16::to_le_bytes(typ_num));
55        out.extend_from_slice(&u32::to_le_bytes(count));
56        out.extend_from_slice(&u32::to_le_bytes(val));
57    }
58    // NULL at IFD end
59    out.extend_from_slice(&[0; 4]);
60
61    // write additional data
62    for &(_, val) in header_data.iter() {
63        if let Value::Rational(nom, denom) = val {
64            out.extend_from_slice(&nom.to_le_bytes());
65            out.extend_from_slice(&denom.to_le_bytes());
66        }
67    }
68
69    assert_eq!(out.len(), header_size);
70    out.extend_from_slice(data);
71    out
72}