Skip to content

Add optional nvJPEG2000 integration for JPEG 2000 GeoTIFF support #1048

@brendancol

Description

@brendancol

Author of Proposal: @brendan

Reason or problem

The geotiff package supports nvCOMP for GPU-accelerated deflate and ZSTD, but can't read or write JPEG 2000 (compression tag 34712). Sentinel-2 and Landsat data commonly ship as J2K-compressed GeoTIFFs, so this is a real gap for satellite imagery workflows.

NVIDIA's nvJPEG2000 library does GPU-accelerated J2K encode/decode. It fits the same optional-library pattern we already use for nvCOMP.

Proposal

Design:

Two tiers, same pattern as existing codecs:

  1. CPU fallback via glymur (optional): Same approach as JPEG (Pillow) and ZSTD (zstandard). Module-level availability flag, lazy import, error message if missing.

  2. GPU via nvJPEG2000 (optional): Same approach as nvCOMP -- lazy ctypes.CDLL loading of libnvjpeg2k.so, cached handle, batch decode/encode. Falls back to CPU glymur when the library isn't found.

Where it plugs in:

  • _compression.py: CPU J2K decompress/compress via glymur
  • _gpu_decode.py: _try_nvjpeg2k_decode() and _nvjpeg2k_encode() using the same ctypes pattern as nvCOMP
  • _writer.py: Add 'jpeg2000' / 'j2k' to _compression_tag() (tag 34712)
  • gpu_decode_tiles(): Try nvJPEG2000 first for tag 34712, fall back to CPU
  • gpu_compress_tiles(): Use nvJPEG2000 when compression is 34712

Usage:

# Write with JPEG 2000 compression
write_geotiff(data, "output.tif", compression="jpeg2000")

# GPU write -- uses nvJPEG2000 if available, else CPU fallback
write_geotiff(cupy_data, "output.tif", compression="jpeg2000", gpu=True)

# Read auto-detects compression from the TIFF tag
da = read_geotiff("sentinel2_j2k.tif")
da = read_geotiff("sentinel2_j2k.tif", gpu=True)  # nvJPEG2000 if available

Satellite imagery uses JPEG 2000 widely, and GPU J2K decode is much faster than CPU on large rasters. The integration follows the existing nvCOMP pattern with no new abstractions.

Stakeholders and impacts

Anyone working with satellite GeoTIFFs that use JPEG 2000 compression. The change is additive -- existing codecs and code paths stay untouched. Both nvJPEG2000 and glymur are optional; the package works fine without either.

Drawbacks

  • nvJPEG2000 needs CUDA 11.x+ and compute capability 7.0+
  • glymur depends on the system OpenJPEG C library
  • JPEG 2000 is lossy by default (lossless mode exists but is less common in TIFF context)

Alternatives

  • rasterio/GDAL handles J2K, but this package aims for zero GDAL dependency
  • Pillow has an OpenJPEG plugin, but it's limited and doesn't cover all J2K profiles

Unresolved questions

  • Whether to expose quality/compression-ratio parameters for lossy encoding
  • How to handle J2K's own internal tile concept vs. TIFF tiles

Additional notes

TIFF compression tag 34712 is defined in TIFF/EP (ISO 12234-2). The nvJPEG2000 library ships with the CUDA toolkit and is available in RAPIDS conda environments.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestgpuCuPy / CUDA GPU support

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions