summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorРуслан Ижбулатов <lrn1986@gmail.com>2015-05-08 03:56:24 +0000
committerJakub Steiner <jimmac@gmail.com>2015-05-13 19:07:38 +0200
commit778e229776e3edc26f5db9743ca1b2da7cc4448b (patch)
treec42845c078b7539c53652f54f2700eef6e655b69
parente60a5be1f100ef8d929124f90b555d8bf06c936b (diff)
downloadadwaita-icon-theme-778e229776e3edc26f5db9743ca1b2da7cc4448b.tar.gz
Major renderpngs modifications
* Depends on Python Pillow library now * Add the --remove-shadows option. Renders cursors without shadows. This depends on the shadows being in a separate layer in adwaita.svg * Add the --hotspots option. Renders hotspots into separate pngs, then finds its coordinates and writes out the xcursorgen input file accordingly. This depends on hotspots layer being present in the adwaita.svg. * Add the --scales option. Makes all cursor canvases one size higher than they normally are (24->32, 32->48 etc). Renders extra cursor variants that are 125% and 150% larger than the nominal size (hence the canvas size increase - otherwise scaled up versions won't fit at all). These scaled versions will look 25% and 50% smaller than normal, respectively. * Add the --min-canvas-size option. Makes all cursor canvases at least this big (padding smaller cursors when necessary). * Add the --fps option. Used to adjust the frame duration written into xcursorgen input files. * Add the --anicursorgen option. Changes the format of the files into something that anicursorgen understands better (changes frame duration from milliseconds to jiffies). * Add the --corner-align option. Aligns cursors to the top-left corner instead of centering them on the canvas. * Add the --invert option. Inverts the color (turning black-fill-white-outlines cursors into white-fill-black-outlines ones) * Inkscape is now being run in shell mode (one instance, fed with commands via stdin). * Add the --number-of-renderers option. Allows multiple Inkscape instances to be run in parallel for rendering speed increase on multicore systems. * Filter SVG files from memory to avoid leaking a file descriptor * Make slices and hotspots normally invisible https://bugzilla.gnome.org/show_bug.cgi?id=749053
-rwxr-xr-xsrc/cursors/renderpngs.py489
1 files changed, 471 insertions, 18 deletions
diff --git a/src/cursors/renderpngs.py b/src/cursors/renderpngs.py
index c0a124e3f..6c4ba8bc3 100755
--- a/src/cursors/renderpngs.py
+++ b/src/cursors/renderpngs.py
@@ -33,27 +33,145 @@ optParser = OptionParser()
optParser.add_option('-d','--debug',action='store_true',dest='debug',help='Enable extra debugging info.')
optParser.add_option('-t','--test',action='store_true',dest='testing',help='Test mode: leave temporary files for examination.')
optParser.add_option('-p','--sliceprefix',action='store',dest='sliceprefix',help='Specifies the prefix to use for individual slice filenames.')
+optParser.add_option('-r','--remove-shadows',action='store_true',dest='remove_shadows',help='Remove shadows the cursors have.')
+optParser.add_option('-o','--hotspots',action='store_true',dest='hotspots',help='Produce hotspot images and hotspot datafiles.')
+optParser.add_option('-s','--scales',action='store_true',dest='scales',help='Produce 125% (Large) and 150% (Extra Large) scaled versions of each image as well.')
+optParser.add_option('-m','--min-canvas-size',action='store',type='int',dest='min_canvas_size',default=-1, help='Cursor canvas must be at least this big (defaults to -1).')
+optParser.add_option('-f','--fps',action='store',type='int',dest='fps',default=60,help='Assume that all animated cursors have this FPS (defaults to 60).')
+optParser.add_option('-a','--anicursorgen',action='store_true',dest='anicur',default=False,help='Assume that anicursorgen will be used to assemble cursors (xcursorgen is assumed by default).')
+optParser.add_option('-c','--corner-align',action='store_true',dest='align_corner',default=False,help='Align cursors to the top-left corner (by default they are centered).')
+optParser.add_option('-i','--invert',action='store_true',dest='invert',default=False,help='Invert colors (disabled by default).')
+optParser.add_option('-n','--number-of-renderers',action='store',type='int',dest='number_of_renderers',default=1, help='Number of renderer instances run in parallel. Defaults to 1. Set to 0 for autodetection.')
-from xml.sax import saxutils, make_parser, SAXParseException, handler
+from xml.sax import saxutils, make_parser, SAXParseException, handler, xmlreader
from xml.sax.handler import feature_namespaces
-import os, sys, tempfile, shutil
+import os, sys, tempfile, shutil, subprocess
+import re
+from threading import Thread
+from PIL import Image
+import multiprocessing
+import io
svgFilename = None
+hotsvgFilename = None
+sizes = [24,32,48,64,96]
+scale_pairs = [(1.25, 's1'), (1.50, 's2')]
+mode_shadows = ['shadows']
+mode_hotspots = ['hotspots']
+mode_slices = ['slices']
+mode_invert = ['invert']
+def natural_sort(l):
+ convert = lambda text: int(text) if text.isdigit() else text.lower()
+ alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ]
+ return sorted(l, key = alphanum_key)
def dbg(msg):
if options.debug:
sys.stderr.write(msg)
def cleanup():
+ global inkscape_instances
+ for inkscape, inkscape_stderr, inkscape_stderr_thread in inkscape_instances:
+ inkscape.communicate ('quit\n')
+ del inkscape
+ del inkscape_stderr_thread
+ del inkscape_stderr
+ del inkscape_instances
if svgFilename != None and os.path.exists(svgFilename):
os.unlink(svgFilename)
+ if hotsvgFilename != None and os.path.exists(hotsvgFilename):
+ os.unlink(hotsvgFilename)
def fatalError(msg):
sys.stderr.write(msg)
cleanup()
sys.exit(20)
+def stderr_reader(inkscape, inkscape_stderr):
+ while True:
+ line = inkscape_stderr.readline()
+ if line and len (line.rstrip ('\n').rstrip ('\r')) > 0:
+ fatalError('ABORTING: Inkscape failed to render a slice: {}'.format (line))
+ elif line:
+ print "STDERR> {}".format (line)
+ else:
+ raise UnexpectedEndOfStream
+
+def find_hotspot (hotfile):
+ img = Image.open(hotfile)
+ pixels = img.load()
+ reddest = [-1, -1, -999999]
+ for y in range(img.size[1]):
+ for x in range(img.size[0]):
+ redness = pixels[x,y][0] - pixels[x,y][1] - pixels[x,y][2]
+ if redness > reddest[2]:
+ reddest = [x, y, redness]
+ return (reddest[0] + 1, reddest[1] + 1)
+
+def cropalign (size, filename):
+ img = Image.open (filename)
+ content_dimensions = img.getbbox ()
+ if content_dimensions is None:
+ content_dimensions = (0, 0, img.size[0], img.size[1])
+ hcropped = content_dimensions[2] - content_dimensions[0]
+ vcropped = content_dimensions[3] - content_dimensions[1]
+ if hcropped > size or vcropped > size:
+ if hcropped > size:
+ left = (hcropped - size) / 2
+ right = (hcropped - size) - left
+ else:
+ left = 0
+ right = 0
+ if vcropped > size:
+ top = (vcropped - size) / 2
+ bottom = (vcropped - size) - top
+ else:
+ top = 0
+ bottom = 0
+ content_dimensions = (content_dimensions[0] + left, content_dimensions[1] + top, content_dimensions[2] - right, content_dimensions[3] - bottom)
+ sys.stderr.write ("WARNING: {} is too big to be cleanly cropped to {} ({}x{} at best), cropping to {}x{}!\n".format (filename, size, hcropped, vcropped, content_dimensions[2] - content_dimensions[0], content_dimensions[3] - content_dimensions[1]))
+ sys.stderr.flush ()
+ if options.testing:
+ img.save (filename + ".orig.png", "png")
+ dbg("{} content is {} {} {} {}".format (filename, content_dimensions[0], content_dimensions[1], content_dimensions[2], content_dimensions[3]))
+ cropimg = img.crop ((content_dimensions[0], content_dimensions[1], content_dimensions[2], content_dimensions[3]))
+ pixels = cropimg.load ()
+ if options.testing:
+ cropimg.save (filename + ".crop.png", "png")
+ if options.align_corner:
+ expimg = cropimg.crop ((0, 0, size, size))
+ result = (content_dimensions[0], content_dimensions[1])
+ else:
+ hslack = size - cropimg.size[0]
+ vslack = size - cropimg.size[1]
+ left = hslack / 2
+ top = vslack / 2
+ expimg = cropimg.crop ((-left, -top, size - left, size - top))
+ result = (content_dimensions[0] - left, content_dimensions[1] - top)
+ pixels = expimg.load ()
+ if options.invert:
+ negative (expimg)
+ expimg.save (filename, "png")
+ del cropimg
+ del img
+ return result
+
+def cropalign_hotspot (new_base, size, filename):
+ if new_base is None:
+ return
+ img = Image.open (filename)
+ expimg = img.crop ((new_base[0], new_base[1], new_base[0] + size, new_base[1] + size))
+ pixels = expimg.load ()
+ expimg.save (filename, "png")
+ del img
+
+def negative (img):
+ pixels = img.load ()
+ for y in range (0, img.size[1]):
+ for x in range (0, img.size[0]):
+ r, g, b, a = pixels[x,y]
+ pixels[x,y] = (255 - r, 255 - g, 255 - b, a)
class SVGRect:
"""Manages a simple rectangular area, along with certain attributes such as a name"""
@@ -65,12 +183,173 @@ class SVGRect:
self.name = name
dbg("New SVGRect: (%s)" % name)
- def renderFromSVG(self, svgFName, sliceFName):
- for size in [24,32,48,64,96]:
- rc = os.system('inkscape --without-gui -w %s -h %s --export-id="%s" --export-png="pngs/%s/%s" "%s"' % (size, size, self.name, str(size)+"x"+str(size), sliceFName, svgFName))
- if rc > 0:
- fatalError('ABORTING: Inkscape failed to render the slice.')
+ def renderFromSVG(self, svgFName, slicename, skipped, roundrobin, hotsvgFName):
+
+ def do_res (size, output, svgFName, skipped, roundrobin):
+ global inkscape_instances
+ if os.path.exists (output):
+ skipped[output] = True
+ return
+ command = '-w {size} -h {size} --export-id="{export_id}" --export-png="{export_png}" {svg}\n'.format (size=size, export_id=self.name, export_png=output, svg=svgFName)
+ dbg("Command: {}".format (command))
+ inkscape_instances[roundrobin[0]][0].stdin.write (command)
+
+ pngsliceFName = slicename + '.png'
+ hotsliceFName = slicename + '.hotspot.png'
+ dbg('Saving slice as: "%s"' % pngsliceFName)
+ for i, size in enumerate (sizes):
+ subdir = 'pngs/{}x{}'.format (size, size)
+ if not os.path.exists (subdir):
+ os.makedirs (subdir)
+ relslice = '{}/{}'.format (subdir, pngsliceFName)
+ do_res (size, relslice, svgFName, skipped, roundrobin)
+ if options.hotspots:
+ hotrelslice = '{}/{}'.format (subdir, hotsliceFName)
+ do_res (size, hotrelslice, hotsvgFName, skipped, roundrobin)
+ for scale in scale_pairs:
+ subdir = 'pngs/{}x{}_{}'.format (size, size, scale[1])
+ relslice = '{}/{}'.format (subdir, pngsliceFName)
+ if not os.path.exists (subdir):
+ os.makedirs (subdir)
+ scaled_size = int (size * scale[0])
+ do_res (scaled_size, relslice, svgFName, skipped, roundrobin)
+ if options.hotspots:
+ hotrelslice = '{}/{}'.format (subdir, hotsliceFName)
+ do_res (scaled_size, hotrelslice, hotsvgFName, skipped, roundrobin)
+ # This is not inside do_res() because we want each instance to work all scales in case scales are enabled,
+ # otherwise instances that get mostly smallscale renders will finish up way before the others
+ roundrobin[0] += 1
+ if roundrobin[0] >= options.number_of_renderers:
+ roundrobin[0] = 0
+
+def get_next_size (index, current_size):
+ if index % 2 == 0:
+ # 24->32, 48->64, 96->128, 192->256
+ return (current_size * 4) / 3
+ else:
+ # 32->48, 64->96, 128->192, 256->384
+ return (current_size * 3) / 2
+
+def get_csize (index, current_size):
+ size = current_size
+ if len (scale_pairs) > 0:
+ size = get_next_size (index, size)
+ return max (options.min_canvas_size, size)
+
+def postprocess_slice (slicename, skipped):
+ pngsliceFName = slicename + '.png'
+ hotsliceFName = slicename + '.hotspot.png'
+
+ for i, size in enumerate (sizes):
+ subdir = 'pngs/{}x{}'.format (size, size)
+ relslice = '{}/{}'.format (subdir, pngsliceFName)
+ csize = get_csize (i, size)
+ if relslice not in skipped:
+ new_base = cropalign (csize, relslice)
+ if options.hotspots:
+ hotrelslice = '{}/{}'.format (subdir, hotsliceFName)
+ cropalign_hotspot (new_base, csize, hotrelslice)
+ for scale in scale_pairs:
+ subdir = 'pngs/{}x{}_{}'.format (size, size, scale[1])
+ relslice = '{}/{}'.format (subdir, pngsliceFName)
+ if relslice not in skipped:
+ new_base = cropalign (csize, relslice)
+ if options.hotspots:
+ hotrelslice = '{}/{}'.format (subdir, hotsliceFName)
+ cropalign_hotspot (new_base, csize, hotrelslice)
+
+def write_xcur(slicename):
+ pngsliceFName = slicename + '.png'
+ hotsliceFName = slicename + '.hotspot.png'
+
+ framenum = -1
+ if slicename[-5:].startswith ('_'):
+ try:
+ framenum = int (slicename[-4:])
+ slicename = slicename[:-5]
+ except:
+ pass
+
+ # This relies on the fact that frame 1 is the first frame of an animation in the rect list
+ # If that is not so, the *icongen input file will end up missing some of the lines
+ if framenum == -1 or framenum == 1:
+ mode = 'wb'
+ else:
+ mode = 'ab'
+ if framenum == -1:
+ fps_field = ''
+ else:
+ if options.anicur:
+ # For anicursorgen use jiffies
+ fps_field = ' {}'.format (int (60.0 / options.fps))
+ else:
+ # For xcursorgen use milliseconds
+ fps_field = ' {}'.format (int (1000.0 / options.fps))
+ xcur = {}
+ xcur['s0'] = open ('pngs/{}.in'.format (slicename), mode)
+ if len (scale_pairs) > 0:
+ xcur['s1'] = open ('pngs/{}.s1.in'.format (slicename), mode)
+ xcur['s2'] = open ('pngs/{}.s2.in'.format (slicename), mode)
+ for i, size in enumerate (sizes):
+ subdir = 'pngs/{}x{}'.format (size, size)
+ relslice = '{}/{}'.format (subdir, pngsliceFName)
+ hotrelslice = '{}/{}'.format (subdir, hotsliceFName)
+ hot = find_hotspot (hotrelslice)
+ csize = get_csize (i, size)
+ xcur['s0'].write ("{csize} {hotx} {hoty} {filename}{fps_field}\n".format (csize=csize, hotx=hot[0], hoty=hot[1], filename='{}x{}/{}'.format (size, size, pngsliceFName), fps_field=fps_field))
+ for scale in scale_pairs:
+ subdir = 'pngs/{}x{}_{}'.format (size, size, scale[1])
+ relslice = '{}/{}'.format (subdir, pngsliceFName)
+ scaled_size = int (size * scale[0])
+ hotrelslice = '{}/{}'.format (subdir, hotsliceFName)
+ hot = find_hotspot (hotrelslice)
+ xcur[scale[1]].write ("{csize} {hotx} {hoty} {filename}{fps_field}\n".format (csize=csize, hotx=hot[0], hoty=hot[1], filename='{}x{}_{}/{}'.format (size, size, scale[1], pngsliceFName), fps_field=fps_field))
+ xcur['s0'].close ()
+ if len (scale_pairs) > 0:
+ xcur['s1'].close ()
+ xcur['s2'].close ()
+
+def sort_file(filename):
+ with open (filename, 'rb') as src:
+ contents = src.readlines ()
+ with open (filename, 'wb') as dst:
+ for line in natural_sort (contents):
+ dst.write (line)
+
+def sort_xcur(slicename, passed):
+ pngsliceFName = slicename + '.png'
+
+ framenum = -1
+ if slicename[-5:].startswith ('_'):
+ try:
+ framenum = int (slicename[-4:])
+ slicename = slicename[:-5]
+ except:
+ pass
+ if slicename in passed:
+ return
+ passed[slicename] = True
+
+ sort_file ('pngs/{}.in'.format (slicename))
+ if len (scale_pairs) > 0:
+ sort_file ('pngs/{}.s1.in'.format (slicename))
+ sort_file ('pngs/{}.s2.in'.format (slicename))
+
+def delete_hotspot(slicename):
+ hotsliceFName = slicename + '.hotspot.png'
+
+ for i, size in enumerate (sizes):
+ subdir = 'pngs/{}x{}'.format (size, size)
+ hotrelslice = '{}/{}'.format (subdir, hotsliceFName)
+ if os.path.exists (hotrelslice):
+ os.unlink (hotrelslice)
+ for scale in scale_pairs:
+ subdir = 'pngs/{}x{}_{}'.format (size, size, scale[1])
+ hotrelslice = '{}/{}'.format (subdir, hotsliceFName)
+ if os.path.exists (hotrelslice):
+ os.unlink (hotrelslice)
+
class SVGHandler(handler.ContentHandler):
"""Base class for SVG parsers"""
def __init__(self):
@@ -162,8 +441,7 @@ class SVGLayerHandler(SVGHandler):
def startElement(self, name, attrs):
"""Generic hook for examining and/or parsing all SVG tags"""
- if options.debug:
- dbg('Beginning element "%s"' % name)
+ dbg('Beginning element "%s"' % name)
if name == 'svg':
self.startElement_svg(name, attrs)
elif name == 'g':
@@ -200,6 +478,137 @@ class SVGLayerHandler(SVGHandler):
write(' </body>\n')
write('</html>\n')
+class SVGFilter (saxutils.XMLFilterBase):
+ def __init__ (self, upstream, downstream, mode, **kwargs):
+ saxutils.XMLFilterBase.__init__(self, upstream)
+ self._downstream = downstream
+ self.mode = mode
+
+ def startDocument (self):
+ self.in_throwaway_layer_stack = [False]
+
+ def startElement (self, localname, attrs):
+ def modify_style (style, old_style, new_style=None):
+ styles = style.split (';')
+ new_styles = []
+ if old_style is not None:
+ match_to = old_style + ':'
+ for s in styles:
+ if len (s) > 0 and (old_style is None or not s.startswith (match_to)):
+ new_styles.append (s)
+ if new_style is not None:
+ new_styles.append (new_style)
+ return ';'.join (new_styles)
+
+ dict = {}
+ is_throwaway_layer = False
+ is_slices = False
+ is_hotspots = False
+ is_shadows = False
+ is_layer = False
+ if localname == 'g':
+ for key, value in attrs.items ():
+ if key == 'inkscape:label':
+ if value == 'slices':
+ is_slices = True
+ elif value == 'hotspots':
+ is_hotspots = True
+ elif value == 'shadows':
+ is_shadows = True
+ elif key == 'inkscape:groupmode':
+ if value == 'layer':
+ is_layer = True
+ if mode_shadows in self.mode and is_shadows:
+ # Only remove the shadows
+ is_throwaway_layer = True
+ elif mode_hotspots in self.mode and not (is_hotspots or is_slices):
+ # Remove all layers but hotspots and slices
+ if localname == 'g':
+ is_throwaway_layer = True
+ idict = {}
+ idict.update (attrs)
+ if 'style' not in attrs.keys ():
+ idict['style'] = ''
+ for key, value in idict.items():
+ alocalname = key
+ if alocalname == 'style':
+ had_style = True
+ if alocalname == 'style' and is_slices:
+ # Make slices invisible. Do not check the mode, because there is
+ # no circumstances where we *want* to render slices
+ value = modify_style (value, 'display', 'display:none')
+ if alocalname == 'style' and is_hotspots:
+ if mode_hotspots in self.mode:
+ # Make hotspots visible in hotspots mode
+ value = modify_style (value, 'display', 'display:inline')
+ else:
+ # Make hotspots invisible otherwise
+ value = modify_style (value, 'display', 'display:none')
+ if alocalname == 'style' and mode_invert in self.mode and is_layer and is_shadows:
+ value = modify_style (value, None, 'filter:url(#InvertFilter)')
+ dict[key] = value
+
+ if self.in_throwaway_layer_stack[0] or is_throwaway_layer:
+ self.in_throwaway_layer_stack.insert(0, True)
+ else:
+ self.in_throwaway_layer_stack.insert(0, False)
+ attrs = xmlreader.AttributesImpl(dict)
+ self._downstream.startElement(localname, attrs)
+
+ def characters(self, content):
+ if self.in_throwaway_layer_stack[0]:
+ return
+ self._downstream.characters(content)
+
+ def endElement(self, localname):
+ if self.in_throwaway_layer_stack.pop(0):
+ return
+ self._downstream.endElement(localname)
+
+def filter_svg (input, output, mode):
+ """filter_svg(input:file, output:file, mode)
+
+ Parses the SVG input from the input stream.
+ For mode == 'hotspots' it filters out all
+ layers except for hotspots and slices. Also makes hotspots
+ visible.
+ For mode == 'shadows' it filters out the shadows layer.
+ """
+
+ mode_objs = []
+ if 'hotspots' in mode:
+ mode_objs.append (mode_hotspots)
+ if 'shadows' in mode:
+ mode_objs.append (mode_shadows)
+ if 'slices' in mode:
+ mode_objs.append (mode_slices)
+ if 'invert' in mode:
+ mode_objs.append (mode_invert)
+ if len (mode_objs) == 0:
+ raise ValueError()
+
+ output_gen = saxutils.XMLGenerator(output)
+ parser = make_parser()
+ filter = SVGFilter(parser, output_gen, mode_objs)
+ filter.setFeature(handler.feature_namespaces, False)
+ filter.setErrorHandler(handler.ErrorHandler())
+ # This little I/O dance is here to ensure that SAX parser does not stash away
+ # an open file descriptor for the input file, which would prevent us from unlinking it later
+ with open (input, 'rb') as inp:
+ contents = inp.read ()
+ contents_io = io.BytesIO (contents)
+ source_object = saxutils.prepare_input_source (contents_io)
+ filter.parse(source_object)
+ del filter
+ del parser
+ del output_gen
+
+def autodetect_threadcount ():
+ try:
+ count = multiprocessing.cpu_count()
+ except NotImplementedError:
+ count = 1
+ return count
if __name__ == '__main__':
# parse command line into arguments and options
@@ -210,8 +619,19 @@ if __name__ == '__main__':
originalFilename = args[0]
svgFilename = originalFilename + '.svg'
- shutil.copyfile(originalFilename, svgFilename)
-
+ hotsvgFilename = originalFilename + '.hotspots.svg'
+ modes = ['slices']
+ if options.remove_shadows:
+ modes.append ('shadows')
+ if options.invert:
+ modes.append ('invert')
+
+ with open (svgFilename, 'wb') as output:
+ filter_svg(originalFilename, output, modes)
+
+ if options.hotspots:
+ with open (hotsvgFilename, 'wb') as output:
+ filter_svg(originalFilename, output, ['hotspots'])
# setup program variables from command line (in other words, handle non-option args)
basename = os.path.splitext(svgFilename)[0]
@@ -219,7 +639,23 @@ if __name__ == '__main__':
sliceprefix = options.sliceprefix
else:
sliceprefix = ''
-
+
+ if not options.scales:
+ del scale_pairs[:]
+
+ if options.number_of_renderers <= 0:
+ options.number_of_renderers = autodetect_threadcount ()
+
+ inkscape_instances = []
+
+ for i in range (0, options.number_of_renderers):
+ inkscape = subprocess.Popen (['inkscape', '--without-gui', '--shell'], stdin=subprocess.PIPE, stderr=subprocess.PIPE)
+ if inkscape is None:
+ fatalError("Failed to start Inkscape shell process")
+ inkscape_stderr = inkscape.stderr
+ inkscape_stderr_thread = Thread (target = stderr_reader, args=(inkscape, inkscape_stderr))
+ inkscape_instances.append ([inkscape, inkscape_stderr, inkscape_stderr_thread])
+
# initialise results before actually attempting to parse the SVG file
svgBounds = SVGRect(0,0,0,0)
rectList = []
@@ -234,7 +670,7 @@ if __name__ == '__main__':
try:
xmlParser.parse(svgFilename)
except SAXParseException, e:
- fatalError("Error parsing SVG file '%s': line %d,col %d: %s. If you're seeing this within inkscape, it probably indicates a bug that should be reported." % (svgfile, e.getLineNumber(), e.getColumnNumber(), e.getMessage()))
+ fatalError("Error parsing SVG file '%s': line %d,col %d: %s. If you're seeing this within inkscape, it probably indicates a bug that should be reported." % (svgFilename, e.getLineNumber(), e.getColumnNumber(), e.getMessage()))
# verify that the svg file actually contained some rectangles.
if len(svgLayerHandler.svg_rects) == 0:
@@ -245,14 +681,31 @@ if __name__ == '__main__':
dbg("Parsing successful.")
#svgLayerHandler.generateXHTMLPage()
-
+ del xmlParser
+
+ skipped = {}
+ roundrobin = [0]
+
# loop through each slice rectangle, and render a PNG image for it
+ svgLayerHandler.svg_rects
for rect in svgLayerHandler.svg_rects:
- sliceFName = sliceprefix + rect.name + '.png'
-
- dbg('Saving slice as: "%s"' % sliceFName)
- rect.renderFromSVG(svgFilename, sliceFName)
+ slicename = sliceprefix + rect.name
+ rect.renderFromSVG(svgFilename, slicename, skipped, roundrobin, hotsvgFilename)
cleanup()
+ for rect in svgLayerHandler.svg_rects:
+ slicename = sliceprefix + rect.name
+ postprocess_slice(slicename, skipped)
+ if options.hotspots:
+ write_xcur(slicename)
+
+ if options.hotspots:
+ passed = {}
+ for rect in svgLayerHandler.svg_rects:
+ slicename = sliceprefix + rect.name
+ sort_xcur(slicename, passed)
+ #if not option.testing:
+ # delete_hotspot(slicename)
+
dbg('Slicing complete.')