summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Wiesmann <daniel.wiesmann@gmail.com>2017-06-08 15:51:19 +0100
committerTim Graham <timograham@gmail.com>2017-06-08 12:44:26 -0400
commitfe5e34a2954afdeaabbee80c762735acdd29a948 (patch)
treefbc10f91b7d17f2410cd4c80793d228a5dd7d613
parent0c3c37a376bac149fe7e7e4b2696f8fb7990e2ab (diff)
Fixed #28288 -- Allowed passing papsz options to GDALRaster initialization.
-rw-r--r--django/contrib/gis/gdal/raster/source.py14
-rw-r--r--docs/ref/contrib/gis/gdal.txt66
-rw-r--r--docs/releases/2.0.txt3
-rw-r--r--tests/gis_tests/gdal_tests/test_raster.py38
4 files changed, 104 insertions, 17 deletions
diff --git a/django/contrib/gis/gdal/raster/source.py b/django/contrib/gis/gdal/raster/source.py
index 609c9d6b46..e871fe4cf5 100644
--- a/django/contrib/gis/gdal/raster/source.py
+++ b/django/contrib/gis/gdal/raster/source.py
@@ -1,6 +1,6 @@
import json
import os
-from ctypes import addressof, byref, c_double, c_void_p
+from ctypes import addressof, byref, c_char_p, c_double, c_void_p
from django.contrib.gis.gdal.driver import Driver
from django.contrib.gis.gdal.error import GDALException
@@ -92,6 +92,16 @@ class GDALRaster(GDALRasterBase):
if 'srid' not in ds_input:
raise GDALException('Specify srid for JSON or dict input.')
+ # Create null terminated gdal options array.
+ papsz_options = []
+ for key, val in ds_input.get('papsz_options', {}).items():
+ option = '{}={}'.format(key, val)
+ papsz_options.append(option.upper().encode())
+ papsz_options.append(None)
+
+ # Convert papszlist to ctypes array.
+ papsz_options = (c_char_p * len(papsz_options))(*papsz_options)
+
# Create GDAL Raster
self._ptr = capi.create_ds(
driver._ptr,
@@ -100,7 +110,7 @@ class GDALRaster(GDALRasterBase):
ds_input['height'],
ds_input.get('nr_of_bands', len(ds_input.get('bands', []))),
ds_input.get('datatype', 6),
- None
+ byref(papsz_options),
)
# Set band data if provided
diff --git a/docs/ref/contrib/gis/gdal.txt b/docs/ref/contrib/gis/gdal.txt
index d6501cbf48..892f045fe6 100644
--- a/docs/ref/contrib/gis/gdal.txt
+++ b/docs/ref/contrib/gis/gdal.txt
@@ -1619,21 +1619,22 @@ the others are described below.
The following table describes all keys that can be set in the ``ds_input``
dictionary.
-=============== ======== ==================================================
-Key Default Usage
-=============== ======== ==================================================
-``srid`` required Mapped to the :attr:`~GDALRaster.srid` attribute
-``width`` required Mapped to the :attr:`~GDALRaster.width` attribute
-``height`` required Mapped to the :attr:`~GDALRaster.height` attribute
-``driver`` ``MEM`` Mapped to the :attr:`~GDALRaster.driver` attribute
-``name`` ``''`` See below
-``origin`` ``0`` Mapped to the :attr:`~GDALRaster.origin` attribute
-``scale`` ``0`` Mapped to the :attr:`~GDALRaster.scale` attribute
-``skew`` ``0`` Mapped to the :attr:`~GDALRaster.width` attribute
-``bands`` ``[]`` See below
-``nr_of_bands`` ``0`` See below
-``datatype`` ``6`` See below
-=============== ======== ==================================================
+================= ======== ==================================================
+Key Default Usage
+================= ======== ==================================================
+``srid`` required Mapped to the :attr:`~GDALRaster.srid` attribute
+``width`` required Mapped to the :attr:`~GDALRaster.width` attribute
+``height`` required Mapped to the :attr:`~GDALRaster.height` attribute
+``driver`` ``MEM`` Mapped to the :attr:`~GDALRaster.driver` attribute
+``name`` ``''`` See below
+``origin`` ``0`` Mapped to the :attr:`~GDALRaster.origin` attribute
+``scale`` ``0`` Mapped to the :attr:`~GDALRaster.scale` attribute
+``skew`` ``0`` Mapped to the :attr:`~GDALRaster.width` attribute
+``bands`` ``[]`` See below
+``nr_of_bands`` ``0`` See below
+``datatype`` ``6`` See below
+``papsz_options`` ``{}`` See below
+================= ======== ==================================================
.. object:: name
@@ -1673,6 +1674,41 @@ Key Default Usage
raster bands values are instantiated as an array of zeros and the "no
data" value is set to ``None``.
+.. object:: papsz_options
+
+ .. versionadded:: 2.0
+
+ A dictionary with raster creation options. The key-value pairs of the
+ input dictionary are passed to the driver on creation of the raster.
+
+ The available options are driver-specific and are described in the
+ documentation of each driver.
+
+ The values in the dictionary are not case-sensitive and are automatically
+ converted to the correct string format upon creation.
+
+ The following example uses some of the options available for the
+ `GTiff driver`__. The result is a compressed signed byte raster with an
+ internal tiling scheme. The internal tiles have a block size of 23 by 23::
+
+ >>> GDALRaster({
+ ... 'driver': 'GTiff',
+ ... 'name': '/path/to/new/file.tif',
+ ... 'srid': 4326,
+ ... 'width': 255,
+ ... 'height': 255,
+ ... 'nr_of_bands': 1,
+ ... 'papsz_options': {
+ ... 'compress': 'packbits',
+ ... 'pixeltype': 'signedbyte',
+ ... 'tiled': 'yes',
+ ... 'blockxsize': 23,
+ ... 'blockysize': 23,
+ ... }
+ ... })
+
+__ http://www.gdal.org/frmt_gtiff.html
+
The ``band_input`` dictionary
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/releases/2.0.txt b/docs/releases/2.0.txt
index 3b7a5a74f1..2c9df4e3ce 100644
--- a/docs/releases/2.0.txt
+++ b/docs/releases/2.0.txt
@@ -83,6 +83,9 @@ Minor features
:attr:`~django.contrib.gis.gdal.GDALRaster.info`, and
:attr:`~django.contrib.gis.gdal.GDALBand.metadata` attributes.
+* Allowed passing driver-specific creation options to
+ :class:`~django.contrib.gis.gdal.GDALRaster` objects using ``papsz_options``.
+
:mod:`django.contrib.messages`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/gis_tests/gdal_tests/test_raster.py b/tests/gis_tests/gdal_tests/test_raster.py
index f82b37a6a9..756b7a2726 100644
--- a/tests/gis_tests/gdal_tests/test_raster.py
+++ b/tests/gis_tests/gdal_tests/test_raster.py
@@ -310,6 +310,44 @@ class GDALRasterTests(SimpleTestCase):
info_ref = [line.strip() for line in gdalinfo.split('\n') if line.strip() != '']
self.assertEqual(info_dyn, info_ref)
+ def test_compressed_file_based_raster_creation(self):
+ rstfile = tempfile.NamedTemporaryFile(suffix='.tif')
+ # Make a compressed copy of an existing raster.
+ compressed = self.rs.warp({'papsz_options': {'compress': 'packbits'}, 'name': rstfile.name})
+ # Check physically if compression worked.
+ self.assertLess(os.path.getsize(compressed.name), os.path.getsize(self.rs.name))
+ if GDAL_VERSION > (1, 11):
+ # Create file-based raster with options from scratch.
+ compressed = GDALRaster({
+ 'datatype': 1,
+ 'driver': 'tif',
+ 'name': rstfile.name,
+ 'width': 40,
+ 'height': 40,
+ 'srid': 3086,
+ 'origin': (500000, 400000),
+ 'scale': (100, -100),
+ 'skew': (0, 0),
+ 'bands': [{
+ 'data': range(40 ^ 2),
+ 'nodata_value': 255,
+ }],
+ 'papsz_options': {
+ 'compress': 'packbits',
+ 'pixeltype': 'signedbyte',
+ 'blockxsize': 23,
+ 'blockysize': 23,
+ }
+ })
+ # Check if options used on creation are stored in metadata.
+ # Reopening the raster ensures that all metadata has been written
+ # to the file.
+ compressed = GDALRaster(compressed.name)
+ self.assertEqual(compressed.metadata['IMAGE_STRUCTURE']['COMPRESSION'], 'PACKBITS',)
+ self.assertEqual(compressed.bands[0].metadata['IMAGE_STRUCTURE']['PIXELTYPE'], 'SIGNEDBYTE')
+ if GDAL_VERSION >= (2, 1):
+ self.assertIn('Block=40x23', compressed.info)
+
def test_raster_warp(self):
# Create in memory raster
source = GDALRaster({