def __init__(self, *args): """ The initialization function may take an OGREnvelope structure, 4-element tuple or list, or 4 individual arguments. """ if len(args) == 1: if isinstance(args[0], OGREnvelope): # OGREnvelope (a ctypes Structure) was passed in. self._envelope = args[0] elif isinstance(args[0], (tuple, list)): # A tuple was passed in. if len(args[0]) != 4: raise GDALException('Incorrect number of tuple elements (%d).' % len(args[0])) else: self._from_sequence(args[0]) else: raise TypeError('Incorrect type of argument: %s' % type(args[0])) elif len(args) == 4: # Individual parameters passed in. # Thanks to ww for the help self._from_sequence([float(a) for a in args]) else: raise GDALException('Incorrect number (%d) of arguments.' % len(args)) # Checking the x,y coordinates if self.min_x > self.max_x: raise GDALException('Envelope minimum X > maximum X.') if self.min_y > self.max_y: raise GDALException('Envelope minimum Y > maximum Y.')
def __setstate__(self, state): wkb, srs = state ptr = capi.from_wkb(wkb, None, byref(c_void_p()), len(wkb)) if not ptr: raise GDALException( 'Invalid OGRGeometry loaded from pickled state.') self.ptr = ptr self.srs = srs
def get_fields(self, field_name): """ Return a list containing the given field name for every Feature in the Layer. """ if field_name not in self.fields: raise GDALException('invalid field name: %s' % field_name) return [feat.get(field_name) for feat in self]
def check_pointer(result, func, cargs): "Make sure the result pointer is valid." if isinstance(result, int): result = c_void_p(result) if result: return result else: raise GDALException('Invalid pointer returned from "%s"' % func.__name__)
def check_geom(result, func, cargs): "Check a function that returns a geometry." # OGR_G_Clone may return an integer, even though the # restype is set to c_void_p if isinstance(result, int): result = c_void_p(result) if not result: raise GDALException('Invalid geometry pointer returned from "%s".' % func.__name__) return result
def __init__(self, feat, layer): """ Initialize Feature from a pointer and its Layer object. """ if not feat: raise GDALException( 'Cannot create OGR Feature, invalid pointer given.') self.ptr = feat self._layer = layer
def expand_to_include(self, *args): """ Modify the envelope to expand to include the boundaries of the passed-in 2-tuple (a point), 4-tuple (an extent) or envelope. """ # We provide a number of different signatures for this method, # and the logic here is all about converting them into a # 4-tuple single parameter which does the actual work of # expanding the envelope. if len(args) == 1: if isinstance(args[0], Envelope): return self.expand_to_include(args[0].tuple) elif hasattr(args[0], 'x') and hasattr(args[0], 'y'): return self.expand_to_include(args[0].x, args[0].y, args[0].x, args[0].y) elif isinstance(args[0], (tuple, list)): # A tuple was passed in. if len(args[0]) == 2: return self.expand_to_include((args[0][0], args[0][1], args[0][0], args[0][1])) elif len(args[0]) == 4: (minx, miny, maxx, maxy) = args[0] if minx < self._envelope.MinX: self._envelope.MinX = minx if miny < self._envelope.MinY: self._envelope.MinY = miny if maxx > self._envelope.MaxX: self._envelope.MaxX = maxx if maxy > self._envelope.MaxY: self._envelope.MaxY = maxy else: raise GDALException('Incorrect number of tuple elements (%d).' % len(args[0])) else: raise TypeError('Incorrect type of argument: %s' % type(args[0])) elif len(args) == 2: # An x and an y parameter were passed in return self.expand_to_include((args[0], args[1], args[0], args[1])) elif len(args) == 4: # Individual parameters passed in. return self.expand_to_include(args) else: raise GDALException('Incorrect number (%d) of arguments.' % len(args[0]))
def as_datetime(self): "Retrieve the Field's value as a tuple of date & time components." yy, mm, dd, hh, mn, ss, tz = [c_int() for i in range(7)] status = capi.get_field_as_datetime(self._feat.ptr, self._index, byref(yy), byref(mm), byref(dd), byref(hh), byref(mn), byref(ss), byref(tz)) if status: return (yy, mm, dd, hh, mn, ss, tz) else: raise GDALException( 'Unable to retrieve date & time information from the field.')
def _flush(self): """ Flush all data from memory into the source file if it exists. The data that needs flushing are geotransforms, coordinate systems, nodata_values and pixel values. This function will be called automatically wherever it is needed. """ # Raise an Exception if the value is being changed in read mode. if not self._write: raise GDALException( 'Raster needs to be opened in write mode to change values.') capi.flush_ds(self._ptr)
def __init__(self, ds_input, ds_driver=False, write=False, encoding='utf-8'): # The write flag. if write: self._write = 1 else: self._write = 0 # See also https://trac.osgeo.org/gdal/wiki/rfc23_ogr_unicode self.encoding = encoding Driver.ensure_registered() if isinstance(ds_input, str): # The data source driver is a void pointer. ds_driver = Driver.ptr_type() try: # OGROpen will auto-detect the data source type. ds = capi.open_ds(force_bytes(ds_input), self._write, byref(ds_driver)) except GDALException: # Making the error message more clear rather than something # like "Invalid pointer returned from OGROpen". raise GDALException('Could not open the datasource at "%s"' % ds_input) elif isinstance(ds_input, self.ptr_type) and isinstance( ds_driver, Driver.ptr_type): ds = ds_input else: raise GDALException('Invalid data source input type: %s' % type(ds_input)) if ds: self.ptr = ds self.driver = Driver(ds_driver) else: # Raise an exception if the returned pointer is NULL raise GDALException('Invalid data source file "%s"' % ds_input)
def __init__(self, type_input): "Figure out the correct OGR Type based upon the input." if isinstance(type_input, OGRGeomType): num = type_input.num elif isinstance(type_input, str): type_input = type_input.lower() if type_input == 'geometry': type_input = 'unknown' num = self._str_types.get(type_input) if num is None: raise GDALException('Invalid OGR String Type "%s"' % type_input) elif isinstance(type_input, int): if type_input not in self._types: raise GDALException('Invalid OGR Integer Type: %d' % type_input) num = type_input else: raise TypeError('Invalid OGR input type given.') # Setting the OGR geometry type number. self.num = num
def __eq__(self, other): """ Return True if the envelopes are equivalent; can compare against other Envelopes and 4-tuples. """ if isinstance(other, Envelope): return (self.min_x == other.min_x) and (self.min_y == other.min_y) and \ (self.max_x == other.max_x) and (self.max_y == other.max_y) elif isinstance(other, tuple) and len(other) == 4: return (self.min_x == other[0]) and (self.min_y == other[1]) and \ (self.max_x == other[2]) and (self.max_y == other[3]) else: raise GDALException('Equivalence testing only works with other Envelopes.')
def add(self, geom): "Add the geometry to this Geometry Collection." if isinstance(geom, OGRGeometry): if isinstance(geom, self.__class__): for g in geom: capi.add_geom(self.ptr, g.ptr) else: capi.add_geom(self.ptr, geom.ptr) elif isinstance(geom, str): tmp = OGRGeometry(geom) capi.add_geom(self.ptr, tmp.ptr) else: raise GDALException('Must add an OGRGeometry.')
def __init__(self, dr_input): """ Initialize an GDAL/OGR driver on either a string or integer input. """ if isinstance(dr_input, str): # If a string name of the driver was passed in self.ensure_registered() # Checking the alias dictionary (case-insensitive) to see if an # alias exists for the given driver. if dr_input.lower() in self._alias: name = self._alias[dr_input.lower()] else: name = dr_input # Attempting to get the GDAL/OGR driver by the string name. for iface in (vcapi, rcapi): driver = c_void_p(iface.get_driver_by_name(force_bytes(name))) if driver: break elif isinstance(dr_input, int): self.ensure_registered() for iface in (vcapi, rcapi): driver = iface.get_driver(dr_input) if driver: break elif isinstance(dr_input, c_void_p): driver = dr_input else: raise GDALException( 'Unrecognized input type for GDAL/OGR Driver: %s' % type(dr_input)) # Making sure we get a valid pointer to the OGR Driver if not driver: raise GDALException( 'Could not initialize GDAL/OGR Driver on input: %s' % dr_input) self.ptr = driver
def __init__(self, layer_ptr, ds): """ Initialize on an OGR C pointer to the Layer and the `DataSource` object that owns this layer. The `DataSource` object is required so that a reference to it is kept with this Layer. This prevents garbage collection of the `DataSource` while this Layer is still active. """ if not layer_ptr: raise GDALException('Cannot create Layer, invalid pointer given') self.ptr = layer_ptr self._ds = ds self._ldefn = capi.get_layer_defn(self._ptr) # Does the Layer support random reading? self._random_read = self.test_capability(b'RandomRead')
def __init__(self, feat, index): """ Initialize on the feature object and the integer index of the field within the feature. """ # Setting the feature pointer and index. self._feat = feat self._index = index # Getting the pointer for this field. fld_ptr = capi.get_feat_field_defn(feat.ptr, index) if not fld_ptr: raise GDALException( 'Cannot create OGR Field, invalid pointer given.') self.ptr = fld_ptr # Setting the class depending upon the OGR Field Type (OFT) self.__class__ = OGRFieldTypes[self.type] # OFTReal with no precision should be an OFTInteger. if isinstance(self, OFTReal) and self.precision == 0: self.__class__ = OFTInteger self._double = True
def gdal_version_info(): 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')}
def __init__(self, geom_input, srs=None): """Initialize Geometry on either WKT or an OGR pointer as input.""" str_instance = isinstance(geom_input, str) # If HEX, unpack input to a binary buffer. if str_instance and hex_regex.match(geom_input): geom_input = memoryview(bytes.fromhex(geom_input)) str_instance = False # Constructing the geometry, if str_instance: wkt_m = wkt_regex.match(geom_input) json_m = json_regex.match(geom_input) if wkt_m: if wkt_m.group('srid'): # If there's EWKT, set the SRS w/value of the SRID. srs = int(wkt_m.group('srid')) if wkt_m.group('type').upper() == 'LINEARRING': # OGR_G_CreateFromWkt doesn't work with LINEARRING WKT. # See https://trac.osgeo.org/gdal/ticket/1992. g = capi.create_geom(OGRGeomType(wkt_m.group('type')).num) capi.import_wkt( g, byref(c_char_p(wkt_m.group('wkt').encode()))) else: g = capi.from_wkt( byref(c_char_p(wkt_m.group('wkt').encode())), None, byref(c_void_p())) elif json_m: g = self._from_json(geom_input.encode()) else: # Seeing if the input is a valid short-hand string # (e.g., 'Point', 'POLYGON'). OGRGeomType(geom_input) g = capi.create_geom(OGRGeomType(geom_input).num) elif isinstance(geom_input, memoryview): # WKB was passed in g = self._from_wkb(geom_input) elif isinstance(geom_input, OGRGeomType): # OGRGeomType was passed in, an empty geometry will be created. g = capi.create_geom(geom_input.num) elif isinstance(geom_input, self.ptr_type): # OGR pointer (c_void_p) was the input. g = geom_input else: raise GDALException( 'Invalid input type for OGR Geometry construction: %s' % type(geom_input)) # Now checking the Geometry pointer before finishing initialization # by setting the pointer for the object. if not g: raise GDALException('Cannot create OGR Geometry from input: %s' % geom_input) self.ptr = g # Assigning the SpatialReference object to the geometry, if valid. if srs: self.srs = srs # Setting the class depending upon the OGR Geometry Type self.__class__ = GEO_CLASSES[self.geom_type.num]
def __init__(self, ds_input, write=False): self._write = 1 if write else 0 Driver.ensure_registered() # Preprocess json inputs. This converts json strings to dictionaries, # which are parsed below the same way as direct dictionary inputs. if isinstance(ds_input, str) and json_regex.match(ds_input): ds_input = json.loads(ds_input) # If input is a valid file path, try setting file as source. if isinstance(ds_input, str): try: # GDALOpen will auto-detect the data source type. self._ptr = capi.open_ds(force_bytes(ds_input), self._write) except GDALException as err: raise GDALException( 'Could not open the datasource at "{}" ({}).'.format( ds_input, err)) elif isinstance(ds_input, bytes): # Create a new raster in write mode. self._write = 1 # Get size of buffer. size = sys.getsizeof(ds_input) # Pass data to ctypes, keeping a reference to the ctypes object so # that the vsimem file remains available until the GDALRaster is # deleted. self._ds_input = c_buffer(ds_input) # Create random name to reference in vsimem filesystem. vsi_path = os.path.join(VSI_FILESYSTEM_BASE_PATH, str(uuid.uuid4())) # Create vsimem file from buffer. capi.create_vsi_file_from_mem_buffer( force_bytes(vsi_path), byref(self._ds_input), size, VSI_TAKE_BUFFER_OWNERSHIP, ) # Open the new vsimem file as a GDALRaster. try: self._ptr = capi.open_ds(force_bytes(vsi_path), self._write) except GDALException: # Remove the broken file from the VSI filesystem. capi.unlink_vsi_file(force_bytes(vsi_path)) raise GDALException( 'Failed creating VSI raster from the input buffer.') elif isinstance(ds_input, dict): # A new raster needs to be created in write mode self._write = 1 # Create driver (in memory by default) driver = Driver(ds_input.get('driver', 'MEM')) # For out of memory drivers, check filename argument if driver.name != 'MEM' and 'name' not in ds_input: raise GDALException( 'Specify name for creation of raster with driver "{}".'. format(driver.name)) # Check if width and height where specified if 'width' not in ds_input or 'height' not in ds_input: raise GDALException( 'Specify width and height attributes for JSON or dict input.' ) # Check if srid was specified 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, force_bytes(ds_input.get('name', '')), ds_input['width'], ds_input['height'], ds_input.get('nr_of_bands', len(ds_input.get('bands', []))), ds_input.get('datatype', 6), byref(papsz_options), ) # Set band data if provided for i, band_input in enumerate(ds_input.get('bands', [])): band = self.bands[i] if 'nodata_value' in band_input: band.nodata_value = band_input['nodata_value'] # Instantiate band filled with nodata values if only # partial input data has been provided. if band.nodata_value is not None and ( 'data' not in band_input or 'size' in band_input or 'shape' in band_input): band.data(data=(band.nodata_value, ), shape=(1, 1)) # Set band data values from input. band.data( data=band_input.get('data'), size=band_input.get('size'), shape=band_input.get('shape'), offset=band_input.get('offset'), ) # Set SRID self.srs = ds_input.get('srid') # Set additional properties if provided if 'origin' in ds_input: self.origin.x, self.origin.y = ds_input['origin'] if 'scale' in ds_input: self.scale.x, self.scale.y = ds_input['scale'] if 'skew' in ds_input: self.skew.x, self.skew.y = ds_input['skew'] elif isinstance(ds_input, c_void_p): # Instantiate the object using an existing pointer to a gdal raster. self._ptr = ds_input else: raise GDALException('Invalid data source input type: "{}".'.format( type(ds_input)))