From 5c9e78b758d3d19c79b5fdb035efaf8a320b3dd6 Mon Sep 17 00:00:00 2001 From: Max Jones <14077947+maxrjones@users.noreply.github.com> Date: Thu, 6 Nov 2025 18:49:28 -0500 Subject: [PATCH 1/7] Add failing test for unknown tag --- README.md | 1 + src/cog.rs | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/README.md b/README.md index e7ec72e..e7998b5 100644 --- a/README.md +++ b/README.md @@ -24,4 +24,5 @@ Download the following file for use in the tests. ```shell aws s3 cp s3://naip-visualization/ny/2022/60cm/rgb/40073/m_4007307_sw_18_060_20220803.tif ./ --request-payer +aws s3 cp s3://"prd-tnm/StagedProducts/Elevation/13/TIFF/current/s14w171/USGS_13_s14w171.tif" ./ --no-sign-request --region us-west-2 ``` diff --git a/src/cog.rs b/src/cog.rs index 99a0f14..0f06cae 100644 --- a/src/cog.rs +++ b/src/cog.rs @@ -55,6 +55,26 @@ mod test { std::fs::write("img.buf", tile).unwrap(); } + #[ignore = "local file"] + #[tokio::test] + #[should_panic(expected = "Unknown GeoKeyTag id: {key_id}: TryFromPrimitiveError { number: 2062 }")] + async fn tmp_towg84() { + let folder = "/Users/kyle/github/developmentseed/async-tiff"; + let path = object_store::path::Path::parse("USGS_13_s14w171.tif").unwrap(); + let store = Arc::new(LocalFileSystem::new_with_prefix(folder).unwrap()); + let reader = Arc::new(ObjectReader::new(store, path)) as Arc; + let prefetch_reader = PrefetchBuffer::new(reader.clone(), 32 * 1024) + .await + .unwrap(); + let mut metadata_reader = TiffMetadataReader::try_open(&prefetch_reader) + .await + .unwrap(); + let _ = metadata_reader + .read_all_ifds(&prefetch_reader) + .await + .unwrap(); + } + #[ignore = "local file"] #[test] fn tmp_tiff_example() { From e1b94ccd226813ac963546341c13a12b87bdd275 Mon Sep 17 00:00:00 2001 From: Max Jones <14077947+maxrjones@users.noreply.github.com> Date: Thu, 6 Nov 2025 18:54:56 -0500 Subject: [PATCH 2/7] Lint --- src/cog.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cog.rs b/src/cog.rs index 0f06cae..82c7940 100644 --- a/src/cog.rs +++ b/src/cog.rs @@ -57,7 +57,9 @@ mod test { #[ignore = "local file"] #[tokio::test] - #[should_panic(expected = "Unknown GeoKeyTag id: {key_id}: TryFromPrimitiveError { number: 2062 }")] + #[should_panic( + expected = "Unknown GeoKeyTag id: {key_id}: TryFromPrimitiveError { number: 2062 }" + )] async fn tmp_towg84() { let folder = "/Users/kyle/github/developmentseed/async-tiff"; let path = object_store::path::Path::parse("USGS_13_s14w171.tif").unwrap(); From ea52a2aec0d97b1b78505f8adba8411eaa607ecb Mon Sep 17 00:00:00 2001 From: Max Jones <14077947+maxrjones@users.noreply.github.com> Date: Thu, 6 Nov 2025 19:11:48 -0500 Subject: [PATCH 3/7] Add support for tag --- src/cog.rs | 5 +---- src/geo/geo_key_directory.rs | 5 +++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cog.rs b/src/cog.rs index 82c7940..9d8fac2 100644 --- a/src/cog.rs +++ b/src/cog.rs @@ -57,10 +57,7 @@ mod test { #[ignore = "local file"] #[tokio::test] - #[should_panic( - expected = "Unknown GeoKeyTag id: {key_id}: TryFromPrimitiveError { number: 2062 }" - )] - async fn tmp_towg84() { + async fn tmp_towgs84() { let folder = "/Users/kyle/github/developmentseed/async-tiff"; let path = object_store::path::Path::parse("USGS_13_s14w171.tif").unwrap(); let store = Arc::new(LocalFileSystem::new_with_prefix(folder).unwrap()); diff --git a/src/geo/geo_key_directory.rs b/src/geo/geo_key_directory.rs index acf9aa2..e341b98 100644 --- a/src/geo/geo_key_directory.rs +++ b/src/geo/geo_key_directory.rs @@ -32,6 +32,7 @@ pub(crate) enum GeoKeyTag { GeogInvFlattening = 2059, GeogAzimuthUnits = 2060, GeogPrimeMeridianLong = 2061, + GeogToWGS84 = 2062, // Projected CRS Parameter Keys ProjectedType = 3072, @@ -101,6 +102,7 @@ pub struct GeoKeyDirectory { /// defined by its longitude relative to the international reference meridian (for the earth /// this is Greenwich). pub geog_prime_meridian_long: Option, + pub geog_to_wgs84: Option>, pub projected_type: Option, pub proj_citation: Option, @@ -154,6 +156,7 @@ impl GeoKeyDirectory { let mut geog_inv_flattening = None; let mut geog_azimuth_units = None; let mut geog_prime_meridian_long = None; + let mut geog_to_wgs84 = None; let mut projected_type = None; let mut proj_citation = None; @@ -206,6 +209,7 @@ impl GeoKeyDirectory { GeoKeyTag::GeogPrimeMeridianLong => { geog_prime_meridian_long = Some(value.into_f64()?) } + GeoKeyTag::GeogToWGS84 => geog_to_wgs84 = Some(value.into_f64_vec()?), GeoKeyTag::ProjectedType => projected_type = Some(value.into_u16()?), GeoKeyTag::ProjCitation => proj_citation = Some(value.into_string()?), GeoKeyTag::Projection => projection = Some(value.into_u16()?), @@ -265,6 +269,7 @@ impl GeoKeyDirectory { geog_inv_flattening, geog_azimuth_units, geog_prime_meridian_long, + geog_to_wgs84, projected_type, proj_citation, From 01a00a07728ebea7ff75ee0b398fd535a8d91b1c Mon Sep 17 00:00:00 2001 From: Max Jones <14077947+maxrjones@users.noreply.github.com> Date: Thu, 6 Nov 2025 19:19:40 -0500 Subject: [PATCH 4/7] Add bindings --- python/DEVELOP.md | 1 + python/src/geo.rs | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/python/DEVELOP.md b/python/DEVELOP.md index 3b97be2..30d0ddc 100644 --- a/python/DEVELOP.md +++ b/python/DEVELOP.md @@ -2,4 +2,5 @@ uv sync --no-install-package async-tiff uv run --no-project maturin develop uv run --no-project mkdocs serve +uv run --no-project pytest --verbose ``` diff --git a/python/src/geo.rs b/python/src/geo.rs index ef33e71..63f8df9 100644 --- a/python/src/geo.rs +++ b/python/src/geo.rs @@ -37,7 +37,8 @@ pub(crate) struct PyGeoKeyDirectory { geog_azimuth_units: Option, #[pyo3(get)] geog_prime_meridian_long: Option, - + #[pyo3(get)] + geog_to_wgs84: Option>, #[pyo3(get)] projected_type: Option, #[pyo3(get)] @@ -117,6 +118,7 @@ impl From for GeoKeyDirectory { geog_inv_flattening: value.geog_inv_flattening, geog_azimuth_units: value.geog_azimuth_units, geog_prime_meridian_long: value.geog_prime_meridian_long, + geog_to_wgs84: value.geog_to_wgs84, projected_type: value.projected_type, proj_citation: value.proj_citation, projection: value.projection, @@ -169,6 +171,7 @@ impl From for PyGeoKeyDirectory { geog_inv_flattening: value.geog_inv_flattening, geog_azimuth_units: value.geog_azimuth_units, geog_prime_meridian_long: value.geog_prime_meridian_long, + geog_to_wgs84: value.geog_to_wgs84, projected_type: value.projected_type, proj_citation: value.proj_citation, projection: value.projection, From 786a51f1813c683421730b6cf0019140039d7572 Mon Sep 17 00:00:00 2001 From: Max Jones <14077947+maxrjones@users.noreply.github.com> Date: Thu, 6 Nov 2025 19:27:22 -0500 Subject: [PATCH 5/7] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e7998b5..b124c1e 100644 --- a/README.md +++ b/README.md @@ -24,5 +24,5 @@ Download the following file for use in the tests. ```shell aws s3 cp s3://naip-visualization/ny/2022/60cm/rgb/40073/m_4007307_sw_18_060_20220803.tif ./ --request-payer -aws s3 cp s3://"prd-tnm/StagedProducts/Elevation/13/TIFF/current/s14w171/USGS_13_s14w171.tif" ./ --no-sign-request --region us-west-2 +aws s3 cp s3://prd-tnm/StagedProducts/Elevation/13/TIFF/current/s14w171/USGS_13_s14w171.tif ./ --no-sign-request --region us-west-2 ``` From 0f4ba6a88867aa4a3990cb873ca65ffe8e9a850b Mon Sep 17 00:00:00 2001 From: Max Jones <14077947+maxrjones@users.noreply.github.com> Date: Mon, 10 Nov 2025 09:49:50 -0500 Subject: [PATCH 6/7] Add docstring --- python/src/geo.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/src/geo.rs b/python/src/geo.rs index 63f8df9..e4611cc 100644 --- a/python/src/geo.rs +++ b/python/src/geo.rs @@ -38,6 +38,8 @@ pub(crate) struct PyGeoKeyDirectory { #[pyo3(get)] geog_prime_meridian_long: Option, #[pyo3(get)] + /// Note: This is not part of the official GeoTIFF specification but is a proposed extension. + /// See https://trac.osgeo.org/geotiff/wiki/TOWGS84GeoKey. geog_to_wgs84: Option>, #[pyo3(get)] projected_type: Option, From e4cecf55414746d82e956fdf2fddc4e6ddf19340 Mon Sep 17 00:00:00 2001 From: Max Jones <14077947+maxrjones@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:05:31 -0500 Subject: [PATCH 7/7] Add tiny test --- src/cog.rs | 19 ---------- tests/geogtowgs_tiff.rs | 31 ++++++++++++++++ .../geogtowgs_subset_USGS_13_s14w171.tif | Bin 0 -> 317 bytes tests/images/readme.md | 35 ++++++++++++++++++ 4 files changed, 66 insertions(+), 19 deletions(-) create mode 100644 tests/geogtowgs_tiff.rs create mode 100644 tests/images/geogtowgs_subset_USGS_13_s14w171.tif create mode 100644 tests/images/readme.md diff --git a/src/cog.rs b/src/cog.rs index 9d8fac2..99a0f14 100644 --- a/src/cog.rs +++ b/src/cog.rs @@ -55,25 +55,6 @@ mod test { std::fs::write("img.buf", tile).unwrap(); } - #[ignore = "local file"] - #[tokio::test] - async fn tmp_towgs84() { - let folder = "/Users/kyle/github/developmentseed/async-tiff"; - let path = object_store::path::Path::parse("USGS_13_s14w171.tif").unwrap(); - let store = Arc::new(LocalFileSystem::new_with_prefix(folder).unwrap()); - let reader = Arc::new(ObjectReader::new(store, path)) as Arc; - let prefetch_reader = PrefetchBuffer::new(reader.clone(), 32 * 1024) - .await - .unwrap(); - let mut metadata_reader = TiffMetadataReader::try_open(&prefetch_reader) - .await - .unwrap(); - let _ = metadata_reader - .read_all_ifds(&prefetch_reader) - .await - .unwrap(); - } - #[ignore = "local file"] #[test] fn tmp_tiff_example() { diff --git a/tests/geogtowgs_tiff.rs b/tests/geogtowgs_tiff.rs new file mode 100644 index 0000000..94e3142 --- /dev/null +++ b/tests/geogtowgs_tiff.rs @@ -0,0 +1,31 @@ +#[cfg(test)] +mod test { + use std::env; + use std::sync::Arc; + + use async_tiff::metadata::{PrefetchBuffer, TiffMetadataReader}; + use async_tiff::reader::{AsyncFileReader, ObjectReader}; + + use object_store::local::LocalFileSystem; + + #[tokio::test] + async fn tmp_towgs84() { + let folder = env::current_dir().unwrap(); + let path = + object_store::path::Path::parse("tests/images/geogtowgs_subset_USGS_13_s14w171.tif") + .unwrap(); + let store: Arc = + Arc::new(LocalFileSystem::new_with_prefix(folder).unwrap()); + let reader = Arc::new(ObjectReader::new(store, path)) as Arc; + let prefetch_reader = PrefetchBuffer::new(reader.clone(), 32 * 1024) + .await + .unwrap(); + let mut metadata_reader = TiffMetadataReader::try_open(&prefetch_reader) + .await + .unwrap(); + let _ = metadata_reader + .read_all_ifds(&prefetch_reader) + .await + .unwrap(); + } +} diff --git a/tests/images/geogtowgs_subset_USGS_13_s14w171.tif b/tests/images/geogtowgs_subset_USGS_13_s14w171.tif new file mode 100644 index 0000000000000000000000000000000000000000..1f21e29d62d4ebb17b5767186c01ca66befb8dbf GIT binary patch literal 317 zcmebD)MAieU|^`2!^pz$`~L^!l9R0Wm;xF27#J9t85n^wV2s3Og0dBWa?DUR2awH% zq(%^E7)T#TTog%M42dlcRl^TdBZDL!3}rI|#n-npGpGRRV?ey2ori%HNb>;=-q_B> zzz$@afh++6Mwo3ZAT|>N&}fJl&;g7LYXulNHny_?)vO>hh-rVj_-cHo+7)X$N?mP4fr{_SQytZ005_j9Pa=C literal 0 HcmV?d00001 diff --git a/tests/images/readme.md b/tests/images/readme.md new file mode 100644 index 0000000..94efdd0 --- /dev/null +++ b/tests/images/readme.md @@ -0,0 +1,35 @@ +`geogtowgs_subset_USGS_13_s14w171.tif` was created from "s3://prd-tnm/StagedProducts/Elevation/13/TIFF/current/s14w171/USGS_13_s14w171.tif" using these commands: + +```bash +gdal_translate USGS_13_s14w171.tif tiny.tif -srcwin 0 0 1 1 -co COMPRESS=DEFLATE +listgeo USGS_13_s14w171.tif > metadata.txt # Then modify to remove information related to spatial extent +cp tiny.tif geogtowgs_subset_USGS_13_s14w171.tif +geotifcp -g metadata.txt tiny.tif geogtowgs_subset_USGS_13_s14w171.tif +listgeo geogtowgs_subset_USGS_13_s14w171.tif +``` + +and this workspace definition: + +```toml +[project] +name = "gdal-workspace" +version = "0.1.0" +description = "workspace for using gdal via pixi" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [] + +[tool.pixi.workspace] +channels = ["conda-forge"] +platforms = ["osx-arm64"] + +[tool.pixi.pypi-dependencies] +gdal-workspace = { path = ".", editable = true } + +[tool.pixi.tasks] + +[tool.pixi.dependencies] +gdal = ">=3.11.5,<4" +libgdal = ">=3.11.5,<4" +geotiff = ">=1.7.4,<2" +``` \ No newline at end of file