#! /usr/bin/python

# Copyright (C) 2000 Intevation GmbH <intevation@intevation.de>
# Author: Bernhard Herzog <bh@intevation.de>
#
# This program is free software under the LGPL (>=v2)
# Read the file COPYING coming with MapIt! for details.

import sys, os
import tempfile
import dscparser
import PIL.Image

#
#       Directory helper functions
#

# Create the directory dir if it doesn't exist yet and all its parent
# directories too
def create_directory(dir):
    if os.path.isdir(dir):
	return
    parent, base = os.path.split(dir)
    if parent:
        create_directory(parent)
    try:
        os.mkdir(dir, 0777)
    except os.error, exc:
        print "can't create directory %s:%s" % (dir, exc)
        raise

# Make the tile directories for the individual scales under the basedir
# for num_factors different scales. The numbes used for the names are
# 'backwards', i.e. num_factors for the lowest resolution and 1 for the
# highest, because that's what mapIt expects
def make_directories(basedir, num_factors):
    dirs = []
    for i in range(num_factors, 0, -1):
        dir = os.path.join(basedir, `i`)
        create_directory(dir)
        dirs.append(dir)
    return dirs


#
#       EPS rendering
#
# Render part of an eps file with ghostscript

gs_command = ('gs -sDEVICE=%(psdevice)s -r72 -dNOPAUSE -dSAFER -q'
              ' %(alphaparams)s'
	      ' -sOutputFile=%(output)s -g%(width)dx%(height)d'
	      ' -c %(scalex)f %(scaley)f scale %(offx)f %(offy)f translate'
	      ' /oldshowpage /showpage load def /showpage \'{}\' def '
	      ' -f%(filename)s -c oldshowpage quit')


def render_tile(filename, width, height, startx, starty, scalex, scaley,
                outputfile, alpha = 1, indexed = 0):
    """Render a region of an EPS-file filename.
    Parameters:

        filename -- name of the EPS-file
        width, height -- size of the output region in pixels
        startx, starty -- lower left corner of the region in point
        scalex, scaley -- scale factors
        outputfile -- name of the output file. The file format is
                      derived from the name by PIL
        alpha -- number of bits for anti-aliasing:
                1 = no antialiasing, 2 = medium, 4 maximum

    """
    temp = tempfile.mktemp()
    try:
        psdevice = "ppmraw"
        offx = -startx
        offy = -starty
        if alpha > 1:
            alphaparams = '-dGraphicsAlphaBits=%d -dTextAlphaBits=%d' \
                          % (alpha, alpha)
        else:
            alphaparams = ''
        output = temp
        print gs_command % locals()
        os.system(gs_command % locals())
        image = PIL.Image.open(temp)
        if indexed:
            image = image.convert(mode = 'P', palette = PIL.Image.ADAPTIVE,
                                  dither = PIL.Image.NONE)
        print 'writing %s' % outputfile
        image.save(outputfile)
    finally:
        try:
	    os.unlink(temp)
	except:
	    pass


class EPSFile:

    """Class to represent one EPS file.

    Public Instance Variables:

        width, height -- size of the bounding box (in pt)
        bbox -- bounding box as a tuple

    Public Methods:

        render tiles -- Render the tiles and create the info file for
                        one specific scale
    """

    def __init__(self, filename):
        self.filename = filename
        self.info = dscparser.parse_eps_file(filename)
        llx, lly, urx, ury = self.info.BoundingBox
        self.width = urx - llx
        self.height = ury - lly
        self.bbox = self.info.BoundingBox

    def render_tiles(self, size, directory, num_tiles_x, num_tiles_y,
                     reference_size):
        scale = min(float(size[0]) / self.width,
                    float(size[1]) / self.height)
        total_width = int(round(scale * self.width))
        total_height = int(round(scale * self.height))
        tile_width = int(round(float(total_width) / num_tiles_x))
        tile_height = int(round(float(total_height) / num_tiles_y))
        # now compute the scale that are actually used from the tile sizes
        scalex = tile_width * num_tiles_x / float(self.width)
        scaley = tile_height * num_tiles_y / float(self.height)

        infofile = open(os.path.join(directory, 'info'), 'w')
        infofile.write("%d\n%d\n" % (tile_width, tile_height))

        llx, lly, urx, ury = self.info.BoundingBox
        extension = '.png'; alpha = 4
        for y in range(num_tiles_y):
            for x in range(num_tiles_x):
                outputfile = os.path.join(directory,
                                          "%dx%d%s" % (x + 1, y + 1,
                                                       extension))
                startx = tile_width * x / scalex + llx
                starty = tile_height * y / scaley + lly
                render_tile(self.filename, tile_width, tile_height,
                            startx, starty, scalex, scaley, outputfile,
                            alpha=alpha, indexed = 1)
                ref_llx = x * reference_size[0] / num_tiles_x
                ref_lly = y * reference_size[1] / num_tiles_y
                ref_urx = (x + 1) * reference_size[0] / num_tiles_x
                ref_ury = (y + 1) * reference_size[1] / num_tiles_y
                infofile.write("# [%d,%d]\n" % (x + 1, y + 1))
                infofile.write("%d\n%d\n%d\n%d\n" % (ref_llx, ref_lly,
                                                     ref_urx, ref_ury))
        infofile.close()
#
#
#

def make_tile_hierarchy(epsfilename, basedir, factors, overview_size):
    eps = EPSFile(epsfilename)
    overview_scale = min(overview_size[0] / eps.width,
                         overview_size[1] / eps.height)
    overview_width = int(round(overview_scale * eps.width))
    overview_height = int(round(overview_scale * eps.height))

    directories = make_directories(basedir, len(factors))

    reference_size = (factors[-1] * overview_size[0],
                      factors[-1] * overview_size[1])
    for i in range(len(factors)):
        size = (factors[i] * overview_width,
                factors[i] * overview_height)
        eps.render_tiles(size, directories[i], factors[i],
                         factors[i], reference_size)
    

def main():
    if len(sys.argv) < 2:
        print 'Usage: epscut epsfile [basedir]'
        sys.exit(1)
    epsfile = sys.argv[1]
    if len(sys.argv) < 3:
        basedir = os.path.splitext(os.path.basename(epsfile))[0]
    else:
        basedir = sys.argv[2]
    #factors = (1, 2)
    factors = (1, 3, 6)
    overview_size = (400, 400)
    make_tile_hierarchy(epsfile, basedir, factors, overview_size)


if __name__ == '__main__':
    main()
