Skip to content

Commit

Permalink
Refactor function order
Browse files Browse the repository at this point in the history
  • Loading branch information
jacebrowning committed Aug 26, 2015
1 parent f7cc318 commit 44e9845
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 62 deletions.
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -9,7 +9,7 @@ PYTHON_MAJOR ?= 3
PYTHON_MINOR ?= 4

# Test settings
UNIT_TEST_COVERAGE := 67
UNIT_TEST_COVERAGE := 66
INTEGRATION_TEST_COVERAGE := 75
COMBINED_TEST_COVERAGE := 95

Expand Down
142 changes: 81 additions & 61 deletions memegen/domain/image.py
Expand Up @@ -14,7 +14,7 @@


class Image:
"""Meme JPEG generated from a template."""
"""JPEG generated by applying text to a template."""

def __init__(self, template, text, root=None):
self.template = template
Expand All @@ -36,74 +36,24 @@ def generate(self):
make_meme(self.text.top, self.text.bottom,
self.template.path, self.path)

def split_sentance(phrase):
''' This function tries to split the phrase into two in as close to same size as possible'''
result = [phrase]
if len(phrase) >= 3 and ' ' in phrase[1:-1]: # can split this string
spaceindx=[i for i in range(len(phrase)) if phrase[i]==' '] #indicies of spaces
close = [abs(spacei-len(phrase)//2) for spacei in spaceindx] #space distance from center
for i, j in zip(close, spaceindx):
if i == min(close):
result = [phrase[:j],phrase[j+1:]]
break
return result

def calc_largest_fontSize(phrase, max_size):
'''Find biggest font size that works'''
font_size = max_size
font = ImageFont.truetype(FONT, font_size)
text_size = font.getsize(phrase)
while text_size[0] > max_size:
font_size = font_size - 1
font = ImageFont.truetype(FONT, font_size)
text_size = font.getsize(phrase)
return font_size

def calc_font_size(top, bottom, max_font_size, min_font_size, max_text_len):
font_size = max_font_size

# Check size when using smallest single line font size
font = ImageFont.truetype(FONT, min_font_size)
top_text_size = font.getsize(top)
bottom_text_size = font.getsize(bottom)

#calculate font size for top text, split if necessary
if top_text_size[0] > max_text_len:
top_phrases = split_sentance(top)
else:
top_phrases = [top]
for phrase in top_phrases:
font_size = min(calc_largest_fontSize(phrase, max_text_len), font_size)

#calculate font size for bottom text, split if necessary
if bottom_text_size[0] > max_text_len:
bottom_phrases = split_sentance(bottom)
else:
bottom_phrases = [bottom]
for phrase in bottom_phrases:
font_size = min(calc_largest_fontSize(phrase, max_text_len), font_size)

#rebuild text with new lines
top = '\n'.join(top_phrases)
bottom = '\n'.join(bottom_phrases)

return font_size, top, bottom

# based on: https://github.com/danieldiekmeier/memegenerator
def make_meme(top, bottom, background, path):
"""Add text to an image and save it."""
img = ImageFile.open(background)

# Resize to a maximum height and width
img.thumbnail((500, 500))
image_size = img.size

# Draw image
draw = ImageDraw.Draw(img)

max_font_size = int(image_size[1] / 5)
min_font_size = int(image_size[1] / 10)
max_text_len = image_size[0] - 20
font_size, top, bottom = calc_font_size(top, bottom, max_font_size, min_font_size, max_text_len)
min_font_size = int(image_size[1] / 15)
max_text_len = image_size[0] - 10
font_size, top, bottom = _optimize_font_size(top, bottom, max_font_size,
min_font_size, max_text_len)
font = ImageFont.truetype(FONT, font_size)

top_text_size = draw.multiline_textsize(top, font)
Expand All @@ -124,13 +74,83 @@ def make_meme(top, bottom, background, path):
for x in range(-outline_range, outline_range + 1):
for y in range(-outline_range, outline_range + 1):
pos = (top_text_position[0] + x, top_text_position[1] + y)
draw.multiline_text(pos, top, (0, 0, 0), font=font, align='center')
draw.multiline_text(pos, top, (0, 0, 0),
font=font, align='center')
pos = (bottom_text_position[0] + x, bottom_text_position[1] + y)
draw.multiline_text(pos, bottom, (0, 0, 0), font=font, align='center')
draw.multiline_text(pos, bottom, (0, 0, 0),
font=font, align='center')

# Draw inner white text
draw.multiline_text(top_text_position, top, (255, 255, 255), font=font, align='center')
draw.multiline_text(bottom_text_position, bottom, (255, 255, 255), font=font, align='center')
draw.multiline_text(top_text_position, top, (255, 255, 255),
font=font, align='center')
draw.multiline_text(bottom_text_position, bottom, (255, 255, 255),
font=font, align='center')

log.info("generated: %s", path)
return img.save(path)


def _optimize_font_size(top, bottom, max_font_size, min_font_size,
max_text_len):
"""Calculate the optimal font size to fit text in a given size."""
font_size = max_font_size

# Check size when using smallest single line font size
font = ImageFont.truetype(FONT, min_font_size)
top_text_size = font.getsize(top)
bottom_text_size = font.getsize(bottom)

# calculate font size for top text, split if necessary
if top_text_size[0] > max_text_len:
top_phrases = _split(top)
else:
top_phrases = [top]
for phrase in top_phrases:
font_size = min(_maximize_font_size(phrase, max_text_len), font_size)

# calculate font size for bottom text, split if necessary
if bottom_text_size[0] > max_text_len:
bottom_phrases = _split(bottom)
else:
bottom_phrases = [bottom]
for phrase in bottom_phrases:
font_size = min(_maximize_font_size(phrase, max_text_len), font_size)

# rebuild text with new lines
top = '\n'.join(top_phrases)
bottom = '\n'.join(bottom_phrases)

return font_size, top, bottom


def _maximize_font_size(text, max_size):
"""Find the biggest font size that will fit."""
font_size = max_size
font = ImageFont.truetype(FONT, font_size)
text_size = font.getsize(text)
while text_size[0] > max_size:
font_size = font_size - 1
font = ImageFont.truetype(FONT, font_size)
text_size = font.getsize(text)
return font_size


def _split(text):
"""Split a line of text into two similarly sized pieces.
>>> _split("Hello, world!")
('Hello,', 'world!')
>>> _split("This is a phrase that can be split.")
('This is a phrase', 'that can be split.')
"""
result = [text]
if len(text) >= 3 and ' ' in text[1:-1]: # can split this string
space_indices = [i for i in range(len(text)) if text[i] == ' ']
space_proximities = [abs(i - len(text) // 2) for i in space_indices]
for i, j in zip(space_proximities, space_indices):
if i == min(space_proximities):
result = (text[:j], text[j + 1:])
break
return result

0 comments on commit 44e9845

Please sign in to comment.