Dokuwiki is centered around collaborative project documentation. An important part of documentation is image editing. Unfortunately, everyone seems to have a different set of tools and fonts for creating images and has different styles for drawing and encoding the images. Scalable Vector Graphics (SVG) offers a highly-promising way for people to produce high, print-quality graphics in a way that also allows for collaborative effort. Unfortuately, SVG is not widely supported in web browsers at the time of this writing. So, a plugin I propose, is to allow SVG input into the text, but then convert the code into a displable image format such as PNG or GIF.
<svg width="30cm" height="10cm" viewBox="0 0 1200 400" xmlns="http://www.w3.org/2000/svg" version="1.1"> <desc>Example rect01 - rectangle with sharp corners</desc> <!-- Show outline of canvas using 'rect' element --> <rect x="1" y="1" width="1198" height="398" fill="red" stroke="blue" stroke-width="5"/> <rect x="400" y="100" width="400" height="50" fill="red" stroke="navy" stroke-width="10" /> </svg>
svgconvert.tmp.tmp directory writable by the webserver.svgconvert./media/svgconvert directory writable by the webserver./conf/dokuwiki.php.$conf['svgdir'] = './inc/svgconvert'; // where SVGConvert is located $conf['svgmedia'] = $conf['mediadir'] . '/svgconvert'; // where does SVGConvert store its images? (currently not used) $conf['svgok'] = 1; // may SVG code be converted to images? 0|1
[...] // In 'parse()', around line 53, add this line: firstpass($table,$text,"#(<svg.*?/svg>)#se","preformat('\\1', 'svg')"); [...] // In 'preparse()', around line 175, add this line: $line = preg_replace("#(<svg(.*?)/svg>)#","",$line); [...] // And around line 177, change the if-condition to this: if(preg_match('#^.*?<(nowiki|code|php|html|file|svg)( (\w+))?>#',$line,$matches)){ [...] // In 'preformat()', around line 755, add this line: if($type == 'svg' && !$conf['svgok']) $type='code'; [...] // and around line 803, add this case to the switch-case-statement: case 'svg': include_once($conf['svgdir'] . '/svg.php'); $text = svg_content($text); break; [...]
As it is right now, it is possible for someone to make an image that is arbitrarily large. This could cause an incredible load on the webserver and could use up all the disk space. Also, this is a new way for messages to be embedded that might be inappropriate without proper filtering. I am seeking help with these and possibly other issues that I'm not prepared to deal with. For me, I will just restrict access to the page.
I hacked this into a plugin (using graphviz and plot as examples)…it ain't pretty but it works for me (may extend it to allow a filename as well). You need to create an area under /data/media (mkdir -p data/media/svg/tmp) and ensure that your webserver can write to it. =G=
<?php /** * svg-Plugin: Parses svg-blocks * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Galen Johnson <solitaryr@gmail.com> * @version 1.0.0 */ if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); require_once(DOKU_PLUGIN.'syntax.php'); /** * All DokuWiki plugins to extend the parser/rendering mechanism * need to inherit from this class */ class syntax_plugin_svgin extends DokuWiki_Syntax_Plugin { function getInfo(){ return array( 'author' => 'Galen Johnson', 'email' => 'solitaryr@gmail.com', 'date' => '2005-12-27', 'name' => 'SVG Plugin', 'desc' => 'Parses blocks of SVG code and converts it to an image', 'url' => '', ); } /** * What kind of syntax are we? */ function getType(){ return 'protected'; } /** * Where to sort in? */ function getSort(){ return 101; } /** * Connect pattern to lexer */ function connectTo($mode) { $this->Lexer->addEntryPattern('<svgin(?=.*\x3C/svgin\x3E)',$mode,'plugin_svgin'); } function postConnect() { $this->Lexer->addExitPattern('</svgin>','plugin_svgin'); } /** * Handle the match */ function handle($match, $state, $pos) { if ( $state == DOKU_LEXER_UNMATCHED ) { $matches = preg_split('/>/u',$match,2); $matches[0] = trim($matches[0]); if ( trim($matches[0]) == '' ) { $matches[0] = NULL; } return array($matches[1],$matches[0]); } return TRUE; } /** * Create output */ function render($mode, &$renderer, $data) { global $conf; if($mode == 'xhtml' && strlen($data[0]) > 1) { if ( !is_dir($conf['mediadir'] . '/svg') ) mkdir($conf['mediadir'] . '/svg', $conf['dmask'], true); $hash = md5(serialize($data[0])); $filename = $conf['mediadir'] . '/svg/'.$hash.'.png'; $url = DOKU_BASE.'/lib/exe/fetch.php?cache='.$cache.'&media='.urlencode('svg:'.$hash.'.png'); $size_str=$data[1]; if ( is_readable($filename) ) { $renderer->doc .= '<img src="'.$url.'" class="media" title="SVG" alt="SVG" />'; return true; } if (!$this->createImage($filename, $data[0], $data[1])) { $renderer->doc .= '<img src="'.$url.'" class="media" title="SVG" alt="SVG" />'; } else { $renderer->doc .= '**ERROR RENDERING SVG**'; } return true; } return false; } function createImage($filename, &$data) { global $conf; $tempdir = $conf['mediadir'].'/svg/tmp'; $tmpfname = tempnam($tempdir, "svg."); file_put_contents($tmpfname, $data); $retval = exec('/usr/bin/convert svg:'.$tmpfname.' png:'.$filename); unlink($tmpfname); return $retval; } } ?>