]> git.lyx.org Git - features.git/commitdiff
Add a script to automatically generate SVG math images from a LyX template.
authorJuergen Spitzmueller <spitz@lyx.org>
Wed, 15 Oct 2014 14:14:05 +0000 (16:14 +0200)
committerJuergen Spitzmueller <spitz@lyx.org>
Wed, 15 Oct 2014 14:14:05 +0000 (16:14 +0200)
This is an adaptation of Georg's generate_symbols_images script, but it uses dvisvgm instead of dvipng.

development/tools/generate_symbols_svg.lyx [new file with mode: 0644]
development/tools/generate_symbols_svg.py [new file with mode: 0755]

diff --git a/development/tools/generate_symbols_svg.lyx b/development/tools/generate_symbols_svg.lyx
new file mode 100644 (file)
index 0000000..7b25adf
--- /dev/null
@@ -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 (executable)
index 0000000..8011e99
--- /dev/null
@@ -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)