Showing huge images with Google Maps

The Google Maps API can be used for other things than maps.

The tiles were created with this python script:

#!/usr/bin/env python

import sys, math
import cairo

if __name__ == '__main__':
    master = cairo.ImageSurface.create_from_png(sys.argv[1])
    dest_width = int(sys.argv[2]) if len(sys.argv) > 2 else 256
    dest_height = int(sys.argv[3]) if len(sys.argv) > 3 else 256
    min_zoom = int(sys.argv[4]) if len(sys.argv) > 4 else 0
    max_zoom = int(sys.argv[5]) if len(sys.argv) > 5 else 0

    vert_tiles = (master.get_width() + dest_width-1) / dest_width
    horiz_tiles = (master.get_height() + dest_height-1) / dest_height

    most_tiles = max(vert_tiles, horiz_tiles)
    base_zoom = int(math.ceil(math.log(most_tiles) / math.log(2)))

    if max_zoom == 0:
        print('Image dimensions: %ux%u' % (master.get_width(), master.get_height()))
        print('Tile dimensions: %ux%u' % (dest_width, dest_height))
        print('Tiles in base zoom: %ux%u' % (vert_tiles, horiz_tiles))
        print('Base zoom level: %u' % base_zoom)
        print('Run with min_zoom and max_zoom parameters to produce tiles.')
        sys.exit(0)

    for z in range(min_zoom, max_zoom+1):
        scale = 2**(z - base_zoom)

        src_width = dest_width * 2**(base_zoom - z)
        src_height = dest_height * 2**(base_zoom - z)

        vert_tiles = int(math.floor((master.get_width() + src_width-1) / src_width))
        horiz_tiles = int(math.floor((master.get_height() + src_height-1) / src_height))
        print('Zoom level %u (tiles: %ux%u)' % (z, vert_tiles, horiz_tiles))

        for y in range(horiz_tiles):
            for x in range(vert_tiles):
                tile = cairo.ImageSurface(cairo.FORMAT_ARGB32, dest_width, dest_height)
                ctx = cairo.Context(tile)

                pattern = cairo.SurfacePattern(master)
                pattern.set_filter(cairo.FILTER_BEST)
                pattern.set_matrix(cairo.Matrix(xx=1.0/scale,
                                                yy=1.0/scale,
                                                x0=x*dest_width/scale,
                                                y0=y*dest_height/scale))

                ctx.set_source(pattern)
                ctx.rectangle(0, 0, dest_width, dest_height)
                ctx.fill()

                print('+ tile-%u-%ux%u.png' % (z, x, y))
                tile.write_to_png('tile-%u-%ux%u.png' % (z, x, y))

It will convert a PNG image to PNG tiles. The script depends on pycairo to do the cutting and scaling of the images. This example converts master.png to tiles of size 256×256 with 1 being the minimum zoom level and 4 being the maximum zoom:

$ pngmaptiler.py master.png 256 256 1 4