def inject_symbol(self, symbol: GenericSymbol, original_image: Image): # Fetch the image in appropriate format text_box_config = self.ctbm.get_config(symbol) resolution = text_box_config.resol if text_box_config else 1 image_quality_prefix = SYMBOL_SOURCE_RESOLUTIONS[resolution] symbol_image = Image.open( os.path.join(PNG_SYMBOL_PATH, f"{image_quality_prefix}", f"{symbol.name}.png"), "r", ) symbol.resolution = resolution # Put symbol and text boxes offset = self.ASSEMBLY_IMAGE_OFFSET assemble_image = Image.new("L", self.ASSEMBLY_IMAGE_SIZE, 255) assemble_image.paste(symbol_image, offset) symbol.size_w, symbol.size_h = symbol_image.size # Move symbol if it is going to be plotted outside the visible region symbol = self.reposition_inside_visible(symbol) self.inject_text(symbol, assemble_image, offset) if symbol.orientation > 0: assemble_image = assemble_image.rotate(symbol.orientation, expand=True) # Paste the generated symbol in the diagram inverted_image = ImageOps.invert(assemble_image) assemble_image.putalpha(inverted_image) original_image.paste(assemble_image, (symbol.x, symbol.y), mask=inverted_image) # Recalculate positioning after the paste [and rotation] self.recalculate_positions(symbol, offset)
def make_beautiful_gif(self, template: Image, avatar: Image) -> BytesIO: gif_list = [frame.copy() for frame in ImageSequence.Iterator(avatar)] img_list = [] num = 0 temp = None for frame in gif_list: template = template.convert("RGBA") frame = frame.convert("RGBA") # frame = frame.rotate(-30, expand=True) # frame = frame.resize((60, 60), Image.ANTIALIAS) template.paste(frame, (370, 45), frame) template.paste(frame, (370, 330), frame) # temp2.thumbnail((320, 320), Image.ANTIALIAS) img_list.append(template) num += 1 temp = BytesIO() template.save(temp, format="GIF", save_all=True, append_images=img_list, duration=0, loop=0) temp.name = "beautiful.gif" if sys.getsizeof(temp) < 8000000 and sys.getsizeof(temp) > 7000000: break return temp
def display_char(img: Image, font: Font, location: Tuple[int, int], character: str) -> None: """Paste a single character from a fontsheet to the display image. Args: img: The display image to be pasted into font: The font class in use location: (x, y) location tuple to paste character character: Character to be pasted Notes: X and Y coordinates are anchored to the top left pixel of the character, and 0,0 is the top left of the display """ # sheet = font.sheetstring # ( # "ABCDEFGHIJKLMNOPQRSTUVWXYZ():;[]abcdefghijklmnopqrstuvwxyz " # "ÄÖÜäöü ⓓⓛⓜⓡⓢⓣⓥ ⓃⓄ'①②- ?!.&é ▷▶▼♂$×./,♀0123456789" # ) # sheet_x = (sheet.index(character) % font.sheetwidth) * font.charwidth # sheet_y = (int(sheet.index(character) / font.sheetwidth)) * font.charheight # char_sprite = font.crop((sheet_x, sheet_y, sheet_x + char_width, sheet_y + char_height)) char_sprite = font.get_character(character) img.paste(char_sprite, location, create_mask(char_sprite))
def printBlog(xy, img: Image, today: datetime, blog, idx = 0): if not blog.get('data'): return x = xy[0] y = xy[1] draw = ImageDraw.Draw(img) date = utils.parseTime(blog['data'][idx]['publishDate']) title = str(blog['data'][idx]['title']) subtitle = str(blog['data'][idx]['subtitle']) twoline, title = linebreakString(draw, title) title = truncateString(draw, title, 370) _, subtitle = linebreakString(draw, subtitle, (3 if twoline else 4), font = rbtv_config.fontTiny) subtitle = truncateString(draw, subtitle, 370, font = rbtv_config.fontTiny) draw.rectangle((0, y, 600, y + 137), fill = 0) draw.text((x + 210, y + 5), title, font = rbtv_config.fontSmall, fill = 255) draw.text((x + 210, y + 5 + (60 if twoline else 30)), subtitle, font = rbtv_config.fontTiny, fill = 255) r = requests.get('https:' + str(blog['data'][idx]['thumbImage'][0]['url'])) preview = Image.open(BytesIO(r.content)) maxsize = (200, 140) tn_image = preview.thumbnail(maxsize) img.paste(preview, (x, y)) delta = getTimeDelta(int((today - date).total_seconds())) draw.text((x, y - 25), delta, font = rbtv_config.fontTiny, fill = 0)
def mark_dig(cell_image: Image, table_index: int, cell_index: int, row_index: int): dir_path = os.path.dirname(os.path.realpath(__file__)) cell_icon = Image.open(os.path.join(dir_path, 'dig.png')).resize((35, 35)) cell_image.paste(cell_icon, (7, 7), cell_icon) write_table_index(cell_icon, table_index) known_digs.append(UnitIconPosition(cell_icon, XY(cell_index, row_index)))
def paste_switch(switch: bool, back: Image, image_on: Image, image_off: Image, left: int, top: int) -> Image: if switch: back.paste(image_on, (left, top)) else: back.paste(image_off, (left, top)) return back
def mark_unit(mark_filename: str, cell_image: Image, table_index: int, cell_index: int, row_index: int): dir_path = os.path.dirname(os.path.realpath(__file__)) cell_icon = Image.open(os.path.join(dir_path, mark_filename)).resize((35, 35)) cell_image.paste(cell_icon, (7, 7), cell_icon) write_table_index(cell_icon, table_index) if do_recon: known_units.append(UnitIconPosition(cell_icon, XY(cell_index, row_index)))
def draw(self, image: Image): mask = None if self.item_type in [self.LABEL, self.TIMESTAMP, self.LEGEND]: en = ImageEnhance.Brightness(self.cache) mask = en.enhance(0) image.paste(self.cache, self.position, mask)
def draw(self, im: Image, im_ry: Image = None): x, y = (0, 0) w, h = im.size for i in range(len(self.children)): c = self.children[i] percent = self.weights[i] / self.weights_total new_w = 0 new_h = 0 if self.is_vertical: new_h = int(percent * h) new_size = (w, new_h) else: new_w = int(percent * w) new_size = (new_w, h) new_image = View.create_image(new_size) new_image_ry = View.create_image(new_size) c.draw(new_image, new_image_ry) im.paste(new_image, (x, y)) if im_ry is not None: im_ry.paste(new_image_ry, (x, y)) x += new_w y += new_h del c, percent, new_w, new_h, new_size, new_image, new_image_ry
def render(self, im: Image) -> None: # Lid image lid = Image.new("1", (WIDTH * 2, HEIGHT * 2), color=0) draw = ImageDraw.Draw(lid) # Draw lid lid_height = int(EYE_HEIGHT * self.y) x1 = WIDTH - EYE_WIDTH y1 = HEIGHT - 1 - HALF_EYE_HEIGHT x2 = WIDTH + EYE_WIDTH y2 = HEIGHT - 1 + lid_height draw.rectangle(((x1, y1), (x2, y2)), fill=1) bend_height = int(EYE_HEIGHT * (1.0 - self.y) * self.bend) x3 = WIDTH - HALF_EYE_WIDTH y3 = HEIGHT - 1 + lid_height - bend_height x4 = WIDTH + HALF_EYE_WIDTH y4 = HEIGHT - 1 + lid_height + bend_height draw.chord(((x3, y3), (x4, y4)), 0, 180, fill=1) # Rotate lid = lid.rotate(self.angle + self.angle_offset, resample=RESAMPLE, expand=0) # Translate and compose location = ((im.size[0] - lid.size[0]) // 2, (im.size[1] - lid.size[1]) // 2 + self.offset) im.paste(self.BLACK, location, lid)
def _paste(bg: Image, p_conf: PasteConf) -> None: """ according to paste configuration paste image over another :param bg: background image :param p_conf: paste configuration :return: None """ with Image.open(p_conf.im_path) as im: im = im.convert('RGBA') im_w, im_h = im.size if p_conf.target_w <= 0 or p_conf.target_h <= 0: print('Target size(w, h) must > 0!') exit() if p_conf.resize_mode == 'scale': # 缩放贴图,以宽 target_w 为准,等比计算高度,可放大缩小 p_conf.target_h = int(p_conf.target_w / im_w * im_h) im = im.resize((p_conf.target_w, p_conf.target_h), Image.ANTIALIAS) elif p_conf.resize_mode == 'trim': # 裁剪贴图,默认中心裁剪,只能缩小 if p_conf.target_w > im_w: p_conf.target_w = im_w if p_conf.target_h > im_h: p_conf.target_h = im_h crop1_x = int((im_w - p_conf.target_w) // 2) crop1_y = int((im_h - p_conf.target_h) // 2) crop2_x = int((im_w + p_conf.target_w) // 2) crop2_y = int((im_h + p_conf.target_h) // 2) crop_box = (crop1_x, crop1_y, crop2_x, crop2_y) im = im.crop(crop_box) bg.paste(im, (p_conf.c_pos_x - p_conf.target_w // 2, p_conf.c_pos_y - p_conf.target_h // 2), im)
def make_wheeze_img(self, template: Image, avatar: Image): # print(template.info) template = template.convert("RGBA") if type(avatar) != str: avatar = avatar.convert("RGBA") template.paste(avatar, (60, 470), avatar) else: font_loc = str(bundled_data_path(self) / "impact.ttf") font1 = ImageFont.truetype(font_loc, 40) draw = ImageDraw.Draw(template) margin = 40 offset = 470 count = 0 for line in textwrap.wrap(avatar, width=10): count += 1 if count == 6: draw.text((margin, offset), f"{line}...", fill=(0, 0, 0), font=font1) break draw.text((margin, offset), f"{line}", fill=(0, 0, 0), font=font1) offset += font1.getsize(line)[1] temp = BytesIO() template.save(temp, format="PNG") temp.name = "wheeze.png" return temp
def draw(self, image: Image, width: int, height: int, draw_x: int, draw_y: int, text: str): slice_path = os.path.join(self.art_repo.art_cache, "{0}_slice{1}x{2}.png".format(self.scryfall_id, width, height)) if os.path.exists(slice_path): log.debug("[%s] Using cache", slice_path) slice_im = Image.open(slice_path) else: log.debug("[%s] Generating slice", slice_path) slice_im = self.generate_slice(width, height) slice_im.save(slice_path) # Now make some text x = 3 y = 3 shadowcolor = (0, 0, 0, 255) fillcolor = (255, 255, 255, 255) log.debug("Drawing text %s", text) draw = ImageDraw.Draw(slice_im) font = self.art_repo.get_small_text_font(height-(y * 2)-2) for i in range(-1, 2): for j in range(-1, 2): draw.text((x + i, y + j), text, font=font, fill=shadowcolor) # now draw the text over it draw.text((x, y), text, font=font, fill=fillcolor) log.debug("Drawing slice at %s x %s", draw_x, draw_y) image.paste(slice_im, (draw_x, draw_y))
def render(self, im: Image) -> None: # Lid image lid = Image.new("1", (self.width * 2, self.height * 2), color=0) draw = ImageDraw.Draw(lid) # Draw lid lid_height = int(self.eye_height * self.y) x1 = self.width - self.scale_factor_lid_height y1 = self.height - 1 - self.half_eye_height x2 = self.width + self.scale_factor_lid_height y2 = self.height - 1 + lid_height draw.rectangle(((x1, y1), (x2, y2)), fill=1) bend_height = int(self.eye_height * (1.0 - self.y) * self.bend) x3 = self.width - self.scale_factor_lid_bend y3 = self.height - 1 + lid_height - bend_height x4 = self.width + self.scale_factor_lid_bend y4 = self.height - 1 + lid_height + bend_height draw.chord(((x3, y3), (x4, y4)), 0, 180, fill=1) # Rotate lid = lid.rotate(self.angle + self.angle_offset, resample=RESAMPLE, expand=0) # Translate and compose location = ((im.size[0] - lid.size[0]) // 2, (im.size[1] - lid.size[1]) // 2 + self.offset) im.paste(self.black, location, lid)
async def draw_player( draw: ImageDraw.Draw, composite: Image, player: Player, character: Image, rank: Image, y_offset: int, ) -> None: ready = is_ready if player.is_ready() else not_ready voice = voice_on if player.is_in_voice() else voice_off y_offset += PLAYER_ONE_START composite.paste(rank, (88, y_offset), rank) composite.paste(ready, (132, y_offset + 11), ready) composite.paste(voice, (155, y_offset + 5), voice) composite.paste(character, (183, y_offset)) try: profile = await player.get_avatar() composite.paste(profile.resize((19, 19)), (226, y_offset + 8)) except Exception: pass draw.text( (255, y_offset + 11), player.get_name(), font=name_font, fill=(81, 81, 81, 255), )
def _draw_outlined_text(self, image: Image, position: Tuple[int, int], content: str, font: ImageFont.ImageFont, background_color: Optional[Union[Tuple, str]] = None, stroke_width: int = 0, stroke_color: Union[Tuple, str] = "#000"): overlay = Image.new('RGBA', image.size) x, y, text_width, text_height = self.get_text_bounding_box( center_position=position, font_size=font.size, text=content) draw = ImageDraw.ImageDraw(overlay, 'RGBA') if background_color is not None: margin = 10 draw.rectangle( [(x - margin, y - margin), (x + text_width + 2 * margin, y + text_height + 2 * margin)], fill=background_color) # Draw inner white text draw.multiline_text((x, y), content, self.text_color, font=font, align='center', stroke_width=stroke_width, stroke_fill=stroke_color) image.paste(overlay, None, overlay)
def display_sprite(img: Image, location: Tuple[int, int], mon: Pokemon) -> None: """Paste sprite and bounding box into display image. Args: img: The display image to be pasted into location: (x, y) location tuple to paste character id: Id of the pokemon sprite to paste gen: Generation to pull sprite from ver: Version within generation to pull sprite from form: Choose form if pokemon has more than one Notes: X and Y coordinates are anchored to the top left of the bounding box for the sprite, 0,0 is the top left of the display. Todo: Sprites are currently stored using sprites from gen 2, but without an indicator by filename to indicate generation. I think the best solution may be to make each sprite file a full sheet, with gen 1 left aligned. This will require shifting all of the sprites over 56 pixels as they are gen 2, but it would help expansion in the future if done now. """ box = Image.open("assets/ui/spritebox.png") sprite_sheet = Image.open("assets/sprites/{:03d}.png".format(id)) # TODO: Put this next line in a try/except or get index errors for high gens # sprite = sprite_sheet.crop((0, 56 * ver, 56, 56 + 56 * ver)) sprite = random.choice(mon.sprites) img.paste(box, location, create_mask(box)) img.paste(sprite, tuple(n + 6 for n in location), create_mask(sprite))
def pentagram(im: Image) -> Image: """Adds pentagram to the image.""" im = im.convert("RGB") wt, ht = im.size penta = Image.open("bot/resources/halloween/bloody-pentagram.png") penta = penta.resize((wt, ht)) im.paste(penta, (0, 0), penta) return im
def get_superimposed_icons(bg: Image, fg: list, size: int = _TILESIZE_WILD, **kwargs) -> Image: """ Returns a PIL image which is the superimposition of a background icon and a foreground icon (or more). """ save = kwargs.get("save") caller = kwargs.get("caller") bg = bg.convert("RGBA") if len(fg) > 1: fg = sort_by_visibility(fg) if caller and caller in fg: fg = [x for x in fg if x != caller] fg = fg[:3] + [caller] else: fg = fg[:4] rsize = int(size * 0.60) offset_x = int(size * (0.45 if save else 0)) offset_y = int(size * (0.50 if save else 0)) c = 0 for obj in fg: c += 1 obj = get_icon_from_name(obj.db.icon).convert("RGBA") obj = obj.resize((rsize, rsize), resample=Image.LANCZOS) bg.paste(obj, (offset_x, offset_y), obj) offset_x += int(size * (0.50 if save else 0.40)) offset_y += int(size * (0.50 if save else 0.35)) if len(fg) == 2 else 0 if c % 2 == 0: offset_x = int(size * (0.45 if save else 0)) offset_y += int(size * (0.50 if save else 0.35)) return bg elif len(fg) == 1: fg = get_icon_from_name(fg[0].db.icon).convert("RGBA") elif len(fg) == 0: fg = get_icon_from_name().convert("RGBA") rsize = int(size * 0.80) fg = fg.resize((rsize, rsize), resample=Image.LANCZOS) width_fg, height_fg = fg.size width_bg, height_bg = bg.size offset_y = (width_bg - width_fg) // 2 offset_x = (height_bg - height_fg) // 2 bg.paste(fg, (offset_x, offset_y), fg) return bg
def deepfry(img: Image, *, colours: ColourTuple = DefaultColours.red, flares: bool = True) -> Image: """ Deepfry a given image. Parameters ---------- img : `Image` Image to manipulate. colours : `ColourTuple`, optional A tuple of the colours to apply on the image. flares : `bool`, optional Whether or not to try and detect faces for applying lens flares. Returns ------- `Image` Deepfried image. """ img = img.copy().convert('RGB') flare_positions = [] if flares: opencv_img = cv2.cvtColor(numpy.array(img), cv2.COLOR_RGB2GRAY) # Crush image to hell and back img = img.convert('RGB') width, height = img.width, img.height img = img.resize((int(width**.75), int(height**.75)), resample=Image.LANCZOS) img = img.resize((int(width**.88), int(height**.88)), resample=Image.BILINEAR) img = img.resize((int(width**.9), int(height**.9)), resample=Image.BICUBIC) img = img.resize((width, height), resample=Image.BICUBIC) img = ImageOps.posterize(img, 4) # Generate colour overlay r = img.split()[0] r = ImageEnhance.Contrast(r).enhance(2.0) r = ImageEnhance.Brightness(r).enhance(1.5) r = ImageOps.colorize(r, colours[0], colours[1]) # Overlay red and yellow onto main image and sharpen the hell out of it img = Image.blend(img, r, 0.75) img = ImageEnhance.Sharpness(img).enhance(100.0) # Apply flares on any detected eyes for flare in flare_positions: flare_transformed = flare_img.copy().resize((flare.size, ) * 2, resample=Image.BILINEAR) img.paste(flare_transformed, (flare.x, flare.y), flare_transformed) return img
def get_layered_icon(base: Image, layers: list) -> Image: """ Add layer on top of base tile. Called by add_rivers() and such. """ base = base.convert("RGB") for layer in layers: layer = get_wild_tile_from_name(layer).convert("RGBA") base.paste(layer, (0, 0), layer) return base
def make_beautiful_img(self, template: Image, avatar: Image) -> BytesIO: # print(template.info) template = template.convert("RGBA") avatar = avatar.convert("RGBA") template.paste(avatar, (370, 45), avatar) template.paste(avatar, (370, 330), avatar) temp = BytesIO() template.save(temp, format="PNG") temp.name = "beautiful.png" return temp
def draw_on(self, image: Image, box: BoxT, debug=False): x1, y1, x2, y2 = box w, h = x2 - x1, y2 - y1 img = Image.new('L', (w, h), 'white') self.node.draw_on(img, (0,0,w,h), debug=debug) if debug: draw = ImageDraw.Draw(img) draw.rectangle((1,1,w-1,h-1)) rotated = img.rotate(self.angle_deg, fillcolor='white') image.paste(rotated, box=box)
def add_darkness(minimap: Image, br: int) -> Image: """ Superimpose darkness levels to the already composed minimap. """ if br < 4: dark_level = "dark" + str(br) fg = os.path.join(_ASSETS_LOCATION, dark_level) + ".png" fg = Image.open(fg).convert("RGBA") minimap.paste(fg, (0, 0), fg) return minimap
def paste(im:Image,b:bytes,screensize,index): w,h = screensize row,col = index x = col*(w-20) y = row*(h-20) box = (x,y) bio = BytesIO() bio.write(b) bio.seek(0) tmp = Image.open(bio) im.paste(tmp,box)
def _render_rotated(img: Image, font: ImageFont, color: Color, x, y, angle, string: str): """render text rotated by an angle by creating a seperate image with the text, rotating it, and pasting it onto the target image""" # create a new image with a transparent alpha channel txt = Image.new("RGBA", (800, 400), (255, 255, 255, 0)) d = ImageDraw.Draw(txt) d.text((0, 0), string, (*color.value, 255), font) w = txt.rotate(angle, resample=Image.BICUBIC, expand=True) img.paste(w, (x, y), w)
def _draw_header(self, img: Image, today: datetime): draw = ImageDraw.Draw(img) #clock rbtv_printer.printClock((0,0), img, today) #views rbtv_printer.printViews((345, 70), img, self.api.getStreamCount()) #views rbtv_printer.printSelf((5, 75), img, self.api.getSelf(), self.api.getNotifications()) #placeholder for preview image img.paste(rbtv_config.preview_placeholder, (600-250, 0)) return img
def paste_single_map(template: Image, map_: Image) -> Image: """ Overlays a single map image on to the template image Args: template (Image): The base template image map_ (Image): The single image to paste on the template Returns: Image: The template image with the map image pasted on """ paste_coords = (148, 652) template.paste(map_, paste_coords) return template
def make_badge(template: Image, avatar: Image): """Create basic badge from regular avatar""" watermark = avatar.convert("RGBA") watermark.putalpha(128) watermark = watermark.resize((100, 100)) id_image = avatar.resize((165, 165)) template.paste(watermark, (845, 45, 945, 145), watermark) template.paste(id_image, (60, 95, 225, 260)) temp = BytesIO() template.save(temp, format="PNG") temp.name = "temp.gif" return temp
def draw(self, im: Image, im_ry: Image = None): x_space = int(im.size[0] * self.s) y_space = int(im.size[1] * self.s) xy = (x_space, y_space) new_size = (int(im.size[0] - (x_space * 2)), int(im.size[1] - (y_space * 2))) new_image = View.create_image(new_size) new_image_ry = View.create_image(new_size) self.c.draw(new_image, new_image_ry) im.paste(new_image, xy) if im_ry is not None: im_ry.paste(new_image_ry, xy)
def spotlight(img: Image, center: (int, int), radius: int) -> Image: width, height = img.size overlay_color = (0, 0, 0, 128) img_overlay = Image.new(size=img.size, color=overlay_color, mode='RGBA') for x in range(width): for y in range(height): dx = x - center[0] dy = y - center[1] distance = math.sqrt(dx * dx + dy * dy) if distance < radius: img_overlay.putpixel((x, y), (0, 0, 0, 0)) img.paste(img_overlay, None, mask=img_overlay) return img
def overlay(img: Image, overlay_color: tuple, orig_file_name:str): """ Place an overlay over an existing image :param img: Image opened with PIL.Image :param overlay_color: four-tuple with color to add to your image :param orig_file_name: name of the original file """ assert len(overlay_color) == 4, 'Overlay color shall be a 4-tuple' img_overlay = Image.new(size=img.size, color=overlay_color, mode='RGBA') img.paste(img_overlay, None, mask=img_overlay) color_string = '_'.join([str(c) for c in overlay_color]) filename = '{orig}_overlay_{color}.jpg'.format(orig=orig_file_name, color=color_string) save_img(img, filename)