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 21/** 22 * All DokuWiki plugins to extend the parser/rendering mechanism 23 * need to inherit from this class 24 */ 25class syntax_plugin_mathpublish extends DokuWiki_Syntax_Plugin { 26 27 protected $enable = false; 28 protected $msg_sent = false; 29 30 /** 31 * syntax_plugin_mathpublish constructor. 32 */ 33 public function __construct() { 34 $this->enable = $this->_requirements_ok(); 35 } 36 37 /** 38 * Syntax Type 39 * 40 * Needs to return one of the mode types defined in $PARSER_MODES in parser.php 41 * 42 * @return string 43 */ 44 public function getType() { 45 return 'substition'; 46 } 47 48 /** 49 * Paragraph Type 50 * 51 * Defines how this syntax is handled regarding paragraphs. This is important 52 * for correct XHTML nesting. Should return one of the following: 53 * 54 * 'normal' - The plugin can be used inside paragraphs 55 * 'block' - Open paragraphs need to be closed before plugin output 56 * 'stack' - Special case. Plugin wraps other paragraphs. 57 * 58 * @see Doku_Handler_Block 59 * 60 * @return string 61 */ 62 public function getPType() { 63 return 'normal'; 64 } 65 66 /** 67 * Sort for applying this mode 68 * 69 * @return int 70 */ 71 public function getSort() { 72 return 208; 73 } 74 75 /** 76 * Connect pattern to lexer 77 * @param string $mode 78 */ 79 public function connectTo($mode) { 80 $this->Lexer->addSpecialPattern('<m.*?>.*?(?:</m>)', $mode, 'plugin_mathpublish'); 81 } 82 83 /** 84 * Handle the match 85 * @param string $match 86 * @param int $state 87 * @param int $pos 88 * @param Doku_Handler $handler 89 * @return array 90 */ 91 public function handle($match, $state, $pos, Doku_Handler $handler) { 92 $match = substr($match, 2, -4); // strip '<m' and '</m>' 93 list($size, $math) = explode('>', $match, 2); 94 if(!$math) { 95 $math = $size; 96 $size = ''; 97 } 98 $size = (int) trim($size); 99 if(!$size) $size = 12; 100 101 if(strlen($math) > 1) { 102 $c_first = $math[0]; 103 $c_last = $math[strlen($math) - 1]; 104 if($c_first == ' ') { 105 if($c_last == ' ') { 106 $align = 'center'; 107 } else { 108 $align = 'right'; 109 } 110 } else { 111 if($c_last == ' ') { 112 $align = 'left'; 113 } else { 114 $align = ''; 115 } 116 }; 117 } else { 118 $align = ''; 119 } 120 121 return (array($size, trim($math), $align)); 122 } 123 124 /** 125 * Create output 126 * @param string $mode 127 * @param Doku_Renderer $R 128 * @param array $data 129 * @return bool 130 */ 131 function render($mode, Doku_Renderer $R, $data) { 132 if(!$this->enable) return true; 133 if($mode != 'xhtml' && $mode != 'odt') return false; 134 global $INPUT; 135 136 list($size, $math, $align) = $data; 137 $scale = 1; 138 if(is_a($R, 'renderer_plugin_dw2pdf')) $scale=3; 139 $size = $size * $scale; 140 $ident = md5($math . '-' . $size); 141 142 // check if we have a cached version available 143 $imagefile = getCacheName($ident, '.mathpublish.png'); 144 if(!file_exists($imagefile) || $INPUT->bool('purge')) { 145 require_once(__DIR__ . '/phpmathpublisher/load.php'); 146 $pmp = new \RL\PhpMathPublisher\PhpMathPublisher('', '', $size); 147 $pmp->getHelper()->setTransparent(true); 148 $pmp->renderImage($math, $imagefile) - 1000; 149 } 150 151 // pass local files to PDF renderer 152 if(is_a($R, 'renderer_plugin_dw2pdf')) { 153 $img = 'dw2pdf://' . $imagefile; 154 } else { 155 $img = DOKU_BASE . 'lib/plugins/mathpublish/img.php?img=' . $ident; 156 } 157 158 list($width, $height) = getimagesize($imagefile); 159 $width = $width/$scale; 160 $height = $height/$scale; 161 162 // output aligned image 163 if($mode == 'odt') { 164 if(!$align) { 165 $align = 'left'; 166 } 167 $R->_odtAddImage($imagefile, $width, $height, $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 '. buildAttributes([ 177 'src' => $img, 178 'class' => $align . ' mathpublish', 179 'alt' => $math, 180 'title' => $math, 181 'width' => $width, 182 'height' => $height, 183 'style' => "display: $display; object-fit: fill;", 184 ]).' />'; 185 } 186 return true; 187 } 188 189 /** 190 * check if php installation has required libraries/functions 191 */ 192 private function _requirements_ok() { 193 if(!function_exists('imagepng')) { 194 $this->_msg($this->getLang('nopng'), -1); 195 return false; 196 } 197 198 if(!function_exists('imagettftext')) { 199 $this->_msg($this->getLang('noft'), -1); 200 return false; 201 } 202 203 return true; 204 } 205 206 /** 207 * used to avoid multiple messages 208 * 209 * @param string $str 210 * @param int $lvl 211 */ 212 protected function _msg($str, $lvl = 0) { 213 if($this->msg_sent) return; 214 215 msg($str, $lvl); 216 $this->msg_sent = true; 217 } 218} 219 220