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]
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
be accessed by specifying the width, height and offset of the
@ -185,6 +185,9 @@ class GDALBand(GDALBase):
if not size:
size = (self.width - offset[0], self.height - offset[1])
if not shape:
shape = size
if any(x <= 0 for x in size):
raise ValueError('Offset too big for this raster.')
@ -192,7 +195,7 @@ class GDALBand(GDALBase):
raise ValueError('Size is larger than raster.')
# 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:
# Set read mode
@ -211,8 +214,8 @@ class GDALBand(GDALBase):
# Access band
capi.band_io(self._ptr, access_flag, offset[0], offset[1],
size[0], size[1], byref(data_array), size[0],
size[1], self.datatype(), 0, 0)
size[0], size[1], byref(data_array), shape[0],
shape[1], self.datatype(), 0, 0)
# Return data as numpy array if possible, otherwise as list
if data is None:

View File

@ -1477,7 +1477,7 @@ blue.
``GDT_UInt32``, ``GDT_Int32``, ``GDT_Float32``, ``GDT_Float64``,
``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
@ -1490,9 +1490,17 @@ blue.
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,
array, and NumPy array. The number of items in the input must correspond to the
total number of pixels in the band, or to the number of pixels for a specific
block of pixel values if the ``offset`` and ``size`` parameters are provided.
array, and NumPy array. The number of items in the input should normally
correspond to the total number of pixels in the band, or to the number
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:
@ -1519,6 +1527,22 @@ blue.
[ 4, -99, -88, 7],
[ 8, -77, -66, 11],
[ 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
========

View File

@ -143,6 +143,10 @@ Minor features
primary key of objects in the ``properties`` dictionary if specific fields
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`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -483,3 +483,24 @@ class GDALBandTests(SimpleTestCase):
else:
rsmem.bands[0].nodata_value = None
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]))