xref: /template/sprintdoc/svg.php (revision 1072ee525dad533b3be798f70f2f831f47df46e1)
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