# Sketch - A Python-based interactive drawing program
# Copyright (C) 1999 by Bernhard Herzog
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

# Export Sketch drawings as raster images using ghostscript to render
# them
#
# This script adds two commands to the Script menu:
#
# Export Raster         Renders the drawing on a white background
#
# Export Raster Alpha   Renders with anti-aliasing and alpha channel, so
#                       that those parts of the page that are not
#                       covered are transparent.
#
# Both commands prompt for a filename. The output file format is
# determined by the filename extension and should be something your PIL
# installation can handle. For the alpha version this should be PNG or
# some other format that can handle an alpha channel.
#
# Both scripts render the drawing at 72ppi and set the image size to the
# dimensions of the page in pt. These settings are not appropriate for
# all purposes so you might want to change them or hack the script to
# ask for them.


import os, tempfile

import Image, ImageChops

import Sketch.Scripting
from Sketch import PostScriptDevice


def make_ps(document):
    file = tempfile.mktemp('.ps')
    device = PostScriptDevice(file, as_eps = 0, document = document)
    document.Draw(device)
    device.Close()
    return file
    

def render_ps(filename, resolution, width, height, orig_x = 0, orig_y = 0,
              prolog = '', antialias = '', gsdevice = 'ppmraw'):
    if prolog:
        prolog = '-c ' + '"' + prolog + '"'

    if antialias:
        antialias = "-dGraphicsAlphaBits=%d" % antialias

    orig_x = -orig_x
    orig_y = -orig_y

    temp = tempfile.mktemp()

    try:
        gs_cmd = ('gs -dNOPAUSE -g%(width)dx%(height)d -r%(resolution)d '
                  '-sOutputFile=%(temp)s %(antialias)s '
                  '-sDEVICE=%(gsdevice)s -q %(prolog)s '
                  '-c %(orig_x)f %(orig_y)f translate '
                  '-f%(filename)s -c quit')
        gs_cmd = gs_cmd % locals()

        os.system(gs_cmd)
        image = Image.open(temp)
        image.load()
        return image
    finally:
       try:
           os.unlink(temp)
       except:
           pass


def export_raster(context, filename, resolution, use_bbox):
    # parameters:
    #
    # filename: filename of the raster image file
    # gsdevice: ghostscript device name for the raster format, e.g. ppmraw
    # resolution: pixel per inch
    
    # instead of the page size one could also use the bounding box
    # (returned by the BoundingRect method).
    if use_bbox:
        left, bottom, right, top = context.document.BoundingRect()
        width = right - left
        height = top - bottom
        x = left; y = bottom
    else:
        width, height = context.document.PageSize()
        x = y = 0
    width = round(width * resolution / 72.0)
    height = round(height * resolution / 72.0)

    temp = make_ps(context.document)
    try:
        image = render_ps(temp, resolution, width, height,
                          orig_x = x, orig_y = y)
    finally:
        os.unlink(temp)
    image.save(filename)


alpha_prolog = "/setrgbcolor {pop pop pop 0 0 0 setrgbcolor} bind def \
/setgray { pop 0 setgray} bind def \
/setcmykcolor { pop pop pop pop 0 0 0 1.0 setcmykcolor} bind def "

def export_alpha(context, filename, resolution, use_bbox = 0):
    ps = make_ps(context.document)

    width, height = context.document.PageSize()
    width = round(width * resolution / 72.0)
    height = round(height * resolution / 72.0)
    rgb = render_ps(ps, resolution, width, height, antialias = 2)
    alpha = render_ps(ps, resolution, width, height, antialias = 2,
                      prolog = alpha_prolog, gsdevice = 'pgmraw')

    alpha = ImageChops.invert(alpha)

    rgb = rgb.convert('RGBA')
    rgb.putalpha(alpha)
    rgb.save(filename)
    
    

filetypes = (('Portable Pixmap', '.ppm'),
             ('Portable Graymap', '.pgm'),
             ('Jpeg',   '.jpg'),
             ('Portable Network Graphics', '.png'))
        
def export_raster_interactive(context, alpha = 0, use_bbox = 0):
    # popup a filedialog and export the document

    doc = context.document

    # construct the tk filetypes list
    extensions = {}
    for text, ext in filetypes:
        extensions[ext] = 1

    # determine a default filename
    basename = os.path.splitext(doc.meta.filename)[0]
    if alpha:
        default_ext = '.png'
    else:
        default_ext = '.ppm'
        
    filename = context.application.GetSaveFilename(
        title = 'Export Raster',
        filetypes = filetypes,
        initialdir = doc.meta.directory,
        initialfile = basename + default_ext)
    if filename:
        ext = os.path.splitext(filename)[1]
        if extensions.has_key(ext):
            if alpha:
                export_alpha(context, filename, 72, use_bbox)
            else:
                export_raster(context, filename, 72, use_bbox)
        else:
            message = 'unknown extension %s' % ext
            context.application.MessageBox(title = 'Export Raster',
                                           message = message)

        


Sketch.Scripting.AddFunction('export_raster', 'Export Raster',
                             export_raster_interactive,
                             script_type = Sketch.Scripting.AdvancedScript)
Sketch.Scripting.AddFunction('export_raster', 'Export Raster Alpha',
                             export_raster_interactive, args = (1,),
                             script_type = Sketch.Scripting.AdvancedScript)
