def render(self, coord, format): """ Render a tile for a coordinate, return PIL Image-like object. Perform metatile slicing here as well, if required, writing the full set of rendered tiles to cache as we go. Note that metatiling and pass-through mode of a Provider are mutually exclusive options """ if self.bounds and self.bounds.excludes(coord): raise NoTileLeftBehind(Image.new('RGBA', (self.dim, self.dim), (0, 0, 0, 0))) srs = self.projection.srs xmin, ymin, xmax, ymax = self.envelope(coord) width, height = self.dim, self.dim provider = self.provider metatile = self.metatile pass_through = provider.pass_through if hasattr(provider, 'pass_through') else False if self.doMetatile(): if pass_through: raise KnownUnknown('Your provider is configured for metatiling and pass_through mode. That does not work') # adjust render size and coverage for metatile xmin, ymin, xmax, ymax = self.metaEnvelope(coord) width, height = self.metaSize(coord) subtiles = self.metaSubtiles(coord) if self.doMetatile() or hasattr(provider, 'renderArea'): # draw an area, defined in projected coordinates tile = provider.renderArea(width, height, srs, xmin, ymin, xmax, ymax, coord.zoom) elif hasattr(provider, 'renderTile'): # draw a single tile width, height = self.dim, self.dim tile = provider.renderTile(width, height, srs, coord) else: raise KnownUnknown('Your provider lacks renderTile and renderArea methods.') if not hasattr(tile, 'save'): raise KnownUnknown('Return value of provider.renderArea() must act like an image; e.g. have a "save" method.') if hasattr(tile, 'size') and tile.size[1] != height: raise KnownUnknown('Your provider returned the wrong image size: %s instead of %d pixels tall.' % (repr(tile.size), self.dim)) if self.bitmap_palette: # this is where we apply the palette if there is one if pass_through: raise KnownUnknown('Cannot apply palette in pass_through mode') if format.lower() == 'png': t_index = self.png_options.get('transparency', None) tile = apply_palette(tile, self.bitmap_palette, t_index) if self.pixel_effect: # this is where we apply the pixel effect if there is one if pass_through: raise KnownUnknown( 'Cannot apply pixel effect in pass_through mode' ) # if tile is an image if format.lower() in ('png', 'jpeg', 'tiff', 'bmp', 'gif'): tile = self.pixel_effect.apply(tile) if self.doMetatile(): # tile will be set again later tile, surtile = None, tile for (other, x, y) in subtiles: buff = StringIO() bbox = (x, y, x + self.dim, y + self.dim) subtile = surtile.crop(bbox) if self.palette256: # this is where we have PIL optimally palette our image subtile = apply_palette256(subtile) subtile.save(buff, format) body = buff.getvalue() if self.write_cache: self.config.cache.save(body, self, other, format) if other == coord: # the one that actually gets returned tile = subtile _addRecentTile(self, other, format, body) elif self.palette256: tile = apply_palette256(tile) return tile
def render(self, coord, format): """ Render a tile for a coordinate, return PIL Image-like object. Perform metatile slicing here as well, if required, writing the full set of rendered tiles to cache as we go. Note that metatiling and pass-through mode of a Provider are mutually exclusive options """ if self.bounds and self.bounds.excludes(coord): raise NoTileLeftBehind(Image.new('RGB', (self.dim, self.dim), (0x99, 0x99, 0x99))) srs = self.projection.srs xmin, ymin, xmax, ymax = self.envelope(coord) width, height = self.dim, self.dim provider = self.provider metatile = self.metatile pass_through = provider.pass_through if hasattr(provider, 'pass_through') else False if self.doMetatile(): if pass_through: raise KnownUnknown('Your provider is configured for metatiling and pass_through mode. That does not work') # adjust render size and coverage for metatile xmin, ymin, xmax, ymax = self.metaEnvelope(coord) width, height = self.metaSize(coord) subtiles = self.metaSubtiles(coord) if self.doMetatile() or hasattr(provider, 'renderArea'): # draw an area, defined in projected coordinates tile = provider.renderArea(width, height, srs, xmin, ymin, xmax, ymax, coord.zoom) elif hasattr(provider, 'renderTile'): # draw a single tile width, height = self.dim, self.dim tile = provider.renderTile(width, height, srs, coord) else: raise KnownUnknown('Your provider lacks renderTile and renderArea methods.') if not hasattr(tile, 'save'): raise KnownUnknown('Return value of provider.renderArea() must act like an image; e.g. have a "save" method.') if hasattr(tile, 'size') and tile.size[1] != height: raise KnownUnknown('Your provider returned the wrong image size: %s instead of %d pixels tall.' % (repr(tile.size), self.dim)) if self.bitmap_palette: # this is where we apply the palette if there is one if pass_through: raise KnownUnknown('Cannot apply palette in pass_through mode') if format.lower() == 'png': t_index = self.png_options.get('transparency', None) tile = apply_palette(tile, self.bitmap_palette, t_index) if self.doMetatile(): # tile will be set again later tile, surtile = None, tile for (other, x, y) in subtiles: buff = StringIO() bbox = (x, y, x + self.dim, y + self.dim) subtile = surtile.crop(bbox) if self.palette256: # this is where we have PIL optimally palette our image subtile = apply_palette256(subtile) subtile.save(buff, format) body = buff.getvalue() if self.write_cache: self.config.cache.save(body, self, other, format) if other == coord: # the one that actually gets returned tile = subtile _addRecentTile(self, other, format, body) return tile