Files
server/usr/share/psa-pear/pear/php/Horde/Image/Svg.php
2026-01-07 20:52:11 +01:00

439 lines
14 KiB
PHP

<?php
/**
* Copyright 2002-2017 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @author Chuck Hagenbuch <chuck@horde.org>
* @category Horde
* @license http://www.horde.org/licenses/lgpl21 LGPL-2.1
* @package Image
*/
/**
* This class implements the Horde_Image:: API for SVG.
*
* @author Chuck Hagenbuch <chuck@horde.org>
* @category Horde
* @copyright 2002-2017 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL-2.1
* @package Image
*
* Requires PEAR XML_SVG
*/
class Horde_Image_Svg extends Horde_Image_Base
{
/**
* SVG document handle.
*
* @var XML_SVG
*/
protected $_svg;
/**
* Capabilites of this driver.
*
* @var array
*/
protected $_capabilities = array(
'canvas',
'circle',
'dashedLine',
'line',
'polygon',
'polyline',
'rectangle',
'roundedRectangle',
'text',
);
/**
* Constructor.
*
* @see Horde_Image_Base::_construct
*/
public function __construct($params, $context = array())
{
parent::__construct($params, $context);
$this->_svg = new XML_SVG_Document(array(
'width' => $this->_width,
'height' => $this->_height,
));
if ($this->_background != 'none') {
$this->rectangle(
0, 0,
$this->_width, $this->_height,
$this->_background, $this->_background
);
}
}
/**
* Returns the MIME type for this image.
*
* @return string The MIME type for this image.
*/
public function getContentType()
{
return 'image/svg+xml';
}
/**
* Displays the current image.
*/
public function display()
{
$this->headers();
$this->_svg->printElement();
}
/**
* Return raw image data.
*
* @param boolean $convert Unused in SVG driver.
* @param array $options Array of options:
* NONE USED in SVG driver.
*
* @return string The raw image data.
*/
public function raw($convert = false, $options = array())
{
return $this->_svg->bufferObject();
}
private function _createSymbol($s, $id)
{
$s->setParam('id', $id);
$defs = new XML_SVG_Defs();
$defs->addChild($s);
$this->_svg->addChild($defs);
}
private function _createDropShadow($id = 'dropShadow')
{
$defs = new XML_SVG_Defs();
$filter = new XML_SVG_Filter(array('id' => $id));
$filter->addPrimitive(
'GaussianBlur',
array(
'in' => 'SourceAlpha',
'stdDeviation' => 2,
'result' => 'blur'
)
);
$filter->addPrimitive(
'Offset',
array(
'in' => 'blur',
'dx' => 4,
'dy' => 4,
'result' => 'offsetBlur'
)
);
$merge = new XML_SVG_FilterPrimitive('Merge');
$merge->addMergeNode('offsetBlur');
$merge->addMergeNode('SourceGraphic');
$filter->addChild($merge);
$defs->addChild($filter);
$this->_svg->addChild($defs);
}
/**
* Draws a text string on the image in a specified location, with the
* specified style information.
*
* @param string $text The text to draw.
* @param integer $x The left x coordinate of the start of the
* text string.
* @param integer $y The top y coordinate of the start of the text
* string.
* @param string $font The font identifier you want to use for the
* text.
* @param string $color The color that you want the text displayed in.
* @param integer $direction An integer that specifies the orientation of
* the text.
* @param string $fontsize Size of the font (small, medium, large, giant)
*/
public function text(
$string, $x, $y, $font = 'monospace', $color = 'black', $direction = 0
)
{
$height = 12;
$style = 'font-family:' . $font . ';font-height:' . $height
. 'px;fill:' . Horde_Image::getHexColor($color) . ';text-anchor:start;';
$transform = 'rotate(' . $direction . ',' . $x . ',' . $y . ')';
$this->_svg->addChild(new XML_SVG_Text(array(
'text' => $string,
'x' => (int)$x,
'y' => (int)$y + $height,
'transform' => $transform,
'style' => $style
)));
}
/**
* Draws a circle.
*
* @param integer $x The x coordinate of the centre.
* @param integer $y The y coordinate of the centre.
* @param integer $r The radius of the circle.
* @param string $color The line color of the circle.
* @param string $fill The color to fill the circle.
*/
public function circle($x, $y, $r, $color, $fill = null)
{
if (!empty($fill)) {
$style = 'fill:' . Horde_Image::getHexColor($fill) . '; ';
} else {
$style = 'fill:none;';
}
$style .= 'stroke:' . Horde_Image::getHexColor($color) . '; stroke-width:1';
$this->_svg->addChild(new XML_SVG_Circle(array(
'cx' => $x,
'cy' => $y,
'r' => $r,
'style' => $style
)));
}
/**
* Draws a polygon based on a set of vertices.
*
* @param array $vertices An array of x and y labeled arrays
* (eg. $vertices[0]['x'], $vertices[0]['y'], ...).
* @param string $color The color you want to draw the polygon with.
* @param string $fill The color to fill the polygon.
*/
public function polygon($verts, $color, $fill = null)
{
if (!empty($fill)) {
$style = 'fill:' . Horde_Image::getHexColor($fill) . '; ';
} else {
$style = 'fill:none;';
}
$style .= 'stroke:' . Horde_Image::getHexColor($color) . '; stroke-width:1';
$points = '';
foreach ($verts as $v) {
$points .= $v['x'] . ',' . $v['y'] . ' ';
}
$points = trim($points);
$this->_svg->addChild(new XML_SVG_Polygon(array(
'points' => $points,
'style' => $style
)));
}
/**
* Draws a rectangle.
*
* @param integer $x The left x-coordinate of the rectangle.
* @param integer $y The top y-coordinate of the rectangle.
* @param integer $width The width of the rectangle.
* @param integer $height The height of the rectangle.
* @param string $color The line color of the rectangle.
* @param string $fill The color to fill the rectangle.
*/
public function rectangle($x, $y, $width, $height, $color, $fill = null)
{
if (!empty($fill) && $fill != 'none') {
$style = 'fill:' . Horde_Image::getHexColor($fill) . '; ';
} else {
$style = 'fill:none;';
}
$style .= 'stroke:' . Horde_Image::getHexColor($color) . '; stroke-width:1';
$this->_svg->addChild(new XML_SVG_Rect(array(
'x' => $x,
'y' => $y,
'width' => $width,
'height' => $height,
'style' => $style
)));
}
/**
* Draws a rounded rectangle.
*
* @param integer $x The left x-coordinate of the rectangle.
* @param integer $y The top y-coordinate of the rectangle.
* @param integer $width The width of the rectangle.
* @param integer $height The height of the rectangle.
* @param integer $round The width of the corner rounding.
* @param string $color The line color of the rectangle.
* @param string $fill The color to fill the rounded rectangle with.
*/
public function roundedRectangle(
$x, $y, $width, $height, $round, $color, $fill
)
{
if (!empty($fill)) {
$style = 'fill:' . Horde_Image::getHexColor($fill) . '; ';
} else {
$style = 'fill:none;';
}
$style .= 'stroke:' . Horde_Image::getHexColor($color) . '; stroke-width:1';
$this->_svg->addChild(new XML_SVG_Rect(
array('x' => $x,
'y' => $y,
'rx' => $round,
'ry' => $round,
'width' => $width,
'height' => $height,
'style' => $style
)));
}
/**
* Draws a line.
*
* @param integer $x0 The x coordinate of the start.
* @param integer $y0 The y coordinate of the start.
* @param integer $x1 The x coordinate of the end.
* @param integer $y1 The y coordinate of the end.
* @param string $color The line color.
* @param string $width The width of the line.
*/
public function line($x1, $y1, $x2, $y2, $color = 'black', $width = 1)
{
$style = 'stroke:' . Horde_Image::getHexColor($color)
. '; stroke-width:' . (int)$width;
$this->_svg->addChild(new XML_SVG_Line(array(
'x1' => $x1,
'y1' => $y1,
'x2' => $x2,
'y2' => $y2,
'style' => $style
)));
}
/**
* Draws a dashed line.
*
* @param integer $x0 The x coordinate of the start.
* @param integer $y0 The y coordinate of the start.
* @param integer $x1 The x coordinate of the end.
* @param integer $y1 The y coordinate of the end.
* @param string $color The line color.
* @param string $width The width of the line.
* @param integer $dash_length The length of a dash on the dashed line
* @param integer $dash_space The length of a space in the dashed line
*/
public function dashedLine(
$x1, $y1, $x2, $y2, $color = 'black', $width = 1, $dash_length = 2,
$dash_space = 2
)
{
$style = 'stroke:' . Horde_Image::getHexColor($color)
. '; stroke-width:' . (int)$width
. '; stroke-dasharray:' . $dash_length . ',' . $dash_space . ';';
$this->_svg->addChild(new XML_SVG_Line(array(
'x1' => $x1,
'y1' => $y1,
'x2' => $x2,
'y2' => $y2,
'style' => $style
)));
}
/**
* Draws a polyline (a non-closed, non-filled polygon) based on a set of
* vertices.
*
* @param array $vertices An array of x and y labeled arrays
* (eg. $vertices[0]['x'], $vertices[0]['y'], ...).
* @param string $color The color you want to draw the line with.
* @param string $width The width of the line.
*/
public function polyline($verts, $color, $width = 1)
{
$style = 'stroke:' . Horde_Image::getHexColor($color)
. '; stroke-width:' . $width . ';fill:none;';
// Calculate the path entry.
$path = '';
$first = true;
foreach ($verts as $vert) {
if ($first) {
$first = false;
$path .= 'M ' . $vert['x'] . ',' . $vert['y'];
} else {
$path .= ' L ' . $vert['x'] . ',' . $vert['y'];
}
}
$this->_svg->addChild(new XML_SVG_Path(array(
'd' => $path,
'style' => $style
)));
}
/**
* Draws an arc.
*
* @param integer $x The x coordinate of the centre.
* @param integer $y The y coordinate of the centre.
* @param integer $r The radius of the arc.
* @param integer $start The start angle of the arc.
* @param integer $end The end angle of the arc.
* @param string $color The line color of the arc.
* @param string $fill The fill color of the arc (defaults to none).
*/
public function arc(
$x, $y, $r, $start, $end, $color = 'black', $fill = null
)
{
if (!empty($fill)) {
$style = 'fill:' . Horde_Image::getHexColor($fill) . '; ';
} else {
$style = 'fill:none;';
}
$style .= 'stroke:' . Horde_Image::getHexColor($color) . '; stroke-width:1';
$mid = round(($start + $end) / 2);
// Calculate the path entry.
$path = '';
// If filled, draw the outline.
if (!empty($fill)) {
// Start at the center of the ellipse the arc is on.
$path .= "M $x,$y ";
// Draw out to ellipse edge.
list($arcX, $arcY) = Horde_Image::circlePoint($start, $r * 2);
$path .= 'L ' . round($x + $arcX) . ',' .
round($y + $arcY) . ' ';
}
// Draw arcs.
list($arcX, $arcY) = Horde_Image::circlePoint($mid, $r * 2);
$path .= "A $r,$r 0 0 1 " .
round($x + $arcX) . ',' .
round($y + $arcY) . ' ';
list($arcX, $arcY) = Horde_Image::circlePoint($end, $r * 2);
$path .= "A $r,$r 0 0 1 " .
round($x + $arcX) . ',' .
round($y + $arcY) . ' ';
// If filled, close the outline.
if (!empty($fill)) {
$path .= 'Z';
}
$path = trim($path);
$this->_svg->addChild(new XML_SVG_Path(array(
'd' => $path,
'style' => $style
)));
}
}