read_vk6/
types.rs

1use chrono::NaiveDateTime;
2use ndarray::{Array2, Array3};
3use std::collections::HashMap;
4
5/// Complete metadata extracted from VK6/VK7 files
6/// Based on LAYOUT_MEASUREMENT_CONDITIONS from Surfalize
7#[derive(Debug, Clone)]
8pub struct Metadata {
9    // String data
10    pub title: Option<String>,
11    pub lens_name: Option<String>,
12    
13    // Timestamp
14    pub timestamp: Option<NaiveDateTime>,
15    pub diff_from_utc: Option<i32>,
16    
17    // Image attributes
18    pub img_attributes: Option<u32>,
19    pub user_interface_mode: Option<u32>,
20    pub color_composite_mode: Option<u32>,
21    pub img_layer_number: Option<u32>,
22    
23    // Measurement modes
24    pub run_mode: Option<u32>,
25    pub peak_mode: Option<u32>,
26    pub sharpening_level: Option<u32>,
27    pub speed: Option<u32>,
28    pub distance: Option<u32>,
29    pub pitch: Option<u32>,
30    
31    // Optical settings
32    pub optical_zoom: Option<f64>,
33    pub objective_magnification: Option<f64>,
34    pub lens_id: Option<u32>,
35    pub num_aperture: Option<u32>,
36    pub head_type: Option<u32>,
37    
38    // Line measurement
39    pub number_of_lines: Option<u32>,
40    pub line0_position: Option<u32>,
41    
42    // PMT (Photomultiplier Tube) settings
43    pub pmt_gain_mode: Option<u32>,
44    pub pmt_gain: Option<u32>,
45    pub pmt_gain_2: Option<u32>,
46    pub pmt_offset: Option<u32>,
47    
48    // Filter settings
49    pub nd_filter: Option<u32>,
50    pub light_filter_type: Option<u32>,
51    
52    // Shutter and exposure
53    pub persist_count: Option<u32>,
54    pub shutter_speed_mode: Option<u32>,
55    pub shutter_speed: Option<u32>,
56    
57    // White balance and color
58    pub white_balance_mode: Option<u32>,
59    pub white_balance_red: Option<u32>,
60    pub white_balance_blue: Option<u32>,
61    pub camera_gain: Option<u32>,
62    pub omit_color_img: Option<u32>,
63    
64    // Compensation
65    pub plane_compensation: Option<u32>,
66    
67    // Units and decimal places
68    pub xy_length_unit: Option<u32>,
69    pub z_length_unit: Option<u32>,
70    pub xy_decimal_place: Option<u32>,
71    pub z_decimal_place: Option<u32>,
72    
73    // Length per pixel/digit (in picometers)
74    pub x_length_per_pixel: Option<u32>,
75    pub y_length_per_pixel: Option<u32>,
76    pub z_length_per_digit: Option<u32>,
77    
78    // Gamma correction
79    pub gamma_reverse: Option<u32>,
80    pub gamma: Option<u32>,
81    pub gamma_correction_offset: Option<u32>,
82    
83    // CCD settings
84    pub ccd_bw_offset: Option<u32>,
85    
86    // Light LUT (Look-Up Table)
87    pub light_lut_mode: Option<u32>,
88    pub light_lut_in0: Option<u32>,
89    pub light_lut_out0: Option<u32>,
90    pub light_lut_in1: Option<u32>,
91    pub light_lut_out1: Option<u32>,
92    pub light_lut_in2: Option<u32>,
93    pub light_lut_out2: Option<u32>,
94    pub light_lut_in3: Option<u32>,
95    pub light_lut_out3: Option<u32>,
96    pub light_lut_in4: Option<u32>,
97    pub light_lut_out4: Option<u32>,
98    
99    // Position
100    pub upper_position: Option<u32>,
101    pub lower_position: Option<u32>,
102    
103    // Effective bit depth
104    pub light_effective_bit_depth: Option<u32>,
105    pub height_effective_bit_depth: Option<u32>,
106    
107    // Additional raw data for future use
108    pub extra: HashMap<String, String>,
109}
110
111impl Metadata {
112    /// Get a summary of the most important metadata fields as a formatted string
113    pub fn summary(&self) -> String {
114        let mut s = String::new();
115        s.push_str("=== VK6 File Metadata ===\n");
116        
117        if let Some(ref title) = self.title {
118            s.push_str(&format!("Title: {}\n", title));
119        }
120        if let Some(ref lens) = self.lens_name {
121            s.push_str(&format!("Lens: {}\n", lens));
122        }
123        if let Some(ref ts) = self.timestamp {
124            s.push_str(&format!("Timestamp: {}\n", ts));
125        }
126        if let Some(zoom) = self.optical_zoom {
127            s.push_str(&format!("Optical Zoom: {}x\n", zoom));
128        }
129        if let Some(mag) = self.objective_magnification {
130            s.push_str(&format!("Objective Magnification: {}x\n", mag));
131        }
132        
133        s.push_str("\nMeasurement Settings:\n");
134        if let Some(mode) = self.run_mode {
135            s.push_str(&format!("  Run Mode: {}\n", mode));
136        }
137        if let Some(speed) = self.speed {
138            s.push_str(&format!("  Speed: {}\n", speed));
139        }
140        if let Some(sharpening) = self.sharpening_level {
141            s.push_str(&format!("  Sharpening Level: {}\n", sharpening));
142        }
143        
144        s.push_str("\nResolution:\n");
145        if let Some(x_len) = self.x_length_per_pixel {
146            s.push_str(&format!("  X: {} pm/pixel ({} µm/pixel)\n", x_len, x_len as f64 * 1e-6));
147        }
148        if let Some(y_len) = self.y_length_per_pixel {
149            s.push_str(&format!("  Y: {} pm/pixel ({} µm/pixel)\n", y_len, y_len as f64 * 1e-6));
150        }
151        if let Some(z_len) = self.z_length_per_digit {
152            s.push_str(&format!("  Z: {} pm/digit ({} µm/digit)\n", z_len, z_len as f64 * 1e-6));
153        }
154        
155        s
156    }
157}
158
159/// The main return struct: height map (µm), pixel steps (µm), metadata, optional RGB image
160#[derive(Debug)]
161pub struct RawSurface {
162    pub height: Array2<f64>,          // shape (rows, cols), units: micrometers
163    pub step_x: f64,                  // µm per pixel
164    pub step_y: f64,
165    pub metadata: Metadata,
166    pub rgb_image: Option<Array3<u8>>, // shape (rows, cols, 3) if present
167}