]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/TeX2png.php
Normalize header
[SourceForge/phpwiki.git] / lib / plugin / TeX2png.php
1 <?php // -*-php-*-
2 rcs_id('$Id$');
3 /*
4  * Copyright (C) Copyright 2004 Pierrick Meignen
5  * 
6  * This file is part of PhpWiki.
7  *
8  * PhpWiki is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * PhpWiki is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with PhpWiki; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 /**
24  * This is a simple version of the original TexToPng plugin which uses 
25  * the powerful plugincached mechanism.
26  * TeX2png uses its own much simplier static cache in images/tex.
27  *
28  * @author: Pierrick Meignen
29  * TODO: use url helpers, windows fixes
30  *       use a better imagepath
31  */
32
33 // needs latex
34 // LaTeX2HTML ftp://ftp.dante.de/tex-archive/support/latex2html
35
36 class WikiPlugin_TeX2png
37 extends WikiPlugin
38 {
39     var $imagepath = 'images/tex';
40     var $latexbin = '/usr/bin/latex';
41     var $dvipsbin = '/usr/bin/dvips';
42     var $pstoimgbin = '/usr/bin/pstoimg';
43
44     function getName () {
45         return _("TeX2png");
46     }
47     
48     function getDescription () {
49         return _("Convert Tex mathematicals expressions to cached png files." .
50                  " This is for small text");
51     }
52     
53     function getVersion() {
54         return preg_replace("/[Revision: $]/", '',"\$Revision$");
55     }
56     
57     function getDefaultArguments() {
58         return array('text' => "$$(a + b)^2 = a^2 + 2 ab + b^2$$");
59     }
60     
61     function parseArgStr($argstr) {
62         // modified from WikiPlugin.php
63         $arg_p = '\w+';
64         $op_p = '(?:\|\|)?=';
65         $word_p = '\S+';
66         $opt_ws = '\s*';
67         $qq_p = '" ( (?:[^"\\\\]|\\\\.)* ) "';
68         //"<--kludge for brain-dead syntax coloring
69         $q_p  = "' ( (?:[^'\\\\]|\\\\.)* ) '";
70         $gt_p = "_\\( $opt_ws $qq_p $opt_ws \\)";
71         $argspec_p = "($arg_p) $opt_ws ($op_p) $opt_ws (?: $qq_p|$q_p|$gt_p|($word_p))";
72         
73         $args = array();
74         $defaults = array();
75         
76         while (preg_match("/^$opt_ws $argspec_p $opt_ws/x", $argstr, $m)) {
77             @ list(,$arg,$op,$qq_val,$q_val,$gt_val,$word_val) = $m;
78             $argstr = substr($argstr, strlen($m[0]));
79             
80             // Remove quotes from string values.
81             if ($qq_val)
82                 // we don't remove backslashes in tex formulas
83                 // $val = stripslashes($qq_val);
84                 $val = $qq_val;
85             elseif ($q_val)
86                 $val = stripslashes($q_val);
87             elseif ($gt_val)
88                 $val = _(stripslashes($gt_val));
89             else
90                 $val = $word_val;
91             
92             if ($op == '=') {
93                 $args[$arg] = $val;
94             }
95             else {
96                 // NOTE: This does work for multiple args. Use the
97                 // separator character defined in your webserver
98                 // configuration, usually & or &amp; (See
99                 // http://www.htmlhelp.com/faq/cgifaq.4.html)
100                 // e.g. <plugin RecentChanges days||=1 show_all||=0 show_minor||=0>
101                 // url: RecentChanges?days=1&show_all=1&show_minor=0
102                 assert($op == '||=');
103                 $defaults[$arg] = $val;
104             }
105         }
106         
107         if ($argstr) {
108             $this->handle_plugin_args_cruft($argstr, $args);
109         }
110         
111         return array($args, $defaults);
112     }
113     
114     function createTexFile($texfile, $text) {
115         // this is the small latex file
116         // which contains only the mathematical
117         // expression
118         $fp = fopen($texfile, 'w');
119         $str = "\documentclass{article}\n";
120         $str .= "\usepackage{amsfonts}\n";
121         $str .= "\usepackage{amssymb}\n";
122         // Here tou can add some package in order 
123         // to produce more sophisticated output 
124         $str .= "\pagestyle{empty}\n";
125         $str .= "\begin{document}\n";
126         $str .= $text . "\n";
127         $str .= "\end{document}";
128         fwrite($fp, $str);
129         fclose($fp);
130         return 0;
131     }
132
133     function createPngFile($imagepath, $imagename) {
134         // to create dvi file from the latex file
135         $commandes = $this->latexbin . " temp.tex;";
136         exec("cd $imagepath;$commandes");
137         // to create png file from the dvi file
138         // there is no option but it is possible
139         // to add one (scale for example)
140         if (file_exists("$imagepath/temp.dvi")){
141             $commandes = $this->dvipsbin . " temp.dvi -o temp.ps;";
142             $commandes .= $this->pstoimgbin . " -type png -margins 0,0 ";
143             $commandes .= "-crop a -geometry 600x300 ";
144             $commandes .= "-aaliastext -color 1 -scale 1.5 ";
145             $commandes .= "temp.ps -o " . $imagename;
146             exec("cd $imagepath;$commandes");
147             unlink("$imagepath/temp.dvi");
148             unlink("$imagepath/temp.ps");
149         } else
150             echo _(" (syntax error for latex) ");
151         // to clean the directory
152         unlink("$imagepath/temp.tex");
153         unlink("$imagepath/temp.aux");
154         unlink("$imagepath/temp.log");
155         return 0;
156     }
157     
158     function isMathExp(&$text) {
159         // this function returns
160         // 0 : text is too long or not a mathematical expression
161         // 1 : text is $xxxxxx$ hence in line
162         // 2 : text is $$xxxx$$ hence centered
163         $last = strlen($text) - 1;
164         if($last >= 250){
165             $text = "Too long !";
166             return 0;
167         } elseif($last <= 1 || strpos($text, '$') != 0){
168             return 0;
169         } elseif(strpos($text, '$', 1) == $last)
170             return 1;
171         elseif($last > 3 && 
172                strpos($text, '$', 1) == 1 && 
173                strpos($text, '$', 2) == $last - 1)
174             return 2;
175         return 0;
176     }
177
178     function tex2png($text) {
179         // the name of the png cached file
180         $imagename = md5($text) . ".png";
181         $url = $this->imagepath . "/$imagename";
182
183         if(!file_exists($url)){
184             if(is_writable($this->imagepath)){
185                 $texfile = $this->imagepath . "/temp.tex";
186                 $this->createTexFile($texfile, $text);     
187                 $this->createPngFile($this->imagepath, $imagename);
188             } else {
189                 $error_html = _("TeX imagepath not writable.");
190                 trigger_error($error_html, E_USER_NOTICE);
191             }
192         }
193
194         // there is always something in the html page
195         // even if the tex directory doesn't exist
196         // or mathematical expression is wrong      
197         switch($this->isMathExp($text)) {
198         case 0: // not a mathematical expression
199             $html = HTML::tt(array('class'=>'tex', 
200                                    'style'=>'color:red;'), $text); 
201             break;
202         case 1: // an inlined mathematical expression
203             $html = HTML::img(array('class'=>'tex', 
204                                     'src' => $url, 
205                                     'alt' => $text)); 
206             break;
207         case 2: // mathematical expression on separate line
208             $html = HTML::img(array('class'=>'tex', 
209                                     'src' => $url, 
210                                     'alt' => $text));
211             $html = HTML::div(array('align' => 'center'), $html); 
212             break;
213         default: 
214             break;
215         }
216         
217         return $html;
218     }
219     
220     function run($dbi, $argstr, &$request, $basepage) {
221         // from text2png.php
222         if ((function_exists('ImageTypes') and (ImageTypes() & IMG_PNG)) 
223             or function_exists("ImagePNG"))
224         {
225             // we have gd & png so go ahead.
226             extract($this->getArgs($argstr, $request));
227             return $this->tex2png($text);
228         } else {
229             // we don't have png and/or gd.
230             $error_html = _("Sorry, this version of PHP cannot create PNG image files.");
231             $link = "http://www.php.net/manual/pl/ref.image.php";
232             $error_html .= sprintf(_("See %s"), $link) .".";
233             trigger_error($error_html, E_USER_NOTICE);
234             return;
235         }
236     }
237 };
238
239 // For emacs users
240 // Local Variables:
241 // mode: php
242 // tab-width: 8
243 // c-basic-offset: 4
244 // c-hanging-comment-ender-p: nil
245 // indent-tabs-mode: nil
246 // End:
247 ?>