1<?php 2/** 3 * Ditaa-Plugin: Converts Ascii-Flowcharts into a png-File 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Dennis Ploeger <develop [at] dieploegers [dot] de> 7 * @author Christoph Mertins <c [dot] mertins [at] gmail [dot] com> 8 * @author Andreas Gohr <andi@splitbrain.org> 9 */ 10 11if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); 12if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 13require_once(DOKU_PLUGIN.'syntax.php'); 14 15class syntax_plugin_ditaa extends DokuWiki_Syntax_Plugin { 16 17 /** 18 * What about paragraphs? 19 */ 20 function getPType(){ 21 return 'normal'; 22 } 23 24 /** 25 * What kind of syntax are we? 26 */ 27 function getType(){ 28 return 'substition'; 29 } 30 31 /** 32 * Where to sort in? 33 */ 34 function getSort(){ 35 return 200; 36 } 37 38 /** 39 * Connect pattern to lexer 40 */ 41 42 function connectTo($mode) { 43 $this->Lexer->addSpecialPattern('<ditaa.*?>\n.*?\n</ditaa>',$mode,'plugin_ditaa'); 44 } 45 46 /** 47 * Handle the match 48 */ 49 function handle($match, $state, $pos, &$handler) { 50 $info = $this->getInfo(); 51 52 // prepare default data 53 $return = array( 54 'width' => 0, 55 'height' => 0, 56 'antialias' => true, 57 'edgesep' => true, 58 'round' => false, 59 'shadow' => true, 60 'scale' => 1, 61 'align' => '', 62 'version' => $info['date'], //forece rebuild of images on update 63 ); 64 65 66 // prepare input 67 $lines = explode("\n",$match); 68 $conf = array_shift($lines); 69 array_pop($lines); 70 71 // match config options 72 if(preg_match('/\b(left|center|right)\b/i',$conf,$match)) $return['align'] = $match[1]; 73 if(preg_match('/\b(\d+)x(\d+)\b/',$conf,$match)){ 74 $return['width'] = $match[1]; 75 $return['height'] = $match[2]; 76 } 77 if(preg_match('/\b(\d+(\.\d+)?)X\b/',$conf,$match)) $return['scale'] = $match[1]; 78 if(preg_match('/\bwidth=([0-9]+)\b/i', $conf,$match)) $return['width'] = $match[1]; 79 if(preg_match('/\bheight=([0-9]+)\b/i', $conf,$match)) $return['height'] = $match[1]; 80 // match boolean toggles 81 if(preg_match_all('/\b(no)?(antialias|edgesep|round|shadow)\b/i',$conf,$matches,PREG_SET_ORDER)){ 82 foreach($matches as $match){ 83 $return[$match[2]] = ! $match[1]; 84 } 85 } 86 87 $input = join("\n",$lines); 88 $return['md5'] = md5($input); // we only pass a hash around 89 90 // store input for later use 91 io_saveFile($this->_cachename($return,'txt'),$input); 92 93 return $return; 94 } 95 96 /** 97 * Cache file is based on parameters that influence the result image 98 */ 99 function _cachename($data,$ext){ 100 unset($data['width']); 101 unset($data['height']); 102 unset($data['align']); 103 return getcachename(join('x',array_values($data)),'.ditaa.'.$ext); 104 } 105 106 /** 107 * Create output 108 */ 109 function render($format, &$R, $data) { 110 if($format == 'xhtml'){ 111 $img = DOKU_BASE.'lib/plugins/ditaa/img.php?'.buildURLparams($data); 112 $R->doc .= '<img src="'.$img.'" class="media'.$data['align'].'" alt=""'; 113 if($data['width']) $R->doc .= ' width="'.$data['width'].'"'; 114 if($data['height']) $R->doc .= ' height="'.$data['height'].'"'; 115 if($data['align'] == 'right') $R->doc .= ' align="right"'; 116 if($data['align'] == 'left') $R->doc .= ' align="left"'; 117 $R->doc .= '/>'; 118 return true; 119 }elseif($format == 'odt'){ 120 $src = $this->_imgfile($data); 121 $R->_odtAddImage($src,$data['width'],$data['height'],$data['align']); 122 return true; 123 } 124 return false; 125 } 126 127 128 /** 129 * Return path to the rendered image on our local system 130 */ 131 function _imgfile($data){ 132 $cache = $this->_cachename($data,'png'); 133 134 // create the file if needed 135 if(!file_exists($cache)){ 136 $in = $this->_cachename($data,'txt'); 137 if($this->getConf('java')){ 138 $ok = $this->_run($data,$in,$cache); 139 }else{ 140 $ok = $this->_remote($data,$in,$cache); 141 } 142 if(!$ok) return false; 143 clearstatcache(); 144 } 145 146 // resized version 147 if($data['width']){ 148 $cache = media_resize_image($cache,'png',$data['width'],$data['height']); 149 } 150 151 // something went wrong, we're missing the file 152 if(!file_exists($cache)) return false; 153 154 return $cache; 155 } 156 157 /** 158 * Render the output remotely at ditaa.org 159 */ 160 function _remote($data,$in,$out){ 161 if(!file_exists($in)){ 162 if($conf['debug']){ 163 dbglog($in,'no such ditaa input file'); 164 } 165 return false; 166 } 167 168 $http = new DokuHTTPClient(); 169 $http->timeout=30; 170 171 $pass = array(); 172 $pass['scale'] = $data['scale']; 173 $pass['timeout'] = 25; 174 $pass['grid'] = io_readFile($in); 175 if(!$data['antialias']) $pass['A'] = 'on'; 176 if(!$data['shadow']) $pass['S'] = 'on'; 177 if($data['round']) $pass['r'] = 'on'; 178 if(!$data['edgesep']) $pass['E'] = 'on'; 179 180 $img = $http->post('http://ditaa.org/ditaa/render',$pass); 181 if(!$img) return false; 182 183 return io_saveFile($out,$img); 184 } 185 186 /** 187 * Run the ditaa Java program 188 */ 189 function _run($data,$in,$out) { 190 global $conf; 191 192 if(!file_exists($in)){ 193 if($conf['debug']){ 194 dbglog($in,'no such ditaa input file'); 195 } 196 return false; 197 } 198 199 $cmd = $this->getConf('java'); 200 $cmd .= ' -Djava.awt.headless=true -Dfile.encoding=UTF-8 -jar'; 201 $cmd .= ' '.escapeshellarg(dirname(__FILE__).'/ditaa/ditaa0_9.jar'); //ditaa jar 202 $cmd .= ' --encoding UTF-8'; 203 $cmd .= ' '.escapeshellarg($in); //input 204 $cmd .= ' '.escapeshellarg($out); //output 205 $cmd .= ' -s '.escapeshellarg($data['scale']); 206 if(!$data['antialias']) $cmd .= ' -A'; 207 if(!$data['shadow']) $cmd .= ' -S'; 208 if($data['round']) $cmd .= ' -r'; 209 if(!$data['edgesep']) $cmd .= ' -E'; 210 211 exec($cmd, $output, $error); 212 213 if ($error != 0){ 214 if($conf['debug']){ 215 dbglog(join("\n",$output),'ditaa command failed: '.$cmd); 216 } 217 return false; 218 } 219 220 return true; 221 } 222 223} 224 225