gifs
parent
396ef9dc1f
commit
4ee6231ce1
|
@ -41,9 +41,7 @@ INJECTABLE_IMAGE_REGEX = r"IMAGE:/images/\1\.webp"
|
||||||
# rdrama.reply_to_comment_easy(175, 1, "assddsfssdssdsd", file=file)
|
# rdrama.reply_to_comment_easy(175, 1, "assddsfssdssdsd", file=file)
|
||||||
|
|
||||||
def comment_with_image(message, image, comment_id, post_id):
|
def comment_with_image(message, image, comment_id, post_id):
|
||||||
output = io.BytesIO()
|
file = {'file': ('based.webp', image.get_binary(), 'image/webp')}
|
||||||
image.save(output, format="webp")
|
|
||||||
file = {'file': ('based.webp', output.getvalue(), 'image/webp')}
|
|
||||||
return rdrama.reply_to_comment_easy(comment_id, post_id, message, file=file)['id']
|
return rdrama.reply_to_comment_easy(comment_id, post_id, message, file=file)['id']
|
||||||
|
|
||||||
class TextLine:
|
class TextLine:
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import math
|
import math
|
||||||
from tkinter import UNITS
|
from tkinter import UNITS
|
||||||
from typing import Union
|
from typing import Tuple, Union
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from PIL import ImageDraw
|
from PIL import ImageDraw, ImageSequence
|
||||||
from PIL import ImageFont
|
from PIL import ImageFont
|
||||||
from PIL import ImageOps
|
from PIL import ImageOps
|
||||||
import requests
|
import requests
|
||||||
|
@ -39,20 +39,20 @@ def create_soy_vs_chad_meme(emoji1, emoji2, caption1, caption2):
|
||||||
right_image = get_emoji_from_rdrama(emoji2)
|
right_image = get_emoji_from_rdrama(emoji2)
|
||||||
|
|
||||||
#Resize images
|
#Resize images
|
||||||
left_image = ImageOps.contain(left_image, (CONTENT_COLUMN, IMAGE_ROW))
|
left_image = left_image.fit((CONTENT_COLUMN, IMAGE_ROW))
|
||||||
right_image = ImageOps.contain(right_image, (CONTENT_COLUMN, IMAGE_ROW))
|
right_image = right_image.fit((CONTENT_COLUMN, IMAGE_ROW))
|
||||||
|
|
||||||
right_image = ImageOps.mirror(right_image)
|
right_image = right_image.flip()
|
||||||
|
|
||||||
#Base image
|
#Base image
|
||||||
base = Image.new(mode="RGB", size=(total_image_size_x,total_image_size_y), color=(255,255,255))
|
base = AnimatedImage.new((total_image_size_x,total_image_size_y))
|
||||||
|
|
||||||
#Add images
|
#Add images
|
||||||
center_and_paste(base, left_image, (LEFT_MARGIN_COLUMN,TOP_MARGIN_ROW), (CONTENT_COLUMN, IMAGE_ROW))
|
base = 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))
|
base = center_and_paste(base, right_image, (LEFT_MARGIN_COLUMN+CONTENT_COLUMN+MIDDLE_MARGIN_COLUMN,TOP_MARGIN_ROW), (CONTENT_COLUMN, IMAGE_ROW))
|
||||||
|
|
||||||
#Text regions
|
#Text regions
|
||||||
add_text_box(base,
|
base = add_text_box(base,
|
||||||
caption1,
|
caption1,
|
||||||
(CONTENT_COLUMN, TEXT_ROW),
|
(CONTENT_COLUMN, TEXT_ROW),
|
||||||
(LEFT_MARGIN_COLUMN, TOP_MARGIN_ROW+IMAGE_ROW+MIDDLE_MARGIN_ROW),
|
(LEFT_MARGIN_COLUMN, TOP_MARGIN_ROW+IMAGE_ROW+MIDDLE_MARGIN_ROW),
|
||||||
|
@ -60,7 +60,7 @@ def create_soy_vs_chad_meme(emoji1, emoji2, caption1, caption2):
|
||||||
align="cht",
|
align="cht",
|
||||||
font="impact.ttf",
|
font="impact.ttf",
|
||||||
color=ColorScheme.WHITE_WITH_BLACK_BORDER)
|
color=ColorScheme.WHITE_WITH_BLACK_BORDER)
|
||||||
add_text_box(base,
|
base = add_text_box(base,
|
||||||
caption2,
|
caption2,
|
||||||
(CONTENT_COLUMN, TEXT_ROW),
|
(CONTENT_COLUMN, TEXT_ROW),
|
||||||
(LEFT_MARGIN_COLUMN+CONTENT_COLUMN+MIDDLE_MARGIN_COLUMN, TOP_MARGIN_ROW+IMAGE_ROW+MIDDLE_MARGIN_ROW),
|
(LEFT_MARGIN_COLUMN+CONTENT_COLUMN+MIDDLE_MARGIN_COLUMN, TOP_MARGIN_ROW+IMAGE_ROW+MIDDLE_MARGIN_ROW),
|
||||||
|
@ -70,17 +70,17 @@ def create_soy_vs_chad_meme(emoji1, emoji2, caption1, caption2):
|
||||||
color=ColorScheme.WHITE_WITH_BLACK_BORDER)
|
color=ColorScheme.WHITE_WITH_BLACK_BORDER)
|
||||||
return base
|
return base
|
||||||
|
|
||||||
def create_classic_meme(image: Image, top_caption : str, bottom_caption : str):
|
def create_classic_meme(image: 'AnimatedImage', top_caption : str, bottom_caption : str) -> 'AnimatedImage':
|
||||||
image_x_size, image_y_size = image.size
|
image_x_size, image_y_size = image.size
|
||||||
UNIT = 5
|
UNIT = 5
|
||||||
caption_size = int(image_y_size/UNIT)
|
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)
|
image = 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)
|
image = 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
|
return image
|
||||||
|
|
||||||
def create_classic_meme_from_url(url : str, top_caption : str, bottom_caption : str):
|
def create_classic_meme_from_url(url : str, top_caption : str, bottom_caption : str) -> 'AnimatedImage':
|
||||||
return create_classic_meme(get_image_file_from_url(url), top_caption, bottom_caption)
|
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):
|
def create_classic_meme_from_emoji(emoji : str, top_caption : str, bottom_caption : str):
|
||||||
|
@ -88,19 +88,19 @@ def create_classic_meme_from_emoji(emoji : str, top_caption : str, bottom_captio
|
||||||
BORDER_SIZE = 100
|
BORDER_SIZE = 100
|
||||||
|
|
||||||
marsey = get_emoji_from_rdrama(emoji)
|
marsey = get_emoji_from_rdrama(emoji)
|
||||||
marsey = ImageOps.contain(marsey, (EMOJI_SIZE, EMOJI_SIZE))
|
marsey = marsey.fit((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 = AnimatedImage.new(size=(EMOJI_SIZE+2*BORDER_SIZE, EMOJI_SIZE+2*BORDER_SIZE))
|
||||||
base.paste(marsey, (BORDER_SIZE, BORDER_SIZE), marsey)
|
base = base.paste(marsey, (BORDER_SIZE, BORDER_SIZE))
|
||||||
|
|
||||||
return create_classic_meme(base, top_caption, bottom_caption)
|
return create_classic_meme(base, top_caption, bottom_caption)
|
||||||
|
|
||||||
def create_modern_meme(image : Image, caption : str):
|
def create_modern_meme(image : 'AnimatedImage', caption : str) -> 'AnimatedImage':
|
||||||
CAPTION_SIZE = 150
|
CAPTION_SIZE = 150
|
||||||
image_x_size, image_y_size = image.size
|
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 = AnimatedImage.new(size=(image_x_size,image_y_size+CAPTION_SIZE))
|
||||||
base.paste(image, (0, CAPTION_SIZE))
|
base = base.paste(image, (0, CAPTION_SIZE))
|
||||||
add_text_box(base, caption, (image_x_size, CAPTION_SIZE), (0,0), font="intreb.ttf",align="chcv")
|
base = add_text_box(base, caption, (image_x_size, CAPTION_SIZE), (0,0), font="intreb.ttf",align="chcv")
|
||||||
return base
|
return base
|
||||||
|
|
||||||
def create_modern_meme_from_url(url : str, caption : str):
|
def create_modern_meme_from_url(url : str, caption : str):
|
||||||
|
@ -111,10 +111,10 @@ def create_modern_meme_from_emoji(emoji: str, caption: str):
|
||||||
BORDER_SIZE = 10
|
BORDER_SIZE = 10
|
||||||
|
|
||||||
marsey = get_emoji_from_rdrama(emoji)
|
marsey = get_emoji_from_rdrama(emoji)
|
||||||
marsey = ImageOps.contain(marsey, (EMOJI_SIZE, EMOJI_SIZE))
|
marsey = marsey.fit((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 = AnimatedImage.new((EMOJI_SIZE+2*BORDER_SIZE, EMOJI_SIZE+2*BORDER_SIZE))
|
||||||
base.paste(marsey, (BORDER_SIZE, BORDER_SIZE), marsey)
|
base = base.paste(marsey, (BORDER_SIZE, BORDER_SIZE))
|
||||||
|
|
||||||
return create_modern_meme(base, caption)
|
return create_modern_meme(base, caption)
|
||||||
|
|
||||||
|
@ -127,10 +127,10 @@ class WebcomicPanel():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def create_image(self) -> Image:
|
def create_image(self) -> Image:
|
||||||
return Image.new(mode="RGB", size=(self.PANEL_SIZE,self.PANEL_SIZE), color=(255,255,255))
|
return AnimatedImage.new((self.PANEL_SIZE,self.PANEL_SIZE))
|
||||||
|
|
||||||
def add_text_box(self, base : Image, caption : str, region_size : tuple[int, int], coordinates : tuple[int, int], align=""):
|
def add_text_box(self, base : Image, caption : str, region_size : tuple[int, int], coordinates : tuple[int, int], align="") -> 'AnimatedImage':
|
||||||
add_text_box(base, caption, region_size, coordinates, align=align, font=self.FONT, color=self.COLOR, init_font_size=int(self.PANEL_SIZE/10))
|
return 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):
|
class OneCharacterWebcomicPanel(WebcomicPanel):
|
||||||
def __init__(self, emoji, caption, words_in_background):
|
def __init__(self, emoji, caption, words_in_background):
|
||||||
|
@ -145,7 +145,7 @@ class OneCharacterWebcomicPanel(WebcomicPanel):
|
||||||
# We put the text in the background of the panel.
|
# We put the text in the background of the panel.
|
||||||
text_region_x_size = int(panel_size_x)
|
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)
|
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))
|
base = 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
|
# We put marsey in the bottom left quadrant
|
||||||
emoji_region_x_size = int(panel_size_x)
|
emoji_region_x_size = int(panel_size_x)
|
||||||
|
@ -153,7 +153,7 @@ class OneCharacterWebcomicPanel(WebcomicPanel):
|
||||||
emoji_placement_position_x = 0
|
emoji_placement_position_x = 0
|
||||||
emoji_placement_position_y = int(panel_size_y/2)
|
emoji_placement_position_y = int(panel_size_y/2)
|
||||||
emoji = get_emoji_from_rdrama(self.emoji)
|
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))
|
base = 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)
|
return add_border_to_image(base)
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ class TwoCharacterWebcomicPanel(WebcomicPanel):
|
||||||
left_emoji_placement_position_x = 0
|
left_emoji_placement_position_x = 0
|
||||||
left_emoji_placement_position_y = int(panel_size_y/2)
|
left_emoji_placement_position_y = int(panel_size_y/2)
|
||||||
left_emoji = get_emoji_from_rdrama(self.left_emoji)
|
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))
|
base = 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
|
# We put the right marsey in the bottom right quadrant
|
||||||
right_emoji_region_x_size = int(panel_size_x/2)
|
right_emoji_region_x_size = int(panel_size_x/2)
|
||||||
|
@ -182,7 +182,7 @@ class TwoCharacterWebcomicPanel(WebcomicPanel):
|
||||||
right_emoji_placement_position_x = int(panel_size_x/2)
|
right_emoji_placement_position_x = int(panel_size_x/2)
|
||||||
right_emoji_placement_position_y = int(panel_size_y/2)
|
right_emoji_placement_position_y = int(panel_size_y/2)
|
||||||
right_emoji = get_emoji_from_rdrama(self.right_emoji)
|
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))
|
base = 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.
|
#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.
|
#The left caption will be all the way to the left. The right caption will be 3/8 to the right.
|
||||||
|
@ -195,14 +195,14 @@ class TwoCharacterWebcomicPanel(WebcomicPanel):
|
||||||
left_text_region_y_size = int(panel_size_y/4)
|
left_text_region_y_size = int(panel_size_y/4)
|
||||||
left_text_region_x_position = 0
|
left_text_region_x_position = 0
|
||||||
left_text_region_y_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")
|
base = 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.
|
# 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_x_size = int(CAPTION_UNITS*(panel_size_x/CAPTION_DIVISOR))
|
||||||
right_text_region_y_size = int(panel_size_y/4)
|
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_x_position = int((CAPTION_DIVISOR-CAPTION_UNITS)*(panel_size_x/8))
|
||||||
right_text_region_y_position = int(panel_size_y/4)
|
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")
|
base = 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)
|
return add_border_to_image(base)
|
||||||
|
|
||||||
|
@ -213,7 +213,7 @@ class TitleCardWebcomicPanel(WebcomicPanel):
|
||||||
def create_image(self) -> Image:
|
def create_image(self) -> Image:
|
||||||
base = super().create_image()
|
base = super().create_image()
|
||||||
|
|
||||||
self.add_text_box(base, self.caption, base.size, (0,0), align="cvch")
|
base = self.add_text_box(base, self.caption, base.size, (0,0), align="cvch")
|
||||||
|
|
||||||
return add_border_to_image(base)
|
return add_border_to_image(base)
|
||||||
|
|
||||||
|
@ -222,20 +222,20 @@ def create_webcomic(layout : 'list[WebcomicPanel]'):
|
||||||
total_image_x_size = assumed_panel_x_size * 2
|
total_image_x_size = assumed_panel_x_size * 2
|
||||||
total_image_y_size = assumed_panel_x_size * math.ceil(len(layout)/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))
|
image = AnimatedImage.new((total_image_x_size, total_image_y_size))
|
||||||
for i in range(len(layout)):
|
for i in range(len(layout)):
|
||||||
panel = layout[i]
|
panel = layout[i]
|
||||||
x = i%2
|
x = i%2
|
||||||
y = math.floor(i/2)
|
y = math.floor(i/2)
|
||||||
image.paste(panel.create_image(), (x*assumed_panel_x_size, y*assumed_panel_y_size))
|
image = image.paste(panel.create_image(), (x*assumed_panel_x_size, y*assumed_panel_y_size))
|
||||||
return image
|
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):
|
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 == "":
|
if caption == "":
|
||||||
return
|
return base
|
||||||
if init_font_size == 0:
|
if init_font_size == 0:
|
||||||
print("Retard moment")
|
print("Retard moment")
|
||||||
return
|
return base
|
||||||
region_x_size, region_y_size = region_size
|
region_x_size, region_y_size = region_size
|
||||||
|
|
||||||
if color == ColorScheme.BLACK:
|
if color == ColorScheme.BLACK:
|
||||||
|
@ -281,10 +281,11 @@ def add_text_box(base : Image, caption : str, region_size : tuple[int, int], coo
|
||||||
image_draw = ImageDraw.Draw(base)
|
image_draw = ImageDraw.Draw(base)
|
||||||
image_draw.rectangle((coordinates, (coordinates[0]+region_size[0], coordinates[1]+region_size[1])), fill="blue")
|
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")
|
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)
|
animated_line_image = AnimatedImage.from_image(line_image.image)
|
||||||
|
return base.paste(animated_line_image, (actual_paste_x_coordinates, actual_paste_y_coordinates))
|
||||||
else:
|
else:
|
||||||
add_text_box(base, caption, region_size, coordinates, font=font, init_font_size=init_font_size-1, align=align, color=color)
|
return 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"):
|
def add_text(base : Image, caption : str, region_size : tuple[int, int], coordinates : tuple[int, int], font : str= "arial.ttf"):
|
||||||
if caption == "":
|
if caption == "":
|
||||||
|
@ -292,29 +293,29 @@ def add_text(base : Image, caption : str, region_size : tuple[int, int], coordin
|
||||||
region_x_size, region_y_size = region_size
|
region_x_size, region_y_size = region_size
|
||||||
line_image = ImageText((region_x_size, region_y_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)
|
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)
|
return base.paste(AnimatedImage.from_image(line_image.image), coordinates)
|
||||||
|
|
||||||
def add_watermark(image : Image, name_of_other_creator):
|
def add_watermark(image : Image, name_of_other_creator):
|
||||||
global watermark_captions
|
global watermark_captions
|
||||||
WATERMARK_HEIGHT = 30
|
WATERMARK_HEIGHT = 30
|
||||||
image_size_x, image_size_y = image.size
|
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 = AnimatedImage.new(size=(image_size_x, image_size_y + WATERMARK_HEIGHT))
|
||||||
base.paste(image)
|
base = base.paste(image, (0,0))
|
||||||
|
|
||||||
marsey = get_emoji_from_rdrama("marseyjamming")
|
marsey = get_emoji_from_rdrama("marseyjamming")
|
||||||
marsey = ImageOps.contain(marsey, (WATERMARK_HEIGHT, WATERMARK_HEIGHT))
|
marsey = marsey.fit((WATERMARK_HEIGHT, WATERMARK_HEIGHT))
|
||||||
base.paste(marsey, (0, image_size_y), marsey)
|
base = base.paste(marsey, (0, image_size_y))
|
||||||
|
|
||||||
text_line_size = int(WATERMARK_HEIGHT/2)
|
text_line_size = int(WATERMARK_HEIGHT/2)
|
||||||
|
|
||||||
caption = choice(watermark_captions)
|
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))
|
base = 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))
|
base = 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
|
return base
|
||||||
|
|
||||||
def center_and_paste(base : Image, to_paste : Image, coordinates: tuple[int, int], box_size : tuple[int, int]):
|
def center_and_paste(base : Image, to_paste : Image, coordinates: tuple[int, int], box_size : tuple[int, int]) -> 'AnimatedImage':
|
||||||
to_paste = ImageOps.contain(to_paste, box_size)
|
to_paste = to_paste.fit(box_size)
|
||||||
|
|
||||||
image_size_x, image_size_y = to_paste.size
|
image_size_x, image_size_y = to_paste.size
|
||||||
box_size_x, box_size_y = box_size
|
box_size_x, box_size_y = box_size
|
||||||
|
@ -329,17 +330,17 @@ def center_and_paste(base : Image, to_paste : Image, coordinates: tuple[int, int
|
||||||
|
|
||||||
x, y = offset_x + box_coordinate_x, offset_y + box_coordinate_y
|
x, y = offset_x + box_coordinate_x, offset_y + box_coordinate_y
|
||||||
|
|
||||||
base.paste(to_paste, (x, y), to_paste)
|
return base.paste(to_paste, (x, y))
|
||||||
|
|
||||||
def add_border_to_image(image : Image, thickness : int = 5):
|
def add_border_to_image(image : Image, thickness : int = 5):
|
||||||
inner_image_x_size, inner_image_y_size = image.size
|
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
|
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 = AnimatedImage.new((outer_image_x_size,outer_image_y_size), color=(0,0,0))
|
||||||
|
|
||||||
outside_image.paste(image, (thickness, thickness))
|
outside_image = outside_image.paste(image, (thickness, thickness))
|
||||||
return outside_image
|
return outside_image
|
||||||
|
|
||||||
def get_emoji_from_rdrama(emoji_name):
|
def get_emoji_from_rdrama(emoji_name) -> 'AnimatedImage':
|
||||||
cleaned_emoji_name : str = emoji_name
|
cleaned_emoji_name : str = emoji_name
|
||||||
should_flip = False
|
should_flip = False
|
||||||
if '!' in emoji_name:
|
if '!' in emoji_name:
|
||||||
|
@ -347,19 +348,20 @@ def get_emoji_from_rdrama(emoji_name):
|
||||||
should_flip = True
|
should_flip = True
|
||||||
|
|
||||||
if (exists(f"emoji_cache/{cleaned_emoji_name}.webp")):
|
if (exists(f"emoji_cache/{cleaned_emoji_name}.webp")):
|
||||||
image = Image.open(f"emoji_cache/{cleaned_emoji_name}.webp")
|
image = AnimatedImage.from_image(Image.open(f"emoji_cache/{cleaned_emoji_name}.webp"))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
image = get_image_file_from_url(f"https://www.rdrama.net/e/{cleaned_emoji_name}.webp")
|
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")
|
image.save(f"emoji_cache/{cleaned_emoji_name}.webp")
|
||||||
if should_flip:
|
if should_flip:
|
||||||
image = ImageOps.mirror(image)
|
image = image.flip()
|
||||||
return image
|
return image
|
||||||
|
|
||||||
def get_image_file_from_url(url):
|
def get_image_file_from_url(url) -> 'AnimatedImage':
|
||||||
r = requests.get(url)
|
r = requests.get(url)
|
||||||
image_file = io.BytesIO(r.content)
|
image_file = io.BytesIO(r.content)
|
||||||
im = Image.open(image_file)
|
im = Image.open(image_file)
|
||||||
return im
|
return AnimatedImage.from_image(im)
|
||||||
|
|
||||||
def parse_caption_file(filename):
|
def parse_caption_file(filename):
|
||||||
if not exists(filename):
|
if not exists(filename):
|
||||||
|
@ -372,7 +374,112 @@ def parse_caption_file(filename):
|
||||||
|
|
||||||
watermark_captions = parse_caption_file(CAPTION_FILENAME)
|
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()
|
class AnimatedImage():
|
||||||
|
def __init__(self, frames : list[Image.Image]):
|
||||||
|
self.frames = frames
|
||||||
|
|
||||||
|
@property
|
||||||
|
def size(self) -> Tuple[int, int]:
|
||||||
|
return self.frames[0].size
|
||||||
|
|
||||||
|
def flip(self) -> 'AnimatedImage':
|
||||||
|
new_frames = []
|
||||||
|
for frame in self.frames:
|
||||||
|
#frame.show()
|
||||||
|
new_frame = ImageOps.mirror(frame)
|
||||||
|
#new_frame.show()
|
||||||
|
new_frames.append(new_frame)
|
||||||
|
return AnimatedImage(new_frames)
|
||||||
|
|
||||||
|
def save(self, filename) -> None:
|
||||||
|
self.frames[0].save(f"{filename}", save_all = True, append_images = self.frames[1:], duration = 100, loop=0)
|
||||||
|
|
||||||
|
def get_binary(self) -> bytes:
|
||||||
|
output = io.BytesIO()
|
||||||
|
self.frames[0].save(output, format="webp", save_all = True, append_images = self.frames[1:], duration = 100, loop=0)
|
||||||
|
return output.getvalue()
|
||||||
|
|
||||||
|
def from_image(image: Image.Image) -> 'AnimatedImage':
|
||||||
|
frames = []
|
||||||
|
for image_frame in ImageSequence.Iterator(image):
|
||||||
|
frames.append(image_frame.copy())
|
||||||
|
return AnimatedImage(frames)
|
||||||
|
|
||||||
|
def paste(self, other : 'AnimatedImage', position : 'Tuple[int, int]') -> 'AnimatedImage':
|
||||||
|
num_self_frames = len(self.frames)
|
||||||
|
num_other_frames = len(other.frames)
|
||||||
|
|
||||||
|
new_frames = []
|
||||||
|
for i in range(get_ideal_number_of_frames(num_self_frames, num_other_frames)):
|
||||||
|
self_frame = self.frames[i%num_self_frames]
|
||||||
|
other_frame = other.frames[i%num_other_frames]
|
||||||
|
|
||||||
|
new_frame = self_frame.copy()
|
||||||
|
try:
|
||||||
|
new_frame.paste(other_frame, position, other_frame)
|
||||||
|
except ValueError:
|
||||||
|
#something about transparently idfk lol
|
||||||
|
new_frame.paste(other_frame, position)
|
||||||
|
new_frames.append(new_frame)
|
||||||
|
return AnimatedImage(new_frames)
|
||||||
|
|
||||||
|
def new(size : Tuple[int, int], color=(255,255,255)) -> 'AnimatedImage':
|
||||||
|
base = Image.new(mode="RGB", size=size, color=color)
|
||||||
|
return AnimatedImage.from_image(base)
|
||||||
|
|
||||||
|
def fit(self, region : Tuple[int, int]) -> 'AnimatedImage':
|
||||||
|
new_frames = []
|
||||||
|
for frame in self.frames:
|
||||||
|
new_frames.append(ImageOps.contain(frame, region))
|
||||||
|
return AnimatedImage(new_frames)
|
||||||
|
|
||||||
|
def prime_decomposition(a):
|
||||||
|
primes = []
|
||||||
|
current = a
|
||||||
|
while True:
|
||||||
|
if current == 1:
|
||||||
|
return primes
|
||||||
|
for i in range(current+1):
|
||||||
|
if i > 1 and current % i == 0:
|
||||||
|
primes.append(i)
|
||||||
|
current = int(current/i)
|
||||||
|
break
|
||||||
|
|
||||||
|
def get_ideal_number_of_frames(frame_count_1, frame_count_2):
|
||||||
|
bigger = max(frame_count_1, frame_count_2)
|
||||||
|
smaller = min(frame_count_1, frame_count_2)
|
||||||
|
|
||||||
|
if (bigger % smaller == 0):
|
||||||
|
return bigger
|
||||||
|
else:
|
||||||
|
product = 1
|
||||||
|
for i in get_leftover_primes(bigger, smaller):
|
||||||
|
product *= i
|
||||||
|
return bigger * i
|
||||||
|
|
||||||
|
def get_leftover_primes(a_, b_):
|
||||||
|
a = max(a_, b_)
|
||||||
|
b = min(a_, b_)
|
||||||
|
a_primes = prime_decomposition(a)
|
||||||
|
b_primes = prime_decomposition(b)
|
||||||
|
|
||||||
|
leftover_primes = []
|
||||||
|
for i in b_primes:
|
||||||
|
if i in a_primes:
|
||||||
|
a_primes.remove(i)
|
||||||
|
else:
|
||||||
|
leftover_primes.append(i)
|
||||||
|
return leftover_primes
|
||||||
|
|
||||||
|
# shooting = get_emoji_from_rdrama("!marseyshooting")
|
||||||
|
# shooting2 = get_emoji_from_rdrama("marseydeterminedgun")
|
||||||
|
|
||||||
|
# base = AnimatedImage.new((500, 500))
|
||||||
|
# base = base.paste(shooting, (0,0))
|
||||||
|
# base = base.paste(shooting2.fit((50, 50)), (250,250))
|
||||||
|
# base = add_text_box(base, "killing time", (100, 500), (0, 400))
|
||||||
|
# base.save("kingshit.webp")
|
||||||
|
#create_soy_vs_chad_meme("bigsmilesoyjak", "!marseyshooting", "I have fun new toys and games for your children", "Die").save("brand_new_meme.webp")
|
||||||
|
|
||||||
# create_webcomic([
|
# create_webcomic([
|
||||||
# TwoCharacterWebcomicPanel("soyjak", "Black people deserve the rope", "marseyconfused", "Why?"),
|
# TwoCharacterWebcomicPanel("soyjak", "Black people deserve the rope", "marseyconfused", "Why?"),
|
||||||
|
@ -381,9 +488,9 @@ watermark_captions = parse_caption_file(CAPTION_FILENAME)
|
||||||
# TitleCardWebcomicPanel("One Hour Later..."),
|
# TitleCardWebcomicPanel("One Hour Later..."),
|
||||||
# TwoCharacterWebcomicPanel("marseytombstone", "", "!marseycry", "He had so much to live for"),
|
# TwoCharacterWebcomicPanel("marseytombstone", "", "!marseycry", "He had so much to live for"),
|
||||||
# OneCharacterWebcomicPanel("marseylaugh", "Just Kidding!", False)
|
# OneCharacterWebcomicPanel("marseylaugh", "Just Kidding!", False)
|
||||||
# ]).show()
|
# ]).save("webcomic.webp")
|
||||||
|
#create_modern_meme_from_url("https://media.giphy.com/media/gYkga3bZav66I/giphy.webp", "me when i see a black person (i am extremely racist)").save("racism.webp")
|
||||||
#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_classic_meme_from_url("https://rdrama.net/assets/images/rDrama/sidebar/98.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)").save("bruh.webp")
|
||||||
#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_modern_meme_from_url("https://cdn.discordapp.com/attachments/1007776259910152292/1007833711540174885/unknown.png", "and then heymoon says the imposter is among us").save("modern_image.webp")
|
||||||
#create_classic_meme_from_emoji("marseycock", "I WANT TO PUT MY DICK", "INSIDE OF MARSEY").show()
|
#create_classic_meme_from_emoji("marseydeterminedgun", "I WANT TO PUT MY DICK", "INSIDE OF MARSEY").save("classic_with_emoji.webp")
|
||||||
#create_modern_meme_from_emoji("rdramajanny", "youll be sorry when i get my mop you BITCH").show()
|
#create_modern_meme_from_emoji("rdramajanny", "youll be sorry when i get my mop you BITCH").save("modern_emoji.webp")
|
Loading…
Reference in New Issue