diff options
author | cc <cc@localhost> | 2025-08-20 19:56:24 -0700 |
---|---|---|
committer | cc <cc@localhost> | 2025-08-20 19:57:14 -0700 |
commit | a7ded0a844feac401be72a5b575cb0e0c3e12e01 (patch) | |
tree | 7d2d48b6258c23a633d18eab9784f8dc1c47d8a2 /src | |
parent | 238a3e31a8fb0eb24de278b9286b9b6caef1c66b (diff) |
Standardize Label Structures
Compress processed masks to simple labels
Dump simple labels to file
Diffstat (limited to 'src')
-rw-r--r-- | src/binfile.rs | 13 | ||||
-rw-r--r-- | src/lib.rs | 17 | ||||
-rw-r--r-- | src/tiff.rs | 84 |
3 files changed, 110 insertions, 4 deletions
diff --git a/src/binfile.rs b/src/binfile.rs index a43f568..5b0b783 100644 --- a/src/binfile.rs +++ b/src/binfile.rs @@ -12,3 +12,16 @@ pub fn dump_u32_vec(file_name: &str, data: Vec<u32>) -> Result<(), Error> { } Ok(()) } + +pub fn dump_u16_vec(file_name: &str, data: Vec<u16>) -> Result<(), Error> { + use std::fs::File; + use std::io::Write; + if let Ok(mut file) = File::create(file_name) { + for value in data { + file.write_all(&value.to_le_bytes())?; + } + } else { + return Err(Error::new(ErrorKind::Other, "Error creating file")); + } + Ok(()) +} @@ -3,6 +3,7 @@ pub mod binfile; pub const TEST_IMAGE_PATH: &str = "../test.tif"; pub const TEST_OUTPUT_PATH: &str = "../test.bin"; +pub const TEST_LABEL_OUTPUT_PATH: &str = "../test.c.bin"; #[cfg(test)] mod tests { @@ -80,7 +81,21 @@ mod tests { fn tiff_data_dump_test() { tiff::ignore_warnings(); if let Some(standard_format) = tiff::as_standard_format(TEST_IMAGE_PATH) { - binfile::dump_u32_vec(TEST_OUTPUT_PATH, standard_format).expect("File output error"); + println!("{:?}", standard_format); + let data = standard_format.buffer; + binfile::dump_u32_vec(TEST_OUTPUT_PATH, data).expect("File output error"); + } else { + assert!(false); + } + } + + #[test] + fn tiff_compressed_data_dump_test() { + tiff::ignore_warnings(); + if let Some(standard_format) = tiff::as_standard_format(TEST_IMAGE_PATH) { + let compressed_format = tiff::standard_to_labels(standard_format); + let data = compressed_format.buffer; + binfile::dump_u16_vec(TEST_LABEL_OUTPUT_PATH, data).expect("File output error"); } else { assert!(false); } diff --git a/src/tiff.rs b/src/tiff.rs index a1d19eb..2baba80 100644 --- a/src/tiff.rs +++ b/src/tiff.rs @@ -1,6 +1,27 @@ use std::os::raw::{c_char, c_uint, c_void, c_longlong, c_long}; use std::ffi::CString; +pub struct StandardOutput { + pub buffer: Vec<u32>, + pub width: usize, + pub height: usize, +} + +pub struct CompressedOutput { + pub buffer: Vec<u16>, + pub width: usize, + pub height: usize, +} + +impl std::fmt::Debug for StandardOutput { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("StandardOutput") + .field("width", &self.width) + .field("height", &self.height) + .finish() + } +} + /// # TIFF Internal Structure /// An opaque type #[repr(C)] @@ -133,7 +154,7 @@ pub fn read(tiff_ptr: *mut TIFF) -> Vec<u8> { total_buf } -pub fn as_standard_format(tiff_file_name: &str) -> Option<Vec<u32>> { +pub fn as_standard_format(tiff_file_name: &str) -> Option<StandardOutput> { if let Some(tiff) = open(tiff_file_name) { let width_opt = get_image_width(tiff); let height_opt = get_image_height(tiff); @@ -153,18 +174,75 @@ pub fn as_standard_format(tiff_file_name: &str) -> Option<Vec<u32>> { for c in 0..channels { let data: u8 = tiff_data[c + channels * (x + width * y)]; let data: u32 = data as u32; - let data = data << (8 * c); + let mut data = data << (8 * c); + if (channels == 4) && (c == 3) { + data = 0; + } standard_buffer[x + width*y] += data; } } } close(tiff); - return Some(standard_buffer); + return Some(StandardOutput { + buffer: standard_buffer, + width, + height, + }); } // Otherwise return None; } +fn flood(source: &StandardOutput, destination: &mut Vec<u16>, + x: usize, y: usize, + from_color: u32, to_color: u16) { + let width = source.width; + let destination_color = destination[x + y * width]; + if destination_color != 0 { + return; + } + let source_color = source.buffer[x + y * width]; + if source_color != from_color { + return; + } + destination[x + y * width] = to_color; + if x > 0 { + flood(source, destination, x-1, y, from_color, to_color); + } + if (x+1) < width { + flood(source, destination, x+1, y, from_color, to_color); + } + if y > 0 { + flood(source, destination, x, y-1, from_color, to_color); + } + if (y+1) < source.height { + flood(source, destination, x, y+1, from_color, to_color); + } +} + +pub fn standard_to_labels(buffer: StandardOutput) -> CompressedOutput { + let mut label: u16 = 1; + let mut output_buffer: Vec<u16> = vec![0u16; buffer.buffer.len()]; + for y in 0..buffer.height { + for x in 0..buffer.width { + let index = x + y*buffer.width; + if buffer.buffer[index] == 0 { + continue; + } + if output_buffer[index] == 0 { + let color = buffer.buffer[index]; + flood(&buffer, &mut output_buffer, x, y, color, label); + label += 1; + } + } + } + return CompressedOutput { + buffer: output_buffer, + width: buffer.width, + height: buffer.height, + }; +} + #[cfg(test)] mod tests { use super::*; |