1 | use crate::encoder::compression::*; |
2 | use crate::error::TiffResult; |
3 | use std::io::{self, Seek, SeekFrom, Write}; |
4 | |
5 | pub fn write_tiff_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> { |
6 | #[cfg (target_endian = "little" )] |
7 | let boi: u8 = 0x49; |
8 | #[cfg (not(target_endian = "little" ))] |
9 | let boi: u8 = 0x4d; |
10 | |
11 | writer.writer.write_all(&[boi, boi])?; |
12 | writer.writer.write_all(&42u16.to_ne_bytes())?; |
13 | writer.offset += 4; |
14 | |
15 | Ok(()) |
16 | } |
17 | |
18 | /// Writes a BigTiff header, excluding the IFD offset field. |
19 | /// |
20 | /// Writes the byte order, version number, offset byte size, and zero constant fields. Does |
21 | // _not_ write the offset to the first IFD, this should be done by the caller. |
22 | pub fn write_bigtiff_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> { |
23 | #[cfg (target_endian = "little" )] |
24 | let boi: u8 = 0x49; |
25 | #[cfg (not(target_endian = "little" ))] |
26 | let boi: u8 = 0x4d; |
27 | |
28 | // byte order indication |
29 | writer.writer.write_all(&[boi, boi])?; |
30 | // version number |
31 | writer.writer.write_all(&43u16.to_ne_bytes())?; |
32 | // bytesize of offsets (pointer size) |
33 | writer.writer.write_all(&8u16.to_ne_bytes())?; |
34 | // always 0 |
35 | writer.writer.write_all(&0u16.to_ne_bytes())?; |
36 | |
37 | // we wrote 8 bytes, so set the internal offset accordingly |
38 | writer.offset += 8; |
39 | |
40 | Ok(()) |
41 | } |
42 | |
43 | pub struct TiffWriter<W> { |
44 | writer: W, |
45 | offset: u64, |
46 | byte_count: u64, |
47 | compressor: Compressor, |
48 | } |
49 | |
50 | impl<W: Write> TiffWriter<W> { |
51 | pub fn new(writer: W) -> Self { |
52 | Self { |
53 | writer, |
54 | offset: 0, |
55 | byte_count: 0, |
56 | compressor: Compressor::default(), |
57 | } |
58 | } |
59 | |
60 | pub fn set_compression(&mut self, compressor: Compressor) { |
61 | self.compressor = compressor; |
62 | } |
63 | |
64 | pub fn reset_compression(&mut self) { |
65 | self.compressor = Compressor::default(); |
66 | } |
67 | |
68 | pub fn offset(&self) -> u64 { |
69 | self.offset |
70 | } |
71 | |
72 | pub fn last_written(&self) -> u64 { |
73 | self.byte_count |
74 | } |
75 | |
76 | pub fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), io::Error> { |
77 | self.byte_count = self.compressor.write_to(&mut self.writer, bytes)?; |
78 | self.offset += self.byte_count; |
79 | Ok(()) |
80 | } |
81 | |
82 | pub fn write_u8(&mut self, n: u8) -> Result<(), io::Error> { |
83 | self.byte_count = self |
84 | .compressor |
85 | .write_to(&mut self.writer, &n.to_ne_bytes())?; |
86 | self.offset += self.byte_count; |
87 | Ok(()) |
88 | } |
89 | |
90 | pub fn write_i8(&mut self, n: i8) -> Result<(), io::Error> { |
91 | self.byte_count = self |
92 | .compressor |
93 | .write_to(&mut self.writer, &n.to_ne_bytes())?; |
94 | self.offset += self.byte_count; |
95 | Ok(()) |
96 | } |
97 | |
98 | pub fn write_u16(&mut self, n: u16) -> Result<(), io::Error> { |
99 | self.byte_count = self |
100 | .compressor |
101 | .write_to(&mut self.writer, &n.to_ne_bytes())?; |
102 | self.offset += self.byte_count; |
103 | |
104 | Ok(()) |
105 | } |
106 | |
107 | pub fn write_i16(&mut self, n: i16) -> Result<(), io::Error> { |
108 | self.byte_count = self |
109 | .compressor |
110 | .write_to(&mut self.writer, &n.to_ne_bytes())?; |
111 | self.offset += self.byte_count; |
112 | |
113 | Ok(()) |
114 | } |
115 | |
116 | pub fn write_u32(&mut self, n: u32) -> Result<(), io::Error> { |
117 | self.byte_count = self |
118 | .compressor |
119 | .write_to(&mut self.writer, &n.to_ne_bytes())?; |
120 | self.offset += self.byte_count; |
121 | |
122 | Ok(()) |
123 | } |
124 | |
125 | pub fn write_i32(&mut self, n: i32) -> Result<(), io::Error> { |
126 | self.byte_count = self |
127 | .compressor |
128 | .write_to(&mut self.writer, &n.to_ne_bytes())?; |
129 | self.offset += self.byte_count; |
130 | |
131 | Ok(()) |
132 | } |
133 | |
134 | pub fn write_u64(&mut self, n: u64) -> Result<(), io::Error> { |
135 | self.byte_count = self |
136 | .compressor |
137 | .write_to(&mut self.writer, &n.to_ne_bytes())?; |
138 | self.offset += self.byte_count; |
139 | |
140 | Ok(()) |
141 | } |
142 | |
143 | pub fn write_i64(&mut self, n: i64) -> Result<(), io::Error> { |
144 | self.byte_count = self |
145 | .compressor |
146 | .write_to(&mut self.writer, &n.to_ne_bytes())?; |
147 | self.offset += self.byte_count; |
148 | |
149 | Ok(()) |
150 | } |
151 | |
152 | pub fn write_f32(&mut self, n: f32) -> Result<(), io::Error> { |
153 | self.byte_count = self |
154 | .compressor |
155 | .write_to(&mut self.writer, &u32::to_ne_bytes(n.to_bits()))?; |
156 | self.offset += self.byte_count; |
157 | |
158 | Ok(()) |
159 | } |
160 | |
161 | pub fn write_f64(&mut self, n: f64) -> Result<(), io::Error> { |
162 | self.byte_count = self |
163 | .compressor |
164 | .write_to(&mut self.writer, &u64::to_ne_bytes(n.to_bits()))?; |
165 | self.offset += self.byte_count; |
166 | |
167 | Ok(()) |
168 | } |
169 | |
170 | pub fn pad_word_boundary(&mut self) -> Result<(), io::Error> { |
171 | if self.offset % 4 != 0 { |
172 | let padding = [0, 0, 0]; |
173 | let padd_len = 4 - (self.offset % 4); |
174 | self.writer.write_all(&padding[..padd_len as usize])?; |
175 | self.offset += padd_len; |
176 | } |
177 | |
178 | Ok(()) |
179 | } |
180 | } |
181 | |
182 | impl<W: Seek> TiffWriter<W> { |
183 | pub fn goto_offset(&mut self, offset: u64) -> Result<(), io::Error> { |
184 | self.offset = offset; |
185 | self.writer.seek(pos:SeekFrom::Start(offset))?; |
186 | Ok(()) |
187 | } |
188 | } |
189 | |