source-class-LatexRender

It appears that you are using AdBlocking software. The cost of running this website is covered by advertisements. If you like it please feel free to a small amount of money to secure the future of this website.
Overview

Classes

Interfaces

Exceptions

Functions

  1: <?php
  2: //============================================================+
  3: // File name   : tce_latexrender.php
  4: // Begin       : 2007-05-18
  5: // Last Update : 2009-11-10
  6: // Author      : Nicola Asuni
  7: //
  8: // Description :
  9: // ------------------------------------------------------------
 10: // This is a PHP5 class for generating images from LaTeX Formulas.
 11: // This class is based on the following:
 12: // LaTeX Rendering Class v0.8 (Licensed under GPL 2)
 13: // Copyright (C) 2003 Benjamin Zeiss <zeiss@math.uni-goettingen.de>
 14: // Currently the project is maintained by Steve Mayer.
 15: // Please check the following Website to obtain the original
 16: // source code: http://www.mayer.dial.pipex.com/tex.htm
 17: // ------------------------------------------------------------
 18: //============================================================+
 19: 
 20: /**
 21:  * @file
 22:  * LaTeX Rendering Class.
 23:  * @package com.tecnick.tcexam.shared
 24:  */
 25: 
 26: // Includes configuration file.
 27: require_once('../../shared/config/tce_latex.php');
 28: 
 29: /**
 30:  * @class LatexRender
 31:  * This is a PHP5 class for generating images from LaTeX Formulas.
 32:  * This class is based on the following:
 33:  * LaTeX Rendering Class v0.8 (Licensed under GPL 2)
 34:  * Copyright (C) 2003 Benjamin Zeiss <zeiss@math.uni-goettingen.de>
 35:  * Currently the project is maintained by Steve Mayer.
 36:  * Please check the following Website to obtain the original
 37:  * source code: http://www.mayer.dial.pipex.com/tex.htm
 38:  * @package com.tecnick.tcexam.shared
 39:  * @authors Benjamin Zeiss, Nicola Asuni
 40:  */
 41: class LatexRender
 42: {
 43: 
 44:     //  ---------- Variable Definitions ---------- * ---------- * ----------
 45: 
 46:     /**
 47:      * Absolute path to images directory.
 48:      * @protected
 49:      */
 50:     protected $picture_path = K_LATEX_PATH_PICTURE;
 51: 
 52:     /**
 53:      * Relative path to images directory.
 54:      * @protected
 55:      */
 56:     protected $picture_path_httpd = K_LATEX_PATH_PICTURE_HTTPD;
 57: 
 58:     /**
 59:      * Path to temporary directory.
 60:      * @protected
 61:      */
 62:     protected $tmp_dir = K_LATEX_TMP_DIR;
 63: 
 64:     /**
 65:      * Path to LATEX.
 66:      * @protected
 67:      */
 68:     protected $latex_path = K_LATEX_PATH_LATEX;
 69: 
 70:     /**
 71:      * Path to DVIPS.
 72:      * @protected
 73:      */
 74:     protected $dvips_path = K_LATEX_PATH_DVIPS;
 75: 
 76:     /**
 77:      * Path to ImageMagick convert.
 78:      * @protected
 79:      */
 80:     protected $convert_path = K_LATEX_PATH_CONVERT;
 81: 
 82:     /**
 83:      * Path to ImageMagick identify.
 84:      * @protected
 85:      */
 86:     protected $identify_path = K_LATEX_PATH_IDENTIFY;
 87: 
 88:     /**
 89:      * Formula density (used by ImageMagick)
 90:      * @protected
 91:      */
 92:     protected $formula_density = K_LATEX_FORMULA_DENSITY;
 93: 
 94:     /**
 95:      * Image width limit in pixels.
 96:      * @protected
 97:      */
 98:     protected $width_limit = K_LATEX_MAX_WIDTH;
 99: 
100:     /**
101:      * Image height limit in pixels.
102:      * @protected
103:      */
104:     protected $height_limit = K_LATEX_MAX_HEIGHT;
105: 
106:     /**
107:      * Size limit for input string.
108:      * @protected
109:      */
110:     protected $string_length_limit = K_LATEX_MAX_LENGHT;
111: 
112:     /**
113:      * Font size.
114:      * @protected
115:      */
116:     protected $font_size = K_LATEX_FONT_SIZE;
117: 
118:     /**
119:      * LaTeX class.
120:      * @protected
121:     */
122:     protected $latexclass = K_LATEX_CLASS;
123: 
124:     /**
125:      * Filename prefix for chached images.
126:      * @protected
127:      */
128:     protected $img_prefix = K_LATEX_IMG_PREFIX;
129: 
130:     /**
131:      * Image format (default = PNG).
132:      * @protected
133:      */
134:     protected $image_format = K_LATEX_IMG_FORMAT;
135: 
136:     /**
137:      * List of unauthorized LaTeX commands.
138:      * @protected
139:      */
140:     protected $latex_tags_blacklist = array('include', 'def', 'command', 'loop', 'repeat', 'open', 'toks', 'output', 'input', 'catcode', 'name', '^^', '\every', '\errhelp', '\errorstopmode', '\scrollmode', '\nonstopmode', '\batchmode', '\read', '\write', 'csname', '\newhelp', '\uppercase', '\lowercase', '\relax', '\aftergroup', '\afterassignment', '\expandafter', '\noexpand', '\special');
141: 
142:     // ------ private ------
143: 
144:     /**
145:      * Error code.
146:      * @private
147:      */
148:     private $errorcode = 0;
149: 
150:     /**
151:      * Temporary filename.
152:      * @private
153:     */
154:     private $tmp_filename = '';
155: 
156:     /**
157:      * Latex formula.
158:      * @private
159:      */
160:     private $latex_formula = '';
161: 
162:     /**
163:      * Image width.
164:      * @private
165:      */
166:     private $img_width = 0;
167: 
168:     /**
169:      * Image height.
170:      * @private
171:      */
172:     private $img_height = 0;
173: 
174: 
175:     //  ---------- constructor / destructor functions ---------- * ---------- * ----------
176: 
177: 
178:     /**
179:      * Class Constructor.
180:      */
181:     public function __construct()
182:     {
183:         $this->tmp_filename = md5(rand());
184:     }
185: 
186:     /**
187:      * Default destructor.
188:      */
189:     public function __destruct()
190:     {
191:     }
192: 
193: 
194:     // ---------- public functions ---------- * ---------- * ---------- * ----------
195: 
196:     // ---------- set functions ----------
197: 
198:     /**
199:      * Set the absolute path to images directory.
200:      * @param $picture_path (string) absolute path to images directory.
201:      */
202:     public function setPathToPicturesDir($picture_path)
203:     {
204:         $this->picture_path = $picture_path;
205:     }
206: 
207:     /**
208:      * Set relative path to images directory.
209:      * @param $picture_path_httpd (string) relative path to images directory.
210:      */
211:     public function setPathToPicturesDirHttpd($picture_path_httpd)
212:     {
213:         $this->picture_path_httpd = $picture_path_httpd;
214:     }
215: 
216:     /**
217:      * Set path to temporary directory.
218:      * @param $tmp_dir (string) path to temporary directory.
219:      */
220:     public function setPathToTempDir($tmp_dir)
221:     {
222:         $this->tmp_dir = $tmp_dir;
223:     }
224: 
225:     /**
226:      * Set path to LATEX.
227:      * @param $latex_path (string) path to LATEX.
228:      */
229:     public function setPathToLatex($latex_path)
230:     {
231:         $this->latex_path = $latex_path;
232:     }
233: 
234:     /**
235:      * Set path to DVIPS.
236:      * @param $dvips_path (string) path to DVIPS.
237:      */
238:     public function setPathToDvips($dvips_path)
239:     {
240:         $this->dvips_path = $dvips_path;
241:     }
242: 
243:     /**
244:      * Set path to ImageMagick convert.
245:      * @param $convert_path (string) path to ImageMagick convert.
246:      */
247:     public function setPathToImageMagicConvert($convert_path)
248:     {
249:         $this->convert_path = $convert_path;
250:     }
251: 
252:     /**
253:      * Set path to ImageMagick identify.
254:      * @param $identify_path (string) path to ImageMagick identify.
255:      */
256:     public function setPathToImageMagicIdentify($identify_path)
257:     {
258:         $this->identify_path = $identify_path;
259:     }
260: 
261:     /**
262:      * Set formula density (used by ImageMagick)
263:      * @param $formula_density (int) formula density.
264:      */
265:     public function setFormulaDensity($formula_density)
266:     {
267:         $this->formula_density = $formula_density;
268:     }
269: 
270:     /**
271:      * Set image width limit in pixels.
272:      * @param $width_limit (string) Max image width in pixels.
273:      */
274:     public function setMaxWidth($width_limit)
275:     {
276:         $this->width_limit = $width_limit;
277:     }
278: 
279:     /**
280:      * Set image height limit in pixels.
281:      * @param $height_limit (string) Max image height in pixels.
282:      */
283:     public function setMaxHeight($height_limit)
284:     {
285:         $this->height_limit = $height_limit;
286:     }
287: 
288:     /**
289:      * Set size limit for input string.
290:      * @param $string_length_limit (string) max lenght for LaTeX string.
291:      */
292:     public function setMaxLenght($string_length_limit)
293:     {
294:         $this->string_length_limit = $string_length_limit;
295:     }
296: 
297:     /**
298:      * Set font size.
299:      * @param $font_size (int) font size in points.
300:      */
301:     public function setFontSize($font_size)
302:     {
303:         $this->font_size = $font_size;
304:     }
305: 
306:     /**
307:      * Set LaTeX class.
308:      * Install extarticle class if you wish to have smaller font sizes.
309:      * @param $latexclass (string) LaTeX class.
310:      */
311:     public function setLatexClass($latexclass)
312:     {
313:         $this->latexclass = $latexclass;
314:     }
315: 
316:     /**
317:      * Set filename prefix for chached images.
318:      * @param $img_prefix (string) filename prefix.
319:      */
320:     public function setFilenamePrefix($img_prefix)
321:     {
322:         $this->img_prefix = $img_prefix;
323:     }
324: 
325:     /**
326:      * Set the image format (default = PNG).
327:      * @param $image_format (string) image format(e.g.: png).
328:      */
329:     public function setImageFormat($image_format)
330:     {
331:         $this->image_format = $image_format;
332:     }
333: 
334:     /**
335:      * Set the list of unauthorized LaTeX commands.
336:      * @param $latex_tags_blacklist (array) array of blacklisted commands.
337:      */
338:     public function setLatexBlackList($latex_tags_blacklist)
339:     {
340:         $this->latex_tags_blacklist = $latex_tags_blacklist;
341:     }
342: 
343:     // ---------- get functions ----------
344: 
345:     /**
346:      * Tries to match the LaTeX Formula given as argument against the
347:      * formula cache. If the picture has not been rendered before, it'll
348:      * try to render the formula and drop it in the picture cache directory.
349:      *
350:      * @param $latex_formula (string) formula in LaTeX format
351:      * @returns the webserver based URL to a picture which contains the
352:      * requested LaTeX formula. If anything fails, the result value is false.
353:      */
354:     public function getFormulaURL($latex_formula)
355:     {
356: 
357:         // circumvent certain security functions of web-software which
358:         // is pretty pointless right here
359:         $latex_formula = preg_replace("/&gt;/i", '>', $latex_formula);
360:         $latex_formula = preg_replace("/&lt;/i", '<', $latex_formula);
361: 
362:         $filename = $this->getFilename($latex_formula);
363:         $full_path_filename = $this->picture_path.''.$filename;
364: 
365:         if (is_file($full_path_filename)) {
366:             return $this->picture_path_httpd.''.$filename;
367:         } else {
368:             // security filter: reject too long formulas
369:             if (strlen($latex_formula) > $this->string_length_limit) {
370:                 $this->errorcode = 1;
371:                 return false;
372:             }
373:             // security filter: try to match against LaTeX-Tags Blacklist
374:             for ($i=0; $i<sizeof($this->latex_tags_blacklist); $i++) {
375:                 if (stristr($latex_formula, $this->latex_tags_blacklist[$i])) {
376:                     $this->errorcode = 2;
377:                     return false;
378:                 }
379:             }
380:             // security checks assume correct formula, let's render it
381:             if ($this->renderLatex($latex_formula)) {
382:                 return $this->picture_path_httpd.''.$filename;
383:             } else {
384:                 return false;
385:             }
386:         }
387:     }
388: 
389:     /**
390:      * Returns Image width
391:      * @returns image width in pixels.
392:      */
393:     public function getImageWidth()
394:     {
395:         return $this->img_width;
396:     }
397: 
398:     /**
399:      * Returns Image height
400:      * @returns image height in pixels.
401:      */
402:     public function getImageHeight()
403:     {
404:         return $this->img_height;
405:     }
406: 
407:     /**
408:      * Returns the error code
409:      * @returns int error code.
410:      */
411:     public function getErrorCode()
412:     {
413:         return $this->errorcode;
414:     }
415: 
416: 
417:     //  --- private functions --------------------------------------------------
418: 
419: 
420:     /**
421:      * Wraps a minimalistic LaTeX document around the formula and returns a string
422:      * containing the whole document as string.
423:      * Customize if you want other fonts for example.
424:      *
425:      * @param $latex_formula (string) formula in LaTeX format
426:      * @returns minimalistic LaTeX document containing the given formula
427:      */
428:     private function getFilename($latex_formula)
429:     {
430:         $filename = $this->img_prefix.md5($latex_formula).'.'.$this->image_format;
431:         return $filename;
432:     }
433: 
434:     /**
435:      * Wraps a minimalistic LaTeX document around the formula and returns a string
436:      * containing the whole document as string.
437:      * Customize if you want other fonts for example.
438:      *
439:      * @param $latex_formula (string) formula in LaTeX format
440:      * @returns minimalistic LaTeX document containing the given formula
441:      */
442:     private function wrapFormula($latex_formula)
443:     {
444:         $string  = '\documentclass['.$this->font_size.'pt]{'.$this->latexclass.'}'."\n";
445:         $string .= '\usepackage[latin1]{inputenc}'."\n";
446:         $string .= '\usepackage{amsmath}'."\n";
447:         $string .= '\usepackage{amsfonts}'."\n";
448:         $string .= '\usepackage{amssymb}'."\n";
449:         $string .= '\pagestyle{empty}'."\n";
450:         $string .= '\begin{document}'."\n";
451:         $string .= '$'.$latex_formula.'$'."\n";
452:         $string .= '\end{document}'."\n";
453:         return $string;
454:     }
455: 
456:     /**
457:      * Removes temporary files.
458:      * @param $current_dir (string) current directory.
459:      * @param $error_code (int) error code.
460:      */
461:     private function cleanTemporaryDirectory($current_dir, $error_code = 0)
462:     {
463:         chdir($this->tmp_dir);
464:         unlink($this->tmp_dir.''.$this->tmp_filename.'.tex');
465:         unlink($this->tmp_dir.''.$this->tmp_filename.'.aux');
466:         unlink($this->tmp_dir.''.$this->tmp_filename.'.log');
467:         unlink($this->tmp_dir.''.$this->tmp_filename.'.dvi');
468:         unlink($this->tmp_dir.''.$this->tmp_filename.'.ps');
469:         unlink($this->tmp_dir.''.$this->tmp_filename.'.'.$this->image_format);
470:         chdir($current_dir);
471:         $this->errorcode = $error_code;
472:     }
473: 
474:     /**
475:      * Check the dimensions of a picture file using 'identify' of the
476:      * ImageMagick tools.
477:      *
478:      * @param $filename (string) path to a picture
479:      * @returns array containing the picture dimensions
480:      */
481:     private function checkImageDimensions($filename)
482:     {
483:         $output = exec($this->identify_path." ".$filename);
484:         if (empty($output)) {
485:             return false;
486:         }
487:         $result = explode(' ', $output);
488:         $dim = explode('x', $result[2]);
489:         $this->img_width = $dim[0];
490:         $this->img_height = $dim[1];
491:         if (($this->img_width > $this->width_limit) or ($this->img_height > $this->height_limit)) {
492:             return false;
493:         }
494:         return true;
495:     }
496: 
497:     /**
498:      * Renders a LaTeX formula by the using the following method:
499:      *  - write the formula into a wrapped tex-file in a temporary directory
500:      *    and change to it
501:      *  - Create a DVI file using latex (tetex)
502:      *  - Convert DVI file to Postscript (PS) using dvips (tetex)
503:      *  - convert, trim and add transparancy by using 'convert' from the
504:      *    ImageMagick package.
505:      *  - Save the resulting image to the picture cache directory using an
506:      *    md5 hash as filename. Already rendered formulas can be found directly
507:      *    this way.
508:      *
509:      * @param $latex_formula (string) LaTeX formula
510:      * @returns true if the picture has been successfully saved to the picture
511:      *          cache directory
512:      */
513:     private function renderLatex($latex_formula)
514:     {
515:         $latex_document = $this->wrapFormula($latex_formula);
516: 
517:         $current_dir = getcwd();
518:         chdir($this->tmp_dir);
519: 
520:         // create temporary latex file
521:         $fp = fopen($this->tmp_dir.''.$this->tmp_filename.'.tex', 'a+');
522:         fputs($fp, $latex_document);
523:         fclose($fp);
524: 
525:         // create temporary DVI file
526:         $command = $this->latex_path.' --interaction=nonstopmode '.$this->tmp_filename.'.tex';
527:         $status_code = exec($command);
528:         if (!$status_code) {
529:             $this->cleanTemporaryDirectory($current_dir, 4);
530:             return false;
531:         }
532: 
533:         // convert DVI file to postscript using DVIPS
534:         $command = $this->dvips_path.' -E '.$this->tmp_filename.'.dvi'.' -o '.$this->tmp_filename.'.ps';
535:         $status_code = exec($command);
536: 
537:         // ImageMagick convert PS to image and trim picture
538:         $command = $this->convert_path.' -density '.$this->formula_density.' -background "#FFFFFF" -depth 8 '.$this->tmp_filename.'.ps '.$this->tmp_filename.'.'.$this->image_format;
539:         $status_code = exec($command);
540: 
541:         // check picture dimensions
542:         if (!$this->checkImageDimensions($this->tmp_filename.'.'.$this->image_format)) {
543:             $this->cleanTemporaryDirectory($current_dir, 7);
544:             return false;
545:         }
546: 
547:         // copy temporary formula file to cached formula directory
548:         $filename = $this->getFilename($latex_formula);
549:         $status_code = copy($this->tmp_filename.'.'.$this->image_format, $filename);
550: 
551:         if (!$status_code) {
552:             $this->cleanTemporaryDirectory($current_dir, 8);
553:             return false;
554:         }
555: 
556:         $this->cleanTemporaryDirectory($current_dir, 0);
557: 
558:         return true;
559:     }
560: } // end of class
561: 
562: //============================================================+
563: // END OF FILE
564: //============================================================+
565: 
 

© 2004-2018 – Nicola Asuni - Tecnick.com - All rights reserved.
about - disclaimer - privacy