Ticket #227: gdal2wktraster_outdb_support.patch

File gdal2wktraster_outdb_support.patch, 15.6 KB (added by jorgearevalo, 3 years ago)
Line 
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