tiny_tiff/
reader.rs

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
63/// open tiff file for reading
64pub 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
74/// close tiff file
75pub fn close(tiff: *mut TinyTiffReaderFile) {
76    unsafe { TinyTIFFReader_close(tiff) };
77}
78
79/// get bits per sample of current frame
80pub fn bits_per_sample(tiff: *mut TinyTiffReaderFile, sample: u16) -> u16 {
81    let bits = unsafe { TinyTIFFReader_getBitsPerSample(tiff, sample as i32) };
82    bits
83}
84
85/// read data from current frame into supplied buffer
86pub 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
92/// get width of current frame
93pub fn width(tiff: *mut TinyTiffReaderFile) -> u32 {
94    let width = unsafe { TinyTIFFReader_getWidth(tiff) };
95    width as u32
96}
97
98/// get height of current frame
99pub fn height(tiff: *mut TinyTiffReaderFile) -> u32 {
100    let height = unsafe { TinyTIFFReader_getHeight(tiff) };
101    height as u32
102}
103
104/// get number of frames
105pub fn count_frames(tiff: *mut TinyTiffReaderFile) -> u32 {
106    let frames = unsafe { TinyTIFFReader_countFrames(tiff) };
107    frames as u32
108}
109
110/// get sample format of current frame
111pub fn sample_format(tiff: *mut TinyTiffReaderFile) -> u16 {
112    let format = unsafe { TinyTIFFReader_getSampleFormat(tiff) };
113    format
114}
115
116/// get samples per pixel of current from
117pub fn samples_per_pixel(tiff: *mut TinyTiffReaderFile) -> u16 {
118    let format = unsafe { TinyTIFFReader_getSamplesPerPixel(tiff) };
119    format
120}
121
122/// get image description of current frame
123pub 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
131/// true if another frame exists
132pub fn has_next(tiff: *mut TinyTiffReaderFile) -> bool {
133    let result = unsafe { TinyTIFFReader_hasNext(tiff) };
134    result != 0
135}
136
137/// read next frame from a multi-frame tiff
138pub fn read_next(tiff: *mut TinyTiffReaderFile) -> bool {
139    let result = unsafe { TinyTIFFReader_readNext(tiff) };
140    result != 0
141}
142
143/// true if no error in last function call
144pub fn success(tiff: *mut TinyTiffReaderFile) -> bool {
145    let result = unsafe { TinyTIFFReader_success(tiff) };
146    result != 0
147}
148
149/// true if error in last function call
150pub fn was_error(tiff: *mut TinyTiffReaderFile) -> bool {
151    let result = unsafe { TinyTIFFReader_wasError(tiff) };
152    result != 0
153}
154
155/// get last error messsage
156pub 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}