gistools/readers/geotiff/
image_util.rs1use crate::parsers::Buffer;
2use alloc::{vec, vec::Vec};
3use core::iter::Sum;
4use half::f16;
5
6#[derive(Debug, Default, Clone, PartialEq)]
8pub enum GTiffDataType {
9 #[default]
11 U8,
12 U16,
14 U32,
16 I8,
18 I16,
20 I32,
22 F16,
24 F32,
26 F64,
28}
29impl GTiffDataType {
30 pub fn to_type(format: u16, bits_per_sample: u16) -> GTiffDataType {
39 match format {
40 1 => {
41 if bits_per_sample <= 8 {
43 return GTiffDataType::U8;
44 } else if bits_per_sample <= 16 {
45 return GTiffDataType::U16;
46 } else if bits_per_sample <= 32 {
47 return GTiffDataType::U32;
48 }
49 }
50 2 => {
51 if bits_per_sample == 8 {
53 return GTiffDataType::I8;
54 } else if bits_per_sample == 16 {
55 return GTiffDataType::I16;
56 } else if bits_per_sample == 32 {
57 return GTiffDataType::I32;
58 }
59 }
60 3 => {
61 match bits_per_sample {
63 16 => {
64 return GTiffDataType::F16;
65 }
66 32 => {
67 return GTiffDataType::F32;
68 }
69 64 => {
70 return GTiffDataType::F64;
71 }
72 _ => {}
73 }
74 }
75 _ => {}
76 }
77 panic!("Unsupported data format/bits_per_sample");
78 }
79}
80
81pub fn sample_sum<T>(array: &[T], start: usize, end: usize) -> T
91where
92 T: Copy + Sum<T>,
93{
94 array[start..end].iter().copied().sum()
95}
96
97pub fn needs_normalization(format: usize, bits_per_sample: usize) -> bool {
106 if (format == 1 || format == 2) && bits_per_sample <= 32 && bits_per_sample.is_multiple_of(8) {
107 false
108 } else {
109 !(format == 3 && (bits_per_sample == 16 || bits_per_sample == 32 || bits_per_sample == 64))
110 }
111}
112
113pub fn normalize_array(
127 in_buffer: Vec<u8>,
128 format: usize,
129 planar_configuration: usize,
130 samples_per_pixel: usize,
131 bits_per_sample: usize,
132 tile_width: usize,
133 tile_height: usize,
134) -> Vec<u8> {
135 let mut view = Buffer::new(in_buffer);
137 let out_size = if planar_configuration == 2 {
138 tile_height * tile_width
139 } else {
140 tile_height * tile_width * samples_per_pixel
141 };
142 let samples_to_transfer = if planar_configuration == 2 { 1 } else { samples_per_pixel };
143 let mut out_array: Vec<u8> = vec![0; out_size];
145 let bit_mask = (1_usize << bits_per_sample) - 1;
148
149 if format == 1 {
150 let pixel_bit_skip = if planar_configuration == 1 {
153 samples_per_pixel * bits_per_sample
154 } else {
155 bits_per_sample
156 };
157
158 let mut bits_per_line = tile_width * pixel_bit_skip;
160 if (bits_per_line & 7) != 0 {
161 bits_per_line = (bits_per_line + 7) & !7;
162 }
163
164 for y in 0..tile_height {
165 let line_bit_offset = y * bits_per_line;
166 for x in 0..tile_width {
167 let pixel_bit_offset = line_bit_offset + x * samples_to_transfer * bits_per_sample;
168 for i in 0..samples_to_transfer {
169 let bit_offset = pixel_bit_offset + i * bits_per_sample;
170 let out_index = (y * tile_width + x) * samples_to_transfer + i;
171
172 let byte_offset = bit_offset / 8;
174 let inner_bit_offset = bit_offset % 8;
175 if inner_bit_offset + bits_per_sample <= 8 {
176 out_array[out_index] = ((view.get_u8_at(byte_offset) as usize
177 >> (8 - bits_per_sample - inner_bit_offset))
178 & bit_mask) as u8;
179 } else if inner_bit_offset + bits_per_sample <= 16 {
180 let val = ((view.get_u16_at(byte_offset) as usize
181 >> (16 - bits_per_sample - inner_bit_offset))
182 & bit_mask) as u16;
183 out_array[out_index * 2] = (val >> 8) as u8;
185 out_array[out_index * 2 + 1] = val as u8;
186 } else if inner_bit_offset + bits_per_sample <= 24 {
187 let raw = ((view.get_u16_at(byte_offset) as usize) << 8)
188 | view.get_u8_at(byte_offset + 2) as usize;
189 let val =
190 ((raw >> (24 - bits_per_sample - inner_bit_offset)) & bit_mask) as u32;
191 out_array[out_index * 3] = (val >> 16) as u8;
192 out_array[out_index * 3 + 1] = (val >> 8) as u8;
193 out_array[out_index * 3 + 2] = val as u8;
194 } else {
195 let val = ((view.get_u32_at(byte_offset) as usize
196 >> (32 - bits_per_sample - inner_bit_offset))
197 & bit_mask) as u32;
198 out_array[out_index * 4] = (val >> 24) as u8;
199 out_array[out_index * 4 + 1] = (val >> 16) as u8;
200 out_array[out_index * 4 + 2] = (val >> 8) as u8;
201 out_array[out_index * 4 + 3] = val as u8;
202 }
203
204 }
217 }
219 }
220 } else if format == 3 {
221 }
233
234 out_array
235}
236
237pub fn get_reader_for_sample(
246 bits_per_sample: u16,
247 format: u16,
248) -> fn(buffer: &[u8], offset: usize, little_endian: bool) -> f64 {
249 match format {
250 0 | 1 => {
251 if bits_per_sample <= 8 {
253 return |buffer: &[u8], offset: usize, _little_endian: bool| -> f64 {
254 buffer[offset] as f64
255 };
257 } else if bits_per_sample <= 16 {
258 return |buffer: &[u8], offset: usize, little_endian: bool| -> f64 {
259 let u16_offset = offset / 2;
260 let bytes = [buffer[u16_offset], buffer[u16_offset + 1]];
261 let value = if little_endian {
262 u16::from_le_bytes(bytes)
263 } else {
264 u16::from_be_bytes(bytes)
265 };
266 value as f64
267 };
268 } else if bits_per_sample <= 32 {
269 return |buffer: &[u8], offset: usize, little_endian: bool| -> f64 {
270 let start = offset / 4;
271 let bytes: [u8; 4] = buffer[start..start + 4].try_into().unwrap();
272 let value = if little_endian {
273 u32::from_le_bytes(bytes)
274 } else {
275 u32::from_be_bytes(bytes)
276 };
277 value as f64
278 };
279 }
280 }
281 2 => {
282 if bits_per_sample <= 8 {
284 return |buffer: &[u8], offset: usize, _little_endian: bool| -> f64 {
285 (buffer[offset] as i8) as f64
286 };
287 } else if bits_per_sample <= 16 {
288 return |buffer: &[u8], offset: usize, little_endian: bool| -> f64 {
289 let i16_offset = offset / 2;
290 let bytes = [buffer[i16_offset], buffer[i16_offset + 1]];
291 (if little_endian {
292 i16::from_le_bytes(bytes)
293 } else {
294 i16::from_be_bytes(bytes)
295 }) as f64
296 };
297 } else if bits_per_sample <= 32 {
298 return |buffer: &[u8], offset: usize, little_endian: bool| -> f64 {
299 let start = offset / 4;
300 let bytes: [u8; 4] = buffer[start..start + 4].try_into().unwrap();
301 (if little_endian {
302 i32::from_le_bytes(bytes)
303 } else {
304 i32::from_be_bytes(bytes)
305 }) as f64
306 };
307 }
308 }
309 3 => {
310 if bits_per_sample <= 16 {
311 return |buffer: &[u8], offset: usize, little_endian: bool| -> f64 {
312 let f16_offset = offset / 2;
313 let bytes = [buffer[f16_offset], buffer[f16_offset + 1]];
314 let value = if little_endian {
315 f16::from_le_bytes(bytes)
316 } else {
317 f16::from_be_bytes(bytes)
318 };
319 value.to_f64()
320 };
321 } else if bits_per_sample <= 32 {
322 return |buffer: &[u8], offset: usize, little_endian: bool| -> f64 {
323 let start = offset / 4;
324 let bytes: [u8; 4] = buffer[start..start + 4].try_into().unwrap();
325 (if little_endian {
326 f32::from_le_bytes(bytes)
327 } else {
328 f32::from_be_bytes(bytes)
329 }) as f64
330 };
331 } else if bits_per_sample <= 64 {
332 return |buffer: &[u8], offset: usize, little_endian: bool| -> f64 {
333 let start = offset / 8;
334 let bytes: [u8; 8] = buffer[start..start + 8].try_into().unwrap();
335 if little_endian {
336 f64::from_le_bytes(bytes)
337 } else {
338 f64::from_be_bytes(bytes)
339 }
340 };
341 }
342 }
343 _ => {}
344 }
345 panic!("Unsupported data format/bits_per_sample: {format} / {bits_per_sample}");
346}