1903f28d7SAndreas Gohr<?php 2903f28d7SAndreas Gohr/** 3903f28d7SAndreas Gohr * graphviz-Plugin: Parses graphviz-blocks 4903f28d7SAndreas Gohr * 5903f28d7SAndreas Gohr * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6903f28d7SAndreas Gohr * @author Carl-Christian Salvesen <calle@ioslo.net> 7517bd836SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 8903f28d7SAndreas Gohr */ 9903f28d7SAndreas Gohr 10903f28d7SAndreas Gohrif(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); 11903f28d7SAndreas Gohrrequire_once(DOKU_INC.'inc/init.php'); 12903f28d7SAndreas Gohrif(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 13903f28d7SAndreas Gohrrequire_once(DOKU_PLUGIN.'syntax.php'); 14903f28d7SAndreas Gohr 15903f28d7SAndreas Gohrclass syntax_plugin_graphviz extends DokuWiki_Syntax_Plugin { 16903f28d7SAndreas Gohr 17517bd836SAndreas Gohr /** 18517bd836SAndreas Gohr * What about paragraphs? 19517bd836SAndreas Gohr */ 20517bd836SAndreas Gohr function getPType(){ 21517bd836SAndreas Gohr return 'normal'; 22903f28d7SAndreas Gohr } 23903f28d7SAndreas Gohr 24903f28d7SAndreas Gohr /** 25903f28d7SAndreas Gohr * What kind of syntax are we? 26903f28d7SAndreas Gohr */ 27903f28d7SAndreas Gohr function getType(){ 28517bd836SAndreas Gohr return 'substition'; 29903f28d7SAndreas Gohr } 30903f28d7SAndreas Gohr 31903f28d7SAndreas Gohr /** 32903f28d7SAndreas Gohr * Where to sort in? 33903f28d7SAndreas Gohr */ 34903f28d7SAndreas Gohr function getSort(){ 35903f28d7SAndreas Gohr return 100; 36903f28d7SAndreas Gohr } 37903f28d7SAndreas Gohr 38903f28d7SAndreas Gohr /** 39903f28d7SAndreas Gohr * Connect pattern to lexer 40903f28d7SAndreas Gohr */ 41903f28d7SAndreas Gohr function connectTo($mode) { 42517bd836SAndreas Gohr $this->Lexer->addSpecialPattern('<graphviz.*?>\n.*?\n</graphviz>',$mode,'plugin_graphviz'); 43903f28d7SAndreas Gohr } 44903f28d7SAndreas Gohr 45903f28d7SAndreas Gohr /** 46903f28d7SAndreas Gohr * Handle the match 47903f28d7SAndreas Gohr */ 48517bd836SAndreas Gohr function handle($match, $state, $pos, &$handler) { 49517bd836SAndreas Gohr $info = $this->getInfo(); 50903f28d7SAndreas Gohr 5167682e69SAndreas Gohr // prepare default data 52517bd836SAndreas Gohr $return = array( 53517bd836SAndreas Gohr 'data' => '', 54517bd836SAndreas Gohr 'width' => 0, 55517bd836SAndreas Gohr 'height' => 0, 56517bd836SAndreas Gohr 'layout' => 'dot', 57517bd836SAndreas Gohr 'align' => '', 58517bd836SAndreas Gohr 'version' => $info['date'], //force rebuild of images on update 59517bd836SAndreas Gohr ); 60903f28d7SAndreas Gohr 61517bd836SAndreas Gohr // prepare input 62517bd836SAndreas Gohr $lines = explode("\n",$match); 63517bd836SAndreas Gohr $conf = array_shift($lines); 64517bd836SAndreas Gohr array_pop($lines); 65517bd836SAndreas Gohr 66517bd836SAndreas Gohr // match config options 67517bd836SAndreas Gohr if(preg_match('/\b(left|center|right)\b/i',$conf,$match)) $return['align'] = $match[1]; 68517bd836SAndreas Gohr if(preg_match('/\b(\d+)x(\d+)\b/',$conf,$match)){ 69517bd836SAndreas Gohr $return['width'] = $match[1]; 70517bd836SAndreas Gohr $return['height'] = $match[2]; 71903f28d7SAndreas Gohr } 72517bd836SAndreas Gohr if(preg_match('/\b(dot|neato|twopi|circo|fdp)\b/i',$conf,$match)){ 73517bd836SAndreas Gohr $return['layout'] = strtolower($match[1]); 74903f28d7SAndreas Gohr } 75517bd836SAndreas Gohr if(preg_match('/\bwidth=([0-9]+)\b/i', $conf,$match)) $return['width'] = $match[1]; 76517bd836SAndreas Gohr if(preg_match('/\bheight=([0-9]+)\b/i', $conf,$match)) $return['height'] = $match[1]; 77517bd836SAndreas Gohr 78517bd836SAndreas Gohr $return['data'] = join("\n",$lines); 79517bd836SAndreas Gohr 80517bd836SAndreas Gohr return $return; 81517bd836SAndreas Gohr } 82517bd836SAndreas Gohr 83903f28d7SAndreas Gohr /** 84903f28d7SAndreas Gohr * Create output 8567682e69SAndreas Gohr * 8667682e69SAndreas Gohr * @todo latex and ODT support 87903f28d7SAndreas Gohr */ 88517bd836SAndreas Gohr function render($format, &$R, $data) { 89517bd836SAndreas Gohr if($format != 'xhtml') return; 90517bd836SAndreas Gohr 9167682e69SAndreas Gohr $img = $this->_imgurl($data); 92517bd836SAndreas Gohr $R->doc .= '<img src="'.$img.'" class="media'.$data['align'].'" alt=""'; 93517bd836SAndreas Gohr if($data['width']) $R->doc .= ' width="'.$data['width'].'"'; 94517bd836SAndreas Gohr if($data['height']) $R->doc .= ' height="'.$data['height'].'"'; 95517bd836SAndreas Gohr if($data['align'] == 'right') $ret .= ' align="right"'; 96517bd836SAndreas Gohr if($data['align'] == 'left') $ret .= ' align="left"'; 97517bd836SAndreas Gohr $R->doc .= '/>'; 98517bd836SAndreas Gohr } 99517bd836SAndreas Gohr 10067682e69SAndreas Gohr /** 10167682e69SAndreas Gohr * Build the image URL using either our own generator or 10267682e69SAndreas Gohr * the Google Chart API 10367682e69SAndreas Gohr */ 10467682e69SAndreas Gohr function _imgurl($data){ 10567682e69SAndreas Gohr if($this->getConf('path')){ 10667682e69SAndreas Gohr // run graphviz on our own server 10767682e69SAndreas Gohr $img = DOKU_BASE.'lib/plugins/graphviz/img.php?'.buildURLparams($data,'&'); 10867682e69SAndreas Gohr }else{ 10967682e69SAndreas Gohr // go through google 11067682e69SAndreas Gohr $pass = array( 11167682e69SAndreas Gohr 'cht' => 'gv:'.$data['layout'], 11267682e69SAndreas Gohr 'chl' => $data['data'], 11367682e69SAndreas Gohr ); 11467682e69SAndreas Gohr if($data['width'] && $data['height']){ 11567682e69SAndreas Gohr $pass['chs'] = $data['width'].'x'.$data['height']; 11667682e69SAndreas Gohr } 11767682e69SAndreas Gohr 11867682e69SAndreas Gohr $img = 'http://chart.apis.google.com/chart?'.buildURLparams($pass,'&'); 11967682e69SAndreas Gohr $img = ml($img,array('w'=>$data['width'],'h'=>$data['height'])); 12067682e69SAndreas Gohr } 12167682e69SAndreas Gohr return $img; 12267682e69SAndreas Gohr } 123517bd836SAndreas Gohr 124517bd836SAndreas Gohr /** 125*9d954370SAndreas Gohr * Return path to created graphviz graph (local only) 126*9d954370SAndreas Gohr */ 127*9d954370SAndreas Gohr function _imgfile($data){ 128*9d954370SAndreas Gohr $w = (int) $data['width']; 129*9d954370SAndreas Gohr $h = (int) $data['height']; 130*9d954370SAndreas Gohr unset($data['width']); 131*9d954370SAndreas Gohr unset($data['height']); 132*9d954370SAndreas Gohr unset($data['align']); 133*9d954370SAndreas Gohr 134*9d954370SAndreas Gohr $cache = getcachename(join('x',array_values($data)),'graphviz.png'); 135*9d954370SAndreas Gohr 136*9d954370SAndreas Gohr // create the file if needed 137*9d954370SAndreas Gohr if(!file_exists($cache)){ 138*9d954370SAndreas Gohr $this->_run($data,$cache); 139*9d954370SAndreas Gohr clearstatcache(); 140*9d954370SAndreas Gohr } 141*9d954370SAndreas Gohr 142*9d954370SAndreas Gohr // resized version 143*9d954370SAndreas Gohr if($w) $cache = media_resize_image($cache,'png',$w,$h); 144*9d954370SAndreas Gohr 145*9d954370SAndreas Gohr return $cache; 146*9d954370SAndreas Gohr } 147*9d954370SAndreas Gohr 148*9d954370SAndreas Gohr /** 149517bd836SAndreas Gohr * Run the graphviz program 150517bd836SAndreas Gohr */ 151517bd836SAndreas Gohr function _run($data,$cache) { 152903f28d7SAndreas Gohr global $conf; 153903f28d7SAndreas Gohr 154517bd836SAndreas Gohr $temp = tempnam($conf['tmpdir'],'graphviz_'); 155517bd836SAndreas Gohr io_saveFile($temp,$data['data']); 156903f28d7SAndreas Gohr 157517bd836SAndreas Gohr $cmd = $this->getConf('path'); 158517bd836SAndreas Gohr $cmd .= ' -Tpng'; 159517bd836SAndreas Gohr $cmd .= ' -K'.$data['layout']; 160517bd836SAndreas Gohr $cmd .= ' -o'.escapeshellarg($cache); //output 161517bd836SAndreas Gohr $cmd .= ' '.escapeshellarg($temp); //input 162903f28d7SAndreas Gohr 163517bd836SAndreas Gohr exec($cmd, $output, $error); 164517bd836SAndreas Gohr @unlink($temp); 165903f28d7SAndreas Gohr 166517bd836SAndreas Gohr if ($error != 0){ 167517bd836SAndreas Gohr if($conf['debug']){ 168517bd836SAndreas Gohr dbglog(join("\n",$output),'graphviz command failed: '.$cmd); 169903f28d7SAndreas Gohr } 170903f28d7SAndreas Gohr return false; 171903f28d7SAndreas Gohr } 172517bd836SAndreas Gohr return true; 173903f28d7SAndreas Gohr } 174903f28d7SAndreas Gohr 175903f28d7SAndreas Gohr} 176903f28d7SAndreas Gohr 177517bd836SAndreas Gohr 178517bd836SAndreas Gohr 179