def test_solid_merge(self): img1 = ImageSource(Image.new("RGB", (10, 10), (255, 0, 255))) img2 = ImageSource(Image.new("RGB", (10, 10), (0, 255, 255))) result = merge_images([img1, img2], ImageOptions(transparent=False)) img = result.as_image() assert img.getpixel((0, 0)) == (0, 255, 255)
def test_solid_merge(self): img1 = ImageSource(Image.new('RGB', (10, 10), (255, 0, 255))) img2 = ImageSource(Image.new('RGB', (10, 10), (0, 255, 255))) result = merge_images([img1, img2], ImageOptions(transparent=False)) img = result.as_image() eq_(img.getpixel((0, 0)), (0, 255, 255))
def test_composite_merge(self): # http://stackoverflow.com/questions/3374878 if not hasattr(Image, 'alpha_composite'): raise SkipTest() img1 = Image.new('RGBA', size=(100, 100), color=(255, 0, 0, 255)) draw = ImageDraw.Draw(img1) draw.rectangle((33, 0, 66, 100), fill=(255, 0, 0, 128)) draw.rectangle((67, 0, 100, 100), fill=(255, 0, 0, 0)) img1 = ImageSource(img1) img2 = Image.new('RGBA', size=(100, 100), color=(0, 255, 0, 255)) draw = ImageDraw.Draw(img2) draw.rectangle((0, 33, 100, 66), fill=(0, 255, 0, 128)) draw.rectangle((0, 67, 100, 100), fill=(0, 255, 0, 0)) img2 = ImageSource(img2) result = merge_images([img2, img1], ImageOptions(transparent=True)) img = result.as_image() eq_(img.mode, 'RGBA') assert_colors_equal(img, [(1089, (0, 255, 0, 255)), (1089, (255, 255, 255, 0)), (1122, (0, 255, 0, 128)), (1122, (128, 126, 0, 255)), (1122, (255, 0, 0, 128)), (1156, (170, 84, 0, 191)), (3300, (255, 0, 0, 255))])
def _query_sources(self, query): """ Query all sources and return the results as a single ImageSource. Multiple sources will be merged into a single image. """ # directly return get_map without merge if ... if (len(self.sources) == 1 and not self.image_merger and # no special image_merger (like BandMerger) not (self.sources[0].coverage and # no clipping coverage self.sources[0].coverage.clip and self.sources[0].coverage.intersects(query.bbox, query.srs)) ): try: return self.sources[0].get_map(query) except BlankImage: return None def get_map_from_source(source): try: img = source.get_map(query) except BlankImage: return None, None else: return (img, source.coverage) layers = [] for layer in async_.imap(get_map_from_source, self.sources): if layer[0] is not None: layers.append(layer) return merge_images(layers, size=query.size, bbox=query.bbox, bbox_srs=query.srs, image_opts=self.tile_mgr.image_opts, merger=self.image_merger)
def test_paletted_merge(self): if not hasattr(Image, 'FASTOCTREE'): raise SkipTest() # generate RGBA images with a transparent rectangle in the lower right img1 = ImageSource(Image.new('RGBA', (50, 50), (0, 255, 0, 255))).as_image() draw = ImageDraw.Draw(img1) draw.rectangle((25, 25, 49, 49), fill=(0, 0, 0, 0)) paletted_img = quantize(img1, alpha=True) assert img_has_transparency(paletted_img) assert paletted_img.mode == 'P' rgba_img = Image.new('RGBA', (50, 50), (255, 0, 0, 255)) draw = ImageDraw.Draw(rgba_img) draw.rectangle((25, 25, 49, 49), fill=(0, 0, 0, 0)) img1 = ImageSource(paletted_img) img2 = ImageSource(rgba_img) # generate base image and merge the others above img3 = ImageSource(Image.new('RGBA', (50, 50), (0, 0, 255, 255))) result = merge_images([img3, img1, img2], ImageOptions(transparent=True)) img = result.as_image() assert img.mode == 'RGBA' eq_(img.getpixel((49, 49)), (0, 0, 255, 255)) eq_(img.getpixel((0, 0)), (255, 0, 0, 255))
def test_composite_merge(self): # http://stackoverflow.com/questions/3374878 if not hasattr(Image, 'alpha_composite'): raise SkipTest() img1 = Image.new('RGBA', size=(100, 100), color=(255, 0, 0, 255)) draw = ImageDraw.Draw(img1) draw.rectangle((33, 0, 66, 100), fill=(255, 0, 0, 128)) draw.rectangle((67, 0, 100, 100), fill=(255, 0, 0, 0)) img1 = ImageSource(img1) img2 = Image.new('RGBA', size =(100, 100), color=(0, 255, 0, 255)) draw = ImageDraw.Draw(img2) draw.rectangle((0, 33, 100, 66), fill=(0, 255, 0, 128)) draw.rectangle((0, 67, 100, 100), fill=(0, 255, 0, 0)) img2 = ImageSource(img2) result = merge_images([img2, img1], ImageOptions(transparent=True)) img = result.as_image() eq_(img.mode, 'RGBA') assert_img_colors_eq(img, [ (1089, (0, 255, 0, 255)), (1089, (255, 255, 255, 0)), (1122, (0, 255, 0, 128)), (1122, (128, 126, 0, 255)), (1122, (255, 0, 0, 128)), (1156, (170, 84, 0, 191)), (3300, (255, 0, 0, 255))])
def test_composite_merge(self): # http://stackoverflow.com/questions/3374878 img1 = Image.new("RGBA", size=(100, 100), color=(255, 0, 0, 255)) draw = ImageDraw.Draw(img1) draw.rectangle((33, 0, 66, 100), fill=(255, 0, 0, 128)) draw.rectangle((67, 0, 100, 100), fill=(255, 0, 0, 0)) img1 = ImageSource(img1) img2 = Image.new("RGBA", size=(100, 100), color=(0, 255, 0, 255)) draw = ImageDraw.Draw(img2) draw.rectangle((0, 33, 100, 66), fill=(0, 255, 0, 128)) draw.rectangle((0, 67, 100, 100), fill=(0, 255, 0, 0)) img2 = ImageSource(img2) result = merge_images([img2, img1], ImageOptions(transparent=True)) img = result.as_image() assert img.mode == "RGBA" assert_img_colors_eq( img, [ (1089, (0, 255, 0, 255)), (1089, (255, 255, 255, 0)), (1122, (0, 255, 0, 128)), (1122, (128, 126, 0, 255)), (1122, (255, 0, 0, 128)), (1156, (170, 84, 0, 191)), (3300, (255, 0, 0, 255)), ], )
def test_opacity_merge_mixed_modes(self): img1 = ImageSource(Image.new('RGBA', (10, 10), (255, 0, 255, 255))) img2 = ImageSource(Image.new('RGB', (10, 10), (0, 255, 255)).convert('P'), image_opts=ImageOptions(opacity=0.5)) result = merge_images([img1, img2], ImageOptions(transparent=True)) img = result.as_image() eq_(img.getpixel((0, 0)), (127, 127, 255, 255))
def test_merge_L(self): img1 = ImageSource(Image.new("RGBA", (10, 10), (255, 0, 255, 255))) img2 = ImageSource(Image.new("L", (10, 10), 100)) # img2 overlays img1 result = merge_images([img1, img2], ImageOptions(transparent=True)) img = result.as_image() assert_img_colors_eq(img, [(10 * 10, (100, 100, 100, 255))])
def test_opacity_merge(self): img1 = ImageSource(Image.new('RGB', (10, 10), (255, 0, 255))) img2 = ImageSource(Image.new('RGB', (10, 10), (0, 255, 255)), image_opts=ImageOptions(opacity=0.5)) result = merge_images([img1, img2], ImageOptions(transparent=False)) img = result.as_image() eq_(img.getpixel((0, 0)), (127, 127, 255))
def test_merge_rgb_with_transp(self): img1 = ImageSource(Image.new("RGB", (10, 10), (255, 0, 255))) raw = Image.new("RGB", (10, 10), (0, 255, 255)) raw.info = {"transparency": (0, 255, 255)} # make full transparent img2 = ImageSource(raw) result = merge_images([img1, img2], ImageOptions(transparent=False)) img = result.as_image() assert img.getpixel((0, 0)) == (255, 0, 255)
def test_merge_rgb_with_transp(self): img1 = ImageSource(Image.new('RGB', (10, 10), (255, 0, 255))) raw = Image.new('RGB', (10, 10), (0, 255, 255)) raw.info = {'transparency': (0, 255, 255)} # make full transparent img2 = ImageSource(raw) result = merge_images([img1, img2], ImageOptions(transparent=False)) img = result.as_image() eq_(img.getpixel((0, 0)), (255, 0, 255))
def test_merge_L(self): img1 = ImageSource(Image.new('RGBA', (10, 10), (255, 0, 255, 255))) img2 = ImageSource(Image.new('L', (10, 10), 100)) # img2 overlays img1 result = merge_images([img1, img2], ImageOptions(transparent=True)) img = result.as_image() assert_img_colors_eq(img, [ (10*10, (100, 100, 100, 255)), ])
def test_opacity_merge_mixed_modes(self): img1 = ImageSource(Image.new("RGBA", (10, 10), (255, 0, 255, 255))) img2 = ImageSource( Image.new("RGB", (10, 10), (0, 255, 255)).convert("P"), image_opts=ImageOptions(opacity=0.5), ) result = merge_images([img1, img2], ImageOptions(transparent=True)) img = result.as_image() assert_img_colors_eq(img, [(10 * 10, (127, 127, 255, 255))])
def test_opacity_merge_mixed_modes(self): img1 = ImageSource(Image.new('RGBA', (10, 10), (255, 0, 255, 255))) img2 = ImageSource(Image.new('RGB', (10, 10), (0, 255, 255)).convert('P'), image_opts=ImageOptions(opacity=0.5)) result = merge_images([img1, img2], ImageOptions(transparent=True)) img = result.as_image() assert_colors_equal(img, [ (10*10, (127, 127, 255, 255)), ])
def test_composite_merge_opacity(self): bg = Image.new("RGBA", size=(100, 100), color=(255, 0, 255, 255)) bg = ImageSource(bg) fg = Image.new("RGBA", size=(100, 100), color=(0, 0, 0, 0)) draw = ImageDraw.Draw(fg) draw.rectangle((10, 10, 89, 89), fill=(0, 255, 255, 255)) fg = ImageSource(fg, image_opts=ImageOptions(opacity=0.5)) result = merge_images([bg, fg], ImageOptions(transparent=True)) img = result.as_image() assert img.mode == "RGBA" assert_img_colors_eq(img, [(3600, (255, 0, 255, 255)), (6400, (128, 127, 255, 255))])
def test_composite_merge_opacity(self): if not hasattr(Image, 'alpha_composite'): raise SkipTest() bg = Image.new('RGBA', size=(100, 100), color=(255, 0, 255, 255)) bg = ImageSource(bg) fg = Image.new('RGBA', size=(100, 100), color=(0, 0, 0, 0)) draw = ImageDraw.Draw(fg) draw.rectangle((10, 10, 89, 89), fill=(0, 255, 255, 255)) fg = ImageSource(fg, image_opts=ImageOptions(opacity=0.5)) result = merge_images([bg, fg], ImageOptions(transparent=True)) img = result.as_image() eq_(img.mode, 'RGBA') assert_img_colors_eq(img, [(3600, (255, 0, 255, 255)), (6400, (128, 127, 255, 255))])
def test_composite_merge_opacity(self): if not hasattr(Image, 'alpha_composite'): raise SkipTest() bg = Image.new('RGBA', size=(100, 100), color=(255, 0, 255, 255)) bg = ImageSource(bg) fg = Image.new('RGBA', size =(100, 100), color=(0, 0, 0, 0)) draw = ImageDraw.Draw(fg) draw.rectangle((10, 10, 89, 89), fill=(0, 255, 255, 255)) fg = ImageSource(fg, image_opts=ImageOptions(opacity=0.5)) result = merge_images([bg, fg], ImageOptions(transparent=True)) img = result.as_image() eq_(img.mode, 'RGBA') assert_img_colors_eq(img, [ (3600, (255, 0, 255, 255)), (6400, (128, 127, 255, 255))])
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. """ return self.tile_mgr.is_cached(tile) def create_tiles(self, tiles): if not self.meta_grid: created_tiles = self._create_single_tiles(tiles) elif self.tile_mgr.minimize_meta_requests and len(tiles) > 1: # use minimal requests only for mulitple tile requests (ie not for TMS) meta_tile = self.meta_grid.minimal_meta_tile( [t.coord for t in tiles]) created_tiles = self._create_meta_tile(meta_tile) else: meta_tiles = [] meta_bboxes = set() for tile in tiles: meta_tile = self.meta_grid.meta_tile(tile.coord) if meta_tile.bbox not in meta_bboxes: meta_tiles.append(meta_tile) meta_bboxes.add(meta_tile.bbox) created_tiles = self._create_meta_tiles(meta_tiles) return created_tiles def _create_single_tiles(self, tiles): if self.tile_mgr.concurrent_tile_creators > 1 and len(tiles) > 1: return self._create_threaded(self._create_single_tile, tiles) created_tiles = [] for tile in tiles: created_tiles.extend(self._create_single_tile(tile)) return created_tiles def _create_threaded(self, create_func, tiles): result = [] async_pool = async .Pool(self.tile_mgr.concurrent_tile_creators) for new_tiles in async_pool.imap(create_func, tiles): result.extend(new_tiles) return result def _create_single_tile(self, tile): tile_bbox = self.grid.tile_bbox(tile.coord) query = MapQuery(tile_bbox, self.grid.tile_size, self.grid.srs, self.tile_mgr.request_format, dimensions=self.dimensions) with self.tile_mgr.lock(tile): if not self.is_cached(tile): source = self._query_sources(query) if not source: return [] if self.tile_mgr.image_opts != source.image_opts: # call as_buffer to force conversion into cache format source.as_buffer(self.tile_mgr.image_opts) source.image_opts = self.tile_mgr.image_opts tile.source = source tile.cacheable = source.cacheable tile = self.tile_mgr.apply_tile_filter(tile) if source.cacheable: self.cache.store_tile(tile) else: self.cache.load_tile(tile) return [tile] def _query_sources(self, query): """ Query all sources and return the results as a single ImageSource. Multiple sources will be merged into a single image. """ # directly return get_map without merge if ... if (len(self.sources) == 1 and not self.image_merger and # no special image_merger (like BandMerger) not (self.sources[0].coverage and # no clipping coverage self.sources[0].coverage.clip and self.sources[0].coverage.intersects( query.bbox, query.srs))): try: return self.sources[0].get_map(query) except BlankImage: return None def get_map_from_source(source): try: img = source.get_map(query) except BlankImage: return None, None else: return (img, source.coverage) layers = [] for layer in async .imap(get_map_from_source, self.sources): if layer[0] is not None: layers.append(layer) return merge_images(layers, size=query.size, bbox=query.bbox, bbox_srs=query.srs, image_opts=self.tile_mgr.image_opts, merger=self.image_merger)
class TileCreator(object): def __init__(self, tile_mgr, dimensions=None): self.cache = tile_mgr.cache self.sources = tile_mgr.sources self.grid = tile_mgr.grid self.meta_grid = tile_mgr.meta_grid self.tile_mgr = tile_mgr self.dimensions = dimensions def is_cached(self, tile): """ Return True if the tile is cached. """ return self.tile_mgr.is_cached(tile) def create_tiles(self, tiles): if not self.meta_grid: created_tiles = self._create_single_tiles(tiles) elif self.tile_mgr.minimize_meta_requests and len(tiles) > 1: # use minimal requests only for mulitple tile requests (ie not for TMS) meta_tile = self.meta_grid.minimal_meta_tile( [t.coord for t in tiles]) created_tiles = self._create_meta_tile(meta_tile) else: meta_tiles = [] meta_bboxes = set() for tile in tiles: meta_tile = self.meta_grid.meta_tile(tile.coord) if meta_tile.bbox not in meta_bboxes: meta_tiles.append(meta_tile) meta_bboxes.add(meta_tile.bbox) created_tiles = self._create_meta_tiles(meta_tiles) return created_tiles def _create_single_tiles(self, tiles): if self.tile_mgr.concurrent_tile_creators > 1 and len(tiles) > 1: return self._create_threaded(self._create_single_tile, tiles) created_tiles = [] for tile in tiles: created_tiles.extend(self._create_single_tile(tile)) return created_tiles def _create_threaded(self, create_func, tiles): result = [] async_pool = async .Pool(self.tile_mgr.concurrent_tile_creators) for new_tiles in async_pool.imap(create_func, tiles): result.extend(new_tiles) return result def _create_single_tile(self, tile): tile_bbox = self.grid.tile_bbox(tile.coord) query = MapQuery(tile_bbox, self.grid.tile_size, self.grid.srs, self.tile_mgr.request_format, dimensions=self.dimensions) with self.tile_mgr.lock(tile): if not self.is_cached(tile): source = self._query_sources(query) if not source: return [] # call as_buffer to force conversion into cache format source.as_buffer(self.tile_mgr.image_opts) source.image_opts = self.tile_mgr.image_opts tile.source = source tile.cacheable = source.cacheable tile = self.tile_mgr.apply_tile_filter(tile) if source.cacheable: self.cache.store_tile(tile) else: self.cache.load_tile(tile) return [tile] def _query_sources(self, query): """ Query all sources and return the results as a single ImageSource. Multiple sources will be merged into a single image. """ if len(self.sources) == 1: try: return self.sources[0].get_map(query) except BlankImage: return None def get_map_from_source(source): try: img = source.get_map(query) except BlankImage: return None else: return img imgs = [] for img in async .imap(get_map_from_source, self.sources): if img is not None: imgs.append(img) if not imgs: return None return merge_images(imgs, size=query.size, image_opts=self.tile_mgr.image_opts)