1use super::decoder::Decoder;
2use crate::{
3 parsers::{RGBA, Reader},
4 proj::Transformer,
5 readers::{
6 FieldTagNames, GTiffDataType, GeoKeyDirectoryKeys, GeoTIFFVectorFeature, GeoTiePoint,
7 ImageDirectory, PhotometricInterpretations, apply_predictor, build_samples,
8 build_transform_from_geo_keys, convert_color_space, geotiff::decoder::get_decoder,
9 get_reader_for_sample, needs_normalization, normalize_array, sample_sum,
10 },
11};
12use alloc::{rc::Rc, vec, vec::Vec};
13use core::cell::RefCell;
14use half::f16;
15use libm::{fmax, fmin, pow, round, sqrt};
16use s2json::{BBox, Properties, VectorGeometry, VectorMultiPoint, VectorPoint};
17
18#[derive(Debug, Clone, Default, PartialEq)]
20pub struct GeoTIFFMetadata {
21 pub height: usize,
23 pub width: usize,
25 pub alpha: bool,
27}
28
29#[derive(Debug, Clone, Default, PartialEq)]
31pub struct Raster {
32 pub width: usize,
34 pub height: usize,
36 pub r#type: GTiffDataType,
38 pub data: Vec<f64>,
40 pub alpha: bool,
42 pub min: f64,
44 pub max: f64,
46}
47impl Raster {
48 pub fn to_u8s(&self) -> Vec<u8> {
50 self.data.iter().map(|x| round(fmax(0., fmin(255., *x))) as u8).collect()
51 }
52 pub fn to_u16s(&self) -> Vec<u16> {
54 self.data.iter().map(|x| round(fmax(0., fmin(65535., *x))) as u16).collect()
55 }
56 pub fn to_u32s(&self) -> Vec<u32> {
58 self.data.iter().map(|x| round(fmax(0., fmin(4294967295., *x))) as u32).collect()
59 }
60 pub fn to_i8s(&self) -> Vec<i8> {
62 self.data.iter().map(|x| round(fmax(-128., fmin(127., *x))) as i8).collect()
63 }
64 pub fn to_i16s(&self) -> Vec<i16> {
66 self.data.iter().map(|x| round(fmax(-32768., fmin(32767., *x))) as i16).collect()
67 }
68 pub fn to_i32s(&self) -> Vec<i32> {
70 self.data.iter().map(|x| round(fmax(-2147483648., fmin(2147483647., *x))) as i32).collect()
71 }
72 pub fn to_f16s(&self) -> Vec<f16> {
74 self.data.iter().map(|x| f16::from_f64(*x)).collect()
75 }
76 pub fn to_f32s(&self) -> Vec<f32> {
78 self.data.iter().map(|x| *x as f32).collect()
79 }
80}
81
82pub type SampleReader = fn(buffer: &[u8], offset: usize, little_endian: bool) -> f64;
84
85pub struct SampleFormat {
87 pub src_sample_offsets: Vec<u32>,
89 pub sample_readers: Vec<SampleReader>,
91}
92
93#[derive(Debug, Clone, Default)]
127pub struct GeoTIFFImage<T: Reader> {
128 reader: Rc<RefCell<T>>,
129 image_directory: ImageDirectory,
130 little_endian: bool,
131 is_tiled: bool,
132 transformer: Rc<RefCell<Transformer>>,
133 decode_fn: Option<Decoder>,
134 src_sample_offsets: Vec<u32>,
135 sample_readers: Vec<SampleReader>,
136 planar_configuration: i16,
137}
138impl<T: Reader> GeoTIFFImage<T> {
139 pub fn new(
141 reader: Rc<RefCell<T>>,
142 image_directory: ImageDirectory,
143 transformer: Rc<RefCell<Transformer>>,
144 little_endian: bool,
145 ) -> Self {
146 build_transform_from_geo_keys(
147 &mut transformer.borrow_mut(),
148 &image_directory.geo_key_directory,
149 );
150 let compression = image_directory.variables.get_short(FieldTagNames::Compression as u16);
151 let planar_configuration = image_directory
152 .variables
153 .get_short(FieldTagNames::PlanarConfiguration as u16)
154 .unwrap_or(1);
155 let is_tiled = !image_directory.variables.has(FieldTagNames::StripOffsets as u16);
156 Self {
157 reader,
158 image_directory,
159 little_endian,
160 is_tiled,
161 transformer,
162 decode_fn: get_decoder(compression.map(|v| v as u16)),
163 src_sample_offsets: Vec::new(),
164 sample_readers: Vec::new(),
165 planar_configuration,
166 }
167 }
168
169 pub fn width(&self) -> usize {
171 self.image_directory.variables.get_short(FieldTagNames::ImageWidth as u16).unwrap_or(0)
172 as usize
173 }
174
175 pub fn height(&self) -> usize {
177 self.image_directory.variables.get_short(FieldTagNames::ImageLength as u16).unwrap_or(0)
178 as usize
179 }
180
181 pub fn tile_width(&self) -> usize {
183 if self.is_tiled {
184 self.image_directory.variables.get_short(FieldTagNames::TileWidth as u16).unwrap_or(0)
185 as usize
186 } else {
187 self.width()
188 }
189 }
190
191 pub fn tile_height(&self) -> usize {
193 if self.is_tiled {
194 self.image_directory.variables.get_short(FieldTagNames::TileLength as u16).unwrap_or(0)
195 as usize
196 } else {
197 let rows_per_strip = self
198 .image_directory
199 .variables
200 .get_short(FieldTagNames::RowsPerStrip as u16)
201 .unwrap_or(0) as usize;
202 self.height().min(rows_per_strip)
203 }
204 }
205
206 pub fn block_width(&self) -> usize {
208 self.tile_width()
209 }
210
211 pub fn block_height(&self, y: usize) -> usize {
213 let tile_height = self.tile_height();
214 let height = self.height();
215 if self.is_tiled || (y + 1) * tile_height <= height {
216 tile_height
217 } else {
218 height - y * tile_height
219 }
220 }
221
222 pub fn bytes_per_pixel(&self) -> usize {
228 let bits_per_sample = self
229 .image_directory
230 .variables
231 .get_u16s(FieldTagNames::BitsPerSample as u16)
232 .unwrap_or_default();
233 let mut bytes = 0;
234 for bit in &bits_per_sample {
235 bytes += (*bit).div_ceil(8) as usize;
236 }
237 bytes
238 }
239
240 pub fn samples_per_pixel(&self) -> usize {
243 self.image_directory.variables.get_short(FieldTagNames::SamplesPerPixel as u16).unwrap_or(1)
244 as usize
245 }
246
247 pub fn get_sample_format(&self, sample_index: Option<usize>) -> u16 {
255 let sample_index = sample_index.unwrap_or(0);
256 *self
257 .image_directory
258 .variables
259 .get_u16s(FieldTagNames::SampleFormat as u16)
260 .unwrap_or_default()
261 .get(sample_index)
262 .unwrap_or(&1)
263 }
264
265 pub fn get_bits_per_sample(&self, sample_index: Option<usize>) -> u16 {
273 let sample_index = sample_index.unwrap_or(0);
274 *self
275 .image_directory
276 .variables
277 .get_u16s(FieldTagNames::BitsPerSample as u16)
278 .unwrap_or_default()
279 .get(sample_index)
280 .unwrap_or(&0)
281 }
282
283 pub fn raster_array_type(&self) -> GTiffDataType {
291 let format = self.get_sample_format(None);
292 let bits_per_sample = self.get_bits_per_sample(None);
293 GTiffDataType::to_type(format, bits_per_sample)
294 }
295
296 pub fn get_tie_point(&self) -> GeoTiePoint {
298 self.image_directory.tie_point
299 }
300
301 pub fn origin(&self) -> VectorPoint<()> {
307 let tiepoint = self.get_tie_point();
316 VectorPoint::new_xyz(tiepoint.x, tiepoint.y, tiepoint.z, None)
317 }
318
319 pub fn origin_ll(&self) -> VectorPoint<()> {
325 let mut origin = self.origin();
326 self.transformer.borrow_mut().forward_mut(&mut origin);
327 origin
328 }
329
330 pub fn resolution(&self) -> VectorPoint<()> {
337 let pixel_scale = self.image_directory.pixel_scale;
339 if pixel_scale.x != 0. || pixel_scale.y != 0. || pixel_scale.z != 0. {
340 return VectorPoint::new_xyz(pixel_scale.x, -pixel_scale.y, pixel_scale.z, None);
341 }
342 let transform = self
344 .image_directory
345 .variables
346 .getf64s(FieldTagNames::ModelTransformation as u16)
347 .unwrap_or_else(|| panic!("The image does not have an affine transformation."));
348 if transform[1] == 0. && transform[4] == 0. {
349 VectorPoint::new_xyz(transform[0], -transform[5], transform[10], None)
350 } else {
351 let x = sqrt(transform[0] * transform[0] + transform[4] * transform[4]);
352 let y = -sqrt(transform[1] * transform[1] + transform[5] * transform[5]);
353 let z = transform[10];
354 VectorPoint::new_xyz(x, y, z, None)
355 }
356 }
357
358 pub fn resolution_ll(&self) -> VectorPoint<()> {
365 let mut resolution = self.resolution();
366 self.transformer.borrow_mut().forward_mut(&mut resolution);
367 resolution
368 }
369
370 pub fn pixel_is_area(&self) -> bool {
375 self.image_directory
376 .geo_key_directory
377 .get_short(GeoKeyDirectoryKeys::GTRasterTypeGeoKey as u16)
378 .unwrap_or(0)
379 == 1
380 }
381
382 pub fn get_bbox(&mut self, transform: bool) -> BBox {
392 let height = self.height() as f64;
393 let width = self.width() as f64;
394 let model_transformation =
395 self.image_directory.variables.getf64s(FieldTagNames::ModelTransformation as u16);
396
397 if transform && let Some(model_transformation) = model_transformation {
398 let [a, b, _c, d, e, f, _g, h] = model_transformation[..8].try_into().unwrap();
399 let corners = [[0., 0.], [0., height], [width, 0.], [width, height]];
400 let projected = corners.map(|[_i, _j]| [d + a * _i + b * _j, h + e * _i + f * _j]);
401 let xs = projected.map(|pt| pt[0]);
402 let ys = projected.map(|pt| pt[1]);
403
404 BBox::new(
405 xs.iter().copied().fold(f64::INFINITY, fmin),
406 ys.iter().copied().fold(f64::INFINITY, fmin),
407 xs.iter().copied().fold(f64::NEG_INFINITY, fmax),
408 ys.iter().copied().fold(f64::NEG_INFINITY, fmax),
409 )
410 } else {
411 let VectorPoint { x: x1, y: y1, .. } = self.origin();
412 let VectorPoint { x: r1, y: r2, .. } = self.resolution();
413 let x2 = x1 + r1 * width;
414 let y2 = y1 + r2 * height;
415 let min_x = fmin(x1, x2);
416 let min_y = fmin(y1, y2);
417 let max_x = fmax(x1, x2);
418 let max_y = fmax(y1, y2);
419
420 if transform {
421 let mut min_vec: VectorPoint<()> = VectorPoint::new_xy(min_x, min_y, None);
422 self.transformer.borrow_mut().forward_mut(&mut min_vec);
423 let mut max_vec: VectorPoint<()> = VectorPoint::new_xy(max_x, max_y, None);
424 self.transformer.borrow_mut().forward_mut(&mut max_vec);
425 BBox::new(min_vec.x, min_vec.y, max_vec.x, max_vec.y)
426 } else {
427 BBox::new(min_x, min_y, max_x, max_y)
428 }
429 }
430 }
431
432 pub fn raster_data(&mut self, samples: Option<Vec<u16>>) -> Raster {
440 let samples =
441 samples.unwrap_or_else(|| (0..self.samples_per_pixel()).map(|v| v as u16).collect());
442 let tile_width = self.tile_width();
444 let tile_height = self.tile_height();
445 let width = self.width();
446 let height = self.height();
447 let sample_per_pixel = self.samples_per_pixel();
448 let bits_per_sample = self
449 .image_directory
450 .variables
451 .get_u16s(FieldTagNames::BitsPerSample as u16)
452 .unwrap_or_default();
453 let mut bytes_per_pixel = self.bytes_per_pixel();
454 let SampleFormat { src_sample_offsets, sample_readers } =
455 self.get_sample_offsets_and_readers(&bits_per_sample, &samples);
456
457 let mut res: Vec<f64> = vec![0.0; width * height * sample_per_pixel];
458 let mut min = f64::INFINITY;
459 let mut max = f64::NEG_INFINITY;
460 let max_x_tile = width.div_ceil(tile_width);
461 let max_y_tile = height.div_ceil(tile_height);
462 for y_tile in 0..max_y_tile {
463 for x_tile in 0..max_x_tile {
464 let mut data: Option<Vec<u8>> = None;
465 if self.planar_configuration == 1 {
466 data = Some(self.get_tile_or_strip(x_tile, y_tile, 0));
467 }
468 for sample_index in 0..samples.len() {
469 let si = sample_index;
470 let sample = samples[sample_index] as usize;
471 if self.planar_configuration == 2 {
472 bytes_per_pixel = bits_per_sample[sample].div_ceil(8) as usize;
473 data = Some(self.get_tile_or_strip(x_tile, y_tile, sample));
474 }
475 let data = data.as_ref().expect("data failed to load");
476 let block_height = self.block_height(y_tile);
477 let first_line = y_tile * tile_height;
478 let first_col = x_tile * tile_width;
479 let last_line = first_line + block_height;
480 let last_col = (x_tile + 1) * tile_width;
481 let reader = sample_readers[si];
482
483 let ymax = block_height
484 .min(
485 (block_height as isize - (last_line as isize - height as isize))
486 as usize,
487 )
488 .min(height - first_line);
489 let xmax = tile_width
490 .min((tile_width as isize - (last_col as isize - width as isize)) as usize)
491 .min(width - first_col);
492
493 for y in 0..ymax {
494 for x in 0..xmax {
495 let pixel_offset = (y * tile_width + x) * bytes_per_pixel;
496 let value = reader(
497 data,
498 pixel_offset + src_sample_offsets[si] as usize,
499 self.little_endian,
500 );
501 if !value.is_nan() {
502 min = min.min(value);
503 max = max.max(value);
504 }
505 let window_coordinate = (y + first_line) * width * samples.len()
506 + (x + first_col) * samples.len()
507 + si;
508 res[window_coordinate] = value;
509 }
510 }
511 }
512 }
513 }
514
515 Raster {
516 r#type: self.raster_array_type(),
517 data: res,
518 width,
519 height,
520 alpha: false,
521 min,
522 max,
523 }
524 }
525
526 pub fn get_rgba(&mut self) -> Raster {
531 let bits_per_sample =
532 self.image_directory.variables.get_u16s(FieldTagNames::BitsPerSample as u16);
533 let extra_samples = self
534 .image_directory
535 .variables
536 .get_u16s(FieldTagNames::ExtraSamples as u16)
537 .unwrap_or_else(|| vec![0])[0];
538 let pi: PhotometricInterpretations = self
539 .image_directory
540 .variables
541 .get_short(FieldTagNames::PhotometricInterpretation as u16)
542 .unwrap_or(0)
543 .into();
544 let samples = build_samples(pi, bits_per_sample, Some(extra_samples.into()));
545
546 let mut raster_data = self.raster_data(Some(samples));
547 let max = pow(2., self.get_bits_per_sample(None) as f64);
548 convert_color_space(
549 pi,
550 &mut raster_data,
551 max,
552 self.image_directory.variables.get_u16s(FieldTagNames::ColorMap as u16),
553 );
554 raster_data.alpha = extra_samples != 0;
555
556 raster_data
557 }
558
559 pub fn get_multi_point_vector(&mut self) -> GeoTIFFVectorFeature {
564 let Raster { width, height, alpha, data, .. } = self.get_rgba();
565 let bbox = self.get_bbox(false);
566 let BBox { left: min_x, bottom: min_y, right: max_x, top: max_y } = bbox;
567 let mut coordinates: VectorMultiPoint<RGBA> = vec![];
568 let rgba_stride = if alpha { 4 } else { 3 };
569 let bound_x = if min_x == max_x { 1. } else { max_x - min_x };
570 let bound_y = if min_y == max_y { 1. } else { max_y - min_y };
571 let area_x_stride =
572 if self.pixel_is_area() { (0.5 / (width as f64)) * bound_x } else { 0. };
573 let area_y_stride =
574 if self.pixel_is_area() { (0.5 / (height as f64)) * bound_y } else { 0. };
575 let pixel_x_stride = if width == 1 { 1 } else { width - 1 };
576 let pixel_y_stride = if height == 1 { 1 } else { height - 1 };
577
578 for y in 0..height {
579 for x in 0..width {
580 let x_pos =
582 min_x + ((x as f64) / (pixel_x_stride as f64)) * bound_x + area_x_stride;
583 let y_pos =
584 min_y + ((y as f64) / (pixel_y_stride as f64)) * bound_y + area_y_stride;
585 let r = data[y * width * rgba_stride + x * rgba_stride];
587 let g = data[y * width * rgba_stride + x * rgba_stride + 1];
588 let b = data[y * width * rgba_stride + x * rgba_stride + 2];
589 let a =
590 if alpha { data[y * width * rgba_stride + x * rgba_stride + 3] } else { 255. };
591 let mut point: VectorPoint<RGBA> = VectorPoint::new_xy(
593 x_pos,
594 y_pos,
595 Some(RGBA { r: r / 255., g: g / 255., b: b / 255., a: a / 255. }),
596 );
597 self.transformer.borrow_mut().forward_mut(&mut point);
598 coordinates.push(point);
600 }
601 }
602
603 GeoTIFFVectorFeature::new_wm(
604 None,
605 Properties::default(),
606 VectorGeometry::new_multipoint(coordinates, Some(bbox.into())),
607 Some(GeoTIFFMetadata { width, height, alpha }),
608 )
609 }
610
611 fn get_tile_or_strip(&mut self, x: usize, y: usize, sample: usize) -> Vec<u8> {
621 let num_tiles_per_row = self.width().div_ceil(self.tile_width());
622 let num_tiles_per_col = self.height().div_ceil(self.tile_height());
623 let index = if self.planar_configuration == 1 {
624 y * num_tiles_per_row + x
625 } else if self.planar_configuration == 2 {
626 sample * num_tiles_per_row * num_tiles_per_col + y * num_tiles_per_row + x
627 } else {
628 0
629 };
630
631 let tile_offsets = self
632 .image_directory
633 .variables
634 .get_u32s(FieldTagNames::TileOffsets as u16)
635 .unwrap_or_default();
636 let tile_byte_counts = self
637 .image_directory
638 .variables
639 .get_u32s(FieldTagNames::TileByteCounts as u16)
640 .unwrap_or_default();
641 let strip_offsets = self
642 .image_directory
643 .variables
644 .get_u32s(FieldTagNames::StripOffsets as u16)
645 .unwrap_or_default();
646 let strip_byte_counts = self
647 .image_directory
648 .variables
649 .get_u32s(FieldTagNames::StripByteCounts as u16)
650 .unwrap_or_default();
651
652 let offset = if self.is_tiled { tile_offsets.get(index) } else { strip_offsets.get(index) };
653 let byte_count =
654 if self.is_tiled { tile_byte_counts.get(index) } else { strip_byte_counts.get(index) };
655 if offset.is_none() || byte_count.is_none() {
656 panic!("Invalid offset or byte count");
657 }
658 let offset = *offset.unwrap() as u64;
659 let byte_count = *byte_count.unwrap() as u64;
660 let slice = self.reader.borrow_mut().slice(Some(offset), Some(offset + byte_count));
661 let mut data = if let Some(decode_fn) = &mut self.decode_fn {
662 decode_fn(
663 &slice,
664 self.image_directory
665 .variables
666 .get(FieldTagNames::JPEGTables as u16)
667 .map(|v| v.0)
668 .as_deref(),
669 )
670 } else {
671 slice
672 };
673 data = self.maybe_apply_predictor(data);
674 let sample_format = self.get_sample_format(None) as usize;
675 let bits_per_sample = self.get_bits_per_sample(None) as usize;
676
677 if needs_normalization(sample_format, bits_per_sample) {
678 normalize_array(
679 data,
680 sample_format,
681 self.planar_configuration as usize,
682 self.samples_per_pixel(),
683 bits_per_sample,
684 self.tile_width(),
685 self.block_height(y),
686 )
687 } else {
688 data
690 }
691 }
692
693 fn maybe_apply_predictor(&mut self, data: Vec<u8>) -> Vec<u8> {
701 let predictor =
702 self.image_directory.variables.get_short(FieldTagNames::Predictor as u16).unwrap_or(1);
703 if predictor == 1 {
704 data
705 } else {
706 let tile_width = if self.is_tiled { self.tile_width() } else { self.width() };
707 let tile_height = if self.is_tiled {
708 self.tile_height()
709 } else {
710 let val = self
711 .image_directory
712 .variables
713 .get_short(FieldTagNames::RowsPerStrip as u16)
714 .unwrap_or_else(|| self.height() as i16);
715 val as usize
716 };
717 let bits_per_sample = self
718 .image_directory
719 .variables
720 .get_u16s(FieldTagNames::BitsPerSample as u16)
721 .unwrap_or_default();
722 apply_predictor(
723 data,
724 predictor,
725 tile_width,
726 tile_height,
727 bits_per_sample,
728 self.planar_configuration,
729 )
730 }
731 }
732
733 fn get_sample_offsets_and_readers(
742 &mut self,
743 bits_per_sample: &[u16],
744 samples: &[u16],
745 ) -> SampleFormat {
746 if self.src_sample_offsets.is_empty()
747 && self.sample_readers.is_empty()
748 && samples.len() == self.sample_readers.len()
749 {
750 return SampleFormat {
751 src_sample_offsets: self.src_sample_offsets.clone(),
752 sample_readers: self.sample_readers.clone(),
753 };
754 }
755 let mut src_sample_offsets: Vec<u32> = vec![];
756 let mut sample_readers = vec![];
757 for sample in samples.iter() {
758 if self.planar_configuration == 1 {
759 src_sample_offsets
760 .push((sample_sum(bits_per_sample, 0, *sample as usize) / 8) as u32);
761 } else {
762 src_sample_offsets.push(0);
763 }
764 let format = self.get_sample_format(Some(*sample as usize));
765 sample_readers.push(get_reader_for_sample(*sample, format));
766 }
767 self.src_sample_offsets = src_sample_offsets.clone();
768 self.sample_readers = sample_readers.clone();
769
770 SampleFormat { src_sample_offsets, sample_readers }
771 }
772}
773
774