xref: /template/sprintdoc/svg.php (revision 3ec07d58b7e4f7d33cfe896e8d5911829f58bcbe)
11072ee52SAndreas Gohr<?php
21072ee52SAndreas Gohr
31072ee52SAndreas Gohrnamespace dokuwiki\template\sprintdoc;
41072ee52SAndreas Gohr
51072ee52SAndreas Gohrif(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__) . '/../../../');
61072ee52SAndreas Gohrrequire_once(DOKU_INC . 'inc/init.php');
71072ee52SAndreas Gohr
81072ee52SAndreas Gohr/**
91072ee52SAndreas Gohr * Custom XML node that allows prepending
101072ee52SAndreas Gohr */
111072ee52SAndreas Gohrclass SvgNode extends \SimpleXMLElement {
121072ee52SAndreas Gohr    /**
131072ee52SAndreas Gohr     * @param string $name Name of the new node
141072ee52SAndreas Gohr     * @param null|string $value
151072ee52SAndreas Gohr     * @return SvgNode
161072ee52SAndreas Gohr     */
171072ee52SAndreas Gohr    public function prependChild($name, $value = null) {
181072ee52SAndreas Gohr        $dom = dom_import_simplexml($this);
191072ee52SAndreas Gohr
201072ee52SAndreas Gohr        $new = $dom->insertBefore(
211072ee52SAndreas Gohr            $dom->ownerDocument->createElement($name, $value),
221072ee52SAndreas Gohr            $dom->firstChild
231072ee52SAndreas Gohr        );
241072ee52SAndreas Gohr
251072ee52SAndreas Gohr        return simplexml_import_dom($new, get_class($this));
261072ee52SAndreas Gohr    }
271072ee52SAndreas Gohr}
281072ee52SAndreas Gohr
291072ee52SAndreas Gohr/**
301072ee52SAndreas Gohr * Manage SVG recoloring
311072ee52SAndreas Gohr */
321072ee52SAndreas Gohrclass SVG {
331072ee52SAndreas Gohr
341072ee52SAndreas Gohr    const IMGDIR = __DIR__ . '/img/';
351072ee52SAndreas Gohr
361072ee52SAndreas Gohr    /** @var SvgNode */
371072ee52SAndreas Gohr    protected $xml;
381072ee52SAndreas Gohr
391072ee52SAndreas Gohr    /**
401072ee52SAndreas Gohr     * SVG constructor
411072ee52SAndreas Gohr     */
421072ee52SAndreas Gohr    public function __construct() {
431072ee52SAndreas Gohr        global $INPUT;
441072ee52SAndreas Gohr
451072ee52SAndreas Gohr        $svg = cleanID($INPUT->str('svg'));
461072ee52SAndreas Gohr        if(blank($svg)) $this->abort(404);
471072ee52SAndreas Gohr
481072ee52SAndreas Gohr        // try local file first
491072ee52SAndreas Gohr        $file = self::IMGDIR . $svg;
501072ee52SAndreas Gohr        if(!file_exists($file)) {
511072ee52SAndreas Gohr            // media files are ACL protected
52*3ec07d58SAndreas Gohr            if(auth_quickaclcheck($svg) < AUTH_READ) $this->abort(403);
531072ee52SAndreas Gohr            $file = mediaFN($svg);
541072ee52SAndreas Gohr        }
551072ee52SAndreas Gohr        // check if media exists
561072ee52SAndreas Gohr        if(!file_exists($file)) $this->abort(404);
571072ee52SAndreas Gohr
581072ee52SAndreas Gohr        $this->xml = simplexml_load_file($file, SvgNode::class);
591072ee52SAndreas Gohr    }
601072ee52SAndreas Gohr
611072ee52SAndreas Gohr    /**
621072ee52SAndreas Gohr     * Generate and output
631072ee52SAndreas Gohr     */
641072ee52SAndreas Gohr    public function out() {
651072ee52SAndreas Gohr        $this->setStyle();
661072ee52SAndreas Gohr        header('image/svg+xml');
671072ee52SAndreas Gohr        echo $this->xml->asXML();
681072ee52SAndreas Gohr    }
691072ee52SAndreas Gohr
701072ee52SAndreas Gohr    /**
711072ee52SAndreas Gohr     * Generate a style setting from the input variables
721072ee52SAndreas Gohr     *
731072ee52SAndreas Gohr     * @return string
741072ee52SAndreas Gohr     */
751072ee52SAndreas Gohr    protected function makeStyle() {
761072ee52SAndreas Gohr        global $INPUT;
771072ee52SAndreas Gohr
781072ee52SAndreas Gohr        $element = 'path'; // FIXME configurable?
791072ee52SAndreas Gohr
801072ee52SAndreas Gohr        $colors = array(
811072ee52SAndreas Gohr            's' => $this->fixColor($INPUT->str('s')),
821072ee52SAndreas Gohr            'f' => $this->fixColor($INPUT->str('f')),
831072ee52SAndreas Gohr            'sh' => $this->fixColor($INPUT->str('sh')),
841072ee52SAndreas Gohr            'fh' => $this->fixColor($INPUT->str('fh')),
851072ee52SAndreas Gohr        );
861072ee52SAndreas Gohr
871072ee52SAndreas Gohr        $style = '';
881072ee52SAndreas Gohr        if($colors['s'] || $colors['f']) {
891072ee52SAndreas Gohr            $style .= $element . '{';
901072ee52SAndreas Gohr            if($colors['s']) $style .= 'stroke:' . $colors['s'] . ';';
911072ee52SAndreas Gohr            if($colors['f']) $style .= 'fill:' . $colors['f'] . ';';
921072ee52SAndreas Gohr            $style .= '}';
931072ee52SAndreas Gohr        }
941072ee52SAndreas Gohr
951072ee52SAndreas Gohr        if($colors['sh'] || $colors['fh']) {
961072ee52SAndreas Gohr            $style .= $element . ':hover{';
971072ee52SAndreas Gohr            if($colors['sh']) $style .= 'stroke:' . $colors['sh'] . ';';
981072ee52SAndreas Gohr            if($colors['fh']) $style .= 'fill:' . $colors['fh'] . ';';
991072ee52SAndreas Gohr            $style .= '}';
1001072ee52SAndreas Gohr        }
1011072ee52SAndreas Gohr
1021072ee52SAndreas Gohr        return $style;
1031072ee52SAndreas Gohr    }
1041072ee52SAndreas Gohr
1051072ee52SAndreas Gohr    /**
1061072ee52SAndreas Gohr     * Takes a hexadecimal color string in the following forms:
1071072ee52SAndreas Gohr     *
1081072ee52SAndreas Gohr     * RGB
1091072ee52SAndreas Gohr     * RRGGBB
1101072ee52SAndreas Gohr     * RRGGBBAA
1111072ee52SAndreas Gohr     *
1121072ee52SAndreas Gohr     * Converts it to rgba() form
1131072ee52SAndreas Gohr     *
1141072ee52SAndreas Gohr     * @param string $color
1151072ee52SAndreas Gohr     * @return string
1161072ee52SAndreas Gohr     */
1171072ee52SAndreas Gohr    protected function fixColor($color) {
1181072ee52SAndreas Gohr        if(preg_match('/^([0-9a-f])([0-9a-f])([0-9a-f])$/i', $color, $m)) {
1191072ee52SAndreas Gohr            $r = hexdec($m[1] . $m[1]);
1201072ee52SAndreas Gohr            $g = hexdec($m[2] . $m[2]);
1211072ee52SAndreas Gohr            $b = hexdec($m[3] . $m[3]);
1221072ee52SAndreas Gohr            $a = hexdec('ff');
1231072ee52SAndreas Gohr        } elseif(preg_match('/^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i', $color, $m)) {
1241072ee52SAndreas Gohr            $r = hexdec($m[1]);
1251072ee52SAndreas Gohr            $g = hexdec($m[2]);
1261072ee52SAndreas Gohr            $b = hexdec($m[3]);
1271072ee52SAndreas Gohr            if(isset($m[4])) {
1281072ee52SAndreas Gohr                $a = hexdec($m[4]);
1291072ee52SAndreas Gohr            } else {
1301072ee52SAndreas Gohr                $a = hexdec('ff');
1311072ee52SAndreas Gohr            }
1321072ee52SAndreas Gohr        } else {
1331072ee52SAndreas Gohr            return '';
1341072ee52SAndreas Gohr        }
1351072ee52SAndreas Gohr
1361072ee52SAndreas Gohr        return "rgba($r,$g,$b,$a)";
1371072ee52SAndreas Gohr    }
1381072ee52SAndreas Gohr
1391072ee52SAndreas Gohr    /**
1401072ee52SAndreas Gohr     * Apply the style to the SVG
1411072ee52SAndreas Gohr     */
1421072ee52SAndreas Gohr    protected function setStyle() {
1431072ee52SAndreas Gohr        $defs = $this->xml->defs;
1441072ee52SAndreas Gohr        if(!$defs) {
1451072ee52SAndreas Gohr            $defs = $this->xml->prependChild('defs');
1461072ee52SAndreas Gohr        }
1471072ee52SAndreas Gohr        $defs->addChild('style', $this->makeStyle());
1481072ee52SAndreas Gohr    }
1491072ee52SAndreas Gohr
1501072ee52SAndreas Gohr    /**
1511072ee52SAndreas Gohr     * Abort processing with given status code
1521072ee52SAndreas Gohr     *
1531072ee52SAndreas Gohr     * @param int $status
1541072ee52SAndreas Gohr     */
1551072ee52SAndreas Gohr    protected function abort($status) {
1561072ee52SAndreas Gohr        http_status($status);
1571072ee52SAndreas Gohr        exit;
1581072ee52SAndreas Gohr    }
1591072ee52SAndreas Gohr
1601072ee52SAndreas Gohr}
1611072ee52SAndreas Gohr
1621072ee52SAndreas Gohr// main
1631072ee52SAndreas Gohr$svg = new SVG();
1641072ee52SAndreas Gohr$svg->out();
1651072ee52SAndreas Gohr
166