Package osgeo :: Package utils :: Module gdal_edit |
[hide private]
[frames] | no frames]

# Source Code for Module osgeo.utils.gdal_edit

      1  #!/usr/bin/env python3
      2  # -*- coding: utf-8 -*-
      3  ###############################################################################
      4  # $Id$
      5  #
      6  #  Project:  GDAL samples
      7  #  Purpose:  Edit in place various information of an existing GDAL dataset
      8  #  Author:   Even Rouault <even dot rouault at spatialys.com>
      9  #
     10  ###############################################################################
     11  #  Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
     12  #
     13  #  Permission is hereby granted, free of charge, to any person obtaining a
     14  #  copy of this software and associated documentation files (the "Software"),
     15  #  to deal in the Software without restriction, including without limitation
     16  #  the rights to use, copy, modify, merge, publish, distribute, sublicense,
     17  #  and/or sell copies of the Software, and to permit persons to whom the
     18  #  Software is furnished to do so, subject to the following conditions:
     19  #
     20  #  The above copyright notice and this permission notice shall be included
     21  #  in all copies or substantial portions of the Software.
     22  #
     23  #  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     24  #  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     25  #  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     26  #  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     27  #  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     28  #  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     29  #  DEALINGS IN THE SOFTWARE.
     30  ###############################################################################
     31
     32  import sys
     33  from osgeo import gdal
     34  from osgeo import osr
     35
     36
     37 -def Usage():
     38      print('Usage: gdal_edit [--help-general] [-ro] [-a_srs srs_def]')
     39      print('                 [-a_ullr ulx uly lrx lry] [-a_ulurll ulx uly urx ury llx lly]')
     40      print('                 [-tr xres yres] [-unsetgt] [-unsetrpc] [-a_nodata value] [-unsetnodata]')
     41      print('                 [-offset value] [-scale value] [-units value]')
     42      print('                 [-colorinterp_X red|green|blue|alpha|gray|undefined]*')
     43      print('                 [-unsetstats] [-stats] [-approx_stats]')
     44      print('                 [-setstats min max mean stddev]')
     45      print('                 [-gcp pixel line easting northing [elevation]]*')
     46      print('                 [-unsetmd] [-oo NAME=VALUE]* [-mo "META-TAG=VALUE"]*  datasetname')
     47      print('')
     48      print('Edit in place various information of an existing GDAL dataset.')
     49      return -1
     50
     51
     52 -def ArgIsNumeric(s):
     53      i = 0
     54
     55      while i < len(s):
     56          if (s[i] < '0' or s[i] > '9') and s[i] != '.' and s[i] != 'e' and s[i] != '+' and s[i] != '-':
     57              return False
     58          i = i + 1
     59
     60      return True
     61
     62
     63 -def gdal_edit(argv):
     64
     65      argv = gdal.GeneralCmdLineProcessor(argv)
     66      if argv is None:
     67          return -1
     68
     69      datasetname = None
     70      srs = None
     71      ulx = None
     72      uly = None
     73      urx = None
     74      ury = None
     75      llx = None
     76      lly = None
     77      lrx = None
     78      lry = None
     79      nodata = None
     80      unsetnodata = False
     81      units = None
     82      xres = None
     83      yres = None
     84      unsetgt = False
     85      unsetstats = False
     86      stats = False
     87      setstats = False
     88      approx_stats = False
     89      unsetmd = False
     90      ro = False
     91      molist = []
     92      gcp_list = []
     93      open_options = []
     94      offset = []
     95      scale = []
     96      colorinterp = {}
     97      unsetrpc = False
     98
     99      i = 1
    100      argc = len(argv)
    101      while i < argc:
    102          if argv[i] == '-ro':
    103              ro = True
    104          elif argv[i] == '-a_srs' and i < len(argv) - 1:
    105              srs = argv[i + 1]
    106              i = i + 1
    107          elif argv[i] == '-a_ullr' and i < len(argv) - 4:
    108              ulx = float(argv[i + 1])
    109              i = i + 1
    110              uly = float(argv[i + 1])
    111              i = i + 1
    112              lrx = float(argv[i + 1])
    113              i = i + 1
    114              lry = float(argv[i + 1])
    115              i = i + 1
    116          elif argv[i] == '-a_ulurll' and i < len(argv) - 6:
    117              ulx = float(argv[i + 1])
    118              i = i + 1
    119              uly = float(argv[i + 1])
    120              i = i + 1
    121              urx = float(argv[i + 1])
    122              i = i + 1
    123              ury = float(argv[i + 1])
    124              i = i + 1
    125              llx = float(argv[i + 1])
    126              i = i + 1
    127              lly = float(argv[i + 1])
    128              i = i + 1
    129          elif argv[i] == '-tr' and i < len(argv) - 2:
    130              xres = float(argv[i + 1])
    131              i = i + 1
    132              yres = float(argv[i + 1])
    133              i = i + 1
    134          elif argv[i] == '-a_nodata' and i < len(argv) - 1:
    135              nodata = float(argv[i + 1])
    136              i = i + 1
    137          elif argv[i] == '-scale' and i < len(argv) :
    138              scale.append(float(argv[i+1]))
    139              i = i + 1
    140              while i < len(argv) - 1 and ArgIsNumeric(argv[i+1]):
    141                  scale.append(float(argv[i+1]))
    142                  i = i + 1
    143          elif argv[i] == '-offset' and i < len(argv) - 1:
    144              offset.append(float(argv[i+1]))
    145              i = i + 1
    146              while i < len(argv) - 1 and ArgIsNumeric(argv[i+1]):
    147                  offset.append(float(argv[i+1]))
    148                  i = i + 1
    149          elif argv[i] == '-mo' and i < len(argv) - 1:
    150              molist.append(argv[i + 1])
    151              i = i + 1
    152          elif argv[i] == '-gcp' and i + 4 < len(argv):
    153              pixel = float(argv[i + 1])
    154              i = i + 1
    155              line = float(argv[i + 1])
    156              i = i + 1
    157              x = float(argv[i + 1])
    158              i = i + 1
    159              y = float(argv[i + 1])
    160              i = i + 1
    161              if i + 1 < len(argv) and ArgIsNumeric(argv[i + 1]):
    162                  z = float(argv[i + 1])
    163                  i = i + 1
    164              else:
    165                  z = 0
    166              gcp = gdal.GCP(x, y, z, pixel, line)
    167              gcp_list.append(gcp)
    168          elif argv[i] == '-unsetgt':
    169              unsetgt = True
    170          elif argv[i] == '-unsetrpc':
    171              unsetrpc = True
    172          elif argv[i] == '-unsetstats':
    173              unsetstats = True
    174          elif argv[i] == '-approx_stats':
    175              stats = True
    176              approx_stats = True
    177          elif argv[i] == '-stats':
    178              stats = True
    179          elif argv[i] == '-setstats' and i < len(argv)-4:
    180              stats = True
    181              setstats = True
    182              if argv[i + 1] != 'None':
    183                  statsmin = float(argv[i + 1])
    184              else:
    185                  statsmin = None
    186              i = i + 1
    187              if argv[i + 1] != 'None':
    188                  statsmax = float(argv[i + 1])
    189              else:
    190                  statsmax = None
    191              i = i + 1
    192              if argv[i + 1] != 'None':
    193                  statsmean = float(argv[i + 1])
    194              else:
    195                  statsmean = None
    196              i = i + 1
    197              if argv[i + 1] != 'None':
    198                  statsdev = float(argv[i + 1])
    199              else:
    200                  statsdev = None
    201              i = i + 1
    202          elif argv[i] == '-units' and i < len(argv) - 1:
    203              units = argv[i + 1]
    204              i = i + 1
    205          elif argv[i] == '-unsetmd':
    206              unsetmd = True
    207          elif argv[i] == '-unsetnodata':
    208              unsetnodata = True
    209          elif argv[i] == '-oo' and i < len(argv) - 1:
    210              open_options.append(argv[i + 1])
    211              i = i + 1
    212          elif argv[i].startswith('-colorinterp_')and i < len(argv) - 1:
    213              band = int(argv[i][len('-colorinterp_'):])
    214              val = argv[i + 1]
    215              if val.lower() == 'red':
    216                  val = gdal.GCI_RedBand
    217              elif val.lower() == 'green':
    218                  val = gdal.GCI_GreenBand
    219              elif val.lower() == 'blue':
    220                  val = gdal.GCI_BlueBand
    221              elif val.lower() == 'alpha':
    222                  val = gdal.GCI_AlphaBand
    223              elif val.lower() == 'gray' or val.lower() == 'grey':
    224                  val = gdal.GCI_GrayIndex
    225              elif val.lower() == 'undefined':
    226                  val = gdal.GCI_Undefined
    227              else:
    228                  sys.stderr.write('Unsupported color interpretation %s.\n' % val +
    229                                   'Only red, green, blue, alpha, gray, undefined are supported.\n')
    230                  return Usage()
    231              colorinterp[band] = val
    232              i = i + 1
    233          elif argv[i][0] == '-':
    234              sys.stderr.write('Unrecognized option : %s\n' % argv[i])
    235              return Usage()
    236          elif datasetname is None:
    237              datasetname = argv[i]
    238          else:
    239              sys.stderr.write('Unexpected option : %s\n' % argv[i])
    240              return Usage()
    241
    242          i = i + 1
    243
    244      if datasetname is None:
    245          return Usage()
    246
    247      if (srs is None and lry is None and yres is None and not unsetgt and
    248              not unsetstats and not stats and not setstats and nodata is None and
    249              not units and not molist and not unsetmd and not gcp_list and
    250              not unsetnodata and not colorinterp and
    251              scale is None and offset is None and not unsetrpc):
    252          print('No option specified')
    253          print('')
    254          return Usage()
    255
    256      exclusive_option = 0
    257      if lry is not None:
    258          exclusive_option = exclusive_option + 1
    259      if lly is not None:  # -a_ulurll
    260          exclusive_option = exclusive_option + 1
    261      if yres is not None:
    262          exclusive_option = exclusive_option + 1
    263      if unsetgt:
    264          exclusive_option = exclusive_option + 1
    265      if exclusive_option > 1:
    266          print('-a_ullr, -a_ulurll, -tr and -unsetgt options are exclusive.')
    267          print('')
    268          return Usage()
    269
    270      if unsetstats and stats:
    271          print('-unsetstats and either -stats or -approx_stats options are exclusive.')
    272          print('')
    273          return Usage()
    274
    275      if unsetnodata and nodata:
    276          print('-unsetnodata and -nodata options are exclusive.')
    277          print('')
    278          return Usage()
    279
    280      if open_options is not None:
    281          if ro:
    282              ds = gdal.OpenEx(datasetname, gdal.OF_RASTER, open_options=open_options)
    283          else:
    284              ds = gdal.OpenEx(datasetname, gdal.OF_RASTER | gdal.OF_UPDATE, open_options=open_options)
    285      # GDAL 1.X compat
    286      elif ro:
    287          ds = gdal.Open(datasetname)
    288      else:
    289          ds = gdal.Open(datasetname, gdal.GA_Update)
    290      if ds is None:
    291          return -1
    292
    293      if scale:
    294          if len(scale) == 1:
    295              scale = scale * ds.RasterCount
    296          elif len(scale) != ds.RasterCount:
    297              print('If more than one scale value is provided, their number must match the number of bands.')
    298              print('')
    299              return Usage()
    300
    301      if offset:
    302          if len(offset) == 1:
    303              offset = offset * ds.RasterCount
    304          elif len(offset) != ds.RasterCount:
    305              print('If more than one offset value is provided, their number must match the number of bands.')
    306              print('')
    307              return Usage()
    308
    309      wkt = None
    310      if srs == '' or srs == 'None':
    311          ds.SetProjection('')
    312      elif srs is not None:
    313          sr = osr.SpatialReference()
    314          if sr.SetFromUserInput(srs) != 0:
    315              print('Failed to process SRS definition: %s' % srs)
    316              return -1
    317          wkt = sr.ExportToWkt()
    318          if not gcp_list:
    319              ds.SetProjection(wkt)
    320
    321      if lry is not None:
    322          gt = [ulx, (lrx - ulx) / ds.RasterXSize, 0,
    323                uly, 0, (lry - uly) / ds.RasterYSize]
    324          ds.SetGeoTransform(gt)
    325
    326      elif lly is not None:  # -a_ulurll
    327          gt = [ulx, (urx - ulx) / ds.RasterXSize, (llx - ulx) / ds.RasterYSize,
    328                uly, (ury - uly) / ds.RasterXSize, (lly - uly) / ds.RasterYSize]
    329          ds.SetGeoTransform(gt)
    330
    331      if yres is not None:
    332          gt = ds.GetGeoTransform()
    333          # Doh ! why is gt a tuple and not an array...
    334          gt = [gt[j] for j in range(6)]
    335          gt[1] = xres
    336          gt[5] = yres
    337          ds.SetGeoTransform(gt)
    338
    339      if unsetgt:
    340          # For now only the GTiff drivers understands full-zero as a hint
    341          # to unset the geotransform
    342          if ds.GetDriver().ShortName == 'GTiff':
    343              ds.SetGeoTransform([0, 0, 0, 0, 0, 0])
    344          else:
    345              ds.SetGeoTransform([0, 1, 0, 0, 0, 1])
    346
    347      if gcp_list:
    348          if wkt is None:
    349              wkt = ds.GetGCPProjection()
    350          if wkt is None:
    351              wkt = ''
    352          ds.SetGCPs(gcp_list, wkt)
    353
    354      if nodata is not None:
    355          for i in range(ds.RasterCount):
    356              ds.GetRasterBand(i + 1).SetNoDataValue(nodata)
    357      elif unsetnodata:
    358          for i in range(ds.RasterCount):
    359              ds.GetRasterBand(i + 1).DeleteNoDataValue()
    360
    361      if scale:
    362          for i in range(ds.RasterCount):
    363              ds.GetRasterBand(i + 1).SetScale(scale[i])
    364
    365      if offset:
    366          for i in range(ds.RasterCount):
    367              ds.GetRasterBand(i + 1).SetOffset(offset[i])
    368
    369      if units:
    370          for i in range(ds.RasterCount):
    371              ds.GetRasterBand(i + 1).SetUnitType(units)
    372
    373      if unsetstats:
    374          for i in range(ds.RasterCount):
    375              band = ds.GetRasterBand(i + 1)
    376              for key in band.GetMetadata().keys():
    377                  if key.startswith('STATISTICS_'):
    378                      band.SetMetadataItem(key, None)
    379
    380      if stats:
    381          for i in range(ds.RasterCount):
    382              ds.GetRasterBand(i + 1).ComputeStatistics(approx_stats)
    383
    384      if setstats:
    385          for i in range(ds.RasterCount):
    386              if statsmin is None or statsmax is None or statsmean is None or statsdev is None:
    387                  ds.GetRasterBand(i+1).ComputeStatistics(approx_stats)
    388                  min,max,mean,stdev = ds.GetRasterBand(i+1).GetStatistics(approx_stats,True)
    389                  if statsmin is None:
    390                      statsmin = min
    391                  if statsmax is None:
    392                      statsmax = max
    393                  if statsmean is None:
    394                      statsmean = mean
    395                  if statsdev is None:
    396                      statsdev = stdev
    397              ds.GetRasterBand(i+1).SetStatistics(statsmin, statsmax, statsmean, statsdev)
    398
    399      if molist:
    400          if unsetmd:
    401              md = {}
    402          else:
    403              md = ds.GetMetadata()
    404          for moitem in molist:
    405              equal_pos = moitem.find('=')
    406              if equal_pos > 0:
    407                  md[moitem[0:equal_pos]] = moitem[equal_pos + 1:]
    408          ds.SetMetadata(md)
    409      elif unsetmd:
    410          ds.SetMetadata({})
    411
    412      for band in colorinterp:
    413          ds.GetRasterBand(band).SetColorInterpretation(colorinterp[band])
    414
    415      if unsetrpc:
    416          ds.SetMetadata(None, 'RPC')
    417
    418      ds = band = None
    419
    420      return 0
    421
    422
    423 -def main(argv):
    424      return gdal_edit(argv)
    425
    426
    427  if __name__ == '__main__':
    428      sys.exit(main(sys.argv))
    429