rotated text

This commit is contained in:
klemek
2020-04-11 21:00:21 +02:00
parent 6a4acebef1
commit 6b0d4cdca0
5 changed files with 111 additions and 29 deletions
+35 -16
View File
@@ -38,24 +38,24 @@ def make(template, texts, debug=False):
:return: :return:
""" """
try: try:
img = Image.open(path.join(TEMPLATES_DIR, template)) img = Image.open(path.join(TEMPLATES_DIR, template)).convert(mode='RGBA')
except OSError as e: except OSError as e:
logger.error(f"Could not read template file '{template}': {e}") logger.error(f"Could not read template file '{template}': {e}")
return None return None
draw = ImageDraw.Draw(img) draw = ImageDraw.Draw(img)
for text in texts: 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 TODO
:param (PIL.ImageDraw.ImageDraw) draw: source image canvas :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 (Text) text:
:param (bool) debug: :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: if text.text is not None and len(text.text.strip()) > 0:
text.init() # load default values text.init() # load default values
if text.font in FONTS: if text.font in FONTS:
text.text, font = fit_text(size, text) text.text, font = fit_text(img.size, text)
draw.text(get_pos(size, text, font), text.text, fill=text.fill, align=text.align, font=font, if text.angle == 0:
stroke_width=round(text.stroke_width * font.size), stroke_fill=text.stroke_fill) draw.text(get_pos(img.size, text, font), text.text, fill=text.fill, align=text.align, font=font,
if debug: stroke_width=round(text.stroke_width * font.size), stroke_fill=text.stroke_fill)
draw.rectangle([(text.x_range[0] * size[0], text.y_range[0] * size[1]), if debug:
(text.x_range[1] * size[0], text.y_range[1] * size[1])], draw.rectangle([(text.x_range[0] * img.size[0], text.y_range[0] * img.size[1]),
None, (text.x_range[1] * img.size[0], text.y_range[1] * img.size[1])],
(128, 128, 128)) 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: else:
logger.warning(f"Invalid font '{text.font}'") logger.warning(f"Invalid font '{text.font}'")
@@ -107,7 +124,7 @@ def fit_text(size, text):
return t, font return t, font
def get_pos(size, text, font): def get_pos(size, text, font, relative=False):
""" """
TODO TODO
@@ -136,5 +153,7 @@ def get_pos(size, text, font):
pos_x = round((min_x + max_x) / 2 - text_size[0] / 2) pos_x = round((min_x + max_x) / 2 - text_size[0] / 2)
else: else:
pos_x = max_x - text_size[0] pos_x = max_x - text_size[0]
if relative:
return pos_x, pos_y return pos_x - min_x, pos_y - min_y
else:
return pos_x, pos_y
+3 -2
View File
@@ -105,9 +105,10 @@ def load_text(j, raw_text, text=None):
text.font = utils.read_key_safe(raw_text, "font", types=[str]) 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.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.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.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) 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 "position" in raw_text:
if raw_text["position"] not in [p.name for p in Pos]: if raw_text["position"] not in [p.name for p in Pos]:
+7
View File
@@ -58,6 +58,7 @@ class Text:
self.x_range = (0, 1) self.x_range = (0, 1)
self.y_range = (0, 1) self.y_range = (0, 1)
self.angle = None
self.font = None self.font = None
self.font_size = None self.font_size = None
@@ -83,6 +84,12 @@ class Text:
""" """
TODO 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: if self.font is None:
self.font = DEFAULT_FONT self.font = DEFAULT_FONT
if self.font_size is None: if self.font_size is None:
+66 -11
View File
@@ -286,14 +286,69 @@
"aliases": ["tom", "jerry"], "aliases": ["tom", "jerry"],
"font": "impact", "font": "impact",
"font_size": 0.07, "font_size": 0.07,
"stroke_fill": [255, 255, 255], "stroke_fill": [
"stroke_width": 0.1, 255,
"texts": [{ 255,
"x_range": [0.07, 0.36], 255
"y_range": [0.69, 0.98], ],
"font_size": 0.05 "stroke_width": 0.1,
},{ "texts": [
"x_range": [0.44, 0.84], {
"y_range": [0.27, 0.59] "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
}
]
}
]