| 1 | *** gdal2wktraster.py 2009-08-16 19:49:33.000000000 +0200 |
|---|
| 2 | --- gdal2wktraster_outdb.py 2009-08-16 19:59:02.000000000 +0200 |
|---|
| 3 | *************** |
|---|
| 4 | *** 2,7 **** |
|---|
| 5 | --- 2,11 ---- |
|---|
| 6 | # |
|---|
| 7 | # $Id: gdal2wktraster.py 4326 2009-07-22 15:14:41Z mloskot $ |
|---|
| 8 | # |
|---|
| 9 | + # 2009-07-26: Support for out-db rasters (experimental). Not under svn control. |
|---|
| 10 | + # This file should be revised by community- |
|---|
| 11 | + # Author: Jorge Arevalo jorgearevalo@gis4free.org |
|---|
| 12 | + # |
|---|
| 13 | # This is a simple utility used to dump GDAL dataset into HEX WKB stream. |
|---|
| 14 | # It's considered as a prototype of raster2pgsql tool planned to develop |
|---|
| 15 | # in future. |
|---|
| 16 | *************** |
|---|
| 17 | *** 63,68 **** |
|---|
| 18 | --- 67,80 ---- |
|---|
| 19 | g_rt_catalog = '' |
|---|
| 20 | g_rt_schema = 'public' |
|---|
| 21 | |
|---|
| 22 | + # Suffix added to the table name to generate a name for out-db raster |
|---|
| 23 | + g_rt_outdb_sufix = '_outdb.tif' |
|---|
| 24 | + |
|---|
| 25 | + # Default path for outdb raster |
|---|
| 26 | + g_rt_outdb_path = '/tmp' |
|---|
| 27 | + |
|---|
| 28 | + # Path separator, changes in each os |
|---|
| 29 | + path_separator = '/' |
|---|
| 30 | ################################################################################ |
|---|
| 31 | # UTILITIES |
|---|
| 32 | VERBOSE = False |
|---|
| 33 | *************** |
|---|
| 34 | *** 93,99 **** |
|---|
| 35 | grp_r.add_option("-k", "--block-size", dest="block_size", action="store", default=None, |
|---|
| 36 | help="uses regular blocking mode with size of block used to tile input raster, specified as WIDTHxHEIGHT") |
|---|
| 37 | grp_r.add_option("-R", "--register", dest="register", action="store_true", default=False, |
|---|
| 38 | ! help="register the raster as a filesystem (out-db) raster") |
|---|
| 39 | grp_r.add_option("-l", "--overview-level", dest="overview_level", action="store", type="int", default=1, |
|---|
| 40 | help='Create overview tables named as ov_<RASTER TABLE>_<LEVEL> and ' |
|---|
| 41 | 'populate with GDAL-provided overviews (regular blocking only)') |
|---|
| 42 | --- 105,113 ---- |
|---|
| 43 | grp_r.add_option("-k", "--block-size", dest="block_size", action="store", default=None, |
|---|
| 44 | help="uses regular blocking mode with size of block used to tile input raster, specified as WIDTHxHEIGHT") |
|---|
| 45 | grp_r.add_option("-R", "--register", dest="register", action="store_true", default=False, |
|---|
| 46 | ! help="register the raster as a filesystem (out-db) raster") |
|---|
| 47 | ! grp_r.add_option("-p", "--path", dest="outdb_path", action="store", default=None, |
|---|
| 48 | ! help="path to register the raster as a filesystem (out-db) raster") |
|---|
| 49 | grp_r.add_option("-l", "--overview-level", dest="overview_level", action="store", type="int", default=1, |
|---|
| 50 | help='Create overview tables named as ov_<RASTER TABLE>_<LEVEL> and ' |
|---|
| 51 | 'populate with GDAL-provided overviews (regular blocking only)') |
|---|
| 52 | *************** |
|---|
| 53 | *** 158,163 **** |
|---|
| 54 | --- 172,181 ---- |
|---|
| 55 | |
|---|
| 56 | if opts.create_raster_overviews_table and opts.overview_level <= 1: |
|---|
| 57 | prs.error('create table for RASTER_OVERVIEWS available only if overviews import requested') |
|---|
| 58 | + |
|---|
| 59 | + if opts.outdb_path is not None and opts.register == False: |
|---|
| 60 | + prs.error('you need to specify -R option if you want to register the raster as outdb raster') |
|---|
| 61 | + |
|---|
| 62 | |
|---|
| 63 | # XXX: Now, if --band=Nth, then only Nth band of all specified rasters is dumped/imported |
|---|
| 64 | # This behavior can be changed to support only single-raster input if --band option used. |
|---|
| 65 | *************** |
|---|
| 66 | *** 676,682 **** |
|---|
| 67 | rt_skew = ( gt[2], gt[4] ) |
|---|
| 68 | rt_scale = ( gt[1] * level, gt[5] * level ) |
|---|
| 69 | |
|---|
| 70 | - |
|---|
| 71 | # TODO: Any way to lookup for SRID based on SRS in WKT? |
|---|
| 72 | #srs = osr.SpatialReference() |
|---|
| 73 | #srs.ImportFromWkt(ds.GetProjection()) |
|---|
| 74 | --- 694,699 ---- |
|---|
| 75 | *************** |
|---|
| 76 | *** 738,823 **** |
|---|
| 77 | check_hex(hexwkb) |
|---|
| 78 | return hexwkb |
|---|
| 79 | |
|---|
| 80 | ! def wkblify_band(options, band, level, xoff, yoff, read_block_size, block_size): |
|---|
| 81 | ! """Writes band of given GDAL dataset into HEX-encoded WKB for WKT Raster output.""" |
|---|
| 82 | assert band is not None, "Error: Missing GDAL raster band" |
|---|
| 83 | |
|---|
| 84 | hexwkb = '' |
|---|
| 85 | |
|---|
| 86 | ! if options.register: |
|---|
| 87 | ! # Off-db raster |
|---|
| 88 | ! # TODO: Do we want to handle options.overview_level? --mloskot |
|---|
| 89 | ! # TODO: Where bandidx and ds come from? --mloskot |
|---|
| 90 | ! hexwkb += wkblify('B', bandidx - 1) |
|---|
| 91 | ! filepath = os.path.abspath((ds.GetFileList()[0]).replace('\\', '\\\\')) |
|---|
| 92 | ! hexwkb += wkblify(str(len(filepath)) + 's', filepath) |
|---|
| 93 | ! hexwkb += wkblify('B', 0) |
|---|
| 94 | else: |
|---|
| 95 | ! # In-db raster |
|---|
| 96 | |
|---|
| 97 | ! # Real NODATA value or Zero'ed byte(s) |
|---|
| 98 | ! hexnodata = wkblify_band_nodata(band) |
|---|
| 99 | ! bytes_per_pixel = len(hexnodata) / 2 # bytes per pixel used to validate hex string |
|---|
| 100 | ! |
|---|
| 101 | ! # Right most column and bottom most row of blocks have |
|---|
| 102 | ! # portions that extend beyond the raster |
|---|
| 103 | ! read_padding_size = calculate_block_pad_size(band, xoff, yoff, read_block_size) |
|---|
| 104 | ! valid_read_block_size = ( read_block_size[0] - read_padding_size[0], |
|---|
| 105 | ! read_block_size[1] - read_padding_size[1] ) |
|---|
| 106 | ! |
|---|
| 107 | ! |
|---|
| 108 | ! if read_padding_size[0] > 0 or read_padding_size[1] > 0: |
|---|
| 109 | ! target_block_size = (valid_read_block_size[0] / level, valid_read_block_size[1] / level) |
|---|
| 110 | ! target_padding_size = (read_padding_size[0] / level, read_padding_size[1] / level) |
|---|
| 111 | ! else: |
|---|
| 112 | ! target_block_size = block_size |
|---|
| 113 | ! target_padding_size = ( 0, 0 ) |
|---|
| 114 | |
|---|
| 115 | ! logit('MSG: Normalize read_block=%s for level=%d to valid_read_block=%s with padding=%s\n' % \ |
|---|
| 116 | ! (read_block_size, level, valid_read_block_size, read_padding_size)) |
|---|
| 117 | ! logit('MSG: Normalize target_block=%s for level=%d to valid_target_block=%s with padding=%s\n' % \ |
|---|
| 118 | ! (block_size, level, target_block_size, target_padding_size)) |
|---|
| 119 | ! logit('MSG: ReadAsArray( %d, %d, %s, %s)\n' % \ |
|---|
| 120 | ! (xoff, yoff, str(valid_read_block_size), str(target_block_size))) |
|---|
| 121 | |
|---|
| 122 | ! assert valid_read_block_size[0] > 0 and valid_read_block_size[1] > 0 |
|---|
| 123 | ! assert target_block_size[0] > 0 and target_block_size[1] > 0 |
|---|
| 124 | |
|---|
| 125 | ! pixels = band.ReadAsArray(xoff, yoff, valid_read_block_size[0], valid_read_block_size[1], |
|---|
| 126 | ! target_block_size[0], target_block_size[1]) |
|---|
| 127 | |
|---|
| 128 | ! # XXX: Use for debugging only |
|---|
| 129 | ! #dump_block_numpy(pixels) |
|---|
| 130 | |
|---|
| 131 | ! out_pixels = numpy.zeros((block_size[1], block_size[0]), pt2numpy(band.DataType)) |
|---|
| 132 | |
|---|
| 133 | ! logit('MSG: Read valid source:\t%d x %d\n' % (len(pixels[0]), len(pixels))) |
|---|
| 134 | ! logit('MSG: Write into block:\t%d x %d\n' % (len(out_pixels[0]), len(out_pixels))) |
|---|
| 135 | |
|---|
| 136 | ! if target_padding_size[0] > 0 or target_padding_size[1] > 0: |
|---|
| 137 | |
|---|
| 138 | ! ysize_read_pixels = len(pixels) |
|---|
| 139 | ! nodata_value = fetch_band_nodata(band) |
|---|
| 140 | |
|---|
| 141 | ! # Apply columns padding |
|---|
| 142 | ! pad_cols = numpy.array([nodata_value] * target_padding_size[0]) |
|---|
| 143 | ! for row in range (0, ysize_read_pixels): |
|---|
| 144 | ! out_line = numpy.append(pixels[row], pad_cols) |
|---|
| 145 | ! out_pixels[row] = out_line |
|---|
| 146 | ! |
|---|
| 147 | ! # Fill rows padding with nodata value |
|---|
| 148 | ! for row in range(ysize_read_pixels, ysize_read_pixels + target_padding_size[1]): |
|---|
| 149 | ! out_pixels[row].fill(nodata_value) |
|---|
| 150 | ! else: |
|---|
| 151 | ! out_pixels = pixels |
|---|
| 152 | |
|---|
| 153 | ! # XXX: Use for debugging only |
|---|
| 154 | ! #dump_block_numpy(out_pixels) |
|---|
| 155 | |
|---|
| 156 | ! hexwkb = binascii.hexlify(out_pixels) |
|---|
| 157 | |
|---|
| 158 | check_hex(hexwkb) |
|---|
| 159 | return hexwkb |
|---|
| 160 | |
|---|
| 161 | def wkblify_raster_level(options, ds, level, band_range): |
|---|
| 162 | assert ds is not None |
|---|
| 163 | --- 755,920 ---- |
|---|
| 164 | check_hex(hexwkb) |
|---|
| 165 | return hexwkb |
|---|
| 166 | |
|---|
| 167 | ! |
|---|
| 168 | ! def wkblify_indb_band(band, level, xoff, yoff, read_block_size, block_size): |
|---|
| 169 | ! """Writes indb band of given GDAL dataset into HEX-encoded WKB for WKT Raster output.""" |
|---|
| 170 | assert band is not None, "Error: Missing GDAL raster band" |
|---|
| 171 | |
|---|
| 172 | hexwkb = '' |
|---|
| 173 | |
|---|
| 174 | ! # Real NODATA value or Zero'ed byte(s) |
|---|
| 175 | ! hexnodata = wkblify_band_nodata(band) |
|---|
| 176 | ! bytes_per_pixel = len(hexnodata) / 2 # bytes per pixel used to validate hex string |
|---|
| 177 | ! |
|---|
| 178 | ! # Right most column and bottom most row of blocks have |
|---|
| 179 | ! # portions that extend beyond the raster |
|---|
| 180 | ! read_padding_size = calculate_block_pad_size(band, xoff, yoff, read_block_size) |
|---|
| 181 | ! valid_read_block_size = ( read_block_size[0] - read_padding_size[0], |
|---|
| 182 | ! read_block_size[1] - read_padding_size[1] ) |
|---|
| 183 | ! |
|---|
| 184 | ! |
|---|
| 185 | ! if read_padding_size[0] > 0 or read_padding_size[1] > 0: |
|---|
| 186 | ! target_block_size = (valid_read_block_size[0] / level, valid_read_block_size[1] / level) |
|---|
| 187 | ! target_padding_size = (read_padding_size[0] / level, read_padding_size[1] / level) |
|---|
| 188 | else: |
|---|
| 189 | ! target_block_size = block_size |
|---|
| 190 | ! target_padding_size = ( 0, 0 ) |
|---|
| 191 | |
|---|
| 192 | ! logit('MSG: Normalize read_block=%s for level=%d to valid_read_block=%s with padding=%s\n' % \ |
|---|
| 193 | ! (read_block_size, level, valid_read_block_size, read_padding_size)) |
|---|
| 194 | ! logit('MSG: Normalize target_block=%s for level=%d to valid_target_block=%s with padding=%s\n' % \ |
|---|
| 195 | ! (block_size, level, target_block_size, target_padding_size)) |
|---|
| 196 | ! logit('MSG: ReadAsArray( %d, %d, %s, %s)\n' % \ |
|---|
| 197 | ! (xoff, yoff, str(valid_read_block_size), str(target_block_size))) |
|---|
| 198 | ! |
|---|
| 199 | ! assert valid_read_block_size[0] > 0 and valid_read_block_size[1] > 0 |
|---|
| 200 | ! assert target_block_size[0] > 0 and target_block_size[1] > 0 |
|---|
| 201 | |
|---|
| 202 | ! pixels = band.ReadAsArray(xoff, yoff, valid_read_block_size[0], valid_read_block_size[1], |
|---|
| 203 | ! target_block_size[0], target_block_size[1]) |
|---|
| 204 | |
|---|
| 205 | ! # XXX: Use for debugging only |
|---|
| 206 | ! #dump_block_numpy(pixels) |
|---|
| 207 | |
|---|
| 208 | ! out_pixels = numpy.zeros((block_size[1], block_size[0]), pt2numpy(band.DataType)) |
|---|
| 209 | |
|---|
| 210 | ! logit('MSG: Read valid source:\t%d x %d\n' % (len(pixels[0]), len(pixels))) |
|---|
| 211 | ! logit('MSG: Write into block:\t%d x %d\n' % (len(out_pixels[0]), len(out_pixels))) |
|---|
| 212 | ! |
|---|
| 213 | ! if target_padding_size[0] > 0 or target_padding_size[1] > 0: |
|---|
| 214 | ! |
|---|
| 215 | ! ysize_read_pixels = len(pixels) |
|---|
| 216 | ! nodata_value = fetch_band_nodata(band) |
|---|
| 217 | |
|---|
| 218 | ! # Apply columns padding |
|---|
| 219 | ! pad_cols = numpy.array([nodata_value] * target_padding_size[0]) |
|---|
| 220 | ! for row in range (0, ysize_read_pixels): |
|---|
| 221 | ! out_line = numpy.append(pixels[row], pad_cols) |
|---|
| 222 | ! out_pixels[row] = out_line |
|---|
| 223 | ! |
|---|
| 224 | ! # Fill rows padding with nodata value |
|---|
| 225 | ! for row in range(ysize_read_pixels, ysize_read_pixels + target_padding_size[1]): |
|---|
| 226 | ! out_pixels[row].fill(nodata_value) |
|---|
| 227 | ! else: |
|---|
| 228 | ! out_pixels = pixels |
|---|
| 229 | |
|---|
| 230 | ! # XXX: Use for debugging only |
|---|
| 231 | ! #dump_block_numpy(out_pixels) |
|---|
| 232 | ! |
|---|
| 233 | ! hexwkb = binascii.hexlify(out_pixels) |
|---|
| 234 | ! |
|---|
| 235 | ! return hexwkb |
|---|
| 236 | ! |
|---|
| 237 | ! def wkblify_outdb_band(options, level, bandidx, band, out_ds, write_to_file): |
|---|
| 238 | ! """Writes outdb band of given GDAL dataset into HEX-encoded WKB for WKT Raster output.""" |
|---|
| 239 | ! assert band is not None, "Error: Missing GDAL raster band" |
|---|
| 240 | ! |
|---|
| 241 | ! # If path to outdb file wasn't specified, g_rt_outdb_path is used |
|---|
| 242 | ! if options.outdb_path is None: |
|---|
| 243 | ! options.outdb_path = g_rt_outdb_path |
|---|
| 244 | |
|---|
| 245 | ! filepath = options.outdb_path + path_separator + options.table + g_rt_outdb_sufix |
|---|
| 246 | |
|---|
| 247 | ! # Write the band to the file |
|---|
| 248 | ! if write_to_file: |
|---|
| 249 | ! # Get band pixels |
|---|
| 250 | ! pixels = band.ReadAsArray(0, 0, band.XSize, band.YSize, |
|---|
| 251 | ! band.XSize, band.YSize) |
|---|
| 252 | ! |
|---|
| 253 | ! # Write pixels in file |
|---|
| 254 | ! out_ds.GetRasterBand(bandidx).WriteArray(pixels) |
|---|
| 255 | |
|---|
| 256 | ! hexwkb = '' |
|---|
| 257 | ! |
|---|
| 258 | ! # 0-based band number |
|---|
| 259 | ! hexwkb += wkblify('B', bandidx - 1) |
|---|
| 260 | ! |
|---|
| 261 | ! # Path to the file, as 0-end string |
|---|
| 262 | ! hexwkb += wkblify(str(len(filepath)) + 's', filepath) |
|---|
| 263 | ! hexwkb += wkblify('B', 0) |
|---|
| 264 | |
|---|
| 265 | ! return hexwkb |
|---|
| 266 | |
|---|
| 267 | ! |
|---|
| 268 | ! def wkblify_band(options, band, level, xoff, yoff, read_block_size, block_size, out_ds, bandidx): |
|---|
| 269 | ! """Writes band of given GDAL dataset into HEX-encoded WKB for WKT Raster output.""" |
|---|
| 270 | ! assert band is not None, "Error: Missing GDAL raster band" |
|---|
| 271 | ! |
|---|
| 272 | ! hexwkb = '' |
|---|
| 273 | ! |
|---|
| 274 | ! # Off-db raster |
|---|
| 275 | ! if options.register: |
|---|
| 276 | ! if xoff == 0 and yoff == 0: |
|---|
| 277 | ! # Only write the band in file the first time called with each band |
|---|
| 278 | ! hexwkb += wkblify_outdb_band(options, level, bandidx, band, out_ds, True) |
|---|
| 279 | ! else: |
|---|
| 280 | ! hexwkb += wkblify_outdb_band(options, level, bandidx, band, out_ds, False) |
|---|
| 281 | ! |
|---|
| 282 | ! # In-db raster |
|---|
| 283 | ! else: |
|---|
| 284 | ! hexwkb += wkblify_indb_band(band, level, xoff, yoff, read_block_size, block_size) |
|---|
| 285 | |
|---|
| 286 | check_hex(hexwkb) |
|---|
| 287 | return hexwkb |
|---|
| 288 | + |
|---|
| 289 | + def create_empty_outdb_dataset(options, ds, band_range): |
|---|
| 290 | + """Creates a blank tiff raster based on the original one.""" |
|---|
| 291 | + assert ds is not None |
|---|
| 292 | + assert len(band_range) == 2 |
|---|
| 293 | + |
|---|
| 294 | + band_from = band_range[0] |
|---|
| 295 | + band_to = band_range[1] |
|---|
| 296 | + |
|---|
| 297 | + # Create new dataset to write TIFF file |
|---|
| 298 | + outdb_file_name = options.table + g_rt_outdb_sufix |
|---|
| 299 | + tiff_width = ds.RasterXSize |
|---|
| 300 | + tiff_height = ds.RasterYSize |
|---|
| 301 | + |
|---|
| 302 | + tiff_nbands = band_to - band_from |
|---|
| 303 | + raster = gdal.GetDriverByName('GTiff') |
|---|
| 304 | + out_ds = raster.Create(outdb_file_name, tiff_width, tiff_height, tiff_nbands) |
|---|
| 305 | + assert out_ds is not None, "Couldn't create out-db Dataset" |
|---|
| 306 | + |
|---|
| 307 | + #logit("Create empty raster of (%f X %f) with %d bands\n" % (tiff_width, tiff_height, tiff_nbands)) |
|---|
| 308 | + |
|---|
| 309 | + # Set data type for all bands |
|---|
| 310 | + for b in range(band_from, band_to): |
|---|
| 311 | + out_band = out_ds.GetRasterBand(b) |
|---|
| 312 | + band = ds.GetRasterBand(b) |
|---|
| 313 | + assert band is not None, "Missing GDAL raster band %d" % b |
|---|
| 314 | + logit("MSG: Band %d\n" % b) |
|---|
| 315 | + out_band.DataType = band.DataType |
|---|
| 316 | + |
|---|
| 317 | + # Create raster GeoTransform |
|---|
| 318 | + gt = ds.GetGeoTransform() |
|---|
| 319 | + out_ds.SetGeoTransform(gt) |
|---|
| 320 | + |
|---|
| 321 | + # Create projection |
|---|
| 322 | + proj = ds.GetProjection() |
|---|
| 323 | + out_ds.SetProjection(proj) |
|---|
| 324 | + |
|---|
| 325 | + return out_ds |
|---|
| 326 | + |
|---|
| 327 | |
|---|
| 328 | def wkblify_raster_level(options, ds, level, band_range): |
|---|
| 329 | assert ds is not None |
|---|
| 330 | *************** |
|---|
| 331 | *** 874,879 **** |
|---|
| 332 | --- 971,981 ---- |
|---|
| 333 | # Write (original) raster to hex binary output |
|---|
| 334 | tile_count = 0 |
|---|
| 335 | hexwkb = '' |
|---|
| 336 | + |
|---|
| 337 | + if options.register: |
|---|
| 338 | + out_ds = create_empty_outdb_dataset(options, ds, band_range) |
|---|
| 339 | + else: |
|---|
| 340 | + out_ds = None |
|---|
| 341 | |
|---|
| 342 | for ycell in range(0, grid_size[1]): |
|---|
| 343 | for xcell in range(0, grid_size[0]): |
|---|
| 344 | *************** |
|---|
| 345 | *** 896,903 **** |
|---|
| 346 | assert band is not None, "Missing GDAL raster band %d" % b |
|---|
| 347 | logit("MSG: Band %d\n" % b) |
|---|
| 348 | |
|---|
| 349 | ! hexwkb += wkblify_band_header(options, band) |
|---|
| 350 | ! hexwkb += wkblify_band(options, band, level, xoff, yoff, read_block_size, block_size) |
|---|
| 351 | |
|---|
| 352 | # INSERT INTO |
|---|
| 353 | check_hex(hexwkb) # TODO: Remove to not to decrease performance |
|---|
| 354 | --- 998,1005 ---- |
|---|
| 355 | assert band is not None, "Missing GDAL raster band %d" % b |
|---|
| 356 | logit("MSG: Band %d\n" % b) |
|---|
| 357 | |
|---|
| 358 | ! hexwkb += wkblify_band_header(options, band) |
|---|
| 359 | ! hexwkb += wkblify_band(options, band, level, xoff, yoff, read_block_size, block_size, out_ds, b) |
|---|
| 360 | |
|---|
| 361 | # INSERT INTO |
|---|
| 362 | check_hex(hexwkb) # TODO: Remove to not to decrease performance |
|---|
| 363 | *************** |
|---|
| 364 | *** 930,936 **** |
|---|
| 365 | band_range = ( 1, ds.RasterCount + 1 ) |
|---|
| 366 | |
|---|
| 367 | # Generate requested overview level (base raster if level = 1) |
|---|
| 368 | ! summary = wkblify_raster_level(options, ds, options.overview_level, band_range) |
|---|
| 369 | SUMMARY.append( summary ) |
|---|
| 370 | |
|---|
| 371 | # Cleanup |
|---|
| 372 | --- 1032,1038 ---- |
|---|
| 373 | band_range = ( 1, ds.RasterCount + 1 ) |
|---|
| 374 | |
|---|
| 375 | # Generate requested overview level (base raster if level = 1) |
|---|
| 376 | ! summary = wkblify_raster_level(options,ds, options.overview_level, band_range) |
|---|
| 377 | SUMMARY.append( summary ) |
|---|
| 378 | |
|---|
| 379 | # Cleanup |
|---|