import math from tkinter import UNITS from typing import Union from PIL import Image from PIL import ImageDraw from PIL import ImageFont from PIL import ImageOps import requests import io from utils import get_real_filename from image_utils import ImageText from os.path import exists from random import choice HIGHLIGHT_MODE = False CAPTION_FILENAME = "watermark_captions.txt" class ColorScheme: BLACK = 0 WHITE_WITH_BLACK_BORDER = 1 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 = 80 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_box(base, caption1, (CONTENT_COLUMN, TEXT_ROW), (LEFT_MARGIN_COLUMN, TOP_MARGIN_ROW+IMAGE_ROW+MIDDLE_MARGIN_ROW), init_font_size=50, align="cht", font="impact.ttf", color=ColorScheme.WHITE_WITH_BLACK_BORDER) add_text_box(base, caption2, (CONTENT_COLUMN, TEXT_ROW), (LEFT_MARGIN_COLUMN+CONTENT_COLUMN+MIDDLE_MARGIN_COLUMN, TOP_MARGIN_ROW+IMAGE_ROW+MIDDLE_MARGIN_ROW), init_font_size=50, align="cht", font="impact.ttf", color=ColorScheme.WHITE_WITH_BLACK_BORDER) return base def create_classic_meme(image: Image, top_caption : str, bottom_caption : str): image_x_size, image_y_size = image.size UNIT = 5 caption_size = int(image_y_size/UNIT) add_text_box(image, top_caption, (image_x_size, caption_size), (0,0), "impact.ttf", 60, align="cvch", color=ColorScheme.WHITE_WITH_BLACK_BORDER) add_text_box(image, bottom_caption, (image_x_size, caption_size), (0,int((UNIT-1)*(image_y_size/UNIT))), "impact.ttf", 60, align="cvch", color=ColorScheme.WHITE_WITH_BLACK_BORDER) return image def create_classic_meme_from_url(url : str, top_caption : str, bottom_caption : str): return create_classic_meme(get_image_file_from_url(url), top_caption, bottom_caption) def create_classic_meme_from_emoji(emoji : str, top_caption : str, bottom_caption : str): EMOJI_SIZE = 400 BORDER_SIZE = 100 marsey = get_emoji_from_rdrama(emoji) marsey = ImageOps.contain(marsey, (EMOJI_SIZE, EMOJI_SIZE)) base = Image.new(mode="RGB", size=(EMOJI_SIZE+2*BORDER_SIZE, EMOJI_SIZE+2*BORDER_SIZE), color=(255,255,255)) base.paste(marsey, (BORDER_SIZE, BORDER_SIZE), marsey) return create_classic_meme(base, top_caption, bottom_caption) def create_modern_meme(image : Image, caption : str): CAPTION_SIZE = 150 image_x_size, image_y_size = image.size base = Image.new(mode="RGB", size=(image_x_size,image_y_size+CAPTION_SIZE), color=(255,255,255)) base.paste(image, (0, CAPTION_SIZE)) add_text_box(base, caption, (image_x_size, CAPTION_SIZE), (0,0), font="intreb.ttf",align="chcv") return base def create_modern_meme_from_url(url : str, caption : str): return create_modern_meme(get_image_file_from_url(url), caption) def create_modern_meme_from_emoji(emoji: str, caption: str): EMOJI_SIZE = 400 BORDER_SIZE = 10 marsey = get_emoji_from_rdrama(emoji) marsey = ImageOps.contain(marsey, (EMOJI_SIZE, EMOJI_SIZE)) base = Image.new(mode="RGB", size=(EMOJI_SIZE+2*BORDER_SIZE, EMOJI_SIZE+2*BORDER_SIZE), color=(255,255,255)) base.paste(marsey, (BORDER_SIZE, BORDER_SIZE), marsey) return create_modern_meme(base, caption) class WebcomicPanel(): PANEL_SIZE = 400 FONT = "Impact.ttf" COLOR = ColorScheme.WHITE_WITH_BLACK_BORDER 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)) def add_text_box(self, base : Image, caption : str, region_size : tuple[int, int], coordinates : tuple[int, int], align=""): add_text_box(base, caption, region_size, coordinates, align=align, font=self.FONT, color=self.COLOR, init_font_size=int(self.PANEL_SIZE/10)) class OneCharacterWebcomicPanel(WebcomicPanel): def __init__(self, emoji, caption, words_in_background): self.emoji = emoji self.caption = caption self.words_in_background = words_in_background def create_image(self) -> Image: base = super().create_image() panel_size_x, panel_size_y = base.size # We put the text in the background of the panel. text_region_x_size = int(panel_size_x) text_region_y_size = int(panel_size_y if self.words_in_background else panel_size_y/2) self.add_text_box(base, self.caption, (text_region_x_size, text_region_y_size), (0,0)) # We put marsey in the bottom left quadrant emoji_region_x_size = int(panel_size_x) 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)) 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 self.add_text_box(base, self.left_caption, (left_text_region_x_size, left_text_region_y_size), (left_text_region_x_position,left_text_region_y_position), align="bl") # 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) self.add_text_box(base, self.right_caption, (right_text_region_x_size, right_text_region_y_size), (right_text_region_x_position,right_text_region_y_position), align="br") 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() self.add_text_box(base, self.caption, base.size, (0,0), align="cvch") 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 image def add_text_box(base : Image, caption : str, region_size : tuple[int, int], coordinates : tuple[int, int], font : str= "arial.ttf", init_font_size = 45, align :str = "", color = ColorScheme.BLACK): if caption == "": return if init_font_size == 0: print("Retard moment") return region_x_size, region_y_size = region_size if color == ColorScheme.BLACK: fill_color = (0,0,0) stroke = None stroke_size = 0 if color == ColorScheme.WHITE_WITH_BLACK_BORDER: fill_color = (255,255,255) stroke = (0,0,0) stroke_size = 3 line_image = ImageText((region_x_size+stroke_size, region_y_size)) place = "left" if "ch" in align: place = "center" actual_text_box_size = line_image.write_text_box((stroke_size,0), caption, region_x_size, font_size=init_font_size, font_filename=font, color=fill_color, stroke_color=stroke, stroke_size=stroke_size, place=place, calculate_only=True) _, actual_text_box_y_size, input_text_block_x_size, actual_text_box_x_size = actual_text_box_size if actual_text_box_y_size <= region_y_size: line_image.write_text_box((stroke_size,0), caption, region_x_size, font_size=init_font_size, font_filename=font, color=fill_color, stroke_color=stroke, stroke_size=stroke_size, place=place) actual_paste_x_coordinates, actual_paste_y_coordinates = coordinates if align != "": y_difference = region_y_size - actual_text_box_y_size x_difference = region_x_size - actual_text_box_x_size # Horizontal Align if "t" in align: #This is the default pass elif "b" in align: actual_paste_y_coordinates+=y_difference elif "cv" in align: actual_paste_y_coordinates += int(y_difference/2) if "l" in align: #This is the default pass elif "r" in align: actual_paste_x_coordinates+=x_difference # elif "ch" in align: # actual_paste_x_coordinates += int(x_difference/2) if HIGHLIGHT_MODE: image_draw = ImageDraw.Draw(base) image_draw.rectangle((coordinates, (coordinates[0]+region_size[0], coordinates[1]+region_size[1])), fill="blue") image_draw.rectangle(((actual_paste_x_coordinates, actual_paste_y_coordinates), (actual_paste_x_coordinates+actual_text_box_x_size, actual_text_box_y_size+actual_paste_y_coordinates)), fill="tan") base.paste(line_image.image, (actual_paste_x_coordinates, actual_paste_y_coordinates), line_image.image) else: add_text_box(base, caption, region_size, coordinates, font=font, init_font_size=init_font_size-1, align=align, color=color) 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, name_of_other_creator): global watermark_captions 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) caption = choice(watermark_captions) add_text(base, f"A meme by {name_of_other_creator} and automeme", (image_size_x, text_line_size), (WATERMARK_HEIGHT, image_size_y)) add_text(base, f"{caption}, 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): 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 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 def parse_caption_file(filename): if not exists(filename): return [] to_return = [] with open(get_real_filename(filename), "r") as f: for id in f.readlines(): to_return.append(id.strip()) return to_return watermark_captions = parse_caption_file(CAPTION_FILENAME) #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, its not fair, why do you always have to bully me around, you are such a bitch, i hate you so much, hitler was right and six million wasnt nearly enough, the jews are responsible for this and they will be punished on the day of the rope, youll be sorry then, plus i am armed and dangerous and i have a gun and i will shoot you if you keep making fun of me plus youll be in troulbe if I kill myself so how do you like that you stupid nigger bitch. fuck", words_in_background=True), # TitleCardWebcomicPanel("One Hour Later..."), # TwoCharacterWebcomicPanel("marseytombstone", "", "!marseycry", "He had so much to live for"), # OneCharacterWebcomicPanel("marseylaugh", "Just Kidding!", False) # ]).show() #create_classic_meme_from_url("https://rdrama.net/images/16603133970578706.webp", "in all seriousness it probably isn't worth the effort because this is just one of many ways they could goad the bot into saying something innapropriate. Like who cares lol its just one of many things they could say.", "also there isn't really any specific harm done to anyone by a bot saying pedophile nonsense, it's offensive at worst and funny at best. i laughed at least. also also this legit is something that only happens every 2500 comments or so (there was another comment a while back where bbbb said something similar)").show() #create_modern_meme_from_url("https://cdn.discordapp.com/attachments/1007776259910152292/1007833711540174885/unknown.png", "and then heymoon says the imposter is among us").show() #create_classic_meme_from_emoji("marseycock", "I WANT TO PUT MY DICK", "INSIDE OF MARSEY").show() #create_modern_meme_from_emoji("rdramajanny", "youll be sorry when i get my mop you BITCH").show()