use std::os::raw::{c_char, c_uint, c_void, c_longlong, c_long}; use std::ffi::CString; use crate::label_formats::LargeLabelFormat; /// # TIFF Internal Structure /// An opaque type #[repr(C)] pub struct TIFF { _unused: [u8; 0], } /// # TIFF Warning Handler Definition type TIFFWarningHandler = Option; /// # TIFF Ignore Warnings Handle unsafe extern "C" fn tiff_ignore_warning_handle(_module: *const c_char, _fmt: *const c_char, _ap: *mut std::ffi::c_void) { // Do nothing } #[link(name = "tiff")] unsafe extern "C" { fn TIFFSetWarningHandler(handler: TIFFWarningHandler) -> TIFFWarningHandler; fn TIFFOpen(filename: *const c_char, mode: *const c_char) -> *mut TIFF; fn TIFFClose(tiff_ptr: *mut TIFF); fn TIFFGetField(tiff_ptr: *mut TIFF, tag: c_uint, ...) -> c_long; fn TIFFStripSize(tiff_ptr: *mut TIFF) -> c_longlong; fn TIFFNumberOfStrips(tiff_ptr: *mut TIFF) -> c_longlong; fn TIFFReadRawStrip(tiff_ptr: *mut TIFF, strip: c_uint, buf: *mut c_void, size: c_longlong) -> c_longlong; } /// From tiff.h const TIFFTAG_IMAGEWIDTH: u32 = 256; /// From tiff.h const TIFFTAG_IMAGEHEIGHT: u32 = 257; /// # Ignore TIFF Warnings pub fn ignore_warnings() { unsafe { let _ = TIFFSetWarningHandler(Some(tiff_ignore_warning_handle)); } } /// # Open TIFF File pub fn open(filename: &str) -> Option<*mut TIFF> { let c_filename = CString::new(filename).expect("Cast error"); let c_mode = CString::new("r").expect("Cast error"); unsafe { let result = TIFFOpen(c_filename.as_ptr(), c_mode.as_ptr()); if result.is_null() { return None; } else { return Some(result); } } } /// # Close TIFF File pub fn close(tiff_ptr: *mut TIFF) { unsafe { TIFFClose(tiff_ptr); } } pub fn get_image_width(tiff_ptr: *mut TIFF) -> Option { let mut width: u32 = 0; unsafe { let status = TIFFGetField(tiff_ptr, TIFFTAG_IMAGEWIDTH, &mut width as *mut u32); if status < 0 { return None; } else { return Some(width as usize); } } } pub fn get_image_height(tiff_ptr: *mut TIFF) -> Option { let mut height: u32 = 0; unsafe { let status = TIFFGetField(tiff_ptr, TIFFTAG_IMAGEHEIGHT, &mut height as *mut u32); if status < 0 { return None; } else { return Some(height as usize); } } } pub fn get_image_channels(tiff_ptr: *mut TIFF) -> usize { let strip_size = get_strip_size(tiff_ptr); let strip_count = get_strip_count(tiff_ptr); let width = get_image_width(tiff_ptr) .expect("Image should have width!"); let height = get_image_height(tiff_ptr) .expect("Image should have height!"); return (strip_size * strip_count) / (width * height); } fn get_strip_size(tiff_ptr: *mut TIFF) -> usize { unsafe { TIFFStripSize(tiff_ptr) as usize } } fn get_strip_count(tiff_ptr: *mut TIFF) -> usize { unsafe { TIFFNumberOfStrips(tiff_ptr) as usize } } fn read_strip(tiff_ptr: *mut TIFF, strip: u32) -> Vec { let strip_size = get_strip_size(tiff_ptr); assert!(strip_size>0); let mut buf: Vec = vec![0u8; strip_size as usize]; unsafe { TIFFReadRawStrip(tiff_ptr, strip, buf.as_mut_ptr() as *mut c_void, strip_size as c_longlong); } buf } pub fn read(tiff_ptr: *mut TIFF) -> Vec { let strip_size = get_strip_size(tiff_ptr); let strip_count = get_strip_count(tiff_ptr); let mut total_buf: Vec = vec![0u8; (strip_size * strip_count) as usize]; for strip_index in 0..strip_count { let sub_buffer: Vec = read_strip(tiff_ptr, strip_index as u32); let base_index = strip_index * strip_size; for data_index in 0..strip_size { let total_index = base_index + data_index; let data = sub_buffer[data_index as usize]; total_buf[total_index as usize] = data; } } total_buf } pub fn to_large_labels(tiff_file_name: &str) -> Option { if let Some(tiff) = open(tiff_file_name) { let width_opt = get_image_width(tiff); let height_opt = get_image_height(tiff); let channels = get_image_channels(tiff); if (width_opt == None) || (height_opt == None) { return None; } if (channels == 0) || (channels > 4) { return None } let width = width_opt.expect("Width Prechecked"); let height = height_opt.expect("Height Prechecked"); let mut large_label_buffer = vec![0u32; (width*height) as usize]; let tiff_data = read(tiff); for x in 0..width { for y in 0..height { for c in 0..channels { let data: u8 = tiff_data[c + channels * (x + width * y)]; let data: u32 = data as u32; let mut data = data << (8 * c); if (channels == 4) && (c == 3) { data = 0; } large_label_buffer[x + width*y] += data; } } } close(tiff); return Some(LargeLabelFormat { buffer: large_label_buffer, width, height, }); } // Otherwise return None; } #[cfg(test)] mod tests { use super::*; #[test] fn tiff_strip_size() { ignore_warnings(); if let Some(t_handle) = open(crate::TEST_IMAGE_PATH) { let strip_size = get_strip_size(t_handle); assert!(strip_size > 0); close(t_handle); } else { assert!(false); } } #[test] fn tiff_strip_count() { ignore_warnings(); if let Some(t_handle) = open(crate::TEST_IMAGE_PATH) { let strip_count = get_strip_count(t_handle); assert!(strip_count > 0); close(t_handle); } else { assert!(false); } } #[test] fn tiff_strip_read() { ignore_warnings(); if let Some(t_handle) = open(crate::TEST_IMAGE_PATH) { let _strip = read_strip(t_handle, 0); close(t_handle); } else { assert!(false); } } }