lyx_mirror/development/tools/generate_symbols_images.py
Georg Baum 45052f56ab Handle text-only wasy symbols correctly.
Some macros defined by wasysym.sty work only in text mode: They either
produce an error in math mode, or wrong output. These symbols are now marked
as text symbols, so that no \ensuremath is created for LaTeX export if they
appear inside \text{}, and the correct images are created.
2013-01-10 21:22:54 +01:00

205 lines
7.1 KiB
Python

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# file generate_symbols_images.py
# This file is part of LyX, the document processor.
# Licence details can be found in the file COPYING.
# author Georg Baum
# Full author contact details are available in file CREDITS
# This script generates a toolbar image for each missing math symbol
# It needs the template document generate_symbols_images.lyx, which must
# contain the placeholder formula '$a$' for generating the png image via
# preview.sty and dvipng.
# The created images are not always optimal, therefore the existing manually
# created images should never be replaced by automatically created ones.
import os, re, string, sys, subprocess, tempfile, shutil
import Image
def usage(prog_name):
return ("Usage: %s lyxexe outputpath\n" % prog_name)
def error(message):
sys.stderr.write(message + '\n')
sys.exit(1)
def getlist(lyxexe, lyxfile):
""" Call LyX and get a list of symbols from mathed debug output.
This way, we can re-use the symbols file parser of LyX, and do not
need to reimplement it in python. """
# The debug is only generated if lyxfile contains a formula
cmd = "%s %s -dbg mathed -x lyx-quit" % (lyxexe, lyxfile)
proc = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE)
(stdout, stderr) = proc.communicate()
regexp = re.compile(r'.*: read symbol \'(\S+)\s+inset:\s+(\S+)\s+draw:\s+(\S*)\s+extra:\s+(\S+)')
# These insets are more complex than simply symbols, so the images need to
# be created manually
skipinsets = ['big', 'font', 'lyxblacktext', 'matrix', 'mbox', 'oldfont', \
'ref', 'split', 'space', 'style']
mathsymbols = []
textsymbols = []
for line in stderr.split('\n'):
m = regexp.match(line)
if m:
inset = m.group(2)
if not inset in skipinsets:
if m.group(4) == 'textmode':
textsymbols.append(m.group(1))
else:
mathsymbols.append(m.group(1))
return (mathsymbols, textsymbols)
def getreplacements(filename):
replacements = {}
replacements['|'] = 'vert'
replacements['/'] = 'slash'
replacements['\\'] = 'backslash'
replacements['*'] = 'ast'
replacements['AA'] = 'textrm_AA'
replacements['O'] = 'textrm_O'
cppfile = open(filename, 'rt')
regexp = re.compile(r'.*"([^"]+)",\s*"([^"]+)"')
found = False
for line in cppfile.readlines():
if found:
m = regexp.match(line)
if m:
replacements[m.group(1)] = m.group(2)
else:
return replacements
elif line.find('PngMap sorted_png_map') == 0:
found = True
def gettoolbaritems(filename):
items = []
uifile = open(filename, 'rt')
regexp = re.compile(r'.*Item "([^"\[]+)(\[\[[^\]]+\]\])?"\s*"math-insert\s+([^"]+)"')
for line in uifile.readlines():
m = regexp.match(line)
if m:
if '\\' + m.group(1) == m.group(3):
items.append(m.group(1))
return items
def getmakefileentries(filename):
items = []
makefile = open(filename, 'rt')
regexp = re.compile(r'.*images/math/(.+)\.png')
for line in makefile.readlines():
m = regexp.match(line)
if m:
items.append(m.group(1))
return items
def createimage(name, path, template, lyxexe, tempdir, math, replacements, toolbaritems, makefileentries):
""" Create the image file for symbol name in path. """
if name in replacements.keys():
filename = replacements[name]
elif name.startswith('lyx'):
print 'Skipping ' + name
return
else:
skipchars = ['|', '/', '\\', '*', '!', '?', ':', ';', '^', '<', '>']
for i in skipchars:
if name.find(i) >= 0:
print 'Skipping ' + name
return
filename = name
pngname = os.path.join(path, filename + '.png')
if name in toolbaritems:
if filename in makefileentries:
suffix = ' (found in toolbar and makefile)'
else:
suffix = ' (found in only in toolbar)'
else:
if filename in makefileentries:
suffix = ' (found only in makefile)'
else:
suffix = ' (not found)'
if os.path.exists(pngname):
print 'Skipping ' + name + suffix
return
print 'Generating ' + name + suffix
lyxname = os.path.join(tempdir, filename)
lyxfile = open(lyxname + '.lyx', 'wt')
if math:
lyxfile.write(template.replace('$a$', '$\\' + name + '$'))
else:
lyxfile.write(template.replace('$a$', '$\\text{\\' + name + '}$'))
lyxfile.close()
cmd = "%s %s.lyx -e dvi" % (lyxexe, lyxname)
proc = subprocess.Popen(cmd, shell=True)
proc.wait()
if proc.returncode != 0:
print 'Error in DVI creation for ' + name
return
# The magnifaction factor is calculated such that we get an image of
# height 18 px for most symbols and document font size 11. Then we can
# add a small border to get the standard math image height of 20 px.
cmd = "dvipng %s.dvi -bg Transparent -D 115 -o %s" % (lyxname, pngname)
proc = subprocess.Popen(cmd, shell=True)
proc.wait()
if proc.returncode != 0:
print 'Error in PNG creation for ' + name
return
image = Image.open(pngname)
(width, height) = image.size
if width < 20 and height < 20:
if width == 19 and height == 19:
padded = Image.new('RGBA', (width+1, height+1), (0, 0, 0, 0))
padded.paste(image, (0, 0))
elif width == 19:
padded = Image.new('RGBA', (width+1, height+2), (0, 0, 0, 0))
padded.paste(image, (0, 1))
elif height == 19:
padded = Image.new('RGBA', (width+2, height+1), (0, 0, 0, 0))
padded.paste(image, (1, 0))
else:
padded = Image.new('RGBA', (width+2, height+2), (0, 0, 0, 0))
padded.paste(image, (1, 1))
padded.convert(image.mode)
padded.save(pngname, "PNG")
def main(argv):
if len(argv) == 3:
(base, ext) = os.path.splitext(argv[0])
(mathsymbols, textsymbols) = getlist(argv[1], base)
cppfile = os.path.join(os.path.dirname(base), '../../src/frontends/qt4/GuiApplication.cpp')
replacements = getreplacements(cppfile)
uifile = os.path.join(os.path.dirname(base), '../../lib/ui/stdtoolbars.inc')
toolbaritems = gettoolbaritems(uifile)
makefile = os.path.join(os.path.dirname(base), '../../lib/Makefile.am')
makefileentries = getmakefileentries(makefile)
lyxtemplate = base + '.lyx'
templatefile = open(base + '.lyx', 'rt')
template = templatefile.read()
templatefile.close()
tempdir = tempfile.mkdtemp()
for i in mathsymbols:
createimage(i, argv[2], template, argv[1], tempdir, True, replacements, toolbaritems, makefileentries)
for i in textsymbols:
createimage(i, argv[2], template, argv[1], tempdir, False, replacements, toolbaritems, makefileentries)
shutil.rmtree(tempdir)
else:
error(usage(argv[0]))
return 0
if __name__ == "__main__":
main(sys.argv)