class TileStacheProvider(object): """An object suitable for use as a TileStache provider. .. py:attribute:: renderer Set this attribute to a renderer instance to use for rendering map tiles. """ def __init__(self, layer): super(TileStacheProvider, self).__init__() self.renderer = TileFetcher() def renderArea(self, width, height, srs, xmin, ymin, xmax, ymax, zoom): spatial_reference = SpatialReference() # this is a special HACK to take account of the fact that the proj4 srs provided by TileStache has the +over # parameter and OGR thinks it is different to EPSG:3857 if srs == TileStache.Geography.SphericalMercator.srs: spatial_reference.ImportFromEPSG(3857) else: spatial_reference.ImportFromProj4(srs) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) cr = cairo.Context(surface) set_geo_transform(cr, xmin, xmax, ymax, ymin, width, height) self.renderer.render_callable(cr, spatial_reference=spatial_reference)() im = Image.frombuffer('RGBA', (width, height), surface.get_data(), 'raw', 'BGRA', 0, 1) return im
def run(args): srs = SpatialReference() if args.epsg is not None: srs.ImportFromEPSG(args.epsg) elif args.proj is not None: srs.ImportFromProj4(args.proj) else: srs.ImportFromEPSG(4326) # default to WGS84 lat/lng left, right, top, bottom = ( args.left*args.units, args.right*args.units, args.top*args.units, args.bottom*args.units ) if args.width is None and args.height is None: print('error: at least one of height or width must be set') sys.exit(1) elif args.height is None: ew, eh = (abs(right-left), abs(top-bottom)) args.height = max(1, int(args.width * eh / ew)) elif args.width is None: ew, eh = (abs(right-left), abs(top-bottom)) args.width = max(1, int(args.height * ew / eh)) size = (args.width, args.height) url_patterns = { 'osm': 'http://otile1.mqcdn.com/tiles/1.0.0/osm/{zoom}/{x}/{y}.jpg', 'aerial': 'http://oatile1.mqcdn.com/tiles/1.0.0/sat/{zoom}/{x}/{y}.jpg', } def url_fetcher(url): http = httplib2.Http(args.cache_dir) rep, content = http.request(url, 'GET') if rep.status != 200: raise foldbeam.renderer.URLFetchError(str(rep.status) + ' ' + rep.reason) return content renderer = TileFetcher( url_pattern=url_patterns['aerial' if args.aerial else 'osm'], url_fetcher=url_fetcher) output_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, size[0], size[1]) context = cairo.Context(output_surface) set_geo_transform(context, left, right, top, bottom, size[0], size[1]) renderer.render_callable(context, spatial_reference=srs)() output_surface.write_to_png(args.output)
def __init__(self, layer): super(TileStacheProvider, self).__init__() self.renderer = TileFetcher()
def run(args): srs = SpatialReference() srs.ImportFromEPSG(4326) # default to WGS84 lat/lng if args.like_filename is not None: like_ds = gdal.Open(args.like_filename) ox, sx, _, oy, _, sy = like_ds.GetGeoTransform() args.width = like_ds.RasterXSize args.height = like_ds.RasterYSize args.left = ox args.right = ox + sx * args.width args.top = oy args.bottom = oy + sy * args.height args.units = 1 # FIXME: projection elif args.cx is not None and args.cy is not None and args.ex is not None and args.ey is not None: args.left = args.cx - args.ex * 0.5 args.right = args.cx + args.ex * 0.5 args.top = args.cy + args.ey * 0.5 args.bottom = args.cy - args.ey * 0.5 elif args.left is None or args.right is None or args.top is None or args.bottom is None: print('error: all of left, right, top and bottom extent must be specified') if args.epsg is not None: srs.ImportFromEPSG(args.epsg) elif args.proj is not None: srs.ImportFromProj4(args.proj) left, right, top, bottom = ( args.left*args.units, args.right*args.units, args.top*args.units, args.bottom*args.units ) if args.width is None and args.height is None: print('error: at least one of height or width must be set') sys.exit(1) elif args.height is None: ew, eh = (abs(right-left), abs(top-bottom)) args.height = max(1, int(args.width * eh / ew)) elif args.width is None: ew, eh = (abs(right-left), abs(top-bottom)) args.width = max(1, int(args.height * ew / eh)) size = (args.width, args.height) url_patterns = { 'osm': 'http://otile1.mqcdn.com/tiles/1.0.0/osm/{zoom}/{x}/{y}.jpg', 'aerial': 'http://ecn.t1.tiles.virtualearth.net/tiles/a{quadkey}.jpeg?g=1647', #'aerial': 'http://oatile1.mqcdn.com/tiles/1.0.0/sat/{zoom}/{x}/{y}.jpg', } def url_fetcher(url): http = httplib2.Http(args.cache_dir) rep, content = http.request(url, 'GET') if rep.status != 200: raise foldbeam.renderer.URLFetchError(str(rep.status) + ' ' + rep.reason) return content renderer = TileFetcher( url_pattern=url_patterns['aerial' if args.aerial else 'osm'], url_fetcher=url_fetcher) if args.output.endswith('.tiff'): import numpy as np image_data = np.zeros((size[1], size[0], 4), dtype=np.uint8) output_surface = cairo.ImageSurface.create_for_data( image_data, cairo.FORMAT_ARGB32, size[0], size[1]) context = cairo.Context(output_surface) set_geo_transform(context, left, right, top, bottom, size[0], size[1]) renderer.render_callable(context, spatial_reference=srs)() ds = gdal_array.OpenArray( np.transpose(image_data[:,:,[2,1,0,3]], (2,0,1))) ds.SetGeoTransform(( left, (right - left) / size[0], 0, top, 0, (bottom - top) / size[1] )) drv = gdal.GetDriverByName('GTiff') drv.Delete(args.output) drv.CreateCopy(args.output, ds, options=('COMPRESS=LZW',)) else: output_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, size[0], size[1]) context = cairo.Context(output_surface) set_geo_transform(context, left, right, top, bottom, size[0], size[1]) renderer.render_callable(context, spatial_reference=srs)() output_surface.write_to_png(args.output)