diff --git a/django/contrib/gis/gdal/prototypes/raster.py b/django/contrib/gis/gdal/prototypes/raster.py index 8b3c3504d4..eb0818e342 100644 --- a/django/contrib/gis/gdal/prototypes/raster.py +++ b/django/contrib/gis/gdal/prototypes/raster.py @@ -62,6 +62,10 @@ get_band_ds = voidptr_output(std_call('GDALGetBandDataset'), [c_void_p]) get_band_datatype = int_output(std_call('GDALGetRasterDataType'), [c_void_p]) get_band_nodata_value = double_output(std_call('GDALGetRasterNoDataValue'), [c_void_p, POINTER(c_int)]) set_band_nodata_value = void_output(std_call('GDALSetRasterNoDataValue'), [c_void_p, c_double]) +if GDAL_VERSION >= (2, 1): + delete_band_nodata_value = void_output(std_call('GDALDeleteRasterNoDataValue'), [c_void_p]) +else: + delete_band_nodata_value = None get_band_statistics = void_output( std_call('GDALGetRasterStatistics'), [ diff --git a/django/contrib/gis/gdal/raster/band.py b/django/contrib/gis/gdal/raster/band.py index a573ef53c8..6ffa011282 100644 --- a/django/contrib/gis/gdal/raster/band.py +++ b/django/contrib/gis/gdal/raster/band.py @@ -151,9 +151,14 @@ class GDALBand(GDALBase): """ Sets the nodata value for this band. """ - if not isinstance(value, (int, float)): - raise ValueError('Nodata value must be numeric.') - capi.set_band_nodata_value(self._ptr, value) + if value is None: + if not capi.delete_band_nodata_value: + raise ValueError('GDAL >= 2.1 required to delete nodata values.') + capi.delete_band_nodata_value(self._ptr) + elif not isinstance(value, (int, float)): + raise ValueError('Nodata value must be numeric or None.') + else: + capi.set_band_nodata_value(self._ptr, value) self._flush() def datatype(self, as_string=False): diff --git a/docs/ref/contrib/gis/gdal.txt b/docs/ref/contrib/gis/gdal.txt index b15bd17d54..ed036de12a 100644 --- a/docs/ref/contrib/gis/gdal.txt +++ b/docs/ref/contrib/gis/gdal.txt @@ -1456,10 +1456,18 @@ blue. to mark pixels that are not valid data. Such pixels should generally not be displayed, nor contribute to analysis operations. + To delete an existing "no data" value, set this property to ``None`` + (requires GDAL ≥ 2.1). + .. versionchanged:: 1.9 This property can now be set as well. + .. versionchanged:: 1.10 + + The "no data" value can now be deleted by setting the + ``nodata_value`` attribute to ``None``. + .. method:: datatype(as_string=False) The data type contained in the band, as an integer constant between 0 diff --git a/tests/gis_tests/gdal_tests/test_raster.py b/tests/gis_tests/gdal_tests/test_raster.py index 8391887f6c..d08071342c 100644 --- a/tests/gis_tests/gdal_tests/test_raster.py +++ b/tests/gis_tests/gdal_tests/test_raster.py @@ -48,6 +48,7 @@ import unittest from django.contrib.gis.gdal import HAS_GDAL from django.contrib.gis.gdal.error import GDALException from django.contrib.gis.shortcuts import numpy +from django.test import SimpleTestCase from django.utils import six from django.utils._os import upath @@ -302,7 +303,7 @@ class GDALRasterTests(unittest.TestCase): @unittest.skipUnless(HAS_GDAL, "GDAL is required") -class GDALBandTests(unittest.TestCase): +class GDALBandTests(SimpleTestCase): def setUp(self): self.rs_path = os.path.join(os.path.dirname(upath(__file__)), '../data/rasters/raster.tif') @@ -467,3 +468,18 @@ class GDALBandTests(unittest.TestCase): 'bands': [{'data': [0], 'nodata_value': 0}], }) self.assertEqual(rsmem.bands[0].statistics(), (None, None, None, None)) + + def test_band_delete_nodata(self): + rsmem = GDALRaster({ + 'srid': 4326, + 'width': 1, + 'height': 1, + 'bands': [{'data': [0], 'nodata_value': 1}], + }) + if GDAL_VERSION < (2, 1): + msg = 'GDAL >= 2.1 required to delete nodata values.' + with self.assertRaisesMessage(ValueError, msg): + rsmem.bands[0].nodata_value = None + else: + rsmem.bands[0].nodata_value = None + self.assertIsNone(rsmem.bands[0].nodata_value)