Skip to content

Apply TIFF Orientation tag in read_geotiff_gpu (#1540)#1546

Merged
brendancol merged 2 commits into
mainfrom
issue-1540
May 11, 2026
Merged

Apply TIFF Orientation tag in read_geotiff_gpu (#1540)#1546
brendancol merged 2 commits into
mainfrom
issue-1540

Conversation

@brendancol
Copy link
Copy Markdown
Contributor

Summary

  • read_geotiff_gpu now applies the TIFF Orientation tag (274) so the GPU and CPU readers return the same pixel buffer for every orientation.
  • Two helpers added: _apply_orientation_gpu (mirrors _apply_orientation on a cupy array) and _apply_orientation_geo_info (post-flip transform update used by both readers).
  • The stripped-fallback and CPU-fallback branches reuse the geo_info returned by read_to_array so the orientation update isn't applied twice.

Context

PR #1521 added _apply_orientation to the CPU path; the GPU pipeline never picked it up. Any TIFF carrying orientation 2-8 (cameras, scanners, some legacy GIS exports) silently disagreed across backends. See #1540 for the reproducer.

The PR also folds in the mirror-flip transform update from #1537 into a shared helper so both readers keep the same coord-fidelity guarantees. (#1537 covers the CPU side standalone; this PR is callable independently because _apply_orientation_geo_info is local to __init__.py.)

Test plan

  • pytest xrspatial/geotiff/tests/test_orientation_gpu.py -q (28 new tests: tiled, stripped, 3-band, mirror-flip sel-fidelity, default no-tag passthrough).
  • pytest xrspatial/geotiff/tests/test_orientation.py xrspatial/geotiff/tests/test_planar_multiband.py xrspatial/geotiff/tests/test_lerc_valid_mask_gpu.py xrspatial/geotiff/tests/test_predictor2_big_endian_gpu_1517.py xrspatial/geotiff/tests/test_gpu_byteswap_1508.py xrspatial/geotiff/tests/test_gpu_strict_fallback_1516.py xrspatial/geotiff/tests/test_gpu_stripped_multiband.py -q (127 passed).
  • pytest xrspatial/geotiff/tests/ -q --no-header --deselect xrspatial/geotiff/tests/test_features.py::TestPalette (960 passed; deselected tests fail on Python 3.14 / matplotlib deepcopy, unrelated).

Closes #1540.

PR #1521 wired up the Orientation tag (274) on the CPU read path but
left the GPU path on the raw stored buffer, so any TIFF written with
orientation 2-8 decoded to different pixel values on CPU vs GPU.

This adds two helpers in xrspatial/geotiff/__init__.py:

- _apply_orientation_gpu mirrors the CPU _apply_orientation slicing
  logic against a cupy ndarray (eight orientations, 2-D and 3-D
  variants).
- _apply_orientation_geo_info centralises the post-flip transform
  update so both read_to_array (CPU) and read_geotiff_gpu update
  GeoTransform consistently.

read_geotiff_gpu now applies orientation post-decode for every
pure-GPU code path, and reuses the geo_info returned by read_to_array
when the CPU fallback path runs (since that path already applies the
remap). A flag (arr_was_cpu_decoded) keeps us from double-applying.

Test coverage: test_orientation_gpu.py exercises every orientation on
single-band tiled, single-band stripped, and 3-band planar=2 tiled
files, plus georef sel-fidelity for the mirror-flip cases.
@github-actions github-actions Bot added the performance PR touches performance-sensitive code label May 10, 2026
@brendancol brendancol requested a review from Copilot May 10, 2026 02:41
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR brings read_geotiff_gpu in line with the CPU GeoTIFF reader by applying the TIFF Orientation tag (274) on the GPU path, and adds GPU-focused regression tests to ensure pixel buffers and (intended) coordinate semantics match across backends.

Changes:

  • Added _apply_orientation_gpu to remap decoded CuPy arrays according to TIFF orientation values 1–8.
  • Added _apply_orientation_geo_info and integrated orientation application into the pure-GPU tiled decode path; CPU-fallback branches now reuse geo_info returned by read_to_array.
  • Added a new GPU test module covering tiled/stripped/multiband orientations and coordinate-selection behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
xrspatial/geotiff/__init__.py Applies TIFF Orientation tag to GPU outputs; introduces shared geo-transform update helper and avoids double-applying orientation on CPU-fallback paths.
xrspatial/geotiff/tests/test_orientation_gpu.py Adds GPU regression tests for orientation remapping, multiband handling, and georeferenced coordinate selection.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread xrspatial/geotiff/tests/test_orientation_gpu.py Outdated
Comment thread xrspatial/geotiff/__init__.py Outdated
Comment thread xrspatial/geotiff/__init__.py Outdated
- GPU code now owns orientation handling end-to-end. Discard the
  geo_info returned by `read_to_array` in all four CPU-fallback paths
  (stripped, planar=2 cpu_fallback_needed, sparse tile, GPU exception)
  and re-derive the post-orientation transform from the pre-extracted
  geo_info via _apply_orientation_geo_info. Works regardless of whether
  the read_to_array 2/3/4 fix in #1539 has merged yet, and avoids the
  double-swap that would otherwise happen for orientations 5-8.
- Test extratags promoted to 5-tuples (33550/33922/34735) for
  consistency with test_orientation.py and tifffile's preferred
  signature.
@brendancol brendancol merged commit d0141db into main May 11, 2026
11 checks passed
brendancol added a commit that referenced this pull request May 11, 2026
Conflict in xrspatial/geotiff/__init__.py: both #1546 (orientation
handling on GPU read) and this PR (#1547 nodata mask) added a new block
between the multi-band shape check and the dtype cast. They are
independent, so kept both. Order matches the stripped early-return path
above: orientation first (so the geo_info transform reflects the post-
flip pixel layout), then nodata mask (so the value semantics agree with
the CPU read).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance PR touches performance-sensitive code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

read_geotiff_gpu ignores TIFF Orientation tag (274)

2 participants