Skip to content

Commit

Permalink
stuff
Browse files Browse the repository at this point in the history
* title generation. random color, random background color, random
  placement, random text transform (romanize, lower), random size...
* put flickr stuff into its own module
  • Loading branch information
vilmibm committed Sep 22, 2016
1 parent b0595d8 commit 9af0b0f
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 64 deletions.
191 changes: 127 additions & 64 deletions randomwaite/__init__.py
Original file line number Diff line number Diff line change
@@ -1,60 1,68 @@
from io import BytesIO
import math
from random import choice, random
import re
import sys
import typing as t
import urllib.request
from enum import Enum
from io import BytesIO
from os import path
from random import choice, random, randrange

import flickrapi
from flickrapi.core import FlickrAPI
from PIL import Image
import tweepy
from flickrapi.core import FlickrAPI
from PIL import Image, ImageDraw, ImageFont

from . import secrets as sec
from .cards import TarotCard, CARDS, get_tarot_card
from .flickr import get_photo

OK_LICENSES = [1,2,4,5,7]
NO_ATTRIBUTION = [7]
DEBUG = True
CARD_WIDTH = 385
CARD_HEIGHT = 666
ZOOM_CHANCE = .25
FONT_PATH = path.join(path.dirname(__file__), 'fonts')
FONTS = ['CantataOne-Regular.ttf']
ROMAN_TABLE = {
'two': 'ii',
'three': 'iii',
'four': 'iv',
'five': 'v',
'six': 'vi',
'seven': 'vii',
'eight': 'viii',
'nine': 'ix',
'ten': 'x',
}
TITLE_ALIGNS = ('left', 'right', 'center')
TITLE_SIZES = {
'large': 50,
'small': 32,
'stupid': 80,
}

Fill = t.Tuple[int]
TitlePlacement = Enum('TitlePlacement', 'top bottom middle random')

break_string_re = re.compile(' ')

# TODO deal with loss of randomness
# TODO reversed/inversed cards
# TODO sentiment analysis of search words
# TODO emoji suites

def random_fill() -> Fill:
return (
randrange(0,255),
randrange(0,255),
randrange(0,255),
randrange(0,255),
)

def maybe_romanize(text: str) -> str:
for english,roman in ROMAN_TABLE.items():
if re.search(english, text, flags=re.I):
return re.sub(english, roman, text, flags=re.I)
return text

class Photo:
__slots__ = ['_url', 'path', '_license', '_data', 'flickr']

def __init__(self, flickr: FlickrAPI, flickr_data: t.Dict) -> None:
self.path = None
self._license = None
self._url = None
self._data = flickr_data
self.flickr = flickr

def needs_attribution(self) -> bool:
return self.license in NO_ATTRIBUTION

@property
def license(self) -> int:
if not self._license:
info = self.flickr.photos.getInfo(photo_id=self._data['id'], secret=self._data['secret'])
self._license = info['photo']['license']
return self._license

@property
def url(self) -> str:
if not self._url:
sizes = self.flickr.photos.getSizes(photo_id=self._data['id'])
self._url = sizes['sizes']['size'][-1]['source']
return self._url

@property
def attribution(self) -> str:
return "TODO"

def get_photo(flickr: FlickrAPI, search: str) -> Photo:
result = flickr.photos.search(text=search, license=OK_LICENSES)
# TODO pull from more than the first page
photos = result['photos']['photo']
return Photo(flickr, choice(photos))

def random_crop(original: Image) -> Image:
min_x0 = 0
Expand Down Expand Up @@ -93,6 101,7 @@ def color_balance(card: TarotCard, original: Image) -> Image:
return original

def row_shift(original: Image) -> Image:
# TODO this doesn't work
row_height = 5
max_x = original.width
max_y = original.height
Expand All @@ -103,9 112,74 @@ def row_shift(original: Image) -> Image:
original.paste(shifted, row_box)


def get_font_path() -> str:
# TODO perhaps take a card and tie font to card
return path.join(FONT_PATH, choice(FONTS))


def place_title(card: TarotCard, im: Image) -> Image:
# boilerplate
title = card.name
position = choice(list(TitlePlacement))
size = choice(list(TITLE_SIZES.keys()))
align = choice(TITLE_ALIGNS)
im = im.convert('RGBA')
font_path = get_font_path()
fnt = ImageFont.truetype(font_path, TITLE_SIZES[size])
txt = Image.new('RGBA', im.size, (0,0,0,0))
d = ImageDraw.Draw(txt)
print(title)
print(position)
print(size)
print(align)

# ~ * randomness * ~
if random() < .5:
title = maybe_romanize(title)

if random() < .6:
title = title.lower()

# check to see if we'd go out of bounds and split text if so
if d.textsize(title, fnt)[0] > im.width:
title = break_string_re.sub('\n', title)

text_w, text_h = d.textsize(title, fnt)

text_x = 0
if text_w < im.width:
text_x = randrange(0, im.width - text_w)


if position == TitlePlacement.top:
text_y = 0
elif position == TitlePlacement.middle:
text_y = im.height // 2
if text_y text_h > im.height:
position = TitlePlacement.bottom
elif position == TitlePlacement.bottom:
text_y = im.height - text_h
elif position == TitlePlacement.random:
text_y = randrange(0, (im.height - text_h))

print(text_x, text_y, text_w, text_h)

# actual drawing
d.rectangle((text_x, text_y, text_w, text_y text_h 15), fill=random_fill())
d.text((text_x, text_y),
title,
font=fnt,
fill=random_fill(),
spacing=1,
align=align)

out = Image.alpha_composite(im, txt)

return out


def main():
flickr = flickrapi.FlickrAPI(sec.FLICKR_KEY, sec.FLICKR_SECRET, format='parsed-json')
flickr = FlickrAPI(sec.FLICKR_KEY, sec.FLICKR_SECRET, format='parsed-json')
twitter_auth = tweepy.OAuthHandler(sec.TWITTER_KEY, sec.TWITTER_SECRET)
twitter_auth.set_access_token(sec.TWITTER_ACCESS_TOKEN, sec.TWITTER_ACCESS_SECRET)
twitter = tweepy.API(twitter_auth)
Expand All @@ -116,14 190,10 @@ def main():

card = get_tarot_card()
photo = get_photo(flickr, card.search)
test_url = 'https://farm6.staticflickr.com/5533/11031461323_e59917dd84_o.jpg'

print('going to fetch {}'.format(photo.url))

# move into Photo
request = urllib.request.urlopen(photo.url)
#request = urllib.request.urlopen(test_url)
original = Image.open(request)
original = Image.open(photo.data)

# 1 Pick random section of image to cut card from
im = random_crop(original)
Expand All @@ -134,20 204,13 @@ def main():
# 3 modify color balance (based on card)
im = color_balance(card, im)

buffer = BytesIO()
im.save(buffer, format='JPEG')
twitter.update_with_media('tarot.jpg', file=buffer)


# TODO no network
#im.save('there.jpg')
im = place_title(card, im)

# 4 potentially emoji bomb, if the card supports it
# 5 glitch step (might not happen)
# 6 text application
# 6a choose font (card based or random?)
# 6b choose size / placement / color of number
# 6c choose size / placement / color of text
# 7 glitch step (will always happen)
if not DEBUG:
buffer = BytesIO()
im.save(buffer, format='JPEG')
twitter.update_with_media('tarot.jpg', file=buffer)
else:
im.save('/tmp/tarot.jpg')

sys.exit(0)
3 changes: 3 additions & 0 deletions randomwaite/cards.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 160,9 @@ def get_tarot_card() -> TarotCard:
'lion', 'salamander', 'authority', 'finances', 'money',
'finance', 'honesty', 'mediation', 'mediate', 'professional',
'fire', 'desert')),
]

TODO = [
# swords
TarotCard('Ace of Swords', ('',)),
TarotCard('Two of Swords', ('',)),
Expand Down
57 changes: 57 additions & 0 deletions randomwaite/flickr.py
Original file line number Diff line number Diff line change
@@ -0,0 1,57 @@
from io import BytesIO
from random import choice
import typing as t
import urllib.request

from flickrapi.core import FlickrAPI

OK_LICENSES = [1,2,4,5,7]
NO_ATTRIBUTION = [7]

class Photo:

def __init__(self, flickr: FlickrAPI, flickr_data: t.Dict) -> None:
self.path = None
self._img_data = None
self._license = None
self._url = None
self._data = flickr_data
self.flickr = flickr

def needs_attribution(self) -> bool:
return self.license in NO_ATTRIBUTION

@property
def license(self) -> int:
if not self._license:
info = self.flickr.photos.getInfo(photo_id=self._data['id'], secret=self._data['secret'])
self._license = info['photo']['license']
return self._license

@property
def url(self) -> str:
if not self._url:
sizes = self.flickr.photos.getSizes(photo_id=self._data['id'])
self._url = sizes['sizes']['size'][-1]['source']
return self._url

@property
def attribution(self) -> str:
return "TODO"

@property
def data(self) -> BytesIO: # TODO I don't think this return type is right
if not self._img_data:
self._img_data = urllib.request.urlopen(self.url)

return self._img_data


def get_photo(flickr: FlickrAPI, search: t.Tuple[str]) -> Photo:
# This will check title, description, and tags for the given word
search = choice(search)
result = flickr.photos.search(text=search, license=OK_LICENSES)

# TODO pull from more than the first page
photos = result['photos']['photo']
return Photo(flickr, choice(photos))
Binary file added randomwaite/fonts/CantataOne-Regular.ttf
Binary file not shown.

0 comments on commit 9af0b0f

Please sign in to comment.