From bcba035b5af1930e374300158d032c21a606af1f Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Mon, 11 May 2026 07:53:12 -0700 Subject: [PATCH 1/2] Sync compression docstrings against actual codec map (#1562) _writer.write listed three codecs ('none', 'deflate', 'lzw') while _compression_tag accepts nine. to_geotiff listed six and omitted 'lz4', 'jpeg2000'/'j2k', and 'lerc'. Update both docstrings to match _VALID_COMPRESSIONS / _compression_tag. Also fill in the missing parameter docs on _writer.write that grew silently as features landed: compression_level, overview_resampling, crs_wkt, raster_type, x_resolution, y_resolution, resolution_unit, gdal_metadata_xml, extra_tags, bigtiff, max_z_error. Docs-only change. --- xrspatial/geotiff/__init__.py | 12 ++++++++---- xrspatial/geotiff/_writer.py | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/xrspatial/geotiff/__init__.py b/xrspatial/geotiff/__init__.py index 3949d2193..e47fe3587 100644 --- a/xrspatial/geotiff/__init__.py +++ b/xrspatial/geotiff/__init__.py @@ -810,10 +810,14 @@ def to_geotiff(data: xr.DataArray | np.ndarray, path, *, nodata : float, int, or None NoData value. compression : str - 'none', 'deflate', 'lzw', 'jpeg', 'packbits', or 'zstd'. - JPEG is lossy and only supports uint8 data (1 or 3 bands). - With ``gpu=True``, JPEG uses nvJPEG for GPU-accelerated - encode/decode when available, falling back to Pillow on CPU. + Codec name. One of ``'none'``, ``'deflate'``, ``'lzw'``, + ``'jpeg'``, ``'packbits'``, ``'zstd'``, ``'lz4'``, + ``'jpeg2000'`` (alias ``'j2k'``), or ``'lerc'``. + ``'jpeg'`` is currently rejected on write because the encoder + omits the JPEGTables tag and produced files do not round-trip + through libtiff / GDAL / rasterio. Use ``'deflate'``, ``'zstd'``, + or ``'lzw'`` instead. ``'lerc'`` accepts ``max_z_error`` for + lossy compression with a bounded per-pixel error. compression_level : int or None Compression effort level. None uses each codec's default (6 for deflate/zstd). Valid ranges: deflate 1-9, zstd 1-22, lz4 0-16. diff --git a/xrspatial/geotiff/_writer.py b/xrspatial/geotiff/_writer.py index 5b5722489..24365231b 100644 --- a/xrspatial/geotiff/_writer.py +++ b/xrspatial/geotiff/_writer.py @@ -998,10 +998,19 @@ def write(data: np.ndarray, path: str, *, Pixel-to-coordinate mapping. crs_epsg : int or None EPSG code. + crs_wkt : str or None + WKT string. Used only when ``crs_epsg`` is None. nodata : float, int, or None NoData value. compression : str - 'none', 'deflate', or 'lzw'. + Codec name. One of ``'none'``, ``'deflate'``, ``'lzw'``, + ``'jpeg'``, ``'packbits'``, ``'zstd'``, ``'lz4'``, + ``'jpeg2000'`` (alias ``'j2k'``), or ``'lerc'``. + compression_level : int or None + Effort level forwarded to the codec. None uses each codec's + default. Valid ranges: deflate 1-9, zstd 1-22, lz4 0-16. + Codecs without a level concept (lzw, packbits, jpeg) accept any + value and ignore it. tiled : bool Use tiled layout (vs strips). tile_size : int @@ -1015,6 +1024,30 @@ def write(data: np.ndarray, path: str, *, overview_levels : list of int or None Overview decimation factors (e.g. [2, 4, 8]). Only used if cog=True. If None and cog=True, auto-generate. + overview_resampling : str + Resampling method for overviews: ``'mean'`` (default), + ``'nearest'``, ``'min'``, ``'max'``, ``'median'``, ``'mode'``, + or ``'cubic'``. + raster_type : int + TIFF ``GTRasterTypeGeoKey`` value. ``1`` (default) = PixelIsArea, + ``2`` = PixelIsPoint. + x_resolution, y_resolution : float or None + Pixels per ``resolution_unit`` along each axis. Written into the + TIFF XResolution / YResolution tags. + resolution_unit : int or None + TIFF ResolutionUnit tag. ``1`` = none, ``2`` = inch, ``3`` = cm. + gdal_metadata_xml : str or None + Raw XML payload written to the ``GDAL_METADATA`` tag. Used to + round-trip arbitrary GDAL-style metadata. + extra_tags : list or None + Additional TIFF tags to emit, as a list of + ``(tag_id, type_id, count, value)`` tuples. + bigtiff : bool or None + Force BigTIFF (64-bit offsets). None auto-promotes when the + estimated file size would exceed the classic-TIFF 4 GB limit. + max_z_error : float + Per-pixel error budget for LERC compression. ``0.0`` (default) + is lossless. Only valid with ``compression='lerc'``. """ comp_tag = _compression_tag(compression) pred_int = normalize_predictor(predictor, data.dtype, comp_tag) From acb69bd6e43f367d1cc0e8d5b23da4ea16628b18 Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Mon, 11 May 2026 09:13:34 -0700 Subject: [PATCH 2/2] Document JPEG constraints and overview_levels list-length semantics - JPEG entry in the compression= list now notes the hard uint8 + 1-or-3 bands constraint enforced in write(). - overview_levels docstring no longer implies the values are decimation factors. The implementation only consumes the list length; each overview unconditionally halves the previous resolution. --- xrspatial/geotiff/_writer.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/xrspatial/geotiff/_writer.py b/xrspatial/geotiff/_writer.py index 24365231b..a4858c130 100644 --- a/xrspatial/geotiff/_writer.py +++ b/xrspatial/geotiff/_writer.py @@ -1006,6 +1006,8 @@ def write(data: np.ndarray, path: str, *, Codec name. One of ``'none'``, ``'deflate'``, ``'lzw'``, ``'jpeg'``, ``'packbits'``, ``'zstd'``, ``'lz4'``, ``'jpeg2000'`` (alias ``'j2k'``), or ``'lerc'``. + ``'jpeg'`` is only valid for ``uint8`` data with 1 or 3 bands; + any other dtype or band count raises ``ValueError``. compression_level : int or None Effort level forwarded to the codec. None uses each codec's default. Valid ranges: deflate 1-9, zstd 1-22, lz4 0-16. @@ -1022,8 +1024,12 @@ def write(data: np.ndarray, path: str, *, cog : bool Write as Cloud Optimized GeoTIFF. overview_levels : list of int or None - Overview decimation factors (e.g. [2, 4, 8]). - Only used if cog=True. If None and cog=True, auto-generate. + Number of overviews to generate, expressed as a list. Only the + list *length* is used: each overview halves the previous one, + regardless of the values supplied (``[2, 4, 8]`` and ``[1, 1, 1]`` + both produce 2x / 4x / 8x decimations). Only used if + ``cog=True``. If None and ``cog=True``, levels auto-generate + until the next halving would fall below ``tile_size``. overview_resampling : str Resampling method for overviews: ``'mean'`` (default), ``'nearest'``, ``'min'``, ``'max'``, ``'median'``, ``'mode'``,