all repos — python-meme-bot @ a17a51edecc18a04aa53c720656248fcce686d9c

Telegram Bot that uses PIL to compute light image processing.

main.py (view raw)

 1from PIL import Image, ImageDraw, ImageFont
 2import textwrap
 3
 4class Meme:
 5
 6    basewidth = 1200             #Width to make the meme
 7    fontBase = 100
 8    letSpacing = 9              #Space between letters
 9    fill = (255, 255, 255)      #TextColor
10    stroke_fill = (0,0,0)             #outlineColor
11    lineSpacing = 10            #Space between lines
12    stroke_width=9              #How thick the outline of the text is
13    fontfile = './impact.ttf'
14
15    def __init__(self, caption, image):
16        self.img = self.createImage(image)
17        self.d = ImageDraw.Draw(self.img)
18
19        self.splitCaption = textwrap.wrap(caption, width=20)  # The text can be wider than the img. If thats the case split the text into multiple lines
20        self.splitCaption.reverse()                           # Draw the lines of text from the bottom up
21
22        fontSize = self.fontBase+10 if len(self.splitCaption) <= 1 else self.fontBase   #If there is only one line, make the text a bit larger
23        self.font = ImageFont.truetype(font=self.fontfile, size=fontSize)
24        # self.shadowFont = ImageFont.truetype(font='./impact.ttf', size=fontSize+10)
25
26    def draw(self):
27        '''
28        Draws text onto this objects img object
29        :return: A pillow image object with text drawn onto the image
30        '''
31        (iw, ih) = self.img.size
32        (_, th) = self.d.textsize(self.splitCaption[0], font=self.font) #Height of the text
33        y = (ih - (ih / 10)) - (th / 2) #The starting y position to draw the last line of text. Text in drawn from the bottom line up
34
35        for cap in self.splitCaption:   #For each line of text
36            (tw, _) = self.d.textsize(cap, font=self.font)  # Getting the position of the text
37            x = ((iw - tw) - (len(cap) * self.letSpacing))/2  # Center the text and account for the spacing between letters
38
39            self.drawLine(x=x, y=y, caption=cap)
40            y = y - th - self.lineSpacing  # Next block of text is higher up
41
42        wpercent = ((self.basewidth/2) / float(self.img.size[0]))
43        hsize = int((float(self.img.size[1]) * float(wpercent)))
44        return self.img.resize((int(self.basewidth/2), hsize))
45
46    def createImage(self, image):
47        '''
48        Resizes the image to a resonable standard size
49        :param image: Path to an image file
50        :return: A pil image object
51        '''
52        img = Image.open(image)
53        wpercent = (self.basewidth / float(img.size[0]))
54        hsize = int((float(img.size[1]) * float(wpercent)))
55        return img.resize((self.basewidth, hsize))
56
57    def drawLine(self, x, y, caption):
58        '''
59        The text gets split into multiple lines if it is wider than the image. This function draws a single line
60        :param x: The starting x coordinate of the text
61        :param y: The starting y coordinate of the text
62        :param caption: The text to write on the image
63        :return: None
64        '''
65        for idx in range(0, len(caption)):  #For each letter in the line of text
66            char = caption[idx]
67            w, h = self.font.getsize(char)  #width and height of the letter
68            self.d.text(
69                (x, y),
70                char,
71                fill=self.fill,
72                stroke_width=self.stroke_width,
73                font=self.font,
74                stroke_fill=self.stroke_fill
75            )  # Drawing the text character by character. This way spacing can be added between letters
76            x += w + self.letSpacing #The next character must be drawn at an x position more to the right
77
78
79
80caption = "Now I Have a Caption"
81image = './my_image.jpg'
82outputImage = './my_captioned_image.jpg'
83
84meme = Meme(caption, image)
85img = meme.draw()
86if img.mode in ("RGBA", "P"):   #Without this the code can break sometimes
87    img = img.convert("RGB")
88img.save(outputImage, optimize=True, quality=80)    #Save with some image optimization