Skip to content

write_geotiff_gpu emits JPEG TIFFs that other readers reject #1845

@brendancol

Description

@brendancol

xrspatial/geotiff/__init__.py has two writer entry points that disagree about compression='jpeg':

  • to_geotiff (around line 1313-1334) rejects compression='jpeg' with a ValueError. The CPU encoder writes self-contained JFIF streams per tile and skips the JPEGTables tag (347), so the resulting files are unreadable by libtiff, GDAL, and rasterio.
  • write_geotiff_gpu (around line 3314 onward) accepts the same value and writes the same broken format. The docstring at line 3374-3384 already calls the path "experimental and internal-reader-only until the JPEGTables fix lands".

A user who happens to land on the GPU writer (directly or via to_geotiff(gpu=True) once the auto-dispatch path is wider) gets a .tif on disk that decodes through xrspatial's own reader and fails everywhere else. There is no warning at write time. The asymmetry between the two writers in the same module is the surprising part.

Proposed fix

Reject compression='jpeg' on write_geotiff_gpu by default with the same error text to_geotiff raises. Add an opt-in allow_internal_only_jpeg: bool = False kwarg for users who want the existing internal-only path. When the flag is set, proceed with the current encode path and emit a GeoTIFFFallbackWarning so it cannot be missed.

An env-var gate was considered and rejected: it is harder to discover, harder to audit at the call site, and forces test code to mutate process state.

Existing tests to update

Tests in xrspatial/geotiff/tests/test_gpu_writer_compression_modes_2026_05_11.py that call write_geotiff_gpu(..., compression='jpeg') will need to pass the new flag to keep exercising the internal path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    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