diff --git a/discord_bot/main.py b/discord_bot/__main__.py similarity index 100% rename from discord_bot/main.py rename to discord_bot/__main__.py diff --git a/meme_otron/img_factory.py b/meme_otron/img_factory.py index 348d213..1ad08de 100644 --- a/meme_otron/img_factory.py +++ b/meme_otron/img_factory.py @@ -38,24 +38,24 @@ def make(template, texts, debug=False): :return: """ try: - img = Image.open(path.join(TEMPLATES_DIR, template)) + img = Image.open(path.join(TEMPLATES_DIR, template)).convert(mode='RGBA') except OSError as e: logger.error(f"Could not read template file '{template}': {e}") return None draw = ImageDraw.Draw(img) for text in texts: - draw_text(draw, img.size, text, debug=debug) + draw_text(draw, img, text, debug=debug) - return img + return img.convert(mode='RGB') -def draw_text(draw, size, text, debug=False): +def draw_text(draw, img, text, debug=False): """ TODO :param (PIL.ImageDraw.ImageDraw) draw: source image canvas - :param (int,int) size: source image size + :param (PIL.Image.Image) img: source image :param (Text) text: :param (bool) debug: """ @@ -64,14 +64,31 @@ def draw_text(draw, size, text, debug=False): if text.text is not None and len(text.text.strip()) > 0: text.init() # load default values if text.font in FONTS: - text.text, font = fit_text(size, text) - draw.text(get_pos(size, text, font), text.text, fill=text.fill, align=text.align, font=font, - stroke_width=round(text.stroke_width * font.size), stroke_fill=text.stroke_fill) - if debug: - draw.rectangle([(text.x_range[0] * size[0], text.y_range[0] * size[1]), - (text.x_range[1] * size[0], text.y_range[1] * size[1])], - None, - (128, 128, 128)) + text.text, font = fit_text(img.size, text) + if text.angle == 0: + draw.text(get_pos(img.size, text, font), text.text, fill=text.fill, align=text.align, font=font, + stroke_width=round(text.stroke_width * font.size), stroke_fill=text.stroke_fill) + if debug: + draw.rectangle([(text.x_range[0] * img.size[0], text.y_range[0] * img.size[1]), + (text.x_range[1] * img.size[0], text.y_range[1] * img.size[1])], + None, (128, 128, 128)) + else: + width = round((text.x_range[1] - text.x_range[0]) * img.size[0]) + height = round((text.y_range[1] - text.y_range[0]) * img.size[1]) + center_x = (text.x_range[0] + text.x_range[1]) * img.size[0] / 2 + center_y = (text.y_range[0] + text.y_range[1]) * img.size[1] / 2 + txt_img = Image.new('RGBA', (width, height)) + txt_draw = ImageDraw.Draw(txt_img) + txt_draw.text(get_pos(img.size, text, font, relative=True), text.text, fill=text.fill, + align=text.align, font=font, stroke_width=round(text.stroke_width * font.size), + stroke_fill=text.stroke_fill) + if debug: + txt_draw.rectangle([(0, 0), (width - 1, height - 1)], + None, (128, 128, 128)) + txt_img = txt_img.rotate(text.angle, expand=1, resample=Image.BILINEAR) + img.paste(txt_img, + (round(center_x - txt_img.size[0] / 2), round(center_y - txt_img.size[1] / 2)), + txt_img) else: logger.warning(f"Invalid font '{text.font}'") @@ -107,7 +124,7 @@ def fit_text(size, text): return t, font -def get_pos(size, text, font): +def get_pos(size, text, font, relative=False): """ TODO @@ -136,5 +153,7 @@ def get_pos(size, text, font): pos_x = round((min_x + max_x) / 2 - text_size[0] / 2) else: pos_x = max_x - text_size[0] - - return pos_x, pos_y + if relative: + return pos_x - min_x, pos_y - min_y + else: + return pos_x, pos_y diff --git a/meme_otron/meme_db.py b/meme_otron/meme_db.py index 4c307e7..2da767e 100644 --- a/meme_otron/meme_db.py +++ b/meme_otron/meme_db.py @@ -105,9 +105,10 @@ def load_text(j, raw_text, text=None): text.font = utils.read_key_safe(raw_text, "font", types=[str]) text.x_range = utils.read_key_safe(raw_text, "x_range", types=[float, int], is_list=True, is_list_size=2) text.y_range = utils.read_key_safe(raw_text, "y_range", types=[float, int], is_list=True, is_list_size=2) - text.font_size = utils.read_key_safe(raw_text, "font_size", types=[float]) + text.angle = utils.read_key_safe(raw_text, "angle", types=[float, int]) + text.font_size = utils.read_key_safe(raw_text, "font_size", types=[float, int]) text.fill = utils.read_key_safe(raw_text, "fill", types=[int], is_list=True, is_list_size=3) - text.stroke_width = utils.read_key_safe(raw_text, "stroke_width", types=[float]) + text.stroke_width = utils.read_key_safe(raw_text, "stroke_width", types=[float, int]) text.stroke_fill = utils.read_key_safe(raw_text, "stroke_fill", types=[int], is_list=True, is_list_size=3) if "position" in raw_text: if raw_text["position"] not in [p.name for p in Pos]: diff --git a/meme_otron/types.py b/meme_otron/types.py index c6a1970..3b04b3b 100644 --- a/meme_otron/types.py +++ b/meme_otron/types.py @@ -58,6 +58,7 @@ class Text: self.x_range = (0, 1) self.y_range = (0, 1) + self.angle = None self.font = None self.font_size = None @@ -83,6 +84,12 @@ class Text: """ TODO """ + if self.x_range is None: + self.x_range = (0, 1) + if self.y_range is None: + self.y_range = (0, 1) + if self.angle is None: + self.angle = 0 if self.font is None: self.font = DEFAULT_FONT if self.font_size is None: diff --git a/memes.json b/memes.json index bb12685..5a83227 100644 --- a/memes.json +++ b/memes.json @@ -286,14 +286,69 @@ "aliases": ["tom", "jerry"], "font": "impact", "font_size": 0.07, - "stroke_fill": [255, 255, 255], - "stroke_width": 0.1, - "texts": [{ - "x_range": [0.07, 0.36], - "y_range": [0.69, 0.98], - "font_size": 0.05 - },{ - "x_range": [0.44, 0.84], - "y_range": [0.27, 0.59] - }] -}] \ No newline at end of file + "stroke_fill": [ + 255, + 255, + 255 + ], + "stroke_width": 0.1, + "texts": [ + { + "x_range": [ + 0.07, + 0.36 + ], + "y_range": [ + 0.69, + 0.98 + ], + "font_size": 0.05 + }, + { + "x_range": [ + 0.44, + 0.84 + ], + "y_range": [ + 0.27, + 0.59 + ] + } + ] +}, + { + "id": "button", + "template": "button.jpg", + "stroke_fill": [ + 255, + 255, + 255 + ], + "stroke_width": 0.1, + "font_size": 0.08, + "texts": [ + { + "x_range": [ + 0.10, + 0.46 + ], + "y_range": [ + 0.46, + 0.80 + ], + "angle": 2 + }, + { + "x_range": [ + 0.48, + 0.88 + ], + "y_range": [ + 0.28, + 0.68 + ], + "angle": -45 + } + ] + } +] \ No newline at end of file