1use libc::FILE;
2use std::ffi::c_void;
3use std::ffi::CStr;
4use std::ffi::CString;
5use std::os::raw::c_char;
6use std::os::raw::c_int;
7
8const TIFF_LAST_ERROR_SIZE: usize = 1024;
9
10#[repr(C)]
11pub struct TinyTiffReaderFrame {
12 width: u32,
13 height: u32,
14 compression: u16,
15 rows_per_strip: u32,
16 strip_offsets: *mut u32,
17 strip_byte_counts: *mut u32,
18 strip_count: u32,
19 samples_per_pixel: u16,
20 bits_per_sample: *mut u16,
21 planar_configuration: u16,
22 sample_format: u16,
23 image_length: u32,
24 description: *mut c_char,
25}
26
27#[repr(C)]
28pub struct TinyTiffReaderFile {
29 file: *mut FILE,
30 last_error: [c_char; TIFF_LAST_ERROR_SIZE],
31 was_error: c_int,
32 system_byte_order: u8,
33 file_byte_order: u8,
34 first_record_offset: u32,
35 next_ifd_offset: u32,
36 file_size: u64,
37 current_frame: TinyTiffReaderFrame,
38}
39
40#[link(name = "tinytiff")]
41extern "C" {
42 fn TinyTIFFReader_open(filename: *const c_char) -> *mut TinyTiffReaderFile;
43 fn TinyTIFFReader_close(tiff: *mut TinyTiffReaderFile);
44 fn TinyTIFFReader_getBitsPerSample(tiff: *mut TinyTiffReaderFile, sample: c_int) -> u16;
45 fn TinyTIFFReader_getSampleData(
46 tiff: *mut TinyTiffReaderFile,
47 sample_data: *mut c_void,
48 sample: u16,
49 ) -> c_int;
50 fn TinyTIFFReader_getWidth(tiff: *mut TinyTiffReaderFile) -> c_int;
51 fn TinyTIFFReader_getHeight(tiff: *mut TinyTiffReaderFile) -> c_int;
52 fn TinyTIFFReader_countFrames(tiff: *mut TinyTiffReaderFile) -> c_int;
53 fn TinyTIFFReader_getSampleFormat(tiff: *mut TinyTiffReaderFile) -> u16;
54 fn TinyTIFFReader_getSamplesPerPixel(tiff: *mut TinyTiffReaderFile) -> u16;
55 fn TinyTIFFReader_getImageDescription(tiff: *mut TinyTiffReaderFile) -> *const c_char;
56 fn TinyTIFFReader_hasNext(tiff: *mut TinyTiffReaderFile) -> c_int;
57 fn TinyTIFFReader_readNext(tiff: *mut TinyTiffReaderFile) -> c_int;
58 fn TinyTIFFReader_success(tiff: *mut TinyTiffReaderFile) -> c_int;
59 fn TinyTIFFReader_wasError(tiff: *mut TinyTiffReaderFile) -> c_int;
60 fn TinyTIFFReader_getLastError(tiff: *mut TinyTiffReaderFile) -> *const c_char;
61}
62
63pub fn open(filename: &str) -> Result<*mut TinyTiffReaderFile, String> {
65 let cfilename = CString::new(filename).unwrap();
66 let pntr = cfilename.as_ptr();
67 let tiff = unsafe { TinyTIFFReader_open(pntr) };
68 match tiff.is_null() {
69 false => Ok(tiff),
70 true => Err(format!("Could not open file: {}", String::from(filename))),
71 }
72}
73
74pub fn close(tiff: *mut TinyTiffReaderFile) {
76 unsafe { TinyTIFFReader_close(tiff) };
77}
78
79pub fn bits_per_sample(tiff: *mut TinyTiffReaderFile, sample: u16) -> u16 {
81 let bits = unsafe { TinyTIFFReader_getBitsPerSample(tiff, sample as i32) };
82 bits
83}
84
85pub fn sample_data<T>(tiff: *mut TinyTiffReaderFile, buffer: &mut Vec<T>, sample: u16) -> bool {
87 let pntr = buffer.as_ptr() as *mut c_void;
88 let data = unsafe { TinyTIFFReader_getSampleData(tiff, pntr, sample) };
89 data != 0
90}
91
92pub fn width(tiff: *mut TinyTiffReaderFile) -> u32 {
94 let width = unsafe { TinyTIFFReader_getWidth(tiff) };
95 width as u32
96}
97
98pub fn height(tiff: *mut TinyTiffReaderFile) -> u32 {
100 let height = unsafe { TinyTIFFReader_getHeight(tiff) };
101 height as u32
102}
103
104pub fn count_frames(tiff: *mut TinyTiffReaderFile) -> u32 {
106 let frames = unsafe { TinyTIFFReader_countFrames(tiff) };
107 frames as u32
108}
109
110pub fn sample_format(tiff: *mut TinyTiffReaderFile) -> u16 {
112 let format = unsafe { TinyTIFFReader_getSampleFormat(tiff) };
113 format
114}
115
116pub fn samples_per_pixel(tiff: *mut TinyTiffReaderFile) -> u16 {
118 let format = unsafe { TinyTIFFReader_getSamplesPerPixel(tiff) };
119 format
120}
121
122pub fn image_description(tiff: *mut TinyTiffReaderFile) -> String {
124 let desc = unsafe { TinyTIFFReader_getImageDescription(tiff) };
125 let desc = unsafe { CStr::from_ptr(desc) };
126 let desc = desc.to_str().unwrap();
127 let desc = String::from(desc);
128 desc
129}
130
131pub fn has_next(tiff: *mut TinyTiffReaderFile) -> bool {
133 let result = unsafe { TinyTIFFReader_hasNext(tiff) };
134 result != 0
135}
136
137pub fn read_next(tiff: *mut TinyTiffReaderFile) -> bool {
139 let result = unsafe { TinyTIFFReader_readNext(tiff) };
140 result != 0
141}
142
143pub fn success(tiff: *mut TinyTiffReaderFile) -> bool {
145 let result = unsafe { TinyTIFFReader_success(tiff) };
146 result != 0
147}
148
149pub fn was_error(tiff: *mut TinyTiffReaderFile) -> bool {
151 let result = unsafe { TinyTIFFReader_wasError(tiff) };
152 result != 0
153}
154
155pub fn last_error(tiff: *mut TinyTiffReaderFile) -> String {
157 let error = unsafe { TinyTIFFReader_getLastError(tiff) };
158 let error = unsafe { CStr::from_ptr(error) };
159 let error = error.to_str().unwrap();
160 let error = String::from(error);
161 error
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn can_open() {
170 let _tiff = open("./tests/test_data/cell8.tif").unwrap();
171 }
172
173 #[test]
174 #[should_panic]
175 fn open_bad_file_panics() {
176 let _tiff = open("./does/not/exist.tif").unwrap();
177 }
178
179 #[test]
180 fn can_close() {
181 let tiff = open("./tests/test_data/cell8.tif").unwrap();
182 close(tiff);
183 }
184
185 #[test]
186 fn can_bits_per_sample() {
187 let tiff = open("./tests/test_data/cell8.tif").unwrap();
188 assert_eq!(bits_per_sample(tiff, 0), 8);
189 close(tiff);
190 }
191
192 #[test]
193 fn can_sample_data() {
194 let tiff = open("./tests/test_data/cell8.tif").unwrap();
195 let width = width(tiff);
196 let height = height(tiff);
197 let size = (width * height) as usize;
198 let mut buffer: Vec<u8> = vec![0u8; size];
199 let result = sample_data(tiff, &mut buffer, 0);
200 close(tiff);
201 assert!(result);
202 assert_eq!(buffer[2], 112 as u8);
203 }
204
205 #[test]
206 fn can_width() {
207 let tiff = open("./tests/test_data/cell8.tif").unwrap();
208 assert_eq!(width(tiff), 191);
209 close(tiff);
210 }
211
212 #[test]
213 fn can_height() {
214 let tiff = open("./tests/test_data/cell8.tif").unwrap();
215 assert_eq!(height(tiff), 159);
216 close(tiff);
217 }
218
219 #[test]
220 fn can_count_frames() {
221 let tiff = open("./tests/test_data/cell8.tif").unwrap();
222 assert_eq!(count_frames(tiff), 1);
223 close(tiff);
224 }
225
226 #[test]
227 fn can_sample_format() {
228 let tiff = open("./tests/test_data/cell8.tif").unwrap();
229 assert_eq!(sample_format(tiff), 1);
230 close(tiff);
231 }
232
233 #[test]
234 fn can_samples_per_pixel() {
235 let tiff = open("./tests/test_data/cell8.tif").unwrap();
236 assert_eq!(samples_per_pixel(tiff), 1);
237 close(tiff);
238 }
239
240 #[test]
241 fn can_image_description() {
242 let tiff = open("./tests/test_data/cell8.tif").unwrap();
243 assert_eq!(image_description(tiff), "image description");
244 close(tiff);
245 }
246
247 #[test]
248 fn can_has_next() {
249 let tiff = open("./tests/test_data/cell8.tif").unwrap();
250 assert!(!has_next(tiff));
251 close(tiff);
252 }
253
254 #[test]
255 fn can_read_next() {
256 let tiff = open("./tests/test_data/cell8.tif").unwrap();
257 assert!(!read_next(tiff));
258 close(tiff);
259 }
260
261 #[test]
262 fn can_success() {
263 let tiff = open("./tests/test_data/cell8.tif").unwrap();
264 assert!(success(tiff));
265 close(tiff);
266 }
267
268 #[test]
269 fn can_was_error() {
270 let tiff = open("./tests/test_data/cell8.tif").unwrap();
271 assert!(!was_error(tiff));
272 close(tiff);
273 }
274
275 #[test]
276 fn can_last_error() {
277 let tiff = open("./tests/test_data/cell8.tif").unwrap();
278 assert_eq!(last_error(tiff), "");
279 close(tiff);
280 }
281}