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