def _make_transparent(img, color, tolerance=10): img.load() if img.mode == 'P': img = img.convert('RGBA') channels = img.split() mask_channels = [] for ch, c in zip(channels, color): # create bit mask for each matched color low_c, high_c = c - tolerance, c + tolerance mask_channels.append( Image.eval(ch, lambda x: 255 if low_c <= x <= high_c else 0)) # multiply channel bit masks to get a single mask alpha = reduce(ImageChops.multiply, mask_channels) # invert to get alpha channel alpha = ImageChops.invert(alpha) if len(channels) == 4: # multiply with existing alpha alpha = ImageChops.multiply(alpha, channels[-1]) img.putalpha(alpha) return img
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)
def _make_transparent(img, color, tolerance=10): img.load() if img.mode == 'P': img = img.convert('RGBA') channels = img.split() mask_channels = [] for ch, c in zip(channels, color): # create bit mask for each matched color low_c, high_c = c-tolerance, c+tolerance mask_channels.append(Image.eval(ch, lambda x: 255 if low_c <= x <= high_c else 0)) # multiply channel bit masks to get a single mask alpha = reduce(ImageChops.multiply, mask_channels) # invert to get alpha channel alpha = ImageChops.invert(alpha) if len(channels) == 4: # multiply with existing alpha alpha = ImageChops.multiply(alpha, channels[-1]) img.putalpha(alpha) return img
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 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, 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_coverage = 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_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_coverage 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_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 len(sources) < self.max_src_images: 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)