Skip to content

write_geotiff_gpu silently mis-orders (band, y, x) DataArrays #1580

@brendancol

Description

@brendancol

Summary

write_geotiff_gpu does not handle band-first (band, y, x) 3D
DataArrays the way the CPU to_geotiff path does. The CPU writer
checks data.dims[0] in ('band', 'bands', 'channel') and moveaxis to
(y, x, band) (see __init__.py:1037). The GPU writer skips that
step entirely and treats arr.shape[2] as the band axis regardless of
dim names, so a rioxarray-style (band, y, x) CuPy DataArray is
written with the band axis stored as image width and the actual width
stored as samples-per-pixel.

to_geotiff(...) auto-dispatches to write_geotiff_gpu when the
input is CuPy-backed, so the same caller code that round-trips fine on
numpy silently produces a transposed, unreadable file on GPU.

Reproduction

import numpy as np, xarray as xr, cupy
from xrspatial.geotiff import open_geotiff, write_geotiff_gpu

arr = np.random.default_rng(0).integers(0, 255, (3, 16, 32), dtype=np.uint8)
da = xr.DataArray(
    cupy.asarray(arr),
    dims=['band', 'y', 'x'],
    coords={'band': np.arange(3),
            'y': np.arange(16, dtype=np.float64),
            'x': np.arange(32, dtype=np.float64)},
    attrs={'crs': 4326},
)
write_geotiff_gpu(da, '/tmp/bandfirst.tif', compression='none')
rd = open_geotiff('/tmp/bandfirst.tif')
print(rd.sizes)  # Frozen({'y': 3, 'x': 16, 'band': 32}) — wrong

Expected: Frozen({'y': 16, 'x': 32, 'band': 3}).

Fix

Mirror the moveaxis branch from the CPU eager path before computing
height, width = arr.shape[:2]. Same condition: 3D and
data.dims[0] in ('band', 'bands', 'channel').

Found by the metadata-propagation sweep (Cat 3 + Cat 5).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions