From 6b5f015195ccf683b6ca5ab6a8425921516225c1 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sun, 1 Sep 2024 13:45:26 +0200 Subject: [PATCH] GDALAutoCreateWarpedVRT(): ignore src nodata value if it cannot be represented in the source band data type --- autotest/gdrivers/vrtwarp.py | 14 +++++++++++ frmts/vrt/vrtwarped.cpp | 49 ++++++++++++++++++++++++++---------- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/autotest/gdrivers/vrtwarp.py b/autotest/gdrivers/vrtwarp.py index e95e0d74b9ec..9b843aa81342 100755 --- a/autotest/gdrivers/vrtwarp.py +++ b/autotest/gdrivers/vrtwarp.py @@ -746,3 +746,17 @@ def test_vrtwarp_autocreatewarpedvrt_int16_nodata_32767(): vrt_ds = gdal.AutoCreateWarpedVRT(ds) assert vrt_ds.GetRasterBand(1).DataType == gdal.GDT_Int16 assert vrt_ds.GetRasterBand(1).GetNoDataValue() == 32767 + + +############################################################################### +# Test gdal.AutoCreateWarpedVRT() on a source nodata value that does not fit +# the source band type + + +def test_vrtwarp_autocreatewarpedvrt_invalid_nodata(): + + ds = gdal.GetDriverByName("MEM").Create("", 1, 1, 1, gdal.GDT_Byte) + ds.SetGeoTransform([0, 1, 0, 0, 0, -1]) + ds.GetRasterBand(1).SetNoDataValue(-9999) + vrt_ds = gdal.AutoCreateWarpedVRT(ds) + assert vrt_ds.GetRasterBand(1).DataType == gdal.GDT_Byte diff --git a/frmts/vrt/vrtwarped.cpp b/frmts/vrt/vrtwarped.cpp index b96cd5071183..ec39b7f1263c 100644 --- a/frmts/vrt/vrtwarped.cpp +++ b/frmts/vrt/vrtwarped.cpp @@ -180,6 +180,9 @@ GDALDatasetH CPL_STDCALL GDALAutoCreateWarpedVRTEx( if (psWO->padfSrcNoDataReal == nullptr && psWO->padfDstNoDataReal == nullptr && psWO->nSrcAlphaBand == 0) { + // If none of the provided input nodata values can be represented in the + // data type of the corresponding source band, ignore them. + int nCountInvalidSrcNoDataReal = 0; for (int i = 0; i < psWO->nBandCount; i++) { GDALRasterBandH rasterBand = @@ -189,22 +192,42 @@ GDALDatasetH CPL_STDCALL GDALAutoCreateWarpedVRTEx( double noDataValue = GDALGetRasterNoDataValue(rasterBand, &hasNoDataValue); - if (hasNoDataValue) + if (hasNoDataValue && + !GDALIsValueExactAs(noDataValue, + GDALGetRasterDataType(rasterBand))) { - // Check if the nodata value is out of range - int bClamped = FALSE; - int bRounded = FALSE; - CPL_IGNORE_RET_VAL(GDALAdjustValueToDataType( - GDALGetRasterDataType(rasterBand), noDataValue, &bClamped, - &bRounded)); - if (!bClamped) + nCountInvalidSrcNoDataReal++; + } + } + + if (nCountInvalidSrcNoDataReal != psWO->nBandCount) + { + for (int i = 0; i < psWO->nBandCount; i++) + { + GDALRasterBandH rasterBand = + GDALGetRasterBand(psWO->hSrcDS, psWO->panSrcBands[i]); + + int hasNoDataValue; + double noDataValue = + GDALGetRasterNoDataValue(rasterBand, &hasNoDataValue); + + if (hasNoDataValue) { - GDALWarpInitNoDataReal(psWO, -1e10); - if (psWO->padfSrcNoDataReal != nullptr && - psWO->padfDstNoDataReal != nullptr) + // Check if the nodata value is out of range + int bClamped = FALSE; + int bRounded = FALSE; + CPL_IGNORE_RET_VAL(GDALAdjustValueToDataType( + GDALGetRasterDataType(rasterBand), noDataValue, + &bClamped, &bRounded)); + if (!bClamped) { - psWO->padfSrcNoDataReal[i] = noDataValue; - psWO->padfDstNoDataReal[i] = noDataValue; + GDALWarpInitNoDataReal(psWO, -1e10); + if (psWO->padfSrcNoDataReal != nullptr && + psWO->padfDstNoDataReal != nullptr) + { + psWO->padfSrcNoDataReal[i] = noDataValue; + psWO->padfDstNoDataReal[i] = noDataValue; + } } } }