xref: /plugin/graphviz/syntax.php (revision 9d954370cc99a7ad567bfa05ad196b85cc4fda55)
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 and ODT support
87     */
88    function render($format, &$R, $data) {
89        if($format != 'xhtml') return;
90
91        $img = $this->_imgurl($data);
92        $R->doc .= '<img src="'.$img.'" class="media'.$data['align'].'" alt=""';
93        if($data['width'])  $R->doc .= ' width="'.$data['width'].'"';
94        if($data['height']) $R->doc .= ' height="'.$data['height'].'"';
95        if($data['align'] == 'right') $ret .= ' align="right"';
96        if($data['align'] == 'left')  $ret .= ' align="left"';
97        $R->doc .= '/>';
98    }
99
100    /**
101     * Build the image URL using either our own generator or
102     * the Google Chart API
103     */
104    function _imgurl($data){
105        if($this->getConf('path')){
106            // run graphviz on our own server
107            $img = DOKU_BASE.'lib/plugins/graphviz/img.php?'.buildURLparams($data,'&');
108        }else{
109            // go through google
110            $pass = array(
111                'cht' => 'gv:'.$data['layout'],
112                'chl' => $data['data'],
113            );
114            if($data['width'] && $data['height']){
115                 $pass['chs'] = $data['width'].'x'.$data['height'];
116            }
117
118            $img = 'http://chart.apis.google.com/chart?'.buildURLparams($pass,'&');
119            $img = ml($img,array('w'=>$data['width'],'h'=>$data['height']));
120        }
121        return $img;
122    }
123
124    /**
125     * Return path to created graphviz graph (local only)
126     */
127    function _imgfile($data){
128        $w = (int) $data['width'];
129        $h = (int) $data['height'];
130        unset($data['width']);
131        unset($data['height']);
132        unset($data['align']);
133
134        $cache = getcachename(join('x',array_values($data)),'graphviz.png');
135
136        // create the file if needed
137        if(!file_exists($cache)){
138            $this->_run($data,$cache);
139            clearstatcache();
140        }
141
142        // resized version
143        if($w) $cache = media_resize_image($cache,'png',$w,$h);
144
145        return $cache;
146    }
147
148    /**
149     * Run the graphviz program
150     */
151    function _run($data,$cache) {
152        global $conf;
153
154        $temp = tempnam($conf['tmpdir'],'graphviz_');
155        io_saveFile($temp,$data['data']);
156
157        $cmd  = $this->getConf('path');
158        $cmd .= ' -Tpng';
159        $cmd .= ' -K'.$data['layout'];
160        $cmd .= ' -o'.escapeshellarg($cache); //output
161        $cmd .= ' '.escapeshellarg($temp); //input
162
163        exec($cmd, $output, $error);
164        @unlink($temp);
165
166        if ($error != 0){
167            if($conf['debug']){
168                dbglog(join("\n",$output),'graphviz command failed: '.$cmd);
169            }
170            return false;
171        }
172        return true;
173    }
174
175}
176
177
178
179