1<?php 2/** 3 * graphviz-Plugin: Parses graphviz-blocks 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Carl-Christian Salvesen <calle@ioslo.net> 7 * @author Andreas Gohr <andi@splitbrain.org> 8 */ 9 10if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); 11require_once(DOKU_INC.'inc/init.php'); 12if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 13require_once(DOKU_PLUGIN.'syntax.php'); 14 15class syntax_plugin_graphviz 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 100; 36 } 37 38 /** 39 * Connect pattern to lexer 40 */ 41 function connectTo($mode) { 42 $this->Lexer->addSpecialPattern('<graphviz.*?>\n.*?\n</graphviz>',$mode,'plugin_graphviz'); 43 } 44 45 /** 46 * Handle the match 47 */ 48 function handle($match, $state, $pos, &$handler) { 49 $info = $this->getInfo(); 50 51 // prepare default data 52 $return = array( 53 'data' => '', 54 'width' => 0, 55 'height' => 0, 56 'layout' => 'dot', 57 'align' => '', 58 'version' => $info['date'], //force rebuild of images on update 59 ); 60 61 // prepare input 62 $lines = explode("\n",$match); 63 $conf = array_shift($lines); 64 array_pop($lines); 65 66 // match config options 67 if(preg_match('/\b(left|center|right)\b/i',$conf,$match)) $return['align'] = $match[1]; 68 if(preg_match('/\b(\d+)x(\d+)\b/',$conf,$match)){ 69 $return['width'] = $match[1]; 70 $return['height'] = $match[2]; 71 } 72 if(preg_match('/\b(dot|neato|twopi|circo|fdp)\b/i',$conf,$match)){ 73 $return['layout'] = strtolower($match[1]); 74 } 75 if(preg_match('/\bwidth=([0-9]+)\b/i', $conf,$match)) $return['width'] = $match[1]; 76 if(preg_match('/\bheight=([0-9]+)\b/i', $conf,$match)) $return['height'] = $match[1]; 77 78 $return['data'] = join("\n",$lines); 79 80 return $return; 81 } 82 83 /** 84 * Create output 85 * 86 * @todo latex support? 87 */ 88 function render($format, &$R, $data) { 89 if($format == 'xhtml'){ 90 $img = $this->_imgurl($data); 91 $R->doc .= '<img src="'.$img.'" class="media'.$data['align'].'" alt=""'; 92 if($data['width']) $R->doc .= ' width="'.$data['width'].'"'; 93 if($data['height']) $R->doc .= ' height="'.$data['height'].'"'; 94 if($data['align'] == 'right') $ret .= ' align="right"'; 95 if($data['align'] == 'left') $ret .= ' align="left"'; 96 $R->doc .= '/>'; 97 return true; 98 }elseif($format == 'odt'){ 99 $src = $this->_imgfile($data); 100 $R->_odtAddImage($src,$data['width'],$data['height'],$data['align']); 101 return true; 102 } 103 return false; 104 } 105 106 /** 107 * Build the image URL using either our own generator or 108 * the Google Chart API 109 */ 110 function _imgurl($data){ 111 if($this->getConf('path')){ 112 // run graphviz on our own server 113 $img = DOKU_BASE.'lib/plugins/graphviz/img.php?'.buildURLparams($data,'&'); 114 }else{ 115 // go through google 116 $pass = array( 117 'cht' => 'gv:'.$data['layout'], 118 'chl' => $data['data'], 119 ); 120 if($data['width'] && $data['height']){ 121 $pass['chs'] = $data['width'].'x'.$data['height']; 122 } 123 124 $img = 'http://chart.apis.google.com/chart?'.buildURLparams($pass,'&'); 125 $img = ml($img,array('w'=>$data['width'],'h'=>$data['height'])); 126 } 127 return $img; 128 } 129 130 /** 131 * Return path to created graphviz graph (local only) 132 */ 133 function _imgfile($data){ 134 $w = (int) $data['width']; 135 $h = (int) $data['height']; 136 unset($data['width']); 137 unset($data['height']); 138 unset($data['align']); 139 140 $cache = getcachename(join('x',array_values($data)),'graphviz.png'); 141 142 // create the file if needed 143 if(!file_exists($cache)){ 144 $this->_run($data,$cache); 145 clearstatcache(); 146 } 147 148 // resized version 149 if($w) $cache = media_resize_image($cache,'png',$w,$h); 150 151 return $cache; 152 } 153 154 /** 155 * Run the graphviz program 156 */ 157 function _run($data,$cache) { 158 global $conf; 159 160 $temp = tempnam($conf['tmpdir'],'graphviz_'); 161 io_saveFile($temp,$data['data']); 162 163 $cmd = $this->getConf('path'); 164 $cmd .= ' -Tpng'; 165 $cmd .= ' -K'.$data['layout']; 166 $cmd .= ' -o'.escapeshellarg($cache); //output 167 $cmd .= ' '.escapeshellarg($temp); //input 168 169 exec($cmd, $output, $error); 170 @unlink($temp); 171 172 if ($error != 0){ 173 if($conf['debug']){ 174 dbglog(join("\n",$output),'graphviz command failed: '.$cmd); 175 } 176 return false; 177 } 178 return true; 179 } 180 181} 182 183 184 185