1#!/usr/bin/env python3 2 3# Copied from gnome-icon-theme and adjusted lightly. 4# 5# GNOME icon theme is distributed under the terms of either 6# GNU LGPL v.3 or Creative Commons BY-SA 3.0 license. 7 8import os 9import sys 10import xml.sax 11import subprocess 12 13INKSCAPE = '/usr/bin/inkscape' 14OPTIPNG = '/usr/bin/optipng' 15SRC = 'ui/icons/src' 16OUT = 'ui/icons' 17 18inkscape_process = None 19 20def optimize_png(png_file): 21 if os.path.exists(OPTIPNG): 22 process = subprocess.Popen([OPTIPNG, '-quiet', '-o7', png_file]) 23 process.wait() 24 25def wait_for_prompt(process, command=None): 26 if command is not None: 27 process.stdin.write((command+'\n').encode('utf-8')) 28 29 # This is kinda ugly ... 30 # Wait for just a '>', or '\n>' if some other char appearead first 31 output = process.stdout.read(1) 32 if output == b'>': 33 return 34 35 output += process.stdout.read(1) 36 while output != b'\n>': 37 output += process.stdout.read(1) 38 output = output[1:] 39 40def start_inkscape(): 41 process = subprocess.Popen([INKSCAPE, '--shell'], bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE) 42 wait_for_prompt(process) 43 return process 44 45def inkscape_render_rect(icon_file, rect, output_file): 46 global inkscape_process 47 if inkscape_process is None: 48 inkscape_process = start_inkscape() 49 wait_for_prompt(inkscape_process, '%s -i %s -e %s' % (icon_file, rect, output_file)) 50 optimize_png(output_file) 51 52class ContentHandler(xml.sax.ContentHandler): 53 ROOT = 0 54 SVG = 1 55 LAYER = 2 56 OTHER = 3 57 TEXT = 4 58 def __init__(self, path, force=False, filter=None): 59 self.stack = [self.ROOT] 60 self.inside = [self.ROOT] 61 self.path = path 62 self.rects = [] 63 self.state = self.ROOT 64 self.chars = "" 65 self.force = force 66 self.filter = filter 67 68 def endDocument(self): 69 pass 70 71 def startElement(self, name, attrs): 72 if self.inside[-1] == self.ROOT: 73 if name == "svg": 74 self.stack.append(self.SVG) 75 self.inside.append(self.SVG) 76 return 77 elif self.inside[-1] == self.SVG: 78 if (name == "g" and ('inkscape:groupmode' in attrs) and ('inkscape:label' in attrs) 79 and attrs['inkscape:groupmode'] == 'layer' and attrs['inkscape:label'].startswith('baseplate')): 80 self.stack.append(self.LAYER) 81 self.inside.append(self.LAYER) 82 self.context = None 83 self.icon_name = None 84 self.rects = [] 85 return 86 elif self.inside[-1] == self.LAYER: 87 if name == "text" and ('inkscape:label' in attrs) and attrs['inkscape:label'] == 'context': 88 self.stack.append(self.TEXT) 89 self.inside.append(self.TEXT) 90 self.text='context' 91 self.chars = "" 92 return 93 elif name == "text" and ('inkscape:label' in attrs) and attrs['inkscape:label'] == 'icon-name': 94 self.stack.append(self.TEXT) 95 self.inside.append(self.TEXT) 96 self.text='icon-name' 97 self.chars = "" 98 return 99 elif name == "rect": 100 self.rects.append(attrs) 101 102 self.stack.append(self.OTHER) 103 104 105 def endElement(self, name): 106 stacked = self.stack.pop() 107 if self.inside[-1] == stacked: 108 self.inside.pop() 109 110 if stacked == self.TEXT and self.text is not None: 111 assert self.text in ['context', 'icon-name'] 112 if self.text == 'context': 113 self.context = self.chars 114 elif self.text == 'icon-name': 115 self.icon_name = self.chars 116 self.text = None 117 elif stacked == self.LAYER: 118 assert self.icon_name 119 assert self.context 120 121 if self.filter is not None and not self.icon_name in self.filter: 122 return 123 124 print (self.context, self.icon_name) 125 for rect in self.rects: 126 width = rect['width'] 127 height = rect['height'] 128 id = rect['id'] 129 130 # dir = os.path.join(OUT, "%sx%s" % (width, height), self.context) 131 dir = os.path.join(OUT, "%sx%s" % (width, height)) 132 outfile = os.path.join(dir, self.icon_name+'.png') 133 if not os.path.exists(dir): 134 os.makedirs(dir) 135 # Do a time based check! 136 if self.force or not os.path.exists(outfile): 137 inkscape_render_rect(self.path, id, outfile) 138 sys.stdout.write('.') 139 else: 140 stat_in = os.stat(self.path) 141 stat_out = os.stat(outfile) 142 if stat_in.st_mtime > stat_out.st_mtime: 143 inkscape_render_rect(self.path, id, outfile) 144 sys.stdout.write('.') 145 else: 146 sys.stdout.write('-') 147 sys.stdout.flush() 148 sys.stdout.write('\n') 149 sys.stdout.flush() 150 151 def characters(self, chars): 152 self.chars += chars.strip() 153 154if len(sys.argv) == 1: 155 if not os.path.exists(OUT): 156 os.mkdir(OUT) 157 print ('Rendering from SVGs in', SRC) 158 for file in os.listdir(SRC): 159 if file[-4:] == '.svg': 160 file = os.path.join(SRC, file) 161 handler = ContentHandler(file) 162 xml.sax.parse(open(file), handler) 163else: 164 file = os.path.join(SRC, sys.argv[1] + '.svg') 165 if len(sys.argv) > 2: 166 icons = sys.argv[2:] 167 else: 168 icons = None 169 if os.path.exists(os.path.join(file)): 170 handler = ContentHandler(file, True, filter=icons) 171 xml.sax.parse(open(file), handler) 172 else: 173 print ("Error: No such file", file) 174 sys.exit(1) 175