def empty_response(self): if self.empty_response_as_png: format = 'png' else: format = self.format if not self._empty_tile: img = BlankImageSource(size=self.grid.tile_size, image_opts=ImageOptions(format=format, transparent=True)) self._empty_tile = img.as_buffer().read() return ImageResponse(self._empty_tile, format=format, timestamp=time.time())
def render(self, tile_request, use_profiles=None): self.requested = True resp = BlankImageSource((256, 256), image_opts=ImageOptions(format='image/png')) resp.timestamp = 0 return resp
def map(self, map_request): self.check_map_request(map_request) params = map_request.params query = MapQuery(params.bbox, params.size, SRS(params.srs), params.format) if map_request.params.get('tiled', 'false').lower() == 'true': query.tiled_only = True orig_query = query if self.srs_extents and params.srs in self.srs_extents: # limit query to srs_extent if query is larger query_extent = MapExtent(params.bbox, SRS(params.srs)) if not self.srs_extents[params.srs].contains(query_extent): limited_extent = self.srs_extents[params.srs].intersection(query_extent) if not limited_extent: img_opts = self.image_formats[params.format_mime_type].copy() img_opts.bgcolor = params.bgcolor img_opts.transparent = params.transparent img = BlankImageSource(size=params.size, image_opts=img_opts, cacheable=True) return Response(img.as_buffer(), content_type=img_opts.format.mime_type) sub_size, offset, sub_bbox = bbox_position_in_image(params.bbox, params.size, limited_extent.bbox) query = MapQuery(sub_bbox, sub_size, SRS(params.srs), params.format) actual_layers = odict() for layer_name in map_request.params.layers: layer = self.layers[layer_name] # only add if layer renders the query if layer.renders_query(query): # if layer is not transparent and will be rendered, # remove already added (then hidden) layers if not layer.transparent: actual_layers = odict() for layer_name, map_layers in layer.map_layers_for_query(query): actual_layers[layer_name] = map_layers authorized_layers, coverage = self.authorized_layers('map', actual_layers.keys(), map_request.http.environ, query_extent=(query.srs.srs_code, query.bbox)) self.filter_actual_layers(actual_layers, map_request.params.layers, authorized_layers) render_layers = [] for layers in actual_layers.values(): render_layers.extend(layers) self.update_query_with_fwd_params(query, params=params, layers=render_layers) raise_source_errors = True if self.on_error == 'raise' else False renderer = LayerRenderer(render_layers, query, map_request, raise_source_errors=raise_source_errors, concurrent_rendering=self.concurrent_layer_renderer) merger = LayerMerger() renderer.render(merger) if self.attribution and not query.tiled_only: merger.add(attribution_image(self.attribution['text'], query.size)) img_opts = self.image_formats[params.format_mime_type].copy() img_opts.bgcolor = params.bgcolor img_opts.transparent = params.transparent result = merger.merge(size=query.size, image_opts=img_opts, bbox=query.bbox, bbox_srs=params.srs, coverage=coverage) if query != orig_query: result = SubImageSource(result, size=orig_query.size, offset=offset, image_opts=img_opts) # Provide the wrapping WSGI app or filter the opportunity to process the # image before it's wrapped up in a response result = self.decorate_img(result, 'wms.map', actual_layers.keys(), map_request.http.environ, (query.srs.srs_code, query.bbox)) try: result_buf = result.as_buffer(img_opts) except IOError, ex: raise RequestError('error while processing image file: %s' % ex, request=map_request)
def empty_response(self): if not self._empty_tile: img = BlankImageSource(size=self.grid.tile_size, image_opts=ImageOptions(format=self.format, transparent=True)) self._empty_tile = img.as_buffer() return ImageResponse(self._empty_tile, time.time())
def setup(self): self.img0 = ImageSource(Image.new("RGB", (10, 10), (0, 10, 20))) self.img1 = ImageSource(Image.new("RGB", (10, 10), (100, 110, 120))) self.img2 = ImageSource(Image.new("RGB", (10, 10), (200, 210, 220))) self.img3 = ImageSource(Image.new("RGB", (10, 10), (0, 255, 0))) self.blank = BlankImageSource(size=(10, 10), image_opts=ImageOptions())
def map(self, map_request): self.check_map_request(map_request) params = map_request.params query = MapQuery(params.bbox, params.size, SRS(params.srs), params.format) if map_request.params.get('tiled', 'false').lower() == 'true': query.tiled_only = True orig_query = query if self.srs_extents and params.srs in self.srs_extents: # limit query to srs_extent if query is larger query_extent = MapExtent(params.bbox, SRS(params.srs)) if not self.srs_extents[params.srs].contains(query_extent): limited_extent = self.srs_extents[params.srs].intersection( query_extent) if not limited_extent: img_opts = self.image_formats[ params.format_mime_type].copy() img_opts.bgcolor = params.bgcolor img_opts.transparent = params.transparent img = BlankImageSource(size=params.size, image_opts=img_opts, cacheable=True) return Response(img.as_buffer(), content_type=img_opts.format.mime_type) sub_size, offset, sub_bbox = bbox_position_in_image( params.bbox, params.size, limited_extent.bbox) query = MapQuery(sub_bbox, sub_size, SRS(params.srs), params.format) actual_layers = odict() for layer_name in map_request.params.layers: layer = self.layers[layer_name] # only add if layer renders the query if layer.renders_query(query): # if layer is not transparent and will be rendered, # remove already added (then hidden) layers if layer.is_opaque(query): actual_layers = odict() for layer_name, map_layers in layer.map_layers_for_query( query): actual_layers[layer_name] = map_layers authorized_layers, coverage = self.authorized_layers( 'map', actual_layers.keys(), map_request.http.environ, query_extent=(query.srs.srs_code, query.bbox)) self.filter_actual_layers(actual_layers, map_request.params.layers, authorized_layers) render_layers = [] for layers in actual_layers.values(): render_layers.extend(layers) self.update_query_with_fwd_params(query, params=params, layers=render_layers) raise_source_errors = True if self.on_error == 'raise' else False renderer = LayerRenderer( render_layers, query, map_request, raise_source_errors=raise_source_errors, concurrent_rendering=self.concurrent_layer_renderer) merger = LayerMerger() renderer.render(merger) if self.attribution and self.attribution.get( 'text') and not query.tiled_only: merger.add(attribution_image(self.attribution['text'], query.size)) img_opts = self.image_formats[params.format_mime_type].copy() img_opts.bgcolor = params.bgcolor img_opts.transparent = params.transparent result = merger.merge(size=query.size, image_opts=img_opts, bbox=query.bbox, bbox_srs=params.srs, coverage=coverage) if query != orig_query: result = SubImageSource(result, size=orig_query.size, offset=offset, image_opts=img_opts) # Provide the wrapping WSGI app or filter the opportunity to process the # image before it's wrapped up in a response result = self.decorate_img(result, 'wms.map', actual_layers.keys(), map_request.http.environ, (query.srs.srs_code, query.bbox)) try: result.georef = GeoReference(bbox=query.bbox, srs=query.srs) result_buf = result.as_buffer(img_opts) except IOError as ex: raise RequestError('error while processing image file: %s' % ex, request=map_request) resp = Response(result_buf, content_type=img_opts.format.mime_type) if query.tiled_only and isinstance(result.cacheable, CacheInfo): cache_info = result.cacheable resp.cache_headers(cache_info.timestamp, etag_data=(cache_info.timestamp, cache_info.size), max_age=self.max_tile_age) resp.make_conditional(map_request.http) if not result.cacheable: resp.cache_headers(no_cache=True) return resp
def merge(self, image_opts, size=None, bbox=None, bbox_srs=None, coverage=None): """ Merge the layers. If the format is not 'png' just return the last image. :param format: The image format for the result. :param size: The size for the merged output. :rtype: `ImageSource` """ if not self.layers: return BlankImageSource(size=size, image_opts=image_opts, cacheable=True) if len(self.layers) == 1: layer_img, layer = self.layers[0] layer_opts = layer_img.image_opts if (((layer_opts and not layer_opts.transparent) or image_opts.transparent) and (not size or size == layer_img.size) and (not layer or not layer.coverage or not layer.coverage.clip) and not coverage): # layer is opaque, no need to make transparent or add bgcolor return layer_img if size is None: size = self.layers[0][0].size cacheable = self.cacheable result = create_image(size, image_opts) for layer_img, layer in self.layers: if not layer_img.cacheable: cacheable = False img = layer_img.as_image() layer_image_opts = layer_img.image_opts if layer_image_opts is None: opacity = None else: opacity = layer_image_opts.opacity if layer and layer.coverage and layer.coverage.clip: img = mask_image(img, bbox, bbox_srs, layer.coverage) if result.mode != 'RGBA': merge_composite = False else: merge_composite = has_alpha_composite_support() if 'transparency' in img.info: # non-paletted PNGs can have a fixed transparency value # convert to RGBA to have full alpha img = img.convert('RGBA') if merge_composite: if opacity is not None and opacity < 1.0: # fade-out img to add opacity value img = img.convert("RGBA") alpha = img.split()[3] alpha = ImageChops.multiply( alpha, ImageChops.constant(alpha, int(255 * opacity))) img.putalpha(alpha) if img.mode in ('RGBA', 'P'): # assume paletted images have transparency if img.mode == 'P': img = img.convert('RGBA') result = Image.alpha_composite(result, img) else: result.paste(img, (0, 0)) else: if opacity is not None and opacity < 1.0: img = img.convert(result.mode) result = Image.blend(result, img, layer_image_opts.opacity) elif img.mode in ('RGBA', 'P'): # assume paletted images have transparency if img.mode == 'P': img = img.convert('RGBA') # paste w transparency mask from layer result.paste(img, (0, 0), img) else: result.paste(img, (0, 0)) # apply global clip coverage if coverage: bg = create_image(size, image_opts) mask = mask_image(result, bbox, bbox_srs, coverage) bg.paste(result, (0, 0), mask) result = bg return ImageSource(result, size=size, image_opts=image_opts, cacheable=cacheable)
def merge(self, sources, image_opts, size=None, bbox=None, bbox_srs=None, coverage=None): if not sources: return BlankImageSource(size=size, image_opts=image_opts, cacheable=True) if size is None: size = sources[0].size # load src bands src_img_bands = [] for i, layer_img in enumerate(sources): img = layer_img.as_image() if i not in self.max_band: # do not split img if not requested by any op src_img_bands.append(None) continue if self.max_band[i] == 3 and img.mode != 'RGBA': # convert to RGBA if band idx 3 is requestd (e.g. P or RGB src) img = img.convert('RGBA') elif img.mode == 'P': img = img.convert('RGB') src_img_bands.append(img.split()) tmp_mode = self.mode if tmp_mode == 'RGBA': result_bands = [None, None, None, None] elif tmp_mode == 'RGB': result_bands = [None, None, None] elif tmp_mode == 'L': result_bands = [None] else: raise ValueError("unsupported destination mode %s", image_opts.mode) for op in self.ops: chan = src_img_bands[op.src_img][op.src_band] if op.factor != 1.0: chan = ImageMath.eval("convert(int(float(a) * %f), 'L')" % op.factor, a=chan) if result_bands[op.dst_band] is None: result_bands[op.dst_band] = chan else: result_bands[op.dst_band] = ImageChops.add( result_bands[op.dst_band], chan, ) else: result_bands[op.dst_band] = chan for i, b in enumerate(result_bands): if b is None: # band not set b = Image.new("L", size, 255 if i == 3 else 0) result_bands[i] = b result = Image.merge(tmp_mode, result_bands) return ImageSource(result, size=size, image_opts=image_opts)
tile_sources = [] for t in tile_collection: # Replace RESCALE_TILE_MISSING with None, before transforming tiles. tile_sources.append(t.source if t.source is not RESCALE_TILE_MISSING else None) tiled_image = TiledImage(tile_sources, src_bbox=src_bbox, src_srs=self.grid.srs, tile_grid=src_tile_grid, tile_size=self.grid.tile_size) tile.source = tiled_image.transform(tile_bbox, self.grid.srs, self.grid.tile_size, self.image_opts) if self.cache_rescaled_tiles: self.cache.store_tile(tile) return tile # RESCALE_TILE_MISSING is a dummy source to prevent a tile cache from loading # a tile that we already found out is missing. RESCALE_TILE_MISSING = BlankImageSource((256, 256), ImageOptions()) class TileCreator(object): def __init__(self, tile_mgr, dimensions=None, image_merger=None, bulk_meta_tiles=False): self.cache = tile_mgr.cache self.sources = tile_mgr.sources self.grid = tile_mgr.grid self.meta_grid = tile_mgr.meta_grid self.bulk_meta_tiles = bulk_meta_tiles self.tile_mgr = tile_mgr self.dimensions = dimensions self.image_merger = image_merger def is_cached(self, tile): """ Return True if the tile is cached.
def render(self, tile_request, use_profiles=None, coverage=None, decorate_img=None): self.requested = True resp = BlankImageSource((256, 256), image_opts=ImageOptions(format='image/png')) resp.timestamp = 0 return resp