xref: /plugin/graphviz/syntax.php (revision fb9a529df399e2fa9f312b28a234fffb8da4cfc5)
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
10*fb9a529dSAndreas Gohr
11903f28d7SAndreas Gohrif(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
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(){
35*fb9a529dSAndreas Gohr        return 200;
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                        'width'     => 0,
54517bd836SAndreas Gohr                        'height'    => 0,
55517bd836SAndreas Gohr                        'layout'    => 'dot',
56517bd836SAndreas Gohr                        'align'     => '',
57517bd836SAndreas Gohr                        'version'   => $info['date'], //force rebuild of images on update
58517bd836SAndreas Gohr                       );
59903f28d7SAndreas Gohr
60517bd836SAndreas Gohr        // prepare input
61517bd836SAndreas Gohr        $lines = explode("\n",$match);
62517bd836SAndreas Gohr        $conf = array_shift($lines);
63517bd836SAndreas Gohr        array_pop($lines);
64517bd836SAndreas Gohr
65517bd836SAndreas Gohr        // match config options
66517bd836SAndreas Gohr        if(preg_match('/\b(left|center|right)\b/i',$conf,$match)) $return['align'] = $match[1];
67517bd836SAndreas Gohr        if(preg_match('/\b(\d+)x(\d+)\b/',$conf,$match)){
68517bd836SAndreas Gohr            $return['width']  = $match[1];
69517bd836SAndreas Gohr            $return['height'] = $match[2];
70903f28d7SAndreas Gohr        }
71517bd836SAndreas Gohr        if(preg_match('/\b(dot|neato|twopi|circo|fdp)\b/i',$conf,$match)){
72517bd836SAndreas Gohr            $return['layout'] = strtolower($match[1]);
73903f28d7SAndreas Gohr        }
74517bd836SAndreas Gohr        if(preg_match('/\bwidth=([0-9]+)\b/i', $conf,$match)) $return['width'] = $match[1];
75517bd836SAndreas Gohr        if(preg_match('/\bheight=([0-9]+)\b/i', $conf,$match)) $return['height'] = $match[1];
76517bd836SAndreas Gohr
77*fb9a529dSAndreas Gohr
78*fb9a529dSAndreas Gohr        $input = join("\n",$lines);
79*fb9a529dSAndreas Gohr        $return['md5'] = md5($input); // we only pass a hash around
80*fb9a529dSAndreas Gohr
81*fb9a529dSAndreas Gohr        // store input for later use
82*fb9a529dSAndreas Gohr        io_saveFile($this->_cachename($return,'txt'),$input);
83517bd836SAndreas Gohr
84517bd836SAndreas Gohr        return $return;
85517bd836SAndreas Gohr    }
86517bd836SAndreas Gohr
87903f28d7SAndreas Gohr    /**
88*fb9a529dSAndreas Gohr     * Cache file is based on parameters that influence the result image
89*fb9a529dSAndreas Gohr     */
90*fb9a529dSAndreas Gohr    function _cachename($data,$ext){
91*fb9a529dSAndreas Gohr        unset($data['width']);
92*fb9a529dSAndreas Gohr        unset($data['height']);
93*fb9a529dSAndreas Gohr        unset($data['align']);
94*fb9a529dSAndreas Gohr        return getcachename(join('x',array_values($data)),'.graphviz.'.$ext);
95*fb9a529dSAndreas Gohr    }
96*fb9a529dSAndreas Gohr
97*fb9a529dSAndreas Gohr    /**
98903f28d7SAndreas Gohr     * Create output
99903f28d7SAndreas Gohr     */
100517bd836SAndreas Gohr    function render($format, &$R, $data) {
101eb42ed8aSAndreas Gohr        if($format == 'xhtml'){
102*fb9a529dSAndreas Gohr            $img = DOKU_BASE.'lib/plugins/graphviz/img.php?'.buildURLparams($data);
103517bd836SAndreas Gohr            $R->doc .= '<img src="'.$img.'" class="media'.$data['align'].'" alt=""';
104517bd836SAndreas Gohr            if($data['width'])  $R->doc .= ' width="'.$data['width'].'"';
105517bd836SAndreas Gohr            if($data['height']) $R->doc .= ' height="'.$data['height'].'"';
106517bd836SAndreas Gohr            if($data['align'] == 'right') $ret .= ' align="right"';
107517bd836SAndreas Gohr            if($data['align'] == 'left')  $ret .= ' align="left"';
108517bd836SAndreas Gohr            $R->doc .= '/>';
109eb42ed8aSAndreas Gohr            return true;
110eb42ed8aSAndreas Gohr        }elseif($format == 'odt'){
111eb42ed8aSAndreas Gohr            $src = $this->_imgfile($data);
112eb42ed8aSAndreas Gohr            $R->_odtAddImage($src,$data['width'],$data['height'],$data['align']);
113eb42ed8aSAndreas Gohr            return true;
114eb42ed8aSAndreas Gohr        }
115eb42ed8aSAndreas Gohr        return false;
116517bd836SAndreas Gohr    }
117517bd836SAndreas Gohr
11867682e69SAndreas Gohr    /**
119*fb9a529dSAndreas Gohr     * Return path to the rendered image on our local system
1209d954370SAndreas Gohr     */
1219d954370SAndreas Gohr    function _imgfile($data){
122*fb9a529dSAndreas Gohr        $cache  = $this->_cachename($data,'png');
1239d954370SAndreas Gohr
1249d954370SAndreas Gohr        // create the file if needed
1259d954370SAndreas Gohr        if(!file_exists($cache)){
126*fb9a529dSAndreas Gohr            $in = $this->_cachename($data,'txt');
127*fb9a529dSAndreas Gohr            if($this->getConf('path')){
128*fb9a529dSAndreas Gohr                $ok = $this->_run($data,$in,$cache);
129*fb9a529dSAndreas Gohr            }else{
130*fb9a529dSAndreas Gohr                $ok = $this->_remote($data,$in,$cache);
131*fb9a529dSAndreas Gohr            }
132*fb9a529dSAndreas Gohr            if(!$ok) return false;
1339d954370SAndreas Gohr            clearstatcache();
1349d954370SAndreas Gohr        }
1359d954370SAndreas Gohr
1369d954370SAndreas Gohr        // resized version
137*fb9a529dSAndreas Gohr        if($data['width']){
138*fb9a529dSAndreas Gohr            $cache = media_resize_image($cache,'png',$data['width'],$data['height']);
139*fb9a529dSAndreas Gohr        }
140*fb9a529dSAndreas Gohr
141*fb9a529dSAndreas Gohr        // something went wrong, we're missing the file
142*fb9a529dSAndreas Gohr        if(!file_exists($cache)) return false;
1439d954370SAndreas Gohr
1449d954370SAndreas Gohr        return $cache;
1459d954370SAndreas Gohr    }
1469d954370SAndreas Gohr
1479d954370SAndreas Gohr    /**
148*fb9a529dSAndreas Gohr     * Render the output remotely at google
149*fb9a529dSAndreas Gohr     */
150*fb9a529dSAndreas Gohr    function _remote($data,$in,$out){
151*fb9a529dSAndreas Gohr        if(!file_exists($in)){
152*fb9a529dSAndreas Gohr            if($conf['debug']){
153*fb9a529dSAndreas Gohr                dbglog($in,'no such graphviz input file');
154*fb9a529dSAndreas Gohr            }
155*fb9a529dSAndreas Gohr            return false;
156*fb9a529dSAndreas Gohr        }
157*fb9a529dSAndreas Gohr
158*fb9a529dSAndreas Gohr        $http = new DokuHTTPClient();
159*fb9a529dSAndreas Gohr        $http->timeout=30;
160*fb9a529dSAndreas Gohr
161*fb9a529dSAndreas Gohr        $pass = array();
162*fb9a529dSAndreas Gohr        $pass['cht'] = 'gv:'.$data['layout'];
163*fb9a529dSAndreas Gohr        $pass['chl'] = io_readFile($in);
164*fb9a529dSAndreas Gohr
165*fb9a529dSAndreas Gohr        $img = $http->post('http://chart.apis.google.com/chart',$pass,'&');
166*fb9a529dSAndreas Gohr        if(!$img) return false;
167*fb9a529dSAndreas Gohr
168*fb9a529dSAndreas Gohr        return io_saveFile($out,$img);
169*fb9a529dSAndreas Gohr    }
170*fb9a529dSAndreas Gohr
171*fb9a529dSAndreas Gohr    /**
172517bd836SAndreas Gohr     * Run the graphviz program
173517bd836SAndreas Gohr     */
174*fb9a529dSAndreas Gohr    function _run($data,$in,$out) {
175903f28d7SAndreas Gohr        global $conf;
176903f28d7SAndreas Gohr
177*fb9a529dSAndreas Gohr        if(!file_exists($in)){
178*fb9a529dSAndreas Gohr            if($conf['debug']){
179*fb9a529dSAndreas Gohr                dbglog($in,'no such graphviz input file');
180*fb9a529dSAndreas Gohr            }
181*fb9a529dSAndreas Gohr            return false;
182*fb9a529dSAndreas Gohr        }
183903f28d7SAndreas Gohr
184517bd836SAndreas Gohr        $cmd  = $this->getConf('path');
185517bd836SAndreas Gohr        $cmd .= ' -Tpng';
186517bd836SAndreas Gohr        $cmd .= ' -K'.$data['layout'];
187*fb9a529dSAndreas Gohr        $cmd .= ' -o'.escapeshellarg($out); //output
188*fb9a529dSAndreas Gohr        $cmd .= ' '.escapeshellarg($in); //input
189903f28d7SAndreas Gohr
190517bd836SAndreas Gohr        exec($cmd, $output, $error);
191903f28d7SAndreas Gohr
192517bd836SAndreas Gohr        if ($error != 0){
193517bd836SAndreas Gohr            if($conf['debug']){
194517bd836SAndreas Gohr                dbglog(join("\n",$output),'graphviz command failed: '.$cmd);
195903f28d7SAndreas Gohr            }
196903f28d7SAndreas Gohr            return false;
197903f28d7SAndreas Gohr        }
198517bd836SAndreas Gohr        return true;
199903f28d7SAndreas Gohr    }
200903f28d7SAndreas Gohr
201903f28d7SAndreas Gohr}
202903f28d7SAndreas Gohr
203517bd836SAndreas Gohr
204517bd836SAndreas Gohr
205