xref: /plugin/ditaa/syntax.php (revision 38c9279020ea3c3abc0a18e7d236f87252b3f01b)
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>
8c5eb4ae0SGerry 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'     => '',
63*38c92790SGerry Weißbach                        'version'   => $info['date'], //force 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    /**
98c5eb4ae0SGerry Weißbach     * Prepares the Data that is used for the cache name
99c5eb4ae0SGerry Weißbach     * Width, height and scale are left out.
100c5eb4ae0SGerry Weißbach     * Ensures sanity.
101c5eb4ae0SGerry Weißbach     */
102c5eb4ae0SGerry Weißbach    function _prepareData($input)
103c5eb4ae0SGerry Weißbach    {
104c5eb4ae0SGerry Weißbach        $output = array();
105c5eb4ae0SGerry Weißbach        foreach( $input as $key => $value ) {
106c5eb4ae0SGerry Weißbach            switch ($key) {
107c5eb4ae0SGerry Weißbach                case 'scale':
108c5eb4ae0SGerry Weißbach                case 'antialias':
109c5eb4ae0SGerry Weißbach                case 'edgesep':
110c5eb4ae0SGerry Weißbach                case 'round':
111c5eb4ae0SGerry Weißbach                case 'shadow':
112c5eb4ae0SGerry Weißbach                    $output[$key] = $value;
113c5eb4ae0SGerry Weißbach            };
114c5eb4ae0SGerry Weißbach        }
115*38c92790SGerry Weißbach
116*38c92790SGerry Weißbach        ksort($output);
117*38c92790SGerry Weißbach        return $output;
118c5eb4ae0SGerry Weißbach    }
119c5eb4ae0SGerry Weißbach
120c5eb4ae0SGerry Weißbach    /**
12195615d6cSAndreas Gohr     * Cache file is based on parameters that influence the result image
12205cbae88SAndreas Gohr     */
12305cbae88SAndreas Gohr    function _cachename($data,$ext){
124c5eb4ae0SGerry Weißbach		$data = $this->_prepareData($data);
12505cbae88SAndreas Gohr        return getcachename(join('x',array_values($data)),'.ditaa.'.$ext);
12605cbae88SAndreas Gohr    }
12705cbae88SAndreas Gohr
12805cbae88SAndreas Gohr    /**
12995615d6cSAndreas Gohr     * Create output
13095615d6cSAndreas Gohr     */
13195615d6cSAndreas Gohr    function render($format, &$R, $data) {
132*38c92790SGerry Weißbach        global $ID;
13395615d6cSAndreas Gohr        if($format == 'xhtml'){
134*38c92790SGerry Weißbach
135*38c92790SGerry Weißbach            // Only use the md5 key
136*38c92790SGerry Weißbach            $img = ml($ID, array('ditaa' => $data['md5']));
13795615d6cSAndreas Gohr            $R->doc .= '<img src="'.$img.'" class="media'.$data['align'].'" alt=""';
13895615d6cSAndreas Gohr            if($data['width'])  $R->doc .= ' width="'.$data['width'].'"';
13995615d6cSAndreas Gohr            if($data['height']) $R->doc .= ' height="'.$data['height'].'"';
140c77baa73SWilli Schönborn            if($data['align'] == 'right') $R->doc .= ' align="right"';
141c77baa73SWilli Schönborn            if($data['align'] == 'left')  $R->doc .= ' align="left"';
14295615d6cSAndreas Gohr            $R->doc .= '/>';
14395615d6cSAndreas Gohr            return true;
14495615d6cSAndreas Gohr        }else if($format == 'odt'){
14595615d6cSAndreas Gohr            $src = $this->_imgfile($data);
14695615d6cSAndreas Gohr            $R->_odtAddImage($src,$data['width'],$data['height'],$data['align']);
14795615d6cSAndreas Gohr            return true;
148*38c92790SGerry Weißbach        }else if($format == 'metadata'){
149*38c92790SGerry Weißbach            // Save for later use
150*38c92790SGerry Weißbach            $R->meta['ditaa'][$data['md5']] = $data;
151*38c92790SGerry Weißbach            return true;
15295615d6cSAndreas Gohr        }
15395615d6cSAndreas Gohr        return false;
15495615d6cSAndreas Gohr    }
15595615d6cSAndreas Gohr
15695615d6cSAndreas Gohr
15795615d6cSAndreas Gohr    /**
15895615d6cSAndreas Gohr     * Return path to the rendered image on our local system
15995615d6cSAndreas Gohr     */
160*38c92790SGerry Weißbach    function _imgfile($id, $data, $secondTry=false){
161*38c92790SGerry Weißbach
16295615d6cSAndreas Gohr        $cache  = $this->_cachename($data,'png');
16395615d6cSAndreas Gohr
16495615d6cSAndreas Gohr        // create the file if needed
16595615d6cSAndreas Gohr        if(!file_exists($cache)){
16695615d6cSAndreas Gohr            $in = $this->_cachename($data,'txt');
167*38c92790SGerry Weißbach            // If this is nt yet here, force geting instructions and writing the thing back.
168*38c92790SGerry Weißbach            if ( $secondTry != true && !file_exists($in)) {
169*38c92790SGerry Weißbach                p_get_instructions( io_readFile( wikiFN( $id) ) );
170*38c92790SGerry Weißbach                return $this->_imgfile($id, $data, true);
171*38c92790SGerry Weißbach            }
172*38c92790SGerry Weißbach
17395615d6cSAndreas Gohr            if($this->getConf('java')){
17495615d6cSAndreas Gohr                $ok = $this->_run($data,$in,$cache);
17595615d6cSAndreas Gohr            }else{
17695615d6cSAndreas Gohr                $ok = $this->_remote($data,$in,$cache);
17795615d6cSAndreas Gohr            }
17895615d6cSAndreas Gohr            if(!$ok) return false;
17995615d6cSAndreas Gohr            clearstatcache();
18095615d6cSAndreas Gohr        }
18195615d6cSAndreas Gohr
18295615d6cSAndreas Gohr        // resized version
18395615d6cSAndreas Gohr        if($data['width']){
18495615d6cSAndreas Gohr            $cache = media_resize_image($cache,'png',$data['width'],$data['height']);
18595615d6cSAndreas Gohr        }
18695615d6cSAndreas Gohr
18795615d6cSAndreas Gohr        // something went wrong, we're missing the file
18895615d6cSAndreas Gohr        if(!file_exists($cache)) return false;
18995615d6cSAndreas Gohr
19095615d6cSAndreas Gohr        return $cache;
19195615d6cSAndreas Gohr    }
19295615d6cSAndreas Gohr
19395615d6cSAndreas Gohr    /**
19405cbae88SAndreas Gohr     * Render the output remotely at ditaa.org
19505cbae88SAndreas Gohr     */
19605cbae88SAndreas Gohr    function _remote($data,$in,$out){
19795615d6cSAndreas Gohr        if(!file_exists($in)){
19895615d6cSAndreas Gohr            if($conf['debug']){
19995615d6cSAndreas Gohr                dbglog($in,'no such ditaa input file');
20095615d6cSAndreas Gohr            }
20195615d6cSAndreas Gohr            return false;
20295615d6cSAndreas Gohr        }
20395615d6cSAndreas Gohr
20405cbae88SAndreas Gohr        $http = new DokuHTTPClient();
20505cbae88SAndreas Gohr        $http->timeout=30;
20605cbae88SAndreas Gohr
20705cbae88SAndreas Gohr        $pass = array();
20805cbae88SAndreas Gohr        $pass['scale']   = $data['scale'];
20905cbae88SAndreas Gohr        $pass['timeout'] = 25;
21005cbae88SAndreas Gohr        $pass['grid']    = io_readFile($in);
21105cbae88SAndreas Gohr        if(!$data['antialias']) $pass['A'] = 'on';
21205cbae88SAndreas Gohr        if(!$data['shadow'])    $pass['S'] = 'on';
21305cbae88SAndreas Gohr        if($data['round'])      $pass['r'] = 'on';
21405cbae88SAndreas Gohr        if(!$data['edgesep'])   $pass['E'] = 'on';
21505cbae88SAndreas Gohr
21605cbae88SAndreas Gohr        $img = $http->post('http://ditaa.org/ditaa/render',$pass);
21705cbae88SAndreas Gohr        if(!$img) return false;
21805cbae88SAndreas Gohr
21995615d6cSAndreas Gohr        return io_saveFile($out,$img);
22005cbae88SAndreas Gohr    }
22105cbae88SAndreas Gohr
222a34ed36bSDennis Ploeger    /**
2232a956e66SAndreas Gohr     * Run the ditaa Java program
224a34ed36bSDennis Ploeger     */
22505cbae88SAndreas Gohr    function _run($data,$in,$out) {
2262a956e66SAndreas Gohr        global $conf;
227a34ed36bSDennis Ploeger
22805cbae88SAndreas Gohr        if(!file_exists($in)){
22905cbae88SAndreas Gohr            if($conf['debug']){
23005cbae88SAndreas Gohr                dbglog($in,'no such ditaa input file');
23105cbae88SAndreas Gohr            }
23205cbae88SAndreas Gohr            return false;
23305cbae88SAndreas Gohr        }
234a34ed36bSDennis Ploeger
2352a956e66SAndreas Gohr        $cmd  = $this->getConf('java');
23636721e14SAndreas Gohr        $cmd .= ' -Djava.awt.headless=true -Dfile.encoding=UTF-8 -jar';
2372a956e66SAndreas Gohr        $cmd .= ' '.escapeshellarg(dirname(__FILE__).'/ditaa/ditaa0_9.jar'); //ditaa jar
23836721e14SAndreas Gohr        $cmd .= ' --encoding UTF-8';
23905cbae88SAndreas Gohr        $cmd .= ' '.escapeshellarg($in); //input
24005cbae88SAndreas Gohr        $cmd .= ' '.escapeshellarg($out); //output
2412a956e66SAndreas Gohr        $cmd .= ' -s '.escapeshellarg($data['scale']);
2422a956e66SAndreas Gohr        if(!$data['antialias']) $cmd .= ' -A';
2432a956e66SAndreas Gohr        if(!$data['shadow'])    $cmd .= ' -S';
2442a956e66SAndreas Gohr        if($data['round'])      $cmd .= ' -r';
2452a956e66SAndreas Gohr        if(!$data['edgesep'])   $cmd .= ' -E';
246a34ed36bSDennis Ploeger
247a34ed36bSDennis Ploeger        exec($cmd, $output, $error);
248a34ed36bSDennis Ploeger
2493c74ed32SAndreas Gohr        if ($error != 0){
2503c74ed32SAndreas Gohr            if($conf['debug']){
2513c74ed32SAndreas Gohr                dbglog(join("\n",$output),'ditaa command failed: '.$cmd);
2523c74ed32SAndreas Gohr            }
2533c74ed32SAndreas Gohr            return false;
2543c74ed32SAndreas Gohr        }
25505cbae88SAndreas Gohr
256a34ed36bSDennis Ploeger        return true;
257a34ed36bSDennis Ploeger    }
258a34ed36bSDennis Ploeger
259a34ed36bSDennis Ploeger}
260a34ed36bSDennis Ploeger
261