155 lines
6.4 KiB
Python
155 lines
6.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
# vi:si:et:sw=4:sts=4:ts=4
|
|
|
|
from __future__ import division
|
|
from optparse import OptionParser
|
|
import os
|
|
import sys
|
|
|
|
import Image
|
|
import ImageDraw
|
|
from oxlib import truncateString, wrapString
|
|
|
|
data_root = os.path.join(os.path.dirname(__file__), 'data')
|
|
|
|
def main():
|
|
|
|
parser = OptionParser()
|
|
parser.add_option('-o', '--oxdb', dest='oxdb', help='0xdb Id')
|
|
parser.add_option('-i', '--imdb', dest='imdb', help='IMDb Id')
|
|
parser.add_option('-t', '--title', dest='title', help='Movie title')
|
|
parser.add_option('-d', '--director', dest='director', help='Director(s)')
|
|
parser.add_option('-f', '--frame', dest='frame', help='Poster frame (image file to be read)')
|
|
parser.add_option('-p', '--poster', dest='poster', help='Poster (image file to be written)')
|
|
parser.add_option('-r', '--restricted', action='store_true', dest='restricted', help='If set, poster frame will have overlay')
|
|
(opts, args) = parser.parse_args()
|
|
if None in (opts.oxdb, opts.title, opts.director, opts.poster):
|
|
parser.print_help()
|
|
sys.exit()
|
|
opts.oxdb = '%s%s' % (opts.oxdb[:2], opts.oxdb[2:8].upper())
|
|
opts.title = opts.title.decode('utf-8')
|
|
opts.director = opts.director.decode('utf-8')
|
|
if opts.imdb == None:
|
|
id = opts.oxdb
|
|
else:
|
|
id = opts.imdb
|
|
|
|
posterWidth = 640
|
|
posterHeight = 1024
|
|
posterImage = Image.new('RGB', (posterWidth, posterHeight))
|
|
fontImage = Image.open(os.path.join(data_root, 'font.monaco.bold.png'))
|
|
oxdbImage = Image.open(os.path.join(data_root, 'logo.0xdb.large.png'))
|
|
|
|
# frame section
|
|
frameHeight = int(posterWidth * 10 / 16)
|
|
if opts.frame:
|
|
frameImage = Image.open(opts.frame)
|
|
if frameImage.size[0] / frameImage.size[1] > posterWidth / frameHeight:
|
|
# poster frame is too wide
|
|
frameImage = frameImage.resize((int(frameImage.size[0] * frameHeight / frameImage.size[1]), frameHeight), Image.ANTIALIAS)
|
|
crop = int((frameImage.size[0] - posterWidth) / 2)
|
|
frameImage = frameImage.crop((crop, 0, crop + posterWidth, frameHeight))
|
|
else:
|
|
# poster frame is not wide enough
|
|
frameImage = frameImage.resize((posterWidth, int(frameImage.size[1] * posterWidth / frameImage.size[0])), Image.ANTIALIAS)
|
|
crop = int((frameImage.size[1] - frameHeight) / 2)
|
|
frameImage = frameImage.crop((0, crop, posterWidth, crop + frameHeight))
|
|
posterImage.paste(frameImage, (0, 0, posterWidth, frameHeight))
|
|
else:
|
|
draw = ImageDraw.Draw(posterImage)
|
|
draw.polygon([(0, 0), (posterWidth, 0), (posterWidth, frameHeight), (0, frameHeight)], fill=(0, 0, 0))
|
|
for y in range(frameHeight):
|
|
for x in range(posterWidth):
|
|
if int((x + y + 54) / 128) % 2:
|
|
posterImage.putpixel((x, y), (32, 32, 32))
|
|
|
|
# restricted
|
|
if opts.restricted:
|
|
for y in range(frameHeight):
|
|
for x in range(posterWidth):
|
|
if int((x + y + 54) / 128) % 2:
|
|
rgb = posterImage.getpixel((x, y))
|
|
rgb = (int(rgb[0] / 2) + 128, int(rgb[1] / 2), int(rgb[2] / 2))
|
|
posterImage.putpixel((x, y), rgb)
|
|
|
|
# director section
|
|
colorHeight = int(posterHeight / 2);
|
|
draw = ImageDraw.Draw(posterImage)
|
|
draw.polygon([(0, frameHeight), (posterWidth, frameHeight), (posterWidth, colorHeight), (0, colorHeight)], fill=(0, 0, 0))
|
|
director = wrapString(opts.director, 36, '\n', True)
|
|
while len(director.split('\n')) > 3:
|
|
director = opts.director.split(', ')
|
|
director.pop()
|
|
opts.director = ', '.join(director)
|
|
director = wrapString(opts.director, 36, '\n', True)
|
|
posterMargin = 16
|
|
imagewrite(posterImage, director, posterMargin, colorHeight - 8 - len(director.split('\n')) * 32, fontImage, 32)
|
|
|
|
# title section
|
|
backgroundColor = getRGB(opts.oxdb)
|
|
draw.polygon([(0, colorHeight), (posterWidth, colorHeight), (posterWidth, posterHeight), (0, posterHeight)], fill=backgroundColor)
|
|
title = wrapString(opts.title, 24, '\n', True)
|
|
lines = title.split('\n')
|
|
if lines > 8:
|
|
# following line commented out since the only known case
|
|
# (http://0xdb.org/0071458) looks better without '...'
|
|
# lines[7] = truncateString(lines[7] + '...', 24)
|
|
title = '\n'.join(lines[:8])
|
|
offset = -6
|
|
posterimage = imagewrite(posterImage, title, posterMargin, colorHeight + posterMargin + offset, fontImage, 48)
|
|
offset = 12
|
|
posterimage = imagewrite(posterImage, id, posterMargin, posterHeight - posterMargin - 96 + offset, fontImage, 96)
|
|
|
|
# 0xdb logo
|
|
x = posterWidth - oxdbImage.size[0] - posterMargin
|
|
y = posterHeight - oxdbImage.size[1] - posterMargin
|
|
for dy in range(oxdbImage.size[1]):
|
|
for dx in range(oxdbImage.size[0]):
|
|
rgb = posterImage.getpixel((x + dx, y + dy))
|
|
bw = oxdbImage.getpixel((dx, dy))[0]
|
|
rgb = tuple(map(lambda x : x + bw, rgb))
|
|
posterImage.putpixel((x + dx, y + dy), rgb)
|
|
|
|
posterImage.save(opts.poster)
|
|
|
|
def getRGB(oxid):
|
|
i = int(int(oxid[2:8], 16) * 762 / 16777216)
|
|
if i < 127:
|
|
return (127, i, 0)
|
|
elif i < 254:
|
|
return (254 - i, 127, 0)
|
|
elif i < 381:
|
|
return (0, 127, i - 254)
|
|
elif i < 508:
|
|
return (0, 508 - i, 127)
|
|
elif i < 635:
|
|
return (i - 508, 0, 127)
|
|
else:
|
|
return (127, 0, 762 - i)
|
|
|
|
def imagewrite(posterImage, string, left, top, fontImage, charHeight):
|
|
x = left
|
|
y = top
|
|
fontWidth = int(fontImage.size[0] / 16)
|
|
fontHeight = int(fontImage.size[1] / 16)
|
|
charWidth = int(fontWidth * charHeight / fontHeight)
|
|
for i in range(len(string)):
|
|
char = string[i:i+1]
|
|
if char == '\n':
|
|
x = left
|
|
y += charHeight
|
|
else:
|
|
ascii = ord(char)
|
|
fontLeft = (ascii % 16) * fontWidth
|
|
fontTop = int(ascii / 16) * fontHeight
|
|
letterImage = fontImage.crop((fontLeft, fontTop, fontLeft + fontWidth, fontTop + fontHeight))
|
|
letterImage = letterImage.resize((charWidth, charHeight), Image.ANTIALIAS)
|
|
for dy in range(charHeight):
|
|
for dx in range(charWidth):
|
|
rgb = posterImage.getpixel((x + dx, y + dy))
|
|
bw = int(letterImage.getpixel((dx, dy))[0] / 2)
|
|
rgb = tuple(map(lambda x : x + bw, rgb))
|
|
posterImage.putpixel((x + dx, y + dy), rgb)
|
|
x += charWidth
|
|
return posterImage
|
|
|