automeme/pillow_fight.py

245 lines
11 KiB
Python

import math
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
from PIL import ImageOps
import requests
import io
from image_utils import ImageText
from os.path import exists
def create_soy_vs_chad_meme(emoji1, emoji2, caption1, caption2):
LEFT_MARGIN_COLUMN = 20
CONTENT_COLUMN = 300
MIDDLE_MARGIN_COLUMN = 80
RIGHT_MARGIN_COLUMN = LEFT_MARGIN_COLUMN
TOP_MARGIN_ROW = 80
IMAGE_ROW = 300
MIDDLE_MARGIN_ROW = 20
TEXT_ROW = 100
BOTTOM_MARGIN_ROW = 200
total_image_size_x = 2*CONTENT_COLUMN + LEFT_MARGIN_COLUMN + RIGHT_MARGIN_COLUMN + MIDDLE_MARGIN_COLUMN
total_image_size_y = TOP_MARGIN_ROW + IMAGE_ROW + MIDDLE_MARGIN_ROW + TEXT_ROW + BOTTOM_MARGIN_ROW
left_image = get_emoji_from_rdrama(emoji1)
right_image = get_emoji_from_rdrama(emoji2)
#Resize images
left_image = ImageOps.contain(left_image, (CONTENT_COLUMN, IMAGE_ROW))
right_image = ImageOps.contain(right_image, (CONTENT_COLUMN, IMAGE_ROW))
right_image = ImageOps.mirror(right_image)
#Base image
base = Image.new(mode="RGB", size=(total_image_size_x,total_image_size_y), color=(255,255,255))
#Add images
center_and_paste(base, left_image, (LEFT_MARGIN_COLUMN,TOP_MARGIN_ROW), (CONTENT_COLUMN, IMAGE_ROW))
center_and_paste(base, right_image, (LEFT_MARGIN_COLUMN+CONTENT_COLUMN+MIDDLE_MARGIN_COLUMN,TOP_MARGIN_ROW), (CONTENT_COLUMN, IMAGE_ROW))
#Text regions
add_text(base, caption1, (CONTENT_COLUMN, TEXT_ROW), (LEFT_MARGIN_COLUMN, TOP_MARGIN_ROW+IMAGE_ROW+MIDDLE_MARGIN_ROW))
add_text(base, caption2, (CONTENT_COLUMN, TEXT_ROW), (LEFT_MARGIN_COLUMN+CONTENT_COLUMN+MIDDLE_MARGIN_COLUMN, TOP_MARGIN_ROW+IMAGE_ROW+MIDDLE_MARGIN_ROW))
return add_watermark(base)
class WebcomicPanel():
PANEL_SIZE = 400
FONT = "Little Story.ttf"
def __init__(self):
pass
def create_image(self) -> Image:
return Image.new(mode="RGB", size=(self.PANEL_SIZE,self.PANEL_SIZE), color=(255,255,255))
class OneCharacterWebcomicPanel(WebcomicPanel):
def __init__(self, emoji, caption):
self.emoji = emoji
self.caption = caption
def create_image(self) -> Image:
base = super().create_image()
panel_size_x, panel_size_y = base.size
# We put marsey in the bottom left quadrant
emoji_region_x_size = int(panel_size_x/2)
emoji_region_y_size = int(panel_size_y/2)
emoji_placement_position_x = 0
emoji_placement_position_y = int(panel_size_y/2)
emoji = get_emoji_from_rdrama(self.emoji)
center_and_paste(base, emoji, (emoji_placement_position_x, emoji_placement_position_y), (emoji_region_x_size, emoji_region_y_size))
# We put the text in the top half of the panel.
text_region_x_size = int(panel_size_x)
text_region_y_size = int(panel_size_y/2)
add_text(base, self.caption, (text_region_x_size, text_region_y_size), (0,0), font=super().FONT)
return add_border_to_image(base)
class TwoCharacterWebcomicPanel(WebcomicPanel):
def __init__(self, left_emoji, left_caption, right_emoji, right_caption):
self.left_emoji = left_emoji
self.left_caption = left_caption
self.right_emoji = right_emoji
self.right_caption = right_caption
def create_image(self) -> Image:
base = super().create_image()
panel_size_x, panel_size_y = base.size
# We put the left marsey in the bottom left quadrant
left_emoji_region_x_size = int(panel_size_x/2)
left_emoji_region_y_size = int(panel_size_y/2)
left_emoji_placement_position_x = 0
left_emoji_placement_position_y = int(panel_size_y/2)
left_emoji = get_emoji_from_rdrama(self.left_emoji)
center_and_paste(base, left_emoji, (left_emoji_placement_position_x, left_emoji_placement_position_y), (left_emoji_region_x_size, left_emoji_region_y_size))
# We put the right marsey in the bottom right quadrant
right_emoji_region_x_size = int(panel_size_x/2)
right_emoji_region_y_size = int(panel_size_y/2)
right_emoji_placement_position_x = int(panel_size_x/2)
right_emoji_placement_position_y = int(panel_size_y/2)
right_emoji = get_emoji_from_rdrama(self.right_emoji)
center_and_paste(base, right_emoji, (right_emoji_placement_position_x, right_emoji_placement_position_y), (right_emoji_region_x_size, right_emoji_region_y_size))
#Each text caption will get 5/8 of the width, and 1/4 of the height of the panel.
#The left caption will be all the way to the left. The right caption will be 3/8 to the right.
CAPTION_UNITS = 5
CAPTION_DIVISOR = 8
# We put the text in the top half of the panel.
left_text_region_x_size = int(CAPTION_UNITS*(panel_size_x/CAPTION_DIVISOR))
left_text_region_y_size = int(panel_size_y/4)
left_text_region_x_position = 0
left_text_region_y_position = 0
add_text(base, self.left_caption, (left_text_region_x_size, left_text_region_y_size), (left_text_region_x_position,left_text_region_y_position), font=super().FONT)
# We put the text in the top half of the panel.
right_text_region_x_size = int(CAPTION_UNITS*(panel_size_x/CAPTION_DIVISOR))
right_text_region_y_size = int(panel_size_y/4)
right_text_region_x_position = int((CAPTION_DIVISOR-CAPTION_UNITS)*(panel_size_x/8))
right_text_region_y_position = int(panel_size_y/4)
add_text(base, self.right_caption, (right_text_region_x_size, right_text_region_y_size), (right_text_region_x_position,right_text_region_y_position), font=super().FONT)
return add_border_to_image(base)
class TitleCardWebcomicPanel(WebcomicPanel):
def __init__(self, caption):
self.caption = caption
def create_image(self) -> Image:
base = super().create_image()
add_text(base, self.caption, base.size, (0,0), font=super().FONT)
return add_border_to_image(base)
def create_webcomic(layout : 'list[WebcomicPanel]'):
assumed_panel_x_size, assumed_panel_y_size = layout[0].create_image().size
total_image_x_size = assumed_panel_x_size * 2
total_image_y_size = assumed_panel_x_size * math.ceil(len(layout)/2)
image = Image.new(mode="RGB", size=(total_image_x_size, total_image_y_size), color=(255,255,255))
for i in range(len(layout)):
panel = layout[i]
x = i%2
y = math.floor(i/2)
image.paste(panel.create_image(), (x*assumed_panel_x_size, y*assumed_panel_y_size))
return add_watermark(image)
def add_text(base : Image, caption : str, region_size : tuple[int, int], coordinates : tuple[int, int], font : str= "arial.ttf"):
if caption == "":
return
region_x_size, region_y_size = region_size
line_image = ImageText((region_x_size, region_y_size))
line_image.fill_text_box((0,0), caption, region_x_size, region_y_size, font_filename=font)
base.paste(line_image.image, coordinates, line_image.image)
def add_watermark(image : Image):
WATERMARK_HEIGHT = 30
image_size_x, image_size_y = image.size
base = Image.new(mode="RGB", size=(image_size_x, image_size_y + WATERMARK_HEIGHT), color=(255,255,255))
base.paste(image)
marsey = get_emoji_from_rdrama("marseyjamming")
marsey = ImageOps.contain(marsey, (WATERMARK_HEIGHT, WATERMARK_HEIGHT))
base.paste(marsey, (0, image_size_y), marsey)
text_line_size = int(WATERMARK_HEIGHT/2)
add_text(base, "A meme by HeyMoon and Foo", (image_size_x, text_line_size), (WATERMARK_HEIGHT, image_size_y))
add_text(base, "For instructions on how to legally build a pipe bomb, go to rdrama.net", (image_size_x, text_line_size), (WATERMARK_HEIGHT, image_size_y+text_line_size))
return base
def center_and_paste(base : Image, to_paste : Image, coordinates: tuple[int, int], box_size : tuple[int, int]):
to_paste = ImageOps.contain(to_paste, box_size)
image_size_x, image_size_y = to_paste.size
box_size_x, box_size_y = box_size
extra_space_x = box_size_x - image_size_x
extra_space_y = box_size_y - image_size_y
offset_x = int(extra_space_x/2)
offset_y = int(extra_space_y/2)
box_coordinate_x, box_coordinate_y = coordinates
x, y = offset_x + box_coordinate_x, offset_y + box_coordinate_y
base.paste(to_paste, (x, y), to_paste)
def add_border_to_image(image : Image, thickness : int = 5):
# image_draw = ImageDraw.Draw(image)
# image_x_size, image_y_size = image.size
# inner_rectangle_x_size, inner_rectangle_y_size = image_x_size - 2*thickness, image_y_size - 2*thickness
# image_draw.rectangle([(0,0),(image_x_size, image_y_size)], fill="black")
# image_draw.rectangle([(thickness, thickness),(image_x_size-thickness, image_y_size-thickness)], fill="white")
inner_image_x_size, inner_image_y_size = image.size
outer_image_x_size, outer_image_y_size = inner_image_x_size + 2*thickness, inner_image_y_size + 2*thickness
outside_image = Image.new(mode="RGB", size=(outer_image_x_size,outer_image_y_size), color=(0,0,0))
outside_image.paste(image, (thickness, thickness))
return outside_image
def wrap_text_for_font(text, region_size, font_size) -> Image:
image = Image.new(mode="RGB", size=region_size, color=(255,255,255))
imageDraw = ImageDraw.ImageDraw()
imageDraw.multiline_text()
def get_emoji_from_rdrama(emoji_name):
cleaned_emoji_name : str = emoji_name
should_flip = False
if '!' in emoji_name:
cleaned_emoji_name = cleaned_emoji_name.replace("!", "")
should_flip = True
if (exists(f"emoji_cache/{cleaned_emoji_name}.webp")):
image = Image.open(f"emoji_cache/{cleaned_emoji_name}.webp")
else:
image = get_image_file_from_url(f"https://www.rdrama.net/e/{cleaned_emoji_name}.webp")
image.save(f"emoji_cache/{cleaned_emoji_name}.webp")
if should_flip:
image = ImageOps.mirror(image)
return image
def get_image_file_from_url(url):
r = requests.get(url)
image_file = io.BytesIO(r.content)
im = Image.open(image_file)
return im
#create_soy_vs_chad_meme("bigsmilesoyjak", "!marseyshooting", "I have fun new toys and games for your children", "Die").show()
create_webcomic([
TwoCharacterWebcomicPanel("soyjak", "Black people deserve the rope", "marseyconfused", "Why?"),
TwoCharacterWebcomicPanel("seethejak", "Because they are degenerate!!!", "marseysmug", "Kinda like you?"),
OneCharacterWebcomicPanel("soycry", "No!! I am a pure aryan white boy and I am special Hitler told me so, so fuck off you nigger cunt. God I hate you so much, if I commit suicide its gonna be your fault, fuck you"),
TitleCardWebcomicPanel("One Hour Later..."),
TwoCharacterWebcomicPanel("marseytombstone", "", "!marseycry", "He had so much to live for"),
OneCharacterWebcomicPanel("marseylaugh", "Just Kidding!")
]).show()