113 lines
3.8 KiB
Python
113 lines
3.8 KiB
Python
from typing import Optional, Tuple, List
|
|
import re
|
|
from PIL import Image
|
|
from io import BytesIO
|
|
|
|
from .types import Text, Pos
|
|
from . import img_factory
|
|
from . import meme_db
|
|
from . import utils
|
|
|
|
right_wmark = Text("Made with meme-otron")
|
|
right_wmark.position = Pos.SE
|
|
right_wmark.fill = (128, 128, 128, 128)
|
|
right_wmark.font_size = 0.02
|
|
right_wmark.x_range = [0.005, 0.995]
|
|
right_wmark.y_range = [0.005, 0.995]
|
|
|
|
left_wmark = Text()
|
|
left_wmark.position = Pos.SW
|
|
left_wmark.fill = (128, 128, 128, 128)
|
|
left_wmark.font_size = 0.02
|
|
left_wmark.x_range = [0.005, 0.995]
|
|
left_wmark.y_range = [0.005, 0.995]
|
|
|
|
simple_text = Text()
|
|
simple_text.align = "left"
|
|
simple_text.position = Pos.W
|
|
simple_text.font_size = 0.04
|
|
simple_text.x_range = [0.01, 0.99]
|
|
simple_text.y_range = [0.2, 0.8]
|
|
|
|
|
|
def compute(*args: str, input_data: Optional[bytes] = None,
|
|
wmark: bool = True, left_wmark_text: Optional[str] = None,
|
|
max_file_size: Optional[int] = None,
|
|
debug: bool = False) -> Tuple[Optional[Image.Image], List[str]]:
|
|
if len(args) < 1:
|
|
return None, ['Not enough arguments']
|
|
|
|
parts = utils.split_arguments(args, "-")
|
|
images = []
|
|
errors = []
|
|
for part in parts:
|
|
img, err = compute_part(*part, input_data=input_data, max_file_size=max_file_size, debug=debug)
|
|
if img is not None:
|
|
images += [img]
|
|
else:
|
|
errors += [err]
|
|
|
|
if len(images) == 0:
|
|
return None, errors
|
|
|
|
output_image = img_factory.compose_image(images)
|
|
|
|
if wmark:
|
|
watermarks = [right_wmark]
|
|
if left_wmark_text is not None:
|
|
watermarks += [left_wmark.variant(left_wmark_text)]
|
|
output_image = img_factory.apply_texts(output_image, watermarks, debug=debug)
|
|
|
|
if max_file_size is not None:
|
|
with BytesIO() as img_file:
|
|
output_image.save(img_file, 'JPEG')
|
|
if img_file.tell() > max_file_size:
|
|
return None, ['Output image too big']
|
|
|
|
return output_image, errors
|
|
|
|
|
|
def compute_part(*args: str, input_data: Optional[bytes] = None,
|
|
max_file_size: Optional[int] = None,
|
|
debug: bool = False) -> Tuple[Optional[Image.Image], Optional[str]]:
|
|
meme_id = utils.sanitize_input(args[0])
|
|
|
|
if meme_id == "text":
|
|
if len(args) <= 1:
|
|
return None, 'Text: not enough arguments'
|
|
texts = [simple_text.variant(arg) for arg in args[1:]]
|
|
return img_factory.build_text_only(texts, debug=debug), None
|
|
elif meme_id == "image":
|
|
if input_data is None or len(input_data) == 0:
|
|
if len(args) <= 1:
|
|
return None, 'Image: received no input data nor URL'
|
|
else:
|
|
input_data, err = utils.read_web(args[1], max_file_size=max_file_size)
|
|
if input_data is None:
|
|
return None, 'Image: ' + err
|
|
img = img_factory.build_image_only(input_data)
|
|
if img is None:
|
|
return None, 'Image: invalid image format'
|
|
else:
|
|
return img, None
|
|
else:
|
|
meme = meme_db.get_meme(meme_id)
|
|
if meme is None:
|
|
error = f"Template: '{meme_id}' not found."
|
|
proposal = meme_db.find_nearest(meme_id)
|
|
if proposal is not None:
|
|
error += f" Did you mean '{proposal}'?"
|
|
return None, error
|
|
if len(args) > 1:
|
|
c = 0
|
|
for i in range(len(meme.texts)):
|
|
if meme.texts[i].text_ref is None:
|
|
if c < len(args) - 1:
|
|
meme.texts[i].text = args[c + 1].replace("\\n", "\n")
|
|
else:
|
|
meme.texts[i].text = ""
|
|
c += 1
|
|
else:
|
|
meme.texts[i].text = meme.texts[meme.texts[i].text_ref].text
|
|
return img_factory.build_from_template(meme.template, meme.texts, debug=debug), None
|