]> git.lyx.org Git - lyx.git/blob - development/tools/generate_symbols_images.py
Add script for automatic toolbar image creation.
[lyx.git] / development / tools / generate_symbols_images.py
1 #! /usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 # file generate_symbols_images.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
10 # Full author contact details are available in file CREDITS
11
12 # This script generates a toolbar image for each missing math symbol
13 # It needs the template document generate_symbols_images.lyx, which must
14 # contain the placeholder formula '$a$' for generating the png image via
15 # preview.sty and dvipng.
16 # The created images are not always optimal, therefore the existing manually
17 # created images should never be replaced by automatically created ones.
18
19
20 import os, re, string, sys, subprocess, tempfile, shutil
21 import Image
22
23 def usage(prog_name):
24     return ("Usage: %s lyxexe outputpath\n" % prog_name)
25
26
27 def error(message):
28     sys.stderr.write(message + '\n')
29     sys.exit(1)
30
31
32 def getlist(lyxexe, lyxfile):
33     """ Call LyX and get a list of symbols from mathed debug output.
34         This way, we can re-use the symbols file parser of LyX, and do not
35         need to reimplement it in python. """
36
37     # The debug is only generated if lyxfile contains a formula
38     cmd = "%s %s -dbg mathed -x lyx-quit" % (lyxexe, lyxfile)
39     proc = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE)
40     (stdout, stderr) = proc.communicate()
41     regexp = re.compile(r'.*: read symbol \'(\S+)\s+inset:\s+(\S+)')
42     # These insets are more complex than simply symbols, so the images need to
43     # be created manually
44     skipinsets = ['big', 'font', 'matrix', 'mbox', 'oldfont', 'ref', 'space']
45     symbols = []
46     for line in stderr.split('\n'):
47         m = regexp.match(line)
48         if m:
49             inset = m.group(2)
50             if not inset in skipinsets:
51                 symbols.append(m.group(1))
52     return symbols
53
54
55 def createimage(name, path, template, lyxexe, tempdir):
56     """ Create the image file for symbol name in path. """
57
58     if name == '|':
59         filename = 'vert'
60     elif name == '/':
61         filename = 'slash'
62     elif name == '\\':
63         filename = 'backslash'
64     elif name == '*':
65         filename = 'ast'
66     elif name.startswith('lyx'):
67         print 'Skipping ' + name
68         return
69     else:
70         skipchars = ['|', '/', '\\', '*', '!', '?', ':', ';', '^', '<', '>']
71         for i in skipchars:
72             if name.find(i) >= 0:
73                 print 'Skipping ' + name
74                 return
75         filename = name
76     pngname = os.path.join(path, filename + '.png')
77     if os.path.exists(pngname):
78         print 'Skipping ' + name
79         return
80     print 'Generating ' + name
81     lyxname = os.path.join(tempdir, filename)
82     lyxfile = open(lyxname + '.lyx', 'wt')
83     lyxfile.write(template.replace('$a$', '$\\' + name + '$'))
84     lyxfile.close()
85     cmd = "%s %s.lyx -e dvi" % (lyxexe, lyxname)
86     proc = subprocess.Popen(cmd, shell=True)
87     proc.wait()
88     if proc.returncode != 0:
89         print 'Error in DVI creation for ' + name
90         return
91     # The magnifaction factor is calculated such that we get an image of
92     # height 18 px for most symbols and document font size 11. Then we can
93     # add a small border to get the standard math image height of 20 px.
94     cmd = "dvipng %s.dvi -bg Transparent -D 115 -o %s" % (lyxname, pngname)
95     proc = subprocess.Popen(cmd, shell=True)
96     proc.wait()
97     if proc.returncode != 0:
98         print 'Error in PNG creation for ' + name
99         return
100     image = Image.open(pngname)
101     (width, height) = image.size
102     if width < 20 and height < 20:
103         if width == 19 and height == 19:
104             padded = Image.new('RGBA', (width+1, height+1), (0, 0, 0, 0))
105             padded.paste(image, (0, 0))
106         elif width == 19:
107             padded = Image.new('RGBA', (width+1, height+2), (0, 0, 0, 0))
108             padded.paste(image, (0, 1))
109         elif height == 19:
110             padded = Image.new('RGBA', (width+2, height+1), (0, 0, 0, 0))
111             padded.paste(image, (1, 0))
112         else:
113             padded = Image.new('RGBA', (width+2, height+2), (0, 0, 0, 0))
114             padded.paste(image, (1, 1))
115         padded.convert(image.mode)
116         padded.save(pngname, "PNG")
117
118
119 def main(argv):
120
121     if len(argv) == 3:
122         (base, ext) = os.path.splitext(argv[0])
123         symbols = getlist(argv[1], base)
124         lyxtemplate = base + '.lyx'
125         templatefile = open(base + '.lyx', 'rt')
126         template = templatefile.read()
127         templatefile.close()
128         tempdir = tempfile.mkdtemp()
129         for i in symbols:
130             createimage(i, argv[2], template, argv[1], tempdir)
131         shutil.rmtree(tempdir)
132     else:
133         error(usage(argv[0]))
134
135     return 0
136
137
138 if __name__ == "__main__":
139     main(sys.argv)