fix: read signed WALOUS rasters safely
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-22 05:26:12 +02:00
parent 86dd1a5689
commit e15a8200fd
2 changed files with 49 additions and 7 deletions
@@ -247,7 +247,10 @@ class WalousLandCoverService:
band = source.read(1, window=window, out_shape=(height, width), masked=True, resampling=Resampling.nearest)
output_transform = from_bounds(*bounds, width, height)
outside_scope = geometry_mask([mapping(clipped_geometry)], out_shape=(height, width), transform=output_transform, invert=False)
raw = np.asarray(band.filled(WalousLandCoverService.NODATA), dtype="uint8")
# The official 2023 GeoTIFF is signed int8 while GDAL exposes
# its nodata sentinel as 255. Filling before widening would
# therefore reject the sentinel as out of range for int8.
raw = np.asarray(np.ma.getdata(band), dtype="uint8")
invalid = np.ma.getmaskarray(band) | outside_scope
if source.nodata is not None:
invalid |= np.isclose(raw.astype("float64"), float(source.nodata))
@@ -476,7 +479,7 @@ class WalousLandCoverService:
raise AppError(code="WALOUS_SELECTION_OUTSIDE_DATASET", message="Selection does not overlap the persisted WALOUS raster", status_code=422)
clipped, transform = mask(source, [mapping(geometry)], crop=True, filled=False, indexes=[1])
band = np.ma.asarray(clipped[0])
raw = np.asarray(band.filled(WalousLandCoverService.NODATA), dtype="uint8")
raw = np.asarray(np.ma.getdata(band), dtype="uint8")
selected = geometry_mask([mapping(geometry)], out_shape=raw.shape, transform=transform, invert=True)
valid = selected & ~np.ma.getmaskarray(band) & (raw != WalousLandCoverService.NODATA)
values = raw[valid]
@@ -553,7 +556,7 @@ class WalousLandCoverService:
scale = min(1.0, max_dimension / max(source.width, source.height))
width, height = max(1, round(source.width * scale)), max(1, round(source.height * scale))
values = source.read(1, out_shape=(height, width), masked=True, resampling=Resampling.nearest)
raw = np.asarray(values.filled(WalousLandCoverService.NODATA), dtype="uint8")
raw = np.asarray(np.ma.getdata(values), dtype="uint8")
rgba = np.zeros((height, width, 4), dtype="uint8")
for value, color in WalousLandCoverService.CLASS_COLORS.items():
selected = raw == value