1<?php 2/** 3 * Math Plugin: incorporate mathematical formulae using MathPublisher into Dokuwiki 4 * 5 * Syntax: <m size>...mathematical formula..</m> 6 * size (optional) base glyph size in pixels, 7 * if not present will use the value of $mathplugin_size global, the value 8 * of which can be set below (default: 12) 9 * 10 * Formulae syntax: refer http://www.xm1math.net/phpmathpublisher/doc/help.html 11 * 12 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 13 * @author Christopher Smith <chris@jalakai.co.uk> 14 * @date 2005-12-17 15 * 16 * phpmathpublisher 17 * @link http://www.xm1math.net/phpmathpublisher/ 18 * @author Pascal Brachet 19 */ 20 21if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../../') . '/'); 22if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/'); 23require_once(DOKU_PLUGIN . 'syntax.php'); 24 25/** 26 * All DokuWiki plugins to extend the parser/rendering mechanism 27 * need to inherit from this class 28 */ 29class syntax_plugin_mathpublish extends DokuWiki_Syntax_Plugin { 30 31 protected $enable = false; 32 protected $msg_sent = false; 33 34 /** 35 * syntax_plugin_mathpublish constructor. 36 */ 37 public function __construct() { 38 $this->enable = $this->_requirements_ok(); 39 } 40 41 /** 42 * Syntax Type 43 * 44 * Needs to return one of the mode types defined in $PARSER_MODES in parser.php 45 * 46 * @return string 47 */ 48 public function getType() { 49 return 'substition'; 50 } 51 52 /** 53 * Paragraph Type 54 * 55 * Defines how this syntax is handled regarding paragraphs. This is important 56 * for correct XHTML nesting. Should return one of the following: 57 * 58 * 'normal' - The plugin can be used inside paragraphs 59 * 'block' - Open paragraphs need to be closed before plugin output 60 * 'stack' - Special case. Plugin wraps other paragraphs. 61 * 62 * @see Doku_Handler_Block 63 * 64 * @return string 65 */ 66 public function getPType() { 67 return 'normal'; 68 } 69 70 /** 71 * Sort for applying this mode 72 * 73 * @return int 74 */ 75 public function getSort() { 76 return 208; 77 } 78 79 /** 80 * Connect pattern to lexer 81 * @param string $mode 82 */ 83 public function connectTo($mode) { 84 $this->Lexer->addSpecialPattern('<m.*?>.*?(?:</m>)', $mode, 'plugin_mathpublish'); 85 } 86 87 /** 88 * Handle the match 89 * @param string $match 90 * @param int $state 91 * @param int $pos 92 * @param Doku_Handler $handler 93 * @return array 94 */ 95 public function handle($match, $state, $pos, Doku_Handler $handler) { 96 $match = substr($match, 2, -4); // strip '<m' and '</m>' 97 list($size, $math) = explode('>', $match, 2); 98 if(!$math) { 99 $math = $size; 100 $size = ''; 101 } 102 $size = (int) trim($size); 103 if(!$size) $size = 12; 104 105 if(strlen($math) > 1) { 106 $c_first = $math{0}; 107 $c_last = $math{strlen($math) - 1}; 108 if($c_first == ' ') { 109 if($c_last == ' ') { 110 $align = 'center'; 111 } else { 112 $align = 'right'; 113 } 114 } else { 115 if($c_last == ' ') { 116 $align = 'left'; 117 } else { 118 $align = ''; 119 } 120 }; 121 } else { 122 $align = ''; 123 } 124 125 return (array($size, trim($math), $align)); 126 } 127 128 /** 129 * Create output 130 * @param string $mode 131 * @param Doku_Renderer $R 132 * @param array $data 133 * @return bool 134 */ 135 function render($mode, Doku_Renderer $R, $data) { 136 if(!$this->enable) return true; 137 if($mode != 'xhtml' && $mode != 'odt') return false; 138 139 list($size, $math, $align) = $data; 140 $ident = md5($math . '-' . $size); 141 142 // check if we have a cached version available 143 $valignfile = getCacheName($ident, '.mathpublish.valign'); 144 $imagefile = getCacheName($ident, '.mathpublish.png'); 145 if(file_exists($valignfile)) { 146 $valign = (int) io_readFile($valignfile); 147 } else { 148 require_once(__DIR__ . '/phpmathpublisher/load.php'); 149 $pmp = new \RL\PhpMathPublisher\PhpMathPublisher('', '', $size); 150 $pmp->getHelper()->setTransparent(true); 151 $valign = $pmp->renderImage($math, $imagefile) - 1000; 152 io_saveFile($valignfile, $valign); 153 } 154 155 // pass local files to PDF renderer 156 if(is_a($R, 'renderer_plugin_dw2pdf')) { 157 $img = 'dw2pdf://' . $imagefile; 158 } else { 159 $img = DOKU_BASE . 'lib/plugins/mathpublish/img.php?img=' . $ident; 160 } 161 162 // output aligned image 163 if($mode == 'odt') { 164 if(!$align) { 165 $align = 'left'; 166 } 167 $R->_odtAddImage($imagefile, NULL, NULL, $align, NULL, NULL); 168 } else { 169 if($align) { 170 $display = 'block'; 171 $align = "media$align"; 172 } else { 173 $display = 'inline-block'; 174 } 175 176 $R->doc .= '<img src="' . $img . '" 177 class="' . $align . ' mathpublish" 178 alt="' . hsc($math) . '" 179 title="' . hsc($math) . '" 180 style="display: ' . $display . '; vertical-align:' . $valign . 'px" />'; 181 } 182 return true; 183 } 184 185 /** 186 * check if php installation has required libraries/functions 187 */ 188 private function _requirements_ok() { 189 if(!function_exists('imagepng')) { 190 $this->_msg($this->getLang('nopng'), -1); 191 return false; 192 } 193 194 if(!function_exists('imagettftext')) { 195 $this->_msg($this->getLang('noft'), -1); 196 return false; 197 } 198 199 return true; 200 } 201 202 /** 203 * used to avoid multiple messages 204 * 205 * @param string $str 206 * @param int $lvl 207 */ 208 protected function _msg($str, $lvl = 0) { 209 if($this->msg_sent) return; 210 211 msg($str, $lvl); 212 $this->msg_sent = true; 213 } 214} 215 216