2 # -*- coding: utf-8 -*-
4 # file generate_symbols_svg.py
5 # This file is part of LyX, the document processor.
6 # Licence details can be found in the file COPYING.
9 # author Juergen Spitzmueller (adaptation for SVG)
11 # Full author contact details are available in file CREDITS
13 # This script generates a toolbar image for each missing math symbol
14 # It needs the template document generate_symbols_svg.lyx, which must
15 # contain the placeholder formula '$a$' for generating the SVG image via
17 # The created images are not always optimal, therefore the existing manually
18 # created images should never be replaced by automatically created ones.
21 import os, re, string, sys, subprocess, tempfile, shutil
25 return ("Usage: %s lyxexe outputpath\n" % prog_name)
29 sys.stderr.write(message + '\n')
33 def getlist(lyxexe, lyxfile):
34 """ Call LyX and get a list of symbols from mathed debug output.
35 This way, we can re-use the symbols file parser of LyX, and do not
36 need to reimplement it in python. """
38 # The debug is only generated if lyxfile contains a formula
39 cmd = "%s %s -dbg mathed -x lyx-quit" % (lyxexe, lyxfile)
40 proc = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE)
41 (stdout, stderr) = proc.communicate()
42 regexp = re.compile(r'.*: read symbol \'(\S+)\s+inset:\s+(\S+)\s+draw:\s+(\S*)\s+extra:\s+(\S+)')
43 # These insets are more complex than simply symbols, so the images need to
45 skipinsets = ['big', 'font', 'lyxblacktext', 'matrix', 'mbox', 'oldfont', \
46 'ref', 'split', 'space', 'style']
49 for line in stderr.split('\n'):
50 m = regexp.match(line)
53 if not inset in skipinsets:
54 if m.group(4) == 'textmode':
55 textsymbols.append(m.group(1))
57 mathsymbols.append(m.group(1))
58 return (mathsymbols, textsymbols)
61 def getreplacements(filename):
63 replacements['|'] = 'vert'
64 replacements['/'] = 'slash'
65 replacements['\\'] = 'backslash'
66 replacements['*'] = 'ast'
67 replacements['AA'] = 'textrm_AA'
68 replacements['O'] = 'textrm_O'
69 cppfile = open(filename, 'rt')
70 regexp = re.compile(r'.*"([^"]+)",\s*"([^"]+)"')
72 for line in cppfile.readlines():
74 m = regexp.match(line)
76 replacements[m.group(1)] = m.group(2)
79 elif line.find('PngMap sorted_png_map') == 0:
83 def gettoolbaritems(filename):
85 uifile = open(filename, 'rt')
86 regexp = re.compile(r'.*Item "([^"\[]+)(\[\[[^\]]+\]\])?"\s*"math-insert\s+([^"]+)"')
87 for line in uifile.readlines():
88 m = regexp.match(line)
90 if '\\' + m.group(1) == m.group(3):
91 items.append(m.group(1))
95 def getmakefileentries(filename):
97 makefile = open(filename, 'rt')
98 regexp = re.compile(r'.*images/math/(.+)\.png')
99 for line in makefile.readlines():
100 m = regexp.match(line)
102 items.append(m.group(1))
106 def createimage(name, path, template, lyxexe, tempdir, math, replacements, toolbaritems, makefileentries):
107 """ Create the image file for symbol name in path. """
109 if name in replacements.keys():
110 filename = replacements[name]
111 elif name.startswith('lyx'):
112 print 'Skipping ' + name
115 skipchars = ['|', '/', '\\', '*', '!', '?', ':', ';', '^', '<', '>']
117 if name.find(i) >= 0:
118 print 'Skipping ' + name
121 svgname = os.path.join(path, filename + '.svgz')
122 if name in toolbaritems:
123 if filename in makefileentries:
124 suffix = ' (found in toolbar and makefile)'
126 suffix = ' (found in only in toolbar)'
128 if filename in makefileentries:
129 suffix = ' (found only in makefile)'
131 suffix = ' (not found)'
132 if os.path.exists(svgname):
133 print 'Skipping ' + name + suffix
135 print 'Generating ' + name + suffix
136 lyxname = os.path.join(tempdir, filename)
137 lyxfile = open(lyxname + '.lyx', 'wt')
139 lyxfile.write(template.replace('$a$', '$\\' + name + '$'))
141 lyxfile.write(template.replace('$a$', '$\\text{\\' + name + '}$'))
143 cmd = "%s %s.lyx -e dvi" % (lyxexe, lyxname)
144 proc = subprocess.Popen(cmd, shell=True)
146 if proc.returncode != 0:
147 print 'Error in DVI creation for ' + name
149 # The magnifaction factor is calculated such that we get an image of
150 # height 18 px for most symbols and document font size 11. Then we can
151 # add a small border to get the standard math image height of 20 px.
152 cmd = "dvisvgm -z --no-fonts --exact --output=%%f %s.dvi %s" % (lyxname, svgname)
153 proc = subprocess.Popen(cmd, shell=True)
155 if proc.returncode != 0:
156 print 'Error in SVG creation for ' + name
163 (base, ext) = os.path.splitext(argv[0])
164 (mathsymbols, textsymbols) = getlist(argv[1], base)
165 cppfile = os.path.join(os.path.dirname(base), '../../src/frontends/qt4/GuiApplication.cpp')
166 replacements = getreplacements(cppfile)
167 uifile = os.path.join(os.path.dirname(base), '../../lib/ui/stdtoolbars.inc')
168 toolbaritems = gettoolbaritems(uifile)
169 makefile = os.path.join(os.path.dirname(base), '../../lib/Makefile.am')
170 makefileentries = getmakefileentries(makefile)
171 lyxtemplate = base + '.lyx'
172 templatefile = open(base + '.lyx', 'rt')
173 template = templatefile.read()
175 tempdir = tempfile.mkdtemp()
176 for i in mathsymbols:
177 createimage(i, argv[2], template, argv[1], tempdir, True, replacements, toolbaritems, makefileentries)
178 for i in textsymbols:
179 createimage(i, argv[2], template, argv[1], tempdir, False, replacements, toolbaritems, makefileentries)
180 shutil.rmtree(tempdir)
182 error(usage(argv[0]))
187 if __name__ == "__main__":