def _colortone(self, image: wand.image.Image, color: str, dst_percent: int, invert: bool) -> None: """ tones either white or black values in image to the provided color, intensity of toning depends on dst_percent :param image: provided image :param color: color to tone image :param dst_percent: percentage of image pixel value to include when blending with provided color, 0 is unchanged, 100 is completely colored in :param invert: if True blacks are modified, if False whites are modified :return: """ mask_src = image.clone() mask_src.colorspace = 'gray' if invert: mask_src.negate() mask_src.alpha_channel = 'copy' src = image.clone() src.colorize(wand.color.Color(color), wand.color.Color('#FFFFFF')) src.composite_channel('alpha', mask_src, 'copy_alpha') image.composite_channel('default_channels', src, 'blend', arguments=str(dst_percent) + "," + str(100 - dst_percent))
def auto_orient(self): image = self.image if image.orientation not in ['top_left', 'undefined']: image = image.clone() if hasattr(image, 'auto_orient'): # Wand 0.4.1 + image.auto_orient() else: orientation_ops = { 'top_right': [image.flop], 'bottom_right': [functools.partial(image.rotate, degree=180.0)], 'bottom_left': [image.flip], 'left_top': [image.flip, functools.partial(image.rotate, degree=90.0)], 'right_top': [functools.partial(image.rotate, degree=90.0)], 'right_bottom': [image.flop, functools.partial(image.rotate, degree=90.0)], 'left_bottom': [functools.partial(image.rotate, degree=270.0)] } fns = orientation_ops.get(image.orientation) if fns: for fn in fns: fn() image.orientation = 'top_left' return WandImage(image)
def auto_orient(self): image = self.image if image.orientation not in ['top_left', 'undefined']: image = image.clone() if hasattr(image, 'auto_orient'): # Wand 0.4.1 + image.auto_orient() else: orientation_ops = { 'top_right': [image.flop], 'bottom_right': [functools.partial(image.rotate, degree=180.0)], 'bottom_left': [image.flip], 'left_top': [image.flip, functools.partial(image.rotate, degree=90.0)], 'right_top': [functools.partial(image.rotate, degree=90.0)], 'right_bottom': [image.flop, functools.partial(image.rotate, degree=90.0)], 'left_bottom': [functools.partial(image.rotate, degree=270.0)] } fns = orientation_ops.get(image.orientation) if fns: for fn in fns: fn() image.orientation = 'top_left' return WandImage(image)
def get_grays(image, width, height): """ 将图片转为灰度图片,并将图片缩小到 width*height,返回灰度像素值列表 """ if isinstance(image, (list, tuple)): if len(image) != width*height: raise ValueError('image sequence length ({}) not equal to width*height ({}).'.format( len(image), width*height )) return image if wand is None and PIL is None: raise ImportError('must have wand or Pillow/PIL installed to use dhash on images.') if wand is not None and isinstance(image, wand.image.Image): with image.clone() as small_image: small_image.type = 'grayscale' small_image.resize((width, height)) blob = small_image.make_blob(format='RGB') return list(blob[::3]) elif PIL is not None and isinstance(image, PIL.Image.Image): gray_image = image.convert('L') small_image = gray_image.resize((width, height), PIL.Image.ANTIALIAS) return list(small_image.getdata()) else: raise ValueError('image must be a wand.image.Image or PIL.Image instance.')
def filter(self, image: wand.image.Image) -> wand.image.Image: """ modified from https://github.com/acoomans/instagram-filters/blob/master/instagram_filters/filters/lomo.py :param image: provided image :return: new filtered image """ filtered_image = image.clone() filtered_image.level(.5, channel="R") filtered_image.level(.5, channel="G") self._vignette(filtered_image) return filtered_image
def filter(self, image: wand.image.Image) -> wand.image.Image: """ modified from https://github.com/acoomans/instagram-filters/blob/master/instagram_filters/filters/nashville.py :param image: :return: new filtered image """ filtered_image = image.clone() self._colortone(filtered_image, '#222b6d', 50, True) self._colortone(filtered_image, '#f7daae', 50, False) filtered_image.sigmoidal_contrast(True, 3, .5 * filtered_image.quantum_range) filtered_image.modulate(100, 150, 100) filtered_image.auto_gamma() return filtered_image
def filter(self, image: wand.image.Image) -> wand.image.Image: """ modified from https://github.com/acoomans/instagram-filters/blob/master/instagram_filters/filters/gotham.py :param image: provided image :return: new filtered image """ filtered_image = image.clone() filtered_image.modulate(120, 10, 100) filtered_image.colorize(wand.color.Color('#222b6d'), wand.color.Color('#333333')) filtered_image.gamma(.9) filtered_image.sigmoidal_contrast(True, 3, .5 * filtered_image.quantum_range) filtered_image.sigmoidal_contrast(True, 3, .5 * filtered_image.quantum_range) return filtered_image
def get_grays(image, width, height): #Convert to gray-scale if isinstance(image, (tuple, list)): if len(image) != width * height: raise ValueError( 'image sequence length ({}) not equal to width*height ({})'. format(len(image), width * height)) return image with image.clone() as image1: image1.type = 'grayscale' image1.resize(width, height) blob = image1.make_blob(format='RGB') return list(blob[::3])
def filter(self, image: wand.image.Image) -> wand.image.Image: """ modified from https://github.com/acoomans/instagram-filters/blob/master/instagram_filters/filters/toaster.py :param image: provided image :return: new filtered image """ filtered_image = image.clone() self._colortone(filtered_image, '#330000', 50, True) filtered_image.modulate(150, 80, 100) filtered_image.gamma(1.2) filtered_image.sigmoidal_contrast(True, 3, .5 * filtered_image.quantum_range) filtered_image.sigmoidal_contrast(True, 3, .5 * filtered_image.quantum_range) self._vignette(filtered_image, 'none', 'LavenderBlush3') self._vignette(filtered_image, '#ff9966', 'none') return filtered_image
def filter(self, image: wand.image.Image) -> wand.image.Image: """ modified from https://github.com/acoomans/instagram-filters/blob/master/instagram_filters/filters/kelvin.py :param image: provided image :return: new filtered image """ filtered_image = image.clone() filtered_image.auto_gamma() filtered_image.modulate(120, 50, 100) with wand.drawing.Drawing() as draw: draw.fill_color = '#FF9900' draw.fill_opacity = 0.2 draw.rectangle(left=0, top=0, width=filtered_image.width, height=filtered_image.height) draw(filtered_image) return filtered_image
def get_grays(image, width, height): """Convert image to grayscale, downsize to width*height, and return list of grayscale integer pixel values (for example, 0 to 255). >>> get_grays([0,0,1,1,1, 0,1,1,3,4, 0,1,6,6,7, 7,7,7,7,9, 8,7,7,8,9], 5, 5) [0, 0, 1, 1, 1, 0, 1, 1, 3, 4, 0, 1, 6, 6, 7, 7, 7, 7, 7, 9, 8, 7, 7, 8, 9] >>> import os >>> test_filename = os.path.join(os.path.dirname(__file__), 'dhash-test.jpg') >>> with wand.image.Image(filename=test_filename) as image: ... get_grays(image, 9, 9)[:18] [95, 157, 211, 123, 94, 79, 75, 75, 78, 96, 116, 122, 113, 93, 75, 82, 81, 79] """ if isinstance(image, (tuple, list)): if len(image) != width * height: raise ValueError( 'image sequence length ({}) not equal to width*height ({})'. format(len(image), width * height)) return image if wand is None and PIL is None: raise ImportError( 'must have wand or Pillow/PIL installed to use dhash on images') if wand is not None and isinstance(image, wand.image.Image): with image.clone() as small_image: small_image.type = 'grayscale' small_image.resize(width, height) blob = small_image.make_blob(format='RGB') if IS_PY3: return list(blob[::3]) else: return [ord(c) for c in blob[::3]] elif PIL is not None and isinstance(image, PIL.Image.Image): # gray_image = image.convert('L') small_image = image.resize((width, height), PIL.Image.ANTIALIAS) return list(small_image.getdata()) else: raise ValueError( 'image must be a wand.image.Image or PIL.Image instance')
def mergeimage(self, image, cfg_section): try: area = CardConfig.str2area(cfg_section["area"]) except KeyError as e: raise CardConfigError("'area' undefined ") from e canvas = self._new_image(width=area.width, height=area.height) img = image.clone() try: resize = cfg_section.getboolean("resize", fallback=DEFAULT_RESIZE) except ValueError as e: raise CardConfigError("'resize' must be a boolean") from e try: trim = cfg_section.getboolean("trim", fallback=DEFAULT_TRIM) except ValueError as e: raise CardConfigError("'trim' must be a boolean") from e try: rotate = cfg_section.getfloat("rotate", fallback=None) except ValueError as e: raise CardConfigError("'rotate' must be a real number") from e if rotate is not None: img.rotate(rotate) if trim: img.trim(color=None) if resize: img.transform(resize="%dx%d" % (area.width, area.height)) canvas.composite(img, gravity=cfg_section.get("gravity", DEFAULT_GRAVITY)) self._image.composite(canvas, self._border + area.x, self._border + area.y)