File: export_raster.py

package info (click to toggle)
sketch 0.6.13-1
  • links: PTS
  • area: main
  • in suites: woody
  • size: 5,284 kB
  • ctags: 8,453
  • sloc: python: 34,711; ansic: 16,543; makefile: 83; sh: 26
file content (256 lines) | stat: -rw-r--r-- 9,010 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# Sketch - A Python-based interactive drawing program
# export_raster script
# Copyright (C) 1999, 2000 by Bernhard Herzog
# 6.12.2000 improved by Bernhard Reiter with Help form Bernhard
#    (used create_star.py by Tamito KAJIYAMA as an example to 
#   build the dialog)
#
# 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 the following to the Script menu:
#
# Export Raster         Renders the drawing on a white background
#
# You can add more with fixed parameters, if you need them frequently
# see the comments below, one example is enabled.
#
# 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.
#

import os, tempfile

import PIL.Image, PIL.ImageChops

import Sketch.Scripting
from Sketch import PostScriptDevice

# for parameter dialogs
from Sketch.UI.sketchdlg import SKModal 
from Tkinter import *

class CreateRasterParametersDlg(SKModal):
    "Create Tk Dialog to ask for raster parameters."
    title = "Choose Raster Parameters"

    def build_dlg(self):
        self.var_ppi = IntVar(self.top)
        self.var_ppi.set(72)
        label = Label(self.top, text="ppi")
        label.grid(column=0, row=0, sticky=E)
        entry = Entry(self.top, width=15, textvariable=self.var_ppi)
        entry.grid(column=1, row=0)

        self.var_alpha = BooleanVar(self.top)
        self.var_alpha.set(1)
        label = Label(self.top, text="w. Transparency")
        label.grid(column=0, row=1, sticky=E)
        entry = Checkbutton(self.top, variable=self.var_alpha)
        entry.grid(column=1, row=1)

        self.var_use_bbox = BooleanVar(self.top)
        self.var_use_bbox.set(0)
        label = Label(self.top, text="use BB information")
        label.grid(column=0, row=2, sticky=E)
        entry = Checkbutton(self.top, variable=self.var_use_bbox)
        entry.grid(column=1, row=2)


        button = Button(self.top, text="OK", command=self.ok)
        button.grid(column=0, row=3, sticky=W)
        button = Button(self.top, text="Cancel", command=self.cancel)
        button.grid(column=1, row=3, sticky=E)

    def ok(self):
        self.close_dlg((self.var_ppi.get(), 
                    self.var_alpha.get(),self.var_use_bbox.get()))

def export_raster_more_interactive(context, alpha = 0, use_bbox = 0,
                                   render_ppi=72):
    "Get Parameter per dialog and run export_raster_interactive()"
    parms = CreateRasterParametersDlg(context.application.root).RunDialog()
    if parms is None:
        return
    else:
        render_ppi=parms[0]
        alpha=parms[1]
        use_bbox=parms[2]

        return export_raster_interactive(context,alpha,use_bbox,render_ppi)


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 = PIL.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):
    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

    ps = make_ps(context.document)

    width = round(width * resolution / 72.0)
    height = round(height * resolution / 72.0)
    rgb = render_ps(ps, resolution, width, height, 
                    orig_x = x, orig_y = y, antialias = 2)
    alpha = render_ps(ps, resolution, width, height,
                        orig_x = x, orig_y = y, antialias = 2, 
                        prolog = alpha_prolog, gsdevice = 'pgmraw')

    alpha = PIL.ImageChops.invert(alpha)

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

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

    doc = context.document

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

    # determine a default filename
    basename = os.path.splitext(doc.meta.filename)[0]
    if alpha:
        default_ext = '.png'
        # shift png up in filetypes so it is displayed accordingly
        filetypes=tuple(filelist[-1:]+filelist[1:-1])
    else:
        default_ext = '.ppm'
        filetypes=tuple(filelist)
        
    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, render_ppi, use_bbox)
            else:
                export_raster(context, filename, render_ppi, 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_more_interactive,
                             script_type = Sketch.Scripting.AdvancedScript)
#Sketch.Scripting.AddFunction('export_raster', 'Export Raster Alpha (Default)',
#                             export_raster_interactive, args = (1,0),
#                             script_type = Sketch.Scripting.AdvancedScript)
Sketch.Scripting.AddFunction('export_raster', 'Export Raster Alpha (100ppi)',
                             export_raster_interactive, args = (1,0,100),
                             script_type = Sketch.Scripting.AdvancedScript)
#Sketch.Scripting.AddFunction('export_raster', 'Export Raster Alpha (120ppi)',
#                             export_raster_interactive, args = (1,0,120),
#                             script_type = Sketch.Scripting.AdvancedScript)