From 6708c011d79f9cd6f3f979f5a693719966bfcc5b Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Wed, 15 Oct 2014 16:14:05 +0200 Subject: [PATCH] Add a script to automatically generate SVG math images from a LyX template. This is an adaptation of Georg's generate_symbols_images script, but it uses dvisvgm instead of dvipng. --- development/tools/generate_symbols_svg.lyx | 128 ++++++++++++++ development/tools/generate_symbols_svg.py | 188 +++++++++++++++++++++ 2 files changed, 316 insertions(+) create mode 100644 development/tools/generate_symbols_svg.lyx create mode 100755 development/tools/generate_symbols_svg.py diff --git a/development/tools/generate_symbols_svg.lyx b/development/tools/generate_symbols_svg.lyx new file mode 100644 index 0000000000..7b25adfea3 --- /dev/null +++ b/development/tools/generate_symbols_svg.lyx @@ -0,0 +1,128 @@ +#LyX 2.1 created this file. For more info see http://www.lyx.org/ +\lyxformat 474 +\begin_document +\begin_header +\textclass article +\begin_preamble +\usepackage{graphics} +\end_preamble +\use_default_options true +\maintain_unincluded_children false +\language english +\language_package default +\inputencoding auto +\fontencoding global +\font_roman default +\font_sans default +\font_typewriter default +\font_math libertine-ntxm +\font_default_family default +\use_non_tex_fonts false +\font_sc false +\font_osf false +\font_sf_scale 100 +\font_tt_scale 100 +\graphics default +\default_output_format default +\output_sync 0 +\bibtex_command default +\index_command default +\paperfontsize 11 +\spacing single +\use_hyperref false +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\index Index +\shortcut idx +\color #008000 +\end_index +\paperwidth 280pt +\paperheight 280pt +\leftmargin 1cm +\topmargin 1cm +\rightmargin 1cm +\bottommargin 1cm +\secnumdepth 3 +\tocdepth 3 +\paragraph_separation indent +\paragraph_indentation default +\quotes_language english +\papercolumns 1 +\papersides 1 +\paperpagestyle empty +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\begin_inset VSpace vfill* +\end_inset + + +\end_layout + +\begin_layout Standard +\align center +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +scalebox{30}{ +\end_layout + +\end_inset + + +\begin_inset Formula $a$ +\end_inset + + +\begin_inset ERT +status open + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset VSpace vfill* +\end_inset + + +\end_layout + +\end_body +\end_document diff --git a/development/tools/generate_symbols_svg.py b/development/tools/generate_symbols_svg.py new file mode 100755 index 0000000000..8011e99131 --- /dev/null +++ b/development/tools/generate_symbols_svg.py @@ -0,0 +1,188 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +# file generate_symbols_svg.py +# This file is part of LyX, the document processor. +# Licence details can be found in the file COPYING. + +# author Georg Baum +# author Juergen Spitzmueller (adaptation for SVG) + +# 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_svg.lyx, which must +# contain the placeholder formula '$a$' for generating the SVG image via +# dvisvgm. +# 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 + svgname = os.path.join(path, filename + '.svgz') + 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(svgname): + 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 = "dvisvgm -z --no-fonts --exact --output=%%f %s.dvi %s" % (lyxname, svgname) + proc = subprocess.Popen(cmd, shell=True) + proc.wait() + if proc.returncode != 0: + print 'Error in SVG creation for ' + name + return + + +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)