# -*- 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 ox 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