# Copyright (C) 2003, 2004 Alex Schroeder # Copyright (C) 2004 Haixing Hu # Copyright (C) 2004, 2005 Todd Neal # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the # Free Software Foundation, Inc. # 59 Temple Place, Suite 330 # Boston, MA 02111-1307 USA # # External programs needed # LaTeX - http://www.latex-project.org # TeX - http://www.tug.org/teTeX/ # # And one of : # dvipng - http://sourceforge.net/projects/dvipng/ # convert - http://www.imagemagick.org/ # # CSS Styles: # span.eqCount # img.LaTeX # img.InlineMath # img.DisplayMath use vars qw($LatexDir $LatexLinkDir $LatexExtendPath $LatexSingleDollars); # One of the following options must be set correctly to the full path of # either dvipng or convert. If both paths are set correctly, dvipng is used # instead of convert my $dvipngPath = "/usr/bin/dvipng"; my $convertPath = "/usr/bin/convert"; # Set $dispErrors to display LaTeX errors inline on the page. my $dispErrors = 1; # Set $useMD5 to 1 if you want to use MD5 hashes for filenames, set it to 0 to use # a url-encoded hash. If $useMD5 is set and the Digest::MD5 module is not available, # latex.pl falls back to urlencode my $useMD5 = 0; # PATH must be extended in order to make latex available along with # any binaries that it may need to work $LatexExtendPath = ':/usr/share/texmf/bin:/usr/bin:/usr/local/bin'; # Allow single dollars signs to escape LaTeX math commands $LatexSingleDollars = 0; # Set $allowPlainTeX to 1 to allow normal LaTeX commands inside of $[ ]$ # to be executed outside of the math environment. This should only be done # if your wiki is not publically editable because of the possible security risk $allowPlainLaTeX = 0; # $LatexDir must be accessible from the outside as $LatexLinkDir. The # first directory is used to *save* the pictures, the second directory # is used to produce the *link* to the pictures. # # Example: You store the images in /org/org.emacswiki/htdocs/test/latex. # This directory is reachable from the outside as http://www.emacswiki.org/test/latex/. # /org/org.emacswiki/htdocs/test is your $DataDir. $LatexDir = "$DataDir/latex"; $LatexLinkDir= "/wiki/latex"; # Text used when referencing equations with EQ(equationLabel) my $eqAbbrev = "Eq. "; # You also need a template stored as $DataDir/template.latex. The # template must contain the string where the LaTeX code is # supposed to go. It will be created on the first run. my $LatexDefaultTemplateName = "$LatexDir/template.latex"; $ModulesDescription .= '

$Id: latex.pl,v 1.14 2005/03/15 14:50:04 tolchz Exp $

'; # Internal Equation counting and referencing variables my $eqCounter = 0; my %eqHash; my $LatexDefaultTemplate = << 'EOT'; \documentclass[12pt]{article} \pagestyle{empty} \begin{document} \end{document} EOT push(@MyRules, \&LatexRule); sub LatexRule { if (m/\G\\\[(\(.*?\))?((.*\n)*?.*?)\\\]/gc) { my $label = $1; my $latex = $2; $label =~ s#\(?\)?##g;# Remove the ()'s from the label and convert case $label =~ tr/A-Z/a-z/; $eqCounter++; $eqHash{$label} = $eqCounter; return &MakeLaTeX("\\begin{displaymath} $latex \\end{displaymath}", "display math",$label); } elsif (m/\G\$\$((.*\n)*?.*?)\$\$/gc) { return &MakeLaTeX("\$\$ $1 \$\$", $LatexSingleDollars ? "display math" : "inline math"); } elsif ($LatexSingleDollars and m/\G\$((.*\n)*?.*?)\$/gc) { return &MakeLaTeX("\$ $1 \$", "inline math"); } elsif ($allowPlainLaTeX && m/\G\$\[((.*\n)*?.*?)\]\$/gc) { #Pick up plain LaTeX commands return &MakeLaTeX(" $1 ", "LaTeX"); } elsif (m/\GEQ\((.*?)\)/gc) { # Handle references to equations my $label = $1; $label =~ tr/A-Z/a-z/; if ($eqHash{$label}) { return $eqAbbrev . "". $eqHash{$label} . ""; } else { return "[ Equation $label not found ]"; } } return undef; } sub MakeLaTeX { my ($latex, $type, $label) = @_; $ENV{PATH} .= $LatexExtendPath if $LatexExtendPath and $ENV{PATH} !~ /$LatexExtendPath/; # Select which binary to use for conversion of dvi to images my $useConvert = 0; if (not -e $dvipngPath) { if (not -e $convertPath) { return "[Error: dvipng binary and convert binary not found at $dvipngPath or $converPath ]"; } else { $useConvert = 1; # Fall back on convert if dvipng is missing and convert exists } } $latex = UnquoteHtml($latex); # Change < back to <, for example # User selects which hash to use my $hash; my $hasMD5; if ($useMD5) { $hasMD5 = eval "require Digest::MD5;"; } if ($useMD5 && $hasMD5) { $hash = Digest::MD5::md5_base64($latex); $hash =~ s/\//a/g; } else { $hash = UrlEncode($latex); $hash =~ s/%//g; } # check cache if (not -f "$LatexDir/$hash.png" or -z "$LatexDir/$hash.png") { #If file doesn't exist or is zero bytes # Then create the image # read template and replace mkdir($LatexDir) unless -d $LatexDir; if (not -f $LatexDefaultTemplateName) { open (F, "> $LatexDefaultTemplateName") or return '[Unable to write template]'; print F $LatexDefaultTemplate; close (F); } my $template = ReadFileOrDie($LatexDefaultTemplateName); $template =~ s//$latex/ig; #setup rendering directory my $dir = "$LatexDir/$hash"; if (-d $dir) { unlink (glob('$dir/*')); } else { mkdir($dir) or return "[Unable to create $dir]"; } chdir ($dir) or return "[Unable to switch to $dir]"; WriteStringToFile ("srender.tex", $template); my $errorText = qx(latex srender.tex); return "[Illegal LaTeX markup:
$latex
]
Error:
$errorText
" if ($? && $dispErrors); return "[Illegal LaTeX markup:
$latex
]
" if $?; my $output; # Use specified binary to convert dvi to png if ($useConvert) { $output = qx($convertPath -antialias -crop 0x0 -density 120x120 -transparent white srender.dvi srender1.png ); return "[convert error $? ($output)]" if $?; } else { $output = qx($dvipngPath -T tight -bg Transparent srender.dvi); return "[dvipng error $? ($output)]" if $?; } my $result; if (-f 'srender1.png' and not -z 'srender1.png') { my $png = ReadFileOrDie("srender1.png"); WriteStringToFile ("$LatexDir/$hash.png", $png); } else { $result = "[Error retrieving image for $latex]"; } } # Finally print the html for the image if ($type eq "inline math") { # inline math return ("$latex"); } elsif ($type eq "display math") { # display math my $ret; if ($label) { $ret = ""; } $ret .= "
$latex ($eqCounter)<\/center>"; return($ret); } else { # latex format return ("$latex"); } unlink (glob('*')); chdir ($LatexDir); rmdir ($dir); return $result; }