#! /usr/bin/python

"""
Usage: pastetiles dir outputfile

Read all image files in the directory dir and paste them into one giant
image and write it as outputfile. The output file type is determined
from the output filename.

The names of the image files must follow the scheme used by the
mapit-tiles, that is, <x>x<y>.<ext> where <x> and <y> are the indices of
the tile. The indices are expected to follow the same scheme as the ones
in the examples where the y index increases from bottom to top.

NOTE: The result image is held completely in memory, so the script may
require *huge* amounts of memory.
"""

import os, sys, re
import PIL.Image


# regex that matches a mpit tile filename. 
rx_image_filename = re.compile(r"(?P<x>[0-9]+)x(?P<y>[0-9]+)\.")

# Find all files in dir that match the regex and return a list of tuples
# of the form (x, y, filename). x and y are the indices of the tile and
# filename is the absolute filename (well, actually 
def find_image_files(dir):
    filenames = os.listdir(dir)
    image_files = []
    xs = []
    ys = []
    for filename in filenames:
        match = rx_image_filename.match(filename)
        if match:
            x = int(match.group("x"))
            y = int(match.group("y"))
            image_files.append((x, y, os.path.join(dir, filename)))
            xs.append(x)
            ys.append(y)
    return xs, ys, image_files


# Read all image files in the directory dir paste them into the result
# image and return the result image.
def paste_tiles(dir):
    xs, ys, imagefiles = find_image_files(dir)
    if not imagefiles:
        sys.stderr.write("No image files in %s\n" % dir)
        return None

    minx = min(xs); maxx = max(xs)
    miny = min(ys); maxy = max(ys)
    
    tile = PIL.Image.open(imagefiles[0][-1])
    tile_width, tile_height = tile.size
    total_width = (maxx - minx + 1) * tile_width
    total_height = (maxy - miny + 1) * tile_height
    result = PIL.Image.new("RGB", (total_width, total_height), 0xFFFFFFFF)
    for x, y, file in imagefiles:
        #print 'processing', file
        tile = PIL.Image.open(file)
        x = (x - minx) * tile_width
        y = (maxy - y) * tile_height
        result.paste(tile, (x, y))
    return result

# main function. Parse the command line parameters, run paste_tiles and
# save the result image.
def main():
    if len(sys.argv) != 3:
        print __doc__
        sys.exit(1)
    dir = sys.argv[1]
    output = sys.argv[2]
    image = paste_tiles(dir)
    if image:
        #print 'saving', output
        image.save(output)


if __name__ == '__main__':
    main()
