Fixed #26417 -- Allowed setting GDALBand data with partial values.

This commit is contained in:
Daniel Wiesmann 2016-03-29 14:42:35 +01:00 committed by Tim Graham
parent 03b6947728
commit 870dd1d38b
4 changed files with 60 additions and 8 deletions

View File

@ -170,7 +170,7 @@ class GDALBand(GDALBase):
dtype = GDAL_PIXEL_TYPES[dtype] dtype = GDAL_PIXEL_TYPES[dtype]
return dtype return dtype
def data(self, data=None, offset=None, size=None, as_memoryview=False): def data(self, data=None, offset=None, size=None, shape=None, as_memoryview=False):
""" """
Reads or writes pixel values for this band. Blocks of data can Reads or writes pixel values for this band. Blocks of data can
be accessed by specifying the width, height and offset of the be accessed by specifying the width, height and offset of the
@ -185,6 +185,9 @@ class GDALBand(GDALBase):
if not size: if not size:
size = (self.width - offset[0], self.height - offset[1]) size = (self.width - offset[0], self.height - offset[1])
if not shape:
shape = size
if any(x <= 0 for x in size): if any(x <= 0 for x in size):
raise ValueError('Offset too big for this raster.') raise ValueError('Offset too big for this raster.')
@ -192,7 +195,7 @@ class GDALBand(GDALBase):
raise ValueError('Size is larger than raster.') raise ValueError('Size is larger than raster.')
# Create ctypes type array generator # Create ctypes type array generator
ctypes_array = GDAL_TO_CTYPES[self.datatype()] * (size[0] * size[1]) ctypes_array = GDAL_TO_CTYPES[self.datatype()] * (shape[0] * shape[1])
if data is None: if data is None:
# Set read mode # Set read mode
@ -211,8 +214,8 @@ class GDALBand(GDALBase):
# Access band # Access band
capi.band_io(self._ptr, access_flag, offset[0], offset[1], capi.band_io(self._ptr, access_flag, offset[0], offset[1],
size[0], size[1], byref(data_array), size[0], size[0], size[1], byref(data_array), shape[0],
size[1], self.datatype(), 0, 0) shape[1], self.datatype(), 0, 0)
# Return data as numpy array if possible, otherwise as list # Return data as numpy array if possible, otherwise as list
if data is None: if data is None:

View File

@ -1477,7 +1477,7 @@ blue.
``GDT_UInt32``, ``GDT_Int32``, ``GDT_Float32``, ``GDT_Float64``, ``GDT_UInt32``, ``GDT_Int32``, ``GDT_Float32``, ``GDT_Float64``,
``GDT_CInt16``, ``GDT_CInt32``, ``GDT_CFloat32``, and ``GDT_CFloat64``. ``GDT_CInt16``, ``GDT_CInt32``, ``GDT_CFloat32``, and ``GDT_CFloat64``.
.. method:: data(data=None, offset=None, size=None) .. method:: data(data=None, offset=None, size=None, shape=None)
.. versionadded:: 1.9 .. versionadded:: 1.9
@ -1490,9 +1490,17 @@ blue.
Data is written to the ``GDALBand`` if the ``data`` parameter is provided. Data is written to the ``GDALBand`` if the ``data`` parameter is provided.
The input can be of one of the following types - packed string, buffer, list, The input can be of one of the following types - packed string, buffer, list,
array, and NumPy array. The number of items in the input must correspond to the array, and NumPy array. The number of items in the input should normally
total number of pixels in the band, or to the number of pixels for a specific correspond to the total number of pixels in the band, or to the number
block of pixel values if the ``offset`` and ``size`` parameters are provided. of pixels for a specific block of pixel values if the ``offset`` and
``size`` parameters are provided.
If the number of items in the input is different from the target pixel
block, the ``shape`` parameter must be specified. The shape is a tuple
that specifies the width and height of the input data in pixels. The
data is then replicated to update the pixel values of the selected
block. This is useful to fill an entire band with a single value, for
instance.
For example: For example:
@ -1519,6 +1527,22 @@ blue.
[ 4, -99, -88, 7], [ 4, -99, -88, 7],
[ 8, -77, -66, 11], [ 8, -77, -66, 11],
[ 12, 13, 14, 15]], dtype=int8) [ 12, 13, 14, 15]], dtype=int8)
>>> bnd.data([1], shape=(1, 1))
>>> bnd.data()
array([[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]], dtype=uint8)
>>> bnd.data(range(4), shape=(1, 4))
array([[0, 0, 0, 0],
[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3]], dtype=uint8)
.. versionchanged:: 1.10
The ``shape`` parameter and the ability to replicate data input when
setting ``GDALBand`` data was added.
Settings Settings
======== ========

View File

@ -143,6 +143,10 @@ Minor features
primary key of objects in the ``properties`` dictionary if specific fields primary key of objects in the ``properties`` dictionary if specific fields
aren't specified. aren't specified.
* The ability to replicate input data on the :meth:`GDALBand.data()
<django.contrib.gis.gdal.GDALBand.data>` method was added. Band data can
now be updated with repeated values efficiently.
:mod:`django.contrib.messages` :mod:`django.contrib.messages`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -483,3 +483,24 @@ class GDALBandTests(SimpleTestCase):
else: else:
rsmem.bands[0].nodata_value = None rsmem.bands[0].nodata_value = None
self.assertIsNone(rsmem.bands[0].nodata_value) self.assertIsNone(rsmem.bands[0].nodata_value)
def test_band_data_replication(self):
band = GDALRaster({
'srid': 4326,
'width': 3,
'height': 3,
'bands': [{'data': range(10, 19), 'nodata_value': 0}],
}).bands[0]
# Variations for input (data, shape, expected result).
combos = (
([1], (1, 1), [1] * 9),
(range(3), (1, 3), [0, 0, 0, 1, 1, 1, 2, 2, 2]),
(range(3), (3, 1), [0, 1, 2, 0, 1, 2, 0, 1, 2]),
)
for combo in combos:
band.data(combo[0], shape=combo[1])
if numpy:
numpy.testing.assert_equal(band.data(), numpy.array(combo[2]).reshape(3, 3))
else:
self.assertEqual(band.data(), list(combo[2]))