1*1072ee52SAndreas Gohr<?php 2*1072ee52SAndreas Gohr 3*1072ee52SAndreas Gohrnamespace dokuwiki\template\sprintdoc; 4*1072ee52SAndreas Gohr 5*1072ee52SAndreas Gohrif(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__) . '/../../../'); 6*1072ee52SAndreas Gohrrequire_once(DOKU_INC . 'inc/init.php'); 7*1072ee52SAndreas Gohr 8*1072ee52SAndreas Gohr/** 9*1072ee52SAndreas Gohr * Custom XML node that allows prepending 10*1072ee52SAndreas Gohr */ 11*1072ee52SAndreas Gohrclass SvgNode extends \SimpleXMLElement { 12*1072ee52SAndreas Gohr /** 13*1072ee52SAndreas Gohr * @param string $name Name of the new node 14*1072ee52SAndreas Gohr * @param null|string $value 15*1072ee52SAndreas Gohr * @return SvgNode 16*1072ee52SAndreas Gohr */ 17*1072ee52SAndreas Gohr public function prependChild($name, $value = null) { 18*1072ee52SAndreas Gohr $dom = dom_import_simplexml($this); 19*1072ee52SAndreas Gohr 20*1072ee52SAndreas Gohr $new = $dom->insertBefore( 21*1072ee52SAndreas Gohr $dom->ownerDocument->createElement($name, $value), 22*1072ee52SAndreas Gohr $dom->firstChild 23*1072ee52SAndreas Gohr ); 24*1072ee52SAndreas Gohr 25*1072ee52SAndreas Gohr return simplexml_import_dom($new, get_class($this)); 26*1072ee52SAndreas Gohr } 27*1072ee52SAndreas Gohr} 28*1072ee52SAndreas Gohr 29*1072ee52SAndreas Gohr/** 30*1072ee52SAndreas Gohr * Manage SVG recoloring 31*1072ee52SAndreas Gohr */ 32*1072ee52SAndreas Gohrclass SVG { 33*1072ee52SAndreas Gohr 34*1072ee52SAndreas Gohr const IMGDIR = __DIR__ . '/img/'; 35*1072ee52SAndreas Gohr 36*1072ee52SAndreas Gohr /** @var SvgNode */ 37*1072ee52SAndreas Gohr protected $xml; 38*1072ee52SAndreas Gohr 39*1072ee52SAndreas Gohr /** 40*1072ee52SAndreas Gohr * SVG constructor 41*1072ee52SAndreas Gohr */ 42*1072ee52SAndreas Gohr public function __construct() { 43*1072ee52SAndreas Gohr global $INPUT; 44*1072ee52SAndreas Gohr 45*1072ee52SAndreas Gohr $svg = cleanID($INPUT->str('svg')); 46*1072ee52SAndreas Gohr if(blank($svg)) $this->abort(404); 47*1072ee52SAndreas Gohr 48*1072ee52SAndreas Gohr // try local file first 49*1072ee52SAndreas Gohr $file = self::IMGDIR . $svg; 50*1072ee52SAndreas Gohr if(!file_exists($file)) { 51*1072ee52SAndreas Gohr // media files are ACL protected 52*1072ee52SAndreas Gohr if(auth_quickaclcheck($svg)) $this->abort(403); 53*1072ee52SAndreas Gohr $file = mediaFN($svg); 54*1072ee52SAndreas Gohr } 55*1072ee52SAndreas Gohr // check if media exists 56*1072ee52SAndreas Gohr if(!file_exists($file)) $this->abort(404); 57*1072ee52SAndreas Gohr 58*1072ee52SAndreas Gohr $this->xml = simplexml_load_file($file, SvgNode::class); 59*1072ee52SAndreas Gohr } 60*1072ee52SAndreas Gohr 61*1072ee52SAndreas Gohr /** 62*1072ee52SAndreas Gohr * Generate and output 63*1072ee52SAndreas Gohr */ 64*1072ee52SAndreas Gohr public function out() { 65*1072ee52SAndreas Gohr $this->setStyle(); 66*1072ee52SAndreas Gohr header('image/svg+xml'); 67*1072ee52SAndreas Gohr echo $this->xml->asXML(); 68*1072ee52SAndreas Gohr } 69*1072ee52SAndreas Gohr 70*1072ee52SAndreas Gohr /** 71*1072ee52SAndreas Gohr * Generate a style setting from the input variables 72*1072ee52SAndreas Gohr * 73*1072ee52SAndreas Gohr * @return string 74*1072ee52SAndreas Gohr */ 75*1072ee52SAndreas Gohr protected function makeStyle() { 76*1072ee52SAndreas Gohr global $INPUT; 77*1072ee52SAndreas Gohr 78*1072ee52SAndreas Gohr $element = 'path'; // FIXME configurable? 79*1072ee52SAndreas Gohr 80*1072ee52SAndreas Gohr $colors = array( 81*1072ee52SAndreas Gohr 's' => $this->fixColor($INPUT->str('s')), 82*1072ee52SAndreas Gohr 'f' => $this->fixColor($INPUT->str('f')), 83*1072ee52SAndreas Gohr 'sh' => $this->fixColor($INPUT->str('sh')), 84*1072ee52SAndreas Gohr 'fh' => $this->fixColor($INPUT->str('fh')), 85*1072ee52SAndreas Gohr ); 86*1072ee52SAndreas Gohr 87*1072ee52SAndreas Gohr $style = ''; 88*1072ee52SAndreas Gohr if($colors['s'] || $colors['f']) { 89*1072ee52SAndreas Gohr $style .= $element . '{'; 90*1072ee52SAndreas Gohr if($colors['s']) $style .= 'stroke:' . $colors['s'] . ';'; 91*1072ee52SAndreas Gohr if($colors['f']) $style .= 'fill:' . $colors['f'] . ';'; 92*1072ee52SAndreas Gohr $style .= '}'; 93*1072ee52SAndreas Gohr } 94*1072ee52SAndreas Gohr 95*1072ee52SAndreas Gohr if($colors['sh'] || $colors['fh']) { 96*1072ee52SAndreas Gohr $style .= $element . ':hover{'; 97*1072ee52SAndreas Gohr if($colors['sh']) $style .= 'stroke:' . $colors['sh'] . ';'; 98*1072ee52SAndreas Gohr if($colors['fh']) $style .= 'fill:' . $colors['fh'] . ';'; 99*1072ee52SAndreas Gohr $style .= '}'; 100*1072ee52SAndreas Gohr } 101*1072ee52SAndreas Gohr 102*1072ee52SAndreas Gohr return $style; 103*1072ee52SAndreas Gohr } 104*1072ee52SAndreas Gohr 105*1072ee52SAndreas Gohr /** 106*1072ee52SAndreas Gohr * Takes a hexadecimal color string in the following forms: 107*1072ee52SAndreas Gohr * 108*1072ee52SAndreas Gohr * RGB 109*1072ee52SAndreas Gohr * RRGGBB 110*1072ee52SAndreas Gohr * RRGGBBAA 111*1072ee52SAndreas Gohr * 112*1072ee52SAndreas Gohr * Converts it to rgba() form 113*1072ee52SAndreas Gohr * 114*1072ee52SAndreas Gohr * @param string $color 115*1072ee52SAndreas Gohr * @return string 116*1072ee52SAndreas Gohr */ 117*1072ee52SAndreas Gohr protected function fixColor($color) { 118*1072ee52SAndreas Gohr if(preg_match('/^([0-9a-f])([0-9a-f])([0-9a-f])$/i', $color, $m)) { 119*1072ee52SAndreas Gohr $r = hexdec($m[1] . $m[1]); 120*1072ee52SAndreas Gohr $g = hexdec($m[2] . $m[2]); 121*1072ee52SAndreas Gohr $b = hexdec($m[3] . $m[3]); 122*1072ee52SAndreas Gohr $a = hexdec('ff'); 123*1072ee52SAndreas Gohr } elseif(preg_match('/^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i', $color, $m)) { 124*1072ee52SAndreas Gohr $r = hexdec($m[1]); 125*1072ee52SAndreas Gohr $g = hexdec($m[2]); 126*1072ee52SAndreas Gohr $b = hexdec($m[3]); 127*1072ee52SAndreas Gohr if(isset($m[4])) { 128*1072ee52SAndreas Gohr $a = hexdec($m[4]); 129*1072ee52SAndreas Gohr } else { 130*1072ee52SAndreas Gohr $a = hexdec('ff'); 131*1072ee52SAndreas Gohr } 132*1072ee52SAndreas Gohr } else { 133*1072ee52SAndreas Gohr return ''; 134*1072ee52SAndreas Gohr } 135*1072ee52SAndreas Gohr 136*1072ee52SAndreas Gohr return "rgba($r,$g,$b,$a)"; 137*1072ee52SAndreas Gohr } 138*1072ee52SAndreas Gohr 139*1072ee52SAndreas Gohr /** 140*1072ee52SAndreas Gohr * Apply the style to the SVG 141*1072ee52SAndreas Gohr */ 142*1072ee52SAndreas Gohr protected function setStyle() { 143*1072ee52SAndreas Gohr $defs = $this->xml->defs; 144*1072ee52SAndreas Gohr if(!$defs) { 145*1072ee52SAndreas Gohr $defs = $this->xml->prependChild('defs'); 146*1072ee52SAndreas Gohr } 147*1072ee52SAndreas Gohr $defs->addChild('style', $this->makeStyle()); 148*1072ee52SAndreas Gohr } 149*1072ee52SAndreas Gohr 150*1072ee52SAndreas Gohr /** 151*1072ee52SAndreas Gohr * Abort processing with given status code 152*1072ee52SAndreas Gohr * 153*1072ee52SAndreas Gohr * @param int $status 154*1072ee52SAndreas Gohr */ 155*1072ee52SAndreas Gohr protected function abort($status) { 156*1072ee52SAndreas Gohr http_status($status); 157*1072ee52SAndreas Gohr exit; 158*1072ee52SAndreas Gohr } 159*1072ee52SAndreas Gohr 160*1072ee52SAndreas Gohr} 161*1072ee52SAndreas Gohr 162*1072ee52SAndreas Gohr// main 163*1072ee52SAndreas Gohr$svg = new SVG(); 164*1072ee52SAndreas Gohr$svg->out(); 165*1072ee52SAndreas Gohr 166