Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions python/python/async_tiff/_geo.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
from collections.abc import Iterable
from typing import Any

class GeoKeyDirectory:
def keys(self) -> list[str]:
"""A list of string keys representing the GeoKey fields."""
def __eq__(self, value: object) -> bool: ...
def __iter__(self) -> Iterable[str]:
"""An iterable of string keys representing the GeoKey fields."""
def __getitem__(self, key: str) -> Any:
"""Access GeoKey fields by string key."""

@property
def model_type(self) -> int | None: ...
@property
Expand Down
10 changes: 10 additions & 0 deletions python/python/async_tiff/_ifd.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from collections.abc import Iterable
from typing import Any
from .enums import (
CompressionMethod,
PhotometricInterpretation,
Expand All @@ -11,6 +13,14 @@ from ._geo import GeoKeyDirectory
Value = int | float | str | tuple[int, int] | list[Value]

class ImageFileDirectory:
def keys(self) -> list[str]:
"""A list of string keys representing the IFD fields."""
def __eq__(self, value: object) -> bool: ...
def __iter__(self) -> Iterable[str]:
"""An iterable of string keys representing the IFD fields."""
def __getitem__(self, key: str) -> Any:
"""Access IFD fields by string key."""

@property
def new_subfile_type(self) -> int | None: ...
@property
Expand Down
212 changes: 211 additions & 1 deletion python/src/geo.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use async_tiff::geo::GeoKeyDirectory;
use pyo3::prelude::*;
use pyo3::IntoPyObjectExt;

#[pyclass(name = "GeoKeyDirectory")]
#[pyclass(name = "GeoKeyDirectory", frozen, eq)]
#[derive(PartialEq)]
pub(crate) struct PyGeoKeyDirectory {
#[pyo3(get)]
model_type: Option<u16>,
Expand Down Expand Up @@ -97,6 +99,214 @@ pub(crate) struct PyGeoKeyDirectory {
vertical_units: Option<u16>,
}

#[pymethods]
impl PyGeoKeyDirectory {
/// This exists to implement the Mapping protocol, so we support `dict(gkd)`.`
fn keys(&self) -> Vec<&'static str> {
let mut keys = vec![];
if self.model_type.is_some() {
keys.push("model_type");
}
if self.raster_type.is_some() {
keys.push("raster_type");
}
if self.citation.is_some() {
keys.push("citation");
}
if self.geographic_type.is_some() {
keys.push("geographic_type");
}
if self.geog_citation.is_some() {
keys.push("geog_citation");
}
if self.geog_geodetic_datum.is_some() {
keys.push("geog_geodetic_datum");
}
if self.geog_prime_meridian.is_some() {
keys.push("geog_prime_meridian");
}
if self.geog_linear_units.is_some() {
keys.push("geog_linear_units");
}
if self.geog_linear_unit_size.is_some() {
keys.push("geog_linear_unit_size");
}
if self.geog_angular_units.is_some() {
keys.push("geog_angular_units");
}
if self.geog_angular_unit_size.is_some() {
keys.push("geog_angular_unit_size");
}
if self.geog_ellipsoid.is_some() {
keys.push("geog_ellipsoid");
}
if self.geog_semi_major_axis.is_some() {
keys.push("geog_semi_major_axis");
}
if self.geog_semi_minor_axis.is_some() {
keys.push("geog_semi_minor_axis");
}
if self.geog_inv_flattening.is_some() {
keys.push("geog_inv_flattening");
}
if self.geog_azimuth_units.is_some() {
keys.push("geog_azimuth_units");
}
if self.geog_prime_meridian_long.is_some() {
keys.push("geog_prime_meridian_long");
}
if self.projected_type.is_some() {
keys.push("projected_type");
}
if self.proj_citation.is_some() {
keys.push("proj_citation");
}
if self.projection.is_some() {
keys.push("projection");
}
if self.proj_coord_trans.is_some() {
keys.push("proj_coord_trans");
}
if self.proj_linear_units.is_some() {
keys.push("proj_linear_units");
}
if self.proj_linear_unit_size.is_some() {
keys.push("proj_linear_unit_size");
}
if self.proj_std_parallel1.is_some() {
keys.push("proj_std_parallel1");
}
if self.proj_std_parallel2.is_some() {
keys.push("proj_std_parallel2");
}
if self.proj_nat_origin_long.is_some() {
keys.push("proj_nat_origin_long");
}
if self.proj_nat_origin_lat.is_some() {
keys.push("proj_nat_origin_lat");
}
if self.proj_false_easting.is_some() {
keys.push("proj_false_easting");
}
if self.proj_false_northing.is_some() {
keys.push("proj_false_northing");
}
if self.proj_false_origin_long.is_some() {
keys.push("proj_false_origin_long");
}
if self.proj_false_origin_lat.is_some() {
keys.push("proj_false_origin_lat");
}
if self.proj_false_origin_easting.is_some() {
keys.push("proj_false_origin_easting");
}
if self.proj_false_origin_northing.is_some() {
keys.push("proj_false_origin_northing");
}
if self.proj_center_long.is_some() {
keys.push("proj_center_long");
}
if self.proj_center_lat.is_some() {
keys.push("proj_center_lat");
}
if self.proj_center_easting.is_some() {
keys.push("proj_center_easting");
}
if self.proj_center_northing.is_some() {
keys.push("proj_center_northing");
}
if self.proj_scale_at_nat_origin.is_some() {
keys.push("proj_scale_at_nat_origin");
}
if self.proj_scale_at_center.is_some() {
keys.push("proj_scale_at_center");
}
if self.proj_azimuth_angle.is_some() {
keys.push("proj_azimuth_angle");
}
if self.proj_straight_vert_pole_long.is_some() {
keys.push("proj_straight_vert_pole_long");
}
if self.vertical.is_some() {
keys.push("vertical");
}
if self.vertical_citation.is_some() {
keys.push("vertical_citation");
}
if self.vertical_datum.is_some() {
keys.push("vertical_datum");
}
if self.vertical_units.is_some() {
keys.push("vertical_units");
}

keys
}

/// This exists to implement the Mapping protocol, so we support `dict(gkd)`.`
fn __iter__<'py>(&'py self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
self.keys().into_pyobject(py)?.call_method0("__iter__")
}

/// Get a GeoKeyDirectory property by name
/// This exists to implement the Mapping protocol, so we support `dict(gkd)`.`
fn __getitem__<'py>(&self, py: Python<'py>, key: &str) -> PyResult<Bound<'py, PyAny>> {
match key {
"model_type" => self.model_type.into_bound_py_any(py),
"raster_type" => self.raster_type.into_bound_py_any(py),
"citation" => self.citation.as_ref().into_bound_py_any(py),
"geographic_type" => self.geographic_type.into_bound_py_any(py),
"geog_citation" => self.geog_citation.as_ref().into_bound_py_any(py),
"geog_geodetic_datum" => self.geog_geodetic_datum.into_bound_py_any(py),
"geog_prime_meridian" => self.geog_prime_meridian.into_bound_py_any(py),
"geog_linear_units" => self.geog_linear_units.into_bound_py_any(py),
"geog_linear_unit_size" => self.geog_linear_unit_size.into_bound_py_any(py),
"geog_angular_units" => self.geog_angular_units.into_bound_py_any(py),
"geog_angular_unit_size" => self.geog_angular_unit_size.into_bound_py_any(py),
"geog_ellipsoid" => self.geog_ellipsoid.into_bound_py_any(py),
"geog_semi_major_axis" => self.geog_semi_major_axis.into_bound_py_any(py),
"geog_semi_minor_axis" => self.geog_semi_minor_axis.into_bound_py_any(py),
"geog_inv_flattening" => self.geog_inv_flattening.into_bound_py_any(py),
"geog_azimuth_units" => self.geog_azimuth_units.into_bound_py_any(py),
"geog_prime_meridian_long" => self.geog_prime_meridian_long.into_bound_py_any(py),
"projected_type" => self.projected_type.into_bound_py_any(py),
"proj_citation" => self.proj_citation.as_ref().into_bound_py_any(py),
"projection" => self.projection.into_bound_py_any(py),
"proj_coord_trans" => self.proj_coord_trans.into_bound_py_any(py),
"proj_linear_units" => self.proj_linear_units.into_bound_py_any(py),
"proj_linear_unit_size" => self.proj_linear_unit_size.into_bound_py_any(py),
"proj_std_parallel1" => self.proj_std_parallel1.into_bound_py_any(py),
"proj_std_parallel2" => self.proj_std_parallel2.into_bound_py_any(py),
"proj_nat_origin_long" => self.proj_nat_origin_long.into_bound_py_any(py),
"proj_nat_origin_lat" => self.proj_nat_origin_lat.into_bound_py_any(py),
"proj_false_easting" => self.proj_false_easting.into_bound_py_any(py),
"proj_false_northing" => self.proj_false_northing.into_bound_py_any(py),
"proj_false_origin_long" => self.proj_false_origin_long.into_bound_py_any(py),
"proj_false_origin_lat" => self.proj_false_origin_lat.into_bound_py_any(py),
"proj_false_origin_easting" => self.proj_false_origin_easting.into_bound_py_any(py),
"proj_false_origin_northing" => self.proj_false_origin_northing.into_bound_py_any(py),
"proj_center_long" => self.proj_center_long.into_bound_py_any(py),
"proj_center_lat" => self.proj_center_lat.into_bound_py_any(py),
"proj_center_easting" => self.proj_center_easting.into_bound_py_any(py),
"proj_center_northing" => self.proj_center_northing.into_bound_py_any(py),
"proj_scale_at_nat_origin" => self.proj_scale_at_nat_origin.into_bound_py_any(py),
"proj_scale_at_center" => self.proj_scale_at_center.into_bound_py_any(py),
"proj_azimuth_angle" => self.proj_azimuth_angle.into_bound_py_any(py),
"proj_straight_vert_pole_long" => {
self.proj_straight_vert_pole_long.into_bound_py_any(py)
}
"vertical" => self.vertical.into_bound_py_any(py),
"vertical_citation" => self.vertical_citation.as_ref().into_bound_py_any(py),
"vertical_datum" => self.vertical_datum.into_bound_py_any(py),
"vertical_units" => self.vertical_units.into_bound_py_any(py),
_ => Err(pyo3::exceptions::PyKeyError::new_err(format!(
"Unknown IFD property: {}",
key
))),
}
}
}

impl From<PyGeoKeyDirectory> for GeoKeyDirectory {
fn from(value: PyGeoKeyDirectory) -> Self {
Self {
Expand Down
Loading