]> git.lyx.org Git - lyx.git/blob - development/tools/generate_symbols_svg.py
Set \origin correctly when upgrading docs
[lyx.git] / development / tools / generate_symbols_svg.py
1 #! /usr/bin/env python
2 # -*- coding: utf-8 -*-
3
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.
7
8 # author Georg Baum
9 # author Juergen Spitzmueller (adaptation for SVG)
10
11 # Full author contact details are available in file CREDITS
12
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
16 # dvisvgm.
17 # The created images are not always optimal, therefore the existing manually
18 # created images should never be replaced by automatically created ones.
19
20
21 import os, re, string, sys, subprocess, tempfile, shutil
22 import Image
23
24 def usage(prog_name):
25     return ("Usage: %s lyxexe outputpath\n" % prog_name)
26
27
28 def error(message):
29     sys.stderr.write(message + '\n')
30     sys.exit(1)
31
32
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. """
37
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
44     # be created manually
45     skipinsets = ['big', 'font', 'lyxblacktext', 'matrix', 'mbox', 'oldfont', \
46                   'ref', 'split', 'space', 'style']
47     mathsymbols = []
48     textsymbols = []
49     for line in stderr.split('\n'):
50         m = regexp.match(line)
51         if m:
52             inset = m.group(2)
53             if not inset in skipinsets:
54                 if m.group(4) == 'textmode':
55                     textsymbols.append(m.group(1))
56                 else:
57                     mathsymbols.append(m.group(1))
58     return (mathsymbols, textsymbols)
59
60
61 def getreplacements(filename):
62     replacements = {}
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*"([^"]+)"')
71     found = False
72     for line in cppfile.readlines():
73         if found:
74             m = regexp.match(line)
75             if m:
76                 replacements[m.group(1)] = m.group(2)
77             else:
78                 return replacements
79         elif line.find('PngMap sorted_png_map') == 0:
80             found = True
81
82
83 def gettoolbaritems(filename):
84     items = []
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)
89         if m:
90             if '\\' + m.group(1) == m.group(3):
91                 items.append(m.group(1))
92     return items
93
94
95 def getmakefileentries(filename):
96     items = []
97     makefile = open(filename, 'rt')
98     regexp = re.compile(r'.*images/math/(.+)\.png')
99     for line in makefile.readlines():
100         m = regexp.match(line)
101         if m:
102             items.append(m.group(1))
103     return items
104
105
106 def createimage(name, path, template, lyxexe, tempdir, math, replacements, toolbaritems, makefileentries):
107     """ Create the image file for symbol name in path. """
108
109     if name in replacements.keys():
110         filename = replacements[name]
111     elif name.startswith('lyx'):
112         print 'Skipping ' + name
113         return
114     else:
115         skipchars = ['|', '/', '\\', '*', '!', '?', ':', ';', '^', '<', '>']
116         for i in skipchars:
117             if name.find(i) >= 0:
118                 print 'Skipping ' + name
119                 return
120         filename = 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)'
125         else:
126             suffix = ' (found in only in toolbar)'
127     else:
128         if filename in makefileentries:
129             suffix = ' (found only in makefile)'
130         else:
131             suffix = ' (not found)'
132     if os.path.exists(svgname):
133         print 'Skipping ' + name + suffix
134         return
135     print 'Generating ' + name + suffix
136     lyxname = os.path.join(tempdir, filename)
137     lyxfile = open(lyxname + '.lyx', 'wt')
138     if math:
139         lyxfile.write(template.replace('$a$', '$\\' + name + '$'))
140     else:
141         lyxfile.write(template.replace('$a$', '$\\text{\\' + name + '}$'))
142     lyxfile.close()
143     cmd = "%s %s.lyx -e dvi" % (lyxexe, lyxname)
144     proc = subprocess.Popen(cmd, shell=True)
145     proc.wait()
146     if proc.returncode != 0:
147         print 'Error in DVI creation for ' + name
148         return
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)
154     proc.wait()
155     if proc.returncode != 0:
156         print 'Error in SVG creation for ' + name
157         return
158
159
160 def main(argv):
161
162     if len(argv) == 3:
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()
174         templatefile.close()
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)
181     else:
182         error(usage(argv[0]))
183
184     return 0
185
186
187 if __name__ == "__main__":
188     main(sys.argv)