django1/django/contrib/gis/gdal/libgdal.py

124 lines
3.4 KiB
Python
Raw Normal View History

import logging
import os
import re
from ctypes import CDLL, CFUNCTYPE, c_char_p, c_int
from ctypes.util import find_library
from django.contrib.gis.gdal.error import GDALException
from django.core.exceptions import ImproperlyConfigured
logger = logging.getLogger('django.contrib.gis')
# Custom library path set?
try:
from django.conf import settings
lib_path = settings.GDAL_LIBRARY_PATH
except (AttributeError, EnvironmentError,
ImportError, ImproperlyConfigured):
lib_path = None
if lib_path:
lib_names = None
elif os.name == 'nt':
# Windows NT shared libraries
lib_names = ['gdal111', 'gdal110', 'gdal19', 'gdal18', 'gdal17']
elif os.name == 'posix':
# *NIX library names.
2016-03-29 06:33:29 +08:00
lib_names = ['gdal', 'GDAL', 'gdal1.11.0', 'gdal1.10.0', 'gdal1.9.0', 'gdal1.8.0', 'gdal1.7.0']
else:
raise GDALException('Unsupported OS "%s"' % os.name)
2012-06-11 05:59:50 +08:00
# Using the ctypes `find_library` utility to find the
# path to the GDAL library from the list of library names.
if lib_names:
for lib_name in lib_names:
lib_path = find_library(lib_name)
if lib_path is not None:
break
2012-06-11 05:59:50 +08:00
if lib_path is None:
2016-03-29 06:33:29 +08:00
raise GDALException(
'Could not find the GDAL library (tried "%s"). Try setting '
'GDAL_LIBRARY_PATH in your settings.' % '", "'.join(lib_names)
)
# This loads the GDAL/OGR C library
lgdal = CDLL(lib_path)
2012-06-11 05:59:50 +08:00
# On Windows, the GDAL binaries have some OSR routines exported with
# STDCALL, while others are not. Thus, the library will also need to
# be loaded up as WinDLL for said OSR functions that require the
# different calling convention.
if os.name == 'nt':
from ctypes import WinDLL
lwingdal = WinDLL(lib_path)
2013-11-03 04:12:09 +08:00
def std_call(func):
"""
Returns the correct STDCALL function for certain OSR routines on Win32
platforms.
"""
if os.name == 'nt':
return lwingdal[func]
else:
return lgdal[func]
2016-11-13 01:11:23 +08:00
2015-02-06 02:25:34 +08:00
# #### Version-information functions. ####
# Returns GDAL library version information with the given key.
_version_info = std_call('GDALVersionInfo')
_version_info.argtypes = [c_char_p]
_version_info.restype = c_char_p
2013-11-03 04:12:09 +08:00
def gdal_version():
"Returns only the GDAL version number information."
2012-09-24 01:59:27 +08:00
return _version_info(b'RELEASE_NAME')
2013-11-03 04:12:09 +08:00
2012-06-11 05:59:50 +08:00
def gdal_full_version():
"Returns the full GDAL version information."
return _version_info('')
2016-11-13 01:11:23 +08:00
version_regex = re.compile(r'^(?P<major>\d+)\.(?P<minor>\d+)(\.(?P<subminor>\d+))?')
2013-11-03 04:12:09 +08:00
def gdal_version_info():
2012-09-24 01:59:27 +08:00
ver = gdal_version().decode()
m = version_regex.match(ver)
if not m:
raise GDALException('Could not parse GDAL version string "%s"' % ver)
return {key: m.group(key) for key in ('major', 'minor', 'subminor')}
2016-11-13 01:11:23 +08:00
_verinfo = gdal_version_info()
GDAL_MAJOR_VERSION = int(_verinfo['major'])
GDAL_MINOR_VERSION = int(_verinfo['minor'])
GDAL_SUBMINOR_VERSION = _verinfo['subminor'] and int(_verinfo['subminor'])
GDAL_VERSION = (GDAL_MAJOR_VERSION, GDAL_MINOR_VERSION, GDAL_SUBMINOR_VERSION)
del _verinfo
# Set library error handling so as errors are logged
CPLErrorHandler = CFUNCTYPE(None, c_int, c_int, c_char_p)
2013-11-03 04:12:09 +08:00
def err_handler(error_class, error_number, message):
logger.error('GDAL_ERROR %d: %s', error_number, message)
2016-11-13 01:11:23 +08:00
err_handler = CPLErrorHandler(err_handler)
2013-11-03 04:12:09 +08:00
def function(name, args, restype):
func = std_call(name)
func.argtypes = args
func.restype = restype
return func
2016-11-13 01:11:23 +08:00
set_error_handler = function('CPLSetErrorHandler', [CPLErrorHandler], CPLErrorHandler)
set_error_handler(err_handler)