Skip to content

geotiff: to_geotiff rejects compression='jpeg' but write_geotiff_gpu accepts it #1651

@brendancol

Description

@brendancol

Summary

to_geotiff rejects compression='jpeg' across every dispatch path (CPU, GPU auto-detect, and gpu=True), but write_geotiff_gpu accepts it and writes a working JPEG file. Since to_geotiff(..., gpu=True) is documented as calling write_geotiff_gpu internally, the two entry points should agree on what compression='jpeg' does.

Reproducer

import tempfile, os, numpy as np, xarray as xr, cupy
import xrspatial.geotiff as geo

arr = np.random.randint(0, 255, (256, 256), dtype=np.uint8)
da_gpu = xr.DataArray(cupy.asarray(arr), dims=['y', 'x'])

with tempfile.TemporaryDirectory() as td:
    # to_geotiff(gpu=True, jpeg) raises ValueError
    try:
        geo.to_geotiff(da_gpu, os.path.join(td, 'a.tif'), compression='jpeg')
    except ValueError as e:
        print('to_geotiff(gpu_data, jpeg):', e)  # rejected

    # write_geotiff_gpu(jpeg) succeeds and produces a readable file
    p = os.path.join(td, 'b.tif')
    geo.write_geotiff_gpu(da_gpu, p, compression='jpeg')
    print('write_geotiff_gpu(gpu_data, jpeg): size=', os.path.getsize(p))
    # round-trips through xrspatial, PIL, and rasterio

The rejection message on to_geotiff says the encoder omits the JPEGTables tag (347) so libtiff/GDAL/rasterio reject the file. In practice the bytes produced by both the CPU _writer.write(compression='jpeg', ...) path and write_geotiff_gpu(compression='jpeg', ...) round-trip through xrspatial, PIL, and rasterio without errors (per-tile JFIF streams are self-contained). The rejection in to_geotiff may be over-cautious.

Severity

HIGH (Cat 5, public API surface drift). write_geotiff_gpu is the documented explicit entry point; users who hit the to_geotiff(gpu=True) rejection cannot rely on the documented equivalence.

Fix options

Pick one:

  1. Drop the JPEG rejection in to_geotiff. Treat JPEG like any other codec and let it pass through to the GPU/CPU writer. Verify the round-trip in CI on multiple readers (libtiff, GDAL, rasterio, PIL).
  2. Add the JPEG rejection to write_geotiff_gpu. Mirror the upfront ValueError on the GPU writer so both entry points fail identically. Document JPEG as "use a different codec" in both docstrings.
  3. Document the per-tile JFIF caveat. Accept JPEG in both writers, but warn (warnings.warn) when the file is missing JPEGTables and may not round-trip through readers that require it.

Option 2 is the most conservative; option 3 surfaces the trade-off without restricting users.

Deprecation impact

None. Whichever option lands, both entry points end up with the same JPEG acceptance contract. No kwarg rename.

Found by /sweep-api-consistency on 2026-05-11.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions