first go at a dispatcher to dynamically recolor SVGs
The script accepts the following parameters: svg - the SVG to load. Either an image in the img directory next to the script or a media file id. ACLs are checked f - wanted fill color s - wanted stroke color fh - wanted fill color on hover sh - wanted stroke color on hover Colors are to be given in hex in the following formats: RGB RRGGBB RRGGBBAA What's missing: * being able to define what is styled, currently hardcoded to 'path' elements only * caching - no need to do all the processing every time * background setting - that would require wrapping an additional <g> or <rect> element around all content and style. I'm not sure how to do that best. * unit tests
This commit is contained in:
parent
43d4ee93fa
commit
1072ee525d
1 changed files with 165 additions and 0 deletions
165
svg.php
Normal file
165
svg.php
Normal file
|
@ -0,0 +1,165 @@
|
|||
<?php
|
||||
|
||||
namespace dokuwiki\template\sprintdoc;
|
||||
|
||||
if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__) . '/../../../');
|
||||
require_once(DOKU_INC . 'inc/init.php');
|
||||
|
||||
/**
|
||||
* Custom XML node that allows prepending
|
||||
*/
|
||||
class SvgNode extends \SimpleXMLElement {
|
||||
/**
|
||||
* @param string $name Name of the new node
|
||||
* @param null|string $value
|
||||
* @return SvgNode
|
||||
*/
|
||||
public function prependChild($name, $value = null) {
|
||||
$dom = dom_import_simplexml($this);
|
||||
|
||||
$new = $dom->insertBefore(
|
||||
$dom->ownerDocument->createElement($name, $value),
|
||||
$dom->firstChild
|
||||
);
|
||||
|
||||
return simplexml_import_dom($new, get_class($this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage SVG recoloring
|
||||
*/
|
||||
class SVG {
|
||||
|
||||
const IMGDIR = __DIR__ . '/img/';
|
||||
|
||||
/** @var SvgNode */
|
||||
protected $xml;
|
||||
|
||||
/**
|
||||
* SVG constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
global $INPUT;
|
||||
|
||||
$svg = cleanID($INPUT->str('svg'));
|
||||
if(blank($svg)) $this->abort(404);
|
||||
|
||||
// try local file first
|
||||
$file = self::IMGDIR . $svg;
|
||||
if(!file_exists($file)) {
|
||||
// media files are ACL protected
|
||||
if(auth_quickaclcheck($svg)) $this->abort(403);
|
||||
$file = mediaFN($svg);
|
||||
}
|
||||
// check if media exists
|
||||
if(!file_exists($file)) $this->abort(404);
|
||||
|
||||
$this->xml = simplexml_load_file($file, SvgNode::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and output
|
||||
*/
|
||||
public function out() {
|
||||
$this->setStyle();
|
||||
header('image/svg+xml');
|
||||
echo $this->xml->asXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a style setting from the input variables
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function makeStyle() {
|
||||
global $INPUT;
|
||||
|
||||
$element = 'path'; // FIXME configurable?
|
||||
|
||||
$colors = array(
|
||||
's' => $this->fixColor($INPUT->str('s')),
|
||||
'f' => $this->fixColor($INPUT->str('f')),
|
||||
'sh' => $this->fixColor($INPUT->str('sh')),
|
||||
'fh' => $this->fixColor($INPUT->str('fh')),
|
||||
);
|
||||
|
||||
$style = '';
|
||||
if($colors['s'] || $colors['f']) {
|
||||
$style .= $element . '{';
|
||||
if($colors['s']) $style .= 'stroke:' . $colors['s'] . ';';
|
||||
if($colors['f']) $style .= 'fill:' . $colors['f'] . ';';
|
||||
$style .= '}';
|
||||
}
|
||||
|
||||
if($colors['sh'] || $colors['fh']) {
|
||||
$style .= $element . ':hover{';
|
||||
if($colors['sh']) $style .= 'stroke:' . $colors['sh'] . ';';
|
||||
if($colors['fh']) $style .= 'fill:' . $colors['fh'] . ';';
|
||||
$style .= '}';
|
||||
}
|
||||
|
||||
return $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a hexadecimal color string in the following forms:
|
||||
*
|
||||
* RGB
|
||||
* RRGGBB
|
||||
* RRGGBBAA
|
||||
*
|
||||
* Converts it to rgba() form
|
||||
*
|
||||
* @param string $color
|
||||
* @return string
|
||||
*/
|
||||
protected function fixColor($color) {
|
||||
if(preg_match('/^([0-9a-f])([0-9a-f])([0-9a-f])$/i', $color, $m)) {
|
||||
$r = hexdec($m[1] . $m[1]);
|
||||
$g = hexdec($m[2] . $m[2]);
|
||||
$b = hexdec($m[3] . $m[3]);
|
||||
$a = hexdec('ff');
|
||||
} elseif(preg_match('/^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i', $color, $m)) {
|
||||
$r = hexdec($m[1]);
|
||||
$g = hexdec($m[2]);
|
||||
$b = hexdec($m[3]);
|
||||
if(isset($m[4])) {
|
||||
$a = hexdec($m[4]);
|
||||
} else {
|
||||
$a = hexdec('ff');
|
||||
}
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
||||
return "rgba($r,$g,$b,$a)";
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the style to the SVG
|
||||
*/
|
||||
protected function setStyle() {
|
||||
$defs = $this->xml->defs;
|
||||
if(!$defs) {
|
||||
$defs = $this->xml->prependChild('defs');
|
||||
}
|
||||
$defs->addChild('style', $this->makeStyle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort processing with given status code
|
||||
*
|
||||
* @param int $status
|
||||
*/
|
||||
protected function abort($status) {
|
||||
http_status($status);
|
||||
exit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// main
|
||||
$svg = new SVG();
|
||||
$svg->out();
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue