Welcome, guest | Sign In | My Account | Store | Cart

This code takes a TeX or LaTeX math expression and converts it into a Tk image suitable for placing in any suitable widget. This technique is ideal for complex documentation where you don't want to maintain a separate set of image files, but is not really fast enough for interactive use (unless your machine is much faster than mine.)

Tcl, 78 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
namespace eval MathToImg {
   image create photo MathToImgHelperImage

   set tmpdir "/tmp"; # configure for platforms!

   # What LaTeX size should we format at?  This looks good on my workstation
   set latexSize huge; # No backslash!

   # Commands
   set latexCommand "latex '\\nonstopmode\\input{%s.tex}'"
   set dvipsCommand "dvips -E -q -o %s.eps %s.dvi"
   set gsCommand "gs -q -dNOPAUSE -dSAFER -sDEVICE=ppmraw           -sOutputFile=%s.ppm %s.eps"

   # Regular expression for finding bounding box
   set BBre {^%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) *$}

   proc external cmd {
      exec sh -c $cmd 2>@stderr </dev/null
   }

   proc mathToImg {latex {packages {}}} {
      # Keep ourselves current-dir neutral
      set cwd [pwd]
      cd $::MathToImg::tmpdir

      # Put a wrapper round the supplied LaTeX source
      set latexSource "\\documentclass{article}\n"
      if {[llength $packages]} {
         # Add needed packages, converting Tcl list to comma-ed list
         append latexSource "\\usepackage{" [join $packages ,] "}"
      }
      append latexSource "\\begin{document} \\$::MathToImg::latexSize              \\pagestyle{empty} \\begin{displaymath}\n% USER CODE START\n"
      append latexSource $latex "\n% USER CODE END\n"
      append latexSource "\\end{displaymath} \\end{document}\n"

      set basename [file tail [file rootname $::argv0]]_mathToImg_[pid]

      set f [open $basename.tex w]
      puts -nonewline $f $latexSource
      close $f

      # LaTeX -> DVI
      external [format $::MathToImg::latexCommand $basename]
      # DVI -> EPS
      external [format $::MathToImg::dvipsCommand $basename $basename]

      # Grok out the size, which we need later...
      set f [open $basename.eps r]
      while {![eof $f]} {
         gets $f line
         if {[regexp $::MathToImg::BBre $line ? x1 y1 x2 y2]} {
            break
         }
      }
      close $f

      # EPS -> PPM
      external [format $::MathToImg::gsCommand $basename $basename]

      # Make the image - we can't go direct as we need the size of
      # the image to handle the cropping correctly.
      set img [image create photo               -height [expr {$y2-$y1}]               -width  [expr {$x2-$x1}]]
      # PS has (0,0) in bottom left, Tk in top left
      MathToImgHelperImage read $basename.ppm
      set h [image height MathToImgHelperImage]
      $img copy MathToImgHelperImage               -from $x1 [expr {$h-$y1}] $x2 [expr {$h-$y2}]
      MathToImgHelperImage blank; # Ditch the data

      # Try to clean up after ourselves!
      catch {eval file delete [glob $basename.*]}

      cd $cwd
      return $img
   }

   namespace export mathToImg
}
namespace import MathToImg::*

Sample use: pack [label .l -image [mathToImg {\sum_{i=1}^9 x_i}]]

Requires: a UNIX with LaTeX, DVIPS and GhostScript installed. Can use rather a lot of intermediate memory, so solutions involving the PS command 'setpagedevice' would be welcome upgrades...

Created by Donal Fellows on Tue, 11 Sep 2001 (MIT)
Tcl recipes (162)
Donal Fellows's recipes (6)

Required Modules

  • (none specified)

Other Information and Tasks