Skip to content

Commit

Permalink
Refactored command-line interface
Browse files Browse the repository at this point in the history
CLI now based on Python argparse conventions.
  • Loading branch information
arthur-e committed Aug 18, 2016
1 parent 816cae0 commit 88e6655
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 61 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ $ ./gdal_extent.py Wayne_county.tiff
To get the width/height of a raster:

```sh
$ ./gdal_extent.py -size Wayne_county.tiff
$ ./gdal_extent.py --size Wayne_county.tiff
1875 1551
```

To get a GeoJSON Polygon for the rectangular extent as a string, with 2 spaces for indentation:

```sh
$ ./gdal_extent.py -geojson -i 2 Wayne_county.tiff
$ ./gdal_extent.py --extent --as-json -i 2 Wayne_county.tiff
{
"coordinates": [
[
Expand Down
124 changes: 65 additions & 59 deletions gdal_extent.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,24 @@
# A command-line utility for getting the extent (bounds) of any raster as
# Well-Known Text (WKT), GeoJSON, or other vector formats.

import argparse
import json
import sys
from osgeo import gdal, ogr

def get_min_max_extent(rast):
class CustomArgumentParser(argparse.ArgumentParser):
def error(self, message):
# Default with no options/ switches: Report min/max bounds
if message.find('unrecognized arguments') >= 0:
main(sys.argv[1:], get_min_max_bounds)
sys.exit(2)

sys.stderr.write('error: %s\n' % message)
self.print_help()
sys.exit(2)


def get_min_max_bounds(rast):
'''
Returns the minimum and maximum coordinate values in the sequence expected
by, e.g., the `-te` switch in various GDAL utiltiies:
Expand All @@ -21,7 +34,7 @@ def get_min_max_extent(rast):
return [gt[0], gt[3] - (ysize * yr), gt[0] + (xsize * xr), gt[3]]


def get_rect_extent_as_geojson(rast, as_string=False):
def get_rect_extent(rast):
'''
Returns the rectangular extent as GeoJSON Polygon string.
'''
Expand All @@ -30,16 +43,11 @@ def get_rect_extent_as_geojson(rast, as_string=False):
# Repeat the last coordinate (for closure)
ext.append(ext[0])

result = {
return {
'coordinates': [ext],
'type': 'Polygon'
}

if as_string:
return json.dumps(result, sort_keys=False, indent=2)

return result


def get_rect_extent_as_sequence(rast):
'''
Expand All @@ -48,7 +56,7 @@ def get_rect_extent_as_sequence(rast):
and moving clockwise.
'''
gt = rast.GetGeoTransform()
c = get_min_max_extent(rast)
c = get_min_max_bounds(rast)
# Top-left, top-right, bottom-right, bottom-left
return [(c[0], c[3]), (c[2], c[3]), (c[2], c[1]), (c[0], c[1])]

Expand All @@ -64,65 +72,63 @@ def stringify(sequence, sep=' '):
return ' '.join(map(str, sequence))


def display_usage():
print('Usage: gdal_extent.py [-geojson|-size] [-i indentation] input_files')
print('')


def main(argv=None):
if argv is None:
argv = sys.argv

argv = gdal.GeneralCmdLineProcessor(argv)
func = get_min_max_extent # Function to call
indent = None # Indentation level
json_out = False # Output is JSON
names = [] # Filenames found

if argv is None:
sys.exit(0)

# Parse command line arguments.
i = 1
while i < len(argv):

if argv[i] == '-i':
indent = int(argv[i + 1])
i += 1

elif argv[i] == '-geojson':
json_out = True
func = get_rect_extent_as_geojson

elif argv[i] == '-size':
func = get_width_height

else:
names.append(argv[i])

i += 1

if len(names) == 0:
sys.stdout.write('No input files selected.')
display_usage()
sys.exit(1)

def main(args, handler, as_json=False, indent=None):
# Execute the function for each filename
for name in names:
for name in args:
ds = gdal.Open(name)

if json_out:
sys.stdout.write(json.dumps(func(ds), sort_keys=False,
# Write results to standard output
if as_json:
sys.stdout.write(json.dumps(handler(ds), sort_keys=False,
indent=indent))

else:
sys.stdout.write(stringify(func(ds)))
sys.stdout.write(stringify(handler(ds)))

sys.stdout.write('\n')
ds = None

return 0


if __name__ == '__main__':
sys.exit(main())
parser = CustomArgumentParser(description='''
A command-line tool for reporting the extent of GDAL datasets:
[-b --bounds] returns the min-max bounds (xmin, ymin, xmax, ymax);
[-e --extent] returns the rectangular extent as a GeoJSON polygon;
[-s --size] returns the width and height.
''')

# Commands
commands_group = parser.add_mutually_exclusive_group()
commands_group.add_argument('-b', '--bounds', metavar='PATH',
nargs='*', help='')
commands_group.add_argument('-e', '--extent', metavar='PATH',
nargs='*', help='')
commands_group.add_argument('-s', '--size', metavar='PATH',
nargs='*', help='')

# Options
parser.add_argument('-j', '--as-json', action='store_true',
help='output GeoJSON')
parser.add_argument('-i', '--indent', metavar='WIDTH', default=None,
help='indentation for output GeoJSON', type=int)

# If no arguments are supplied...
if len(sys.argv) == 1:
parser.print_usage()
sys.exit(1)

args = parser.parse_args()
kwargs = {
'as_json': args.as_json,
'indent': args.indent
}

if args.bounds:
main(args.bounds, get_min_max_bounds, **kwargs)

elif args.extent:
kwargs['as_json'] = True # Force JSON output
main(args.extent, get_rect_extent, **kwargs)

elif args.size:
main(args.size, get_width_height, **kwargs)

0 comments on commit 88e6655

Please sign in to comment.