1a34ed36bSDennis Ploeger<?php 2a34ed36bSDennis Ploeger/** 3a34ed36bSDennis Ploeger * Ditaa-Plugin: Converts Ascii-Flowcharts into a png-File 4a34ed36bSDennis Ploeger * 5a34ed36bSDennis Ploeger * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6a34ed36bSDennis Ploeger * @author Dennis Ploeger <develop [at] dieploegers [dot] de> 7a34ed36bSDennis Ploeger * @author Christoph Mertins <c [dot] mertins [at] gmail [dot] com> 8*c5eb4ae0SGerry Weißbach * @author Gerry Weißbach / i-net software <tools [at] inetsoftware [dot] de> 9d402f512SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 10a34ed36bSDennis Ploeger */ 11a34ed36bSDennis Ploeger 12a34ed36bSDennis Ploegerif(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); 13a34ed36bSDennis Ploegerif(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 14a34ed36bSDennis Ploegerrequire_once(DOKU_PLUGIN.'syntax.php'); 15a34ed36bSDennis Ploeger 16a34ed36bSDennis Ploegerclass syntax_plugin_ditaa extends DokuWiki_Syntax_Plugin { 17a34ed36bSDennis Ploeger 18a34ed36bSDennis Ploeger /** 19a34ed36bSDennis Ploeger * What about paragraphs? 20a34ed36bSDennis Ploeger */ 21a34ed36bSDennis Ploeger function getPType(){ 22a34ed36bSDennis Ploeger return 'normal'; 23a34ed36bSDennis Ploeger } 24a34ed36bSDennis Ploeger 25a34ed36bSDennis Ploeger /** 26a34ed36bSDennis Ploeger * What kind of syntax are we? 27a34ed36bSDennis Ploeger */ 28a34ed36bSDennis Ploeger function getType(){ 29a34ed36bSDennis Ploeger return 'substition'; 30a34ed36bSDennis Ploeger } 31a34ed36bSDennis Ploeger 32a34ed36bSDennis Ploeger /** 33a34ed36bSDennis Ploeger * Where to sort in? 34a34ed36bSDennis Ploeger */ 35a34ed36bSDennis Ploeger function getSort(){ 36a34ed36bSDennis Ploeger return 200; 37a34ed36bSDennis Ploeger } 38a34ed36bSDennis Ploeger 39a34ed36bSDennis Ploeger /** 4072a2bf1dSAndreas Gohr * Connect pattern to lexer 41a34ed36bSDennis Ploeger */ 42a34ed36bSDennis Ploeger 43a34ed36bSDennis Ploeger function connectTo($mode) { 4472a2bf1dSAndreas Gohr $this->Lexer->addSpecialPattern('<ditaa.*?>\n.*?\n</ditaa>',$mode,'plugin_ditaa'); 45a34ed36bSDennis Ploeger } 46a34ed36bSDennis Ploeger 47a34ed36bSDennis Ploeger /** 48a34ed36bSDennis Ploeger * Handle the match 49a34ed36bSDennis Ploeger */ 5072a2bf1dSAndreas Gohr function handle($match, $state, $pos, &$handler) { 512a956e66SAndreas Gohr $info = $this->getInfo(); 522a956e66SAndreas Gohr 5372a2bf1dSAndreas Gohr // prepare default data 5472a2bf1dSAndreas Gohr $return = array( 5572a2bf1dSAndreas Gohr 'width' => 0, 5672a2bf1dSAndreas Gohr 'height' => 0, 5772a2bf1dSAndreas Gohr 'antialias' => true, 5872a2bf1dSAndreas Gohr 'edgesep' => true, 5972a2bf1dSAndreas Gohr 'round' => false, 6072a2bf1dSAndreas Gohr 'shadow' => true, 6172a2bf1dSAndreas Gohr 'scale' => 1, 6272a2bf1dSAndreas Gohr 'align' => '', 632a956e66SAndreas Gohr 'version' => $info['date'], //forece rebuild of images on update 6472a2bf1dSAndreas Gohr ); 65a34ed36bSDennis Ploeger 66a34ed36bSDennis Ploeger 6772a2bf1dSAndreas Gohr // prepare input 6872a2bf1dSAndreas Gohr $lines = explode("\n",$match); 6972a2bf1dSAndreas Gohr $conf = array_shift($lines); 7072a2bf1dSAndreas Gohr array_pop($lines); 7172a2bf1dSAndreas Gohr 7272a2bf1dSAndreas Gohr // match config options 7372a2bf1dSAndreas Gohr if(preg_match('/\b(left|center|right)\b/i',$conf,$match)) $return['align'] = $match[1]; 7472a2bf1dSAndreas Gohr if(preg_match('/\b(\d+)x(\d+)\b/',$conf,$match)){ 7572a2bf1dSAndreas Gohr $return['width'] = $match[1]; 7672a2bf1dSAndreas Gohr $return['height'] = $match[2]; 77a34ed36bSDennis Ploeger } 782a956e66SAndreas Gohr if(preg_match('/\b(\d+(\.\d+)?)X\b/',$conf,$match)) $return['scale'] = $match[1]; 7972a2bf1dSAndreas Gohr if(preg_match('/\bwidth=([0-9]+)\b/i', $conf,$match)) $return['width'] = $match[1]; 8072a2bf1dSAndreas Gohr if(preg_match('/\bheight=([0-9]+)\b/i', $conf,$match)) $return['height'] = $match[1]; 8172a2bf1dSAndreas Gohr // match boolean toggles 8272a2bf1dSAndreas Gohr if(preg_match_all('/\b(no)?(antialias|edgesep|round|shadow)\b/i',$conf,$matches,PREG_SET_ORDER)){ 8372a2bf1dSAndreas Gohr foreach($matches as $match){ 8472a2bf1dSAndreas Gohr $return[$match[2]] = ! $match[1]; 8572a2bf1dSAndreas Gohr } 8672a2bf1dSAndreas Gohr } 8772a2bf1dSAndreas Gohr 8805cbae88SAndreas Gohr $input = join("\n",$lines); 8905cbae88SAndreas Gohr $return['md5'] = md5($input); // we only pass a hash around 9005cbae88SAndreas Gohr 9105cbae88SAndreas Gohr // store input for later use 9205cbae88SAndreas Gohr io_saveFile($this->_cachename($return,'txt'),$input); 9372a2bf1dSAndreas Gohr 9472a2bf1dSAndreas Gohr return $return; 95a34ed36bSDennis Ploeger } 96a34ed36bSDennis Ploeger 97a34ed36bSDennis Ploeger /** 98*c5eb4ae0SGerry Weißbach * Prepares the Data that is used for the cache name 99*c5eb4ae0SGerry Weißbach * Width, height and scale are left out. 100*c5eb4ae0SGerry Weißbach * Ensures sanity. 101*c5eb4ae0SGerry Weißbach */ 102*c5eb4ae0SGerry Weißbach function _prepareData($input) 103*c5eb4ae0SGerry Weißbach { 104*c5eb4ae0SGerry Weißbach $output = array(); 105*c5eb4ae0SGerry Weißbach foreach( $input as $key => $value ) { 106*c5eb4ae0SGerry Weißbach switch ($key) { 107*c5eb4ae0SGerry Weißbach case 'scale': 108*c5eb4ae0SGerry Weißbach case 'antialias': 109*c5eb4ae0SGerry Weißbach case 'edgesep': 110*c5eb4ae0SGerry Weißbach case 'round': 111*c5eb4ae0SGerry Weißbach case 'shadow': 112*c5eb4ae0SGerry Weißbach case 'md5': 113*c5eb4ae0SGerry Weißbach $output[$key] = $value; 114*c5eb4ae0SGerry Weißbach }; 115*c5eb4ae0SGerry Weißbach } 116*c5eb4ae0SGerry Weißbach } 117*c5eb4ae0SGerry Weißbach 118*c5eb4ae0SGerry Weißbach /** 11995615d6cSAndreas Gohr * Cache file is based on parameters that influence the result image 12005cbae88SAndreas Gohr */ 12105cbae88SAndreas Gohr function _cachename($data,$ext){ 122*c5eb4ae0SGerry Weißbach $data = $this->_prepareData($data); 12305cbae88SAndreas Gohr return getcachename(join('x',array_values($data)),'.ditaa.'.$ext); 12405cbae88SAndreas Gohr } 12505cbae88SAndreas Gohr 12605cbae88SAndreas Gohr /** 12795615d6cSAndreas Gohr * Create output 12895615d6cSAndreas Gohr */ 12995615d6cSAndreas Gohr function render($format, &$R, $data) { 13095615d6cSAndreas Gohr if($format == 'xhtml'){ 13195615d6cSAndreas Gohr $img = DOKU_BASE.'lib/plugins/ditaa/img.php?'.buildURLparams($data); 13295615d6cSAndreas Gohr $R->doc .= '<img src="'.$img.'" class="media'.$data['align'].'" alt=""'; 13395615d6cSAndreas Gohr if($data['width']) $R->doc .= ' width="'.$data['width'].'"'; 13495615d6cSAndreas Gohr if($data['height']) $R->doc .= ' height="'.$data['height'].'"'; 135c77baa73SWilli Schönborn if($data['align'] == 'right') $R->doc .= ' align="right"'; 136c77baa73SWilli Schönborn if($data['align'] == 'left') $R->doc .= ' align="left"'; 13795615d6cSAndreas Gohr $R->doc .= '/>'; 13895615d6cSAndreas Gohr return true; 13995615d6cSAndreas Gohr }elseif($format == 'odt'){ 14095615d6cSAndreas Gohr $src = $this->_imgfile($data); 14195615d6cSAndreas Gohr $R->_odtAddImage($src,$data['width'],$data['height'],$data['align']); 14295615d6cSAndreas Gohr return true; 14395615d6cSAndreas Gohr } 14495615d6cSAndreas Gohr return false; 14595615d6cSAndreas Gohr } 14695615d6cSAndreas Gohr 14795615d6cSAndreas Gohr 14895615d6cSAndreas Gohr /** 14995615d6cSAndreas Gohr * Return path to the rendered image on our local system 15095615d6cSAndreas Gohr */ 15195615d6cSAndreas Gohr function _imgfile($data){ 15295615d6cSAndreas Gohr $cache = $this->_cachename($data,'png'); 15395615d6cSAndreas Gohr 15495615d6cSAndreas Gohr // create the file if needed 15595615d6cSAndreas Gohr if(!file_exists($cache)){ 15695615d6cSAndreas Gohr $in = $this->_cachename($data,'txt'); 15795615d6cSAndreas Gohr if($this->getConf('java')){ 15895615d6cSAndreas Gohr $ok = $this->_run($data,$in,$cache); 15995615d6cSAndreas Gohr }else{ 16095615d6cSAndreas Gohr $ok = $this->_remote($data,$in,$cache); 16195615d6cSAndreas Gohr } 16295615d6cSAndreas Gohr if(!$ok) return false; 16395615d6cSAndreas Gohr clearstatcache(); 16495615d6cSAndreas Gohr } 16595615d6cSAndreas Gohr 16695615d6cSAndreas Gohr // resized version 16795615d6cSAndreas Gohr if($data['width']){ 16895615d6cSAndreas Gohr $cache = media_resize_image($cache,'png',$data['width'],$data['height']); 16995615d6cSAndreas Gohr } 17095615d6cSAndreas Gohr 17195615d6cSAndreas Gohr // something went wrong, we're missing the file 17295615d6cSAndreas Gohr if(!file_exists($cache)) return false; 17395615d6cSAndreas Gohr 17495615d6cSAndreas Gohr return $cache; 17595615d6cSAndreas Gohr } 17695615d6cSAndreas Gohr 17795615d6cSAndreas Gohr /** 17805cbae88SAndreas Gohr * Render the output remotely at ditaa.org 17905cbae88SAndreas Gohr */ 18005cbae88SAndreas Gohr function _remote($data,$in,$out){ 18195615d6cSAndreas Gohr if(!file_exists($in)){ 18295615d6cSAndreas Gohr if($conf['debug']){ 18395615d6cSAndreas Gohr dbglog($in,'no such ditaa input file'); 18495615d6cSAndreas Gohr } 18595615d6cSAndreas Gohr return false; 18695615d6cSAndreas Gohr } 18795615d6cSAndreas Gohr 18805cbae88SAndreas Gohr $http = new DokuHTTPClient(); 18905cbae88SAndreas Gohr $http->timeout=30; 19005cbae88SAndreas Gohr 19105cbae88SAndreas Gohr $pass = array(); 19205cbae88SAndreas Gohr $pass['scale'] = $data['scale']; 19305cbae88SAndreas Gohr $pass['timeout'] = 25; 19405cbae88SAndreas Gohr $pass['grid'] = io_readFile($in); 19505cbae88SAndreas Gohr if(!$data['antialias']) $pass['A'] = 'on'; 19605cbae88SAndreas Gohr if(!$data['shadow']) $pass['S'] = 'on'; 19705cbae88SAndreas Gohr if($data['round']) $pass['r'] = 'on'; 19805cbae88SAndreas Gohr if(!$data['edgesep']) $pass['E'] = 'on'; 19905cbae88SAndreas Gohr 20005cbae88SAndreas Gohr $img = $http->post('http://ditaa.org/ditaa/render',$pass); 20105cbae88SAndreas Gohr if(!$img) return false; 20205cbae88SAndreas Gohr 20395615d6cSAndreas Gohr return io_saveFile($out,$img); 20405cbae88SAndreas Gohr } 20505cbae88SAndreas Gohr 206a34ed36bSDennis Ploeger /** 2072a956e66SAndreas Gohr * Run the ditaa Java program 208a34ed36bSDennis Ploeger */ 20905cbae88SAndreas Gohr function _run($data,$in,$out) { 2102a956e66SAndreas Gohr global $conf; 211a34ed36bSDennis Ploeger 21205cbae88SAndreas Gohr if(!file_exists($in)){ 21305cbae88SAndreas Gohr if($conf['debug']){ 21405cbae88SAndreas Gohr dbglog($in,'no such ditaa input file'); 21505cbae88SAndreas Gohr } 21605cbae88SAndreas Gohr return false; 21705cbae88SAndreas Gohr } 218a34ed36bSDennis Ploeger 2192a956e66SAndreas Gohr $cmd = $this->getConf('java'); 22036721e14SAndreas Gohr $cmd .= ' -Djava.awt.headless=true -Dfile.encoding=UTF-8 -jar'; 2212a956e66SAndreas Gohr $cmd .= ' '.escapeshellarg(dirname(__FILE__).'/ditaa/ditaa0_9.jar'); //ditaa jar 22236721e14SAndreas Gohr $cmd .= ' --encoding UTF-8'; 22305cbae88SAndreas Gohr $cmd .= ' '.escapeshellarg($in); //input 22405cbae88SAndreas Gohr $cmd .= ' '.escapeshellarg($out); //output 2252a956e66SAndreas Gohr $cmd .= ' -s '.escapeshellarg($data['scale']); 2262a956e66SAndreas Gohr if(!$data['antialias']) $cmd .= ' -A'; 2272a956e66SAndreas Gohr if(!$data['shadow']) $cmd .= ' -S'; 2282a956e66SAndreas Gohr if($data['round']) $cmd .= ' -r'; 2292a956e66SAndreas Gohr if(!$data['edgesep']) $cmd .= ' -E'; 230a34ed36bSDennis Ploeger 231a34ed36bSDennis Ploeger exec($cmd, $output, $error); 232a34ed36bSDennis Ploeger 2333c74ed32SAndreas Gohr if ($error != 0){ 2343c74ed32SAndreas Gohr if($conf['debug']){ 2353c74ed32SAndreas Gohr dbglog(join("\n",$output),'ditaa command failed: '.$cmd); 2363c74ed32SAndreas Gohr } 2373c74ed32SAndreas Gohr return false; 2383c74ed32SAndreas Gohr } 23905cbae88SAndreas Gohr 240a34ed36bSDennis Ploeger return true; 241a34ed36bSDennis Ploeger } 242a34ed36bSDennis Ploeger 243a34ed36bSDennis Ploeger} 244a34ed36bSDennis Ploeger 245