add arsenalberlin poster script; update 0xdb poster script; add new 0xdb poster font; some costmetic changes

This commit is contained in:
rolux 2013-06-06 18:21:49 +02:00
parent b3b5278f94
commit d8dd1bde5a
6 changed files with 371 additions and 95 deletions

Binary file not shown.

View file

@ -15,133 +15,181 @@ import ImageDraw
import json import json
from optparse import OptionParser from optparse import OptionParser
import ox import ox
from ox.image import drawText, wrapText from ox.image import drawText, getRGB, getTextSize, wrapText
from StringIO import StringIO
import sys import sys
static_root = os.path.join(os.path.dirname(__file__), 'data') static_root = os.path.join(os.path.dirname(__file__), 'data')
def render_poster(data, poster): def render_poster(data, poster):
title = ox.decode_html(data.get('title', '')) title = ox.decode_html(data.get('title', '')).upper()
director = u', '.join(data.get('director', [])) director = ox.decode_html(u', '.join(data.get('director', []))).upper()
director = ox.decode_html(director)
year = str(data.get('year', '')) year = str(data.get('year', ''))
series = data.get('isSeries', False) duration = data.get('duration')
oxdb_id = data['oxdbId'] oxdb_id = data['oxdbId']
imdb_id = data['id'] imdb_id = data['id']
frame = data.get('frame') frame = data.get('frame')
timeline = data.get('timeline') timeline = data.get('timeline')
id = imdb_id or oxdb_id
def get_oxdb_color(oxdb_id, series=False): poster_size = (640, 1024)
i = int(round((int(oxdb_id[2:10], 16) * 762 / pow(2, 32)))) frame_size = (640, 480)
if i < 127: frame_ratio = frame_size[0] / frame_size[1]
color = (127, i, 0) logo_size = (64, 32)
elif i < 254: small_frames = 8
color = (254 - i, 127, 0) small_frame_size = (80, 64)
elif i < 381: small_frame_ratio = small_frame_size[0] / small_frame_size[1]
color = (0, 127, i - 254) timeline_size = (640, 64)
elif i < 508: margin = 16
color = (0, 508 - i, 127) font_size_small = 32
elif i < 635: font_size_large = 48
color = (i - 508, 0, 127) font_file = os.path.join(static_root, 'MontserratRegular.ttf')
else: hue = int(oxdb_id[2:10], 16) / pow(2, 32) * 360
color = (127, 0, 762 - i) background_color = getRGB([hue, 1, 0.25])
if series: foreground_color = getRGB([hue, 1, 0.75])
color = tuple(map(lambda x: x + 128, color)) poster_image = Image.new('RGB', poster_size)
return color
poster_width = 640
poster_height = 1024
poster_ratio = poster_width / poster_height
poster_image = Image.new('RGB', (poster_width, poster_height))
draw = ImageDraw.Draw(poster_image) draw = ImageDraw.Draw(poster_image)
font_file = os.path.join(static_root, 'DejaVuSansCondensedBold.ttf')
font_size = { # background
'small': 28, draw.rectangle(
'large': 42, ((0, frame_size[1] + small_frame_size[1]), (poster_size[0], poster_size[1] - timeline_size[1])),
} fill=background_color
)
# frame # frame
frame_width = poster_width
frame_ratio = 4 / 3
frame_height = int(round(frame_width / frame_ratio))
if frame: if frame:
frame_image = Image.open(frame) frame_image = Image.open(frame)
frame_image_ratio = frame_image.size[0] / frame_image.size[1] frame_image_ratio = frame_image.size[0] / frame_image.size[1]
if frame_ratio < frame_image_ratio: if frame_ratio < frame_image_ratio:
frame_image = frame_image.resize((int(frame_height * frame_image_ratio), frame_height), Image.ANTIALIAS) frame_image = frame_image.resize((int(frame_size[1] * frame_image_ratio), frame_size[1]), Image.ANTIALIAS)
left = int((frame_image.size[0] - frame_width) / 2) left = int((frame_image.size[0] - frame_size[0]) / 2)
frame_image = frame_image.crop((left, 0, left + frame_width, frame_height)) frame_image = frame_image.crop((left, 0, left + frame_size[0], frame_size[1]))
else: else:
frame_image = frame_image.resize((frame_width, int(frame_width / frame_image_ratio)), Image.ANTIALIAS) frame_image = frame_image.resize((frame_size[0], int(frame_size[0] / frame_image_ratio)), Image.ANTIALIAS)
top = int((frame_image.size[1] - frame_height) / 2) top = int((frame_image.size[1] - frame_height) / 2)
frame_image = frame_image.crop((0, top, frame_width, top + frame_height)) frame_image = frame_image.crop((0, top, frame_size[0], top + frame_size[1]))
poster_image.paste(frame_image, (0, 0)) poster_image.paste(frame_image, (0, 0))
# timeline # logo
timeline_width = poster_width logo_image = Image.open(os.path.join(static_root, 'logo.png'))
timeline_height = 64 logo_image = logo_image.resize(logo_size, Image.ANTIALIAS)
if timeline: for y in range(logo_size[1]):
timeline_image = Image.open(timeline) for x in range(logo_size[0]):
timeline_image = timeline_image.resize((timeline_width, timeline_height), Image.ANTIALIAS) poster_color = poster_image.getpixel((margin + x, margin + y))
poster_image.paste(timeline_image, (0, frame_height)) logo_lightness = logo_image.getpixel((x, y))[0] / 255
logo_alpha = logo_image.getpixel((x, y))[3] / 255
logo_color = getRGB([hue, 1, logo_lightness])
color = tuple([int(logo_color[i] * logo_alpha + poster_color[i] * (1 - logo_alpha)) for i in range(3)])
poster_image.putpixel((margin + x, margin + y), color)
# small frames
for i in range(small_frames):
position = duration * (i + 1) / (small_frames + 1)
small_frame_url = 'https://0xdb.org/%s/96p%f.jpg' % (id, round(position * 25) / 25)
small_frame_image = Image.open(StringIO(ox.net.read_url(small_frame_url)))
small_frame_image_ratio = small_frame_image.size[0] / small_frame_image.size[1]
if frame_ratio < frame_image_ratio:
small_frame_image = small_frame_image.resize((int(small_frame_size[1] * small_frame_image_ratio), small_frame_size[1]), Image.ANTIALIAS)
left = int((small_frame_image.size[0] - small_frame_size[0]) / 2)
small_frame_image = small_frame_image.crop((left, 0, left + small_frame_size[0], small_frame_size[1]))
else:
small_frame_image = small_frame_image.resize((small_frame_size[0], int(small_frame_size[0] / small_frame_image_ratio)), Image.ANTIALIAS)
top = int((small_frame_image.size[1] - small_frame_height) / 2)
small_frame_image = small_frame_image.crop((0, top, small_frame_size[0], top + small_frame_size[1]))
poster_image.paste(small_frame_image, (i * small_frame_size[0], frame_size[1]))
# text # text
text_width = poster_width offset_top = frame_size[1] + small_frame_size[1] + margin - 8
text_height = poster_height - frame_height - timeline_height text_height = poster_size[1] - frame_size[1] - small_frame_size[1] - 3 * margin - font_size_large - timeline_size[1]
text_top = frame_height + timeline_height
text_bottom = text_top + text_height
text_margin = 16
text_color = get_oxdb_color(oxdb_id, series)
font_color = tuple(map(lambda x: x - 128 if series else x + 128, text_color))
draw.rectangle([(0, text_top), (text_width, text_bottom)], fill=text_color)
offset_top = text_top + text_margin
if not director: if not director:
title_max_lines = 7 title_max_lines = int(text_height / font_size_large)
else: else:
title_max_lines = min(len(wrapText(title, text_width - 2 * text_margin, 0, font_file, font_size['large'])), 6) title_max_lines = min(len(wrapText(
director_max_lines = 9 - int((title_max_lines * 3 - 1) / 2) title,
if director: poster_size[0] - 2 * margin,
lines = wrapText(director, text_width - 2 * text_margin, director_max_lines, font_file, font_size['small']) 0,
for i, line in enumerate(lines): font_file,
size = drawText(poster_image, (text_margin, offset_top), line, font_file, font_size['small'], font_color) font_size_large
offset_top += font_size['small'] + 2 )), int(text_height - margin - font_size_small) / font_size_large)
offset_top += size[1] - font_size['small'] + text_margin / 2 director_max_lines = int((text_height - title_max_lines * font_size_large) / font_size_small)
lines = wrapText(title, text_width - 2 * text_margin, title_max_lines, font_file, font_size['large'])
for i, line in enumerate(lines):
size = drawText(poster_image, (text_margin, offset_top + 5), line, font_file, font_size['large'], font_color)
offset_top += font_size['large'] + 3
offset_top += size[1] - font_size['small'] + text_margin / 2
if year:
drawText(poster_image, (text_margin, offset_top), year, font_file, font_size['small'], font_color)
item_id = imdb_id or oxdb_id
drawText(poster_image, (text_margin, text_bottom - text_margin - font_size['large'] + 2), item_id, font_file, font_size['large'], font_color)
# logo # title
logo_height = 32 lines = wrapText(
logo_image = Image.open(os.path.join(static_root, 'logo.png')) title,
logo_width = int(round(logo_height * logo_image.size[0] / logo_image.size[1])) poster_size[0] - 2 * margin,
logo_image = logo_image.resize((logo_width, logo_height), Image.ANTIALIAS) title_max_lines,
logo_left = text_width - text_margin - logo_width font_file,
logo_top = text_bottom - text_margin - logo_height font_size_large
for y in range(logo_height): )
for x in range(logo_width): for line in lines:
poster_color = poster_image.getpixel((logo_left + x, logo_top + y)) drawText(
logo_color = logo_image.getpixel((x, y))[0] poster_image,
alpha = logo_image.getpixel((x, y))[3] (margin, offset_top),
if series: line,
poster_color = tuple(map(lambda x: int(x - (logo_color - 16) * alpha / 255), poster_color)) font_file,
else: font_size_large,
poster_color = tuple(map(lambda x: int(x + (logo_color - 16) * alpha / 255), poster_color)) foreground_color
poster_image.putpixel((logo_left + x, logo_top + y), poster_color) )
offset_top += font_size_large
offset_top += margin
# director
if director:
lines = wrapText(
director,
poster_size[0] - 2 * margin,
director_max_lines,
font_file,
font_size_small
)
for line in lines:
drawText(
poster_image,
(margin, offset_top),
line,
font_file,
font_size_small,
foreground_color
)
offset_top += font_size_small
# year
if year:
drawText(
poster_image,
(margin, poster_size[1] - timeline_size[1] - margin - font_size_large),
year,
font_file,
font_size_large,
foreground_color
)
# id
drawText(
poster_image,
(
poster_size[0] - margin - getTextSize(poster_image, id, font_file, font_size_small)[0],
poster_size[1] - timeline_size[1] - margin - font_size_small
),
id,
font_file,
font_size_small,
foreground_color
)
# timeline
if timeline:
timeline_image = Image.open(timeline)
timeline_image = timeline_image.resize(timeline_size, Image.ANTIALIAS)
poster_image.paste(timeline_image, (0, poster_size[1] - timeline_size[1]))
poster_image.save(poster) poster_image.save(poster)
def main(): def main():
parser = OptionParser() parser = OptionParser()
parser.add_option('-p', '--poster', dest='poster', help='Poster (image file to be written)')
parser.add_option('-d', '--data', dest='data', help='json file with metadata', default=None) parser.add_option('-d', '--data', dest='data', help='json file with metadata', default=None)
parser.add_option('-p', '--poster', dest='poster', help='Poster (image file to be written)')
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
if None in (options.data, options.poster): if None in (options.data, options.poster):

228
scripts/poster.arsenalberlin.py Executable file
View file

@ -0,0 +1,228 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division
import os
root_dir = os.path.normpath(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
# using virtualenv's activate_this.py to reorder sys.path
activate_this = os.path.join(root_dir, 'bin', 'activate_this.py')
execfile(activate_this, dict(__file__=activate_this))
import Image
import ImageDraw
import json
from optparse import OptionParser
import ox
from ox.image import getRGB, drawText, wrapText
import sys
static_root = os.path.join(os.path.dirname(__file__), 'data')
def render_poster(data, poster):
title = ox.decode_html(data.get('title', ''))
director = u', '.join(data.get('director', []))
director = ox.decode_html(director)
year = str(data.get('year', ''))
frame = data.get('frame')
timeline = data.get('timeline')
poster_width = 704
poster_height = 1024
frame_height = 512
frame_ratio = poster_width / frame_height
timeline_height = 64
text_margin = 16
text_width = poster_width - 2 * text_margin
poster_image = Image.new('RGB', (poster_width, poster_height))
draw = ImageDraw.Draw(poster_image)
font_file = os.path.join(static_root, 'SourceSansProSemibold.ttf')
font_size = {'arsenal': 120, 'director': 32, 'title': 48, 'year': 426}
font_lightness = {'arsenal': 0.7, 'director': 0.8, 'title': 0.8, 'year': 0.6}
poster_lightness = {'image': 0.2, 'text': 0.4}
if year:
hue = int(year) % 100 / 100 * 360
saturation = 1
else:
hue = 0
saturation = 0
# background
draw.rectangle(
[(0, frame_height), (poster_width, poster_height - timeline_height)],
fill=getRGB((hue, saturation, poster_lightness['text']))
)
# year
if year:
drawText(
poster_image,
(-93, poster_height - timeline_height - font_size['year'] + 6),
year,
font_file,
font_size['year'],
getRGB((hue, saturation, font_lightness['year']))
)
# arsenal
for y in [-1, 1]:
for x in [-1, 1]:
drawText(
poster_image,
(-9 + x, poster_height - timeline_height - font_size['arsenal'] + 1 + y),
'Indiancine.ma',
font_file,
font_size['arsenal'],
getRGB((hue, saturation, poster_lightness['text']))
)
drawText(
poster_image,
(-9, poster_height - timeline_height - font_size['arsenal'] + 1),
'Indiancine.ma',
font_file,
font_size['arsenal'],
getRGB((hue, saturation, font_lightness['arsenal']))
)
# director and title
offset_top = frame_height + text_margin
if not director:
title_max_lines = 8
else:
title_max_lines = min(len(wrapText(
title,
text_width,
0,
font_file,
font_size['title']
)), 7)
director_max_lines = 11 - int((title_max_lines * 3 - 1) / 2)
# director
if director:
lines = wrapText(
director,
text_width,
director_max_lines,
font_file,
font_size['director']
)
for line in lines:
for y in [-1, 1]:
for x in [-1, 1]:
drawText(
poster_image,
(text_margin + x, offset_top + y),
line,
font_file,
font_size['director'],
getRGB((hue, saturation, poster_lightness['text']))
)
size = drawText(
poster_image,
(text_margin, offset_top),
line,
font_file,
font_size['director'],
getRGB((hue, saturation, font_lightness['director']))
)
offset_top += font_size['director'] + 2
offset_top += size[1] - font_size['director'] - 2
# title
lines = wrapText(
title,
text_width,
title_max_lines,
font_file,
font_size['title']
)
for line in lines:
for y in [-1, 1]:
for x in [-1, 1]:
drawText(
poster_image,
(text_margin + x, offset_top + y),
line,
font_file,
font_size['title'],
getRGB((hue, saturation, poster_lightness['text']))
)
drawText(
poster_image,
(text_margin, offset_top),
line,
font_file,
font_size['title'],
getRGB((hue, saturation, font_lightness['title']))
)
offset_top += font_size['title'] + 3
# frame
if frame:
frame_image = Image.open(frame)
frame_image_ratio = frame_image.size[0] / frame_image.size[1]
if frame_ratio < frame_image_ratio:
frame_image = frame_image.resize(
(int(frame_height * frame_image_ratio), frame_height),
Image.ANTIALIAS
)
left = int((frame_image.size[0] - poster_width) / 2)
frame_image = frame_image.crop(
(left, 0, left + poster_width, frame_height)
)
else:
frame_image = frame_image.resize(
(poster_width, int(poster_width / frame_image_ratio)),
Image.ANTIALIAS
)
top = int((frame_image.size[1] - frame_height) / 2)
frame_image = frame_image.crop(
(0, top, poster_width, top + frame_height)
)
poster_image.paste(frame_image, (0, 0))
else:
draw.rectangle(
[(0, 0), (poster_width, frame_height)],
fill=getRGB((hue, saturation, poster_lightness['image']))
)
# timeline
if timeline:
timeline_image = Image.open(timeline)
timeline_image = timeline_image.resize(
(poster_width, timeline_height),
Image.ANTIALIAS
)
poster_image.paste(timeline_image, (0, poster_height - timeline_height))
else:
draw.rectangle(
[(0, poster_height - timeline_height), (poster_width, poster_height)],
fill=getRGB((hue, saturation, poster_lightness['image']))
)
poster_image.save(poster, quality=100)
def main():
parser = OptionParser()
parser.add_option('-d', '--data', dest='data', help='json file with metadata', default=None)
parser.add_option('-p', '--poster', dest='poster', help='Poster (image file to be written)')
(options, args) = parser.parse_args()
if None in (options.data, options.poster):
parser.print_help()
sys.exit()
if options.data == '-':
data = json.load(sys.stdin)
else:
with open(options.data) as f:
data = json.load(f)
render_poster(data, options.poster)
if __name__ == "__main__":
main()

View file

@ -208,8 +208,8 @@ def render_poster(data, poster):
def main(): def main():
parser = OptionParser() parser = OptionParser()
parser.add_option('-p', '--poster', dest='poster', help='Poster (image file to be written)')
parser.add_option('-d', '--data', dest='data', help='json file with metadata', default=None) parser.add_option('-d', '--data', dest='data', help='json file with metadata', default=None)
parser.add_option('-p', '--poster', dest='poster', help='Poster (image file to be written)')
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
if None in (options.data, options.poster): if None in (options.data, options.poster):
parser.print_help() parser.print_help()

View file

@ -66,8 +66,8 @@ def render_poster(data, poster):
def main(): def main():
parser = OptionParser() parser = OptionParser()
parser.add_option('-p', '--poster', dest='poster', help='Poster (image file to be written)')
parser.add_option('-d', '--data', dest='data', help='json file with metadata', default=None) parser.add_option('-d', '--data', dest='data', help='json file with metadata', default=None)
parser.add_option('-p', '--poster', dest='poster', help='Poster (image file to be written)')
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
if None in (options.data, options.poster): if None in (options.data, options.poster):

View file

@ -141,8 +141,8 @@ i '''
def main(): def main():
parser = OptionParser() parser = OptionParser()
parser.add_option('-p', '--poster', dest='poster', help='Poster (image file to be written)')
parser.add_option('-d', '--data', dest='data', help='json file with metadata', default=None) parser.add_option('-d', '--data', dest='data', help='json file with metadata', default=None)
parser.add_option('-p', '--poster', dest='poster', help='Poster (image file to be written)')
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
if None in (options.data, options.poster): if None in (options.data, options.poster):