vtenext/Image/Canvas/SWF.php
2021-04-28 20:10:26 +02:00

866 lines
27 KiB
PHP

<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Class for handling output in SWF flash format.
*
* Requires PHP extension ming
*
* LICENSE: This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version. This library is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details. You should have received a copy of
* the GNU Lesser General Public License along with this library; if not, write
* to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*
* @category Images
* @package Image_Canvas
* @author Torsten Roehr <troehr@php.net>
* @author Stefan Neufeind <pear.neufeind@speedpartner.de>
* @copyright 2003-2009 The PHP Group
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version SVN: $Id$
* @link http://pear.php.net/package/Image_Canvas
*/
/**
* Include file Image/Canvas.php
*/
require_once 'Image/Canvas.php';
/**
* Include file Image/Canvas/Color.php
*/
require_once 'Image/Canvas/Color.php';
/**
* SVG Canvas class.
*
* @category Images
* @package Image_Canvas
* @author Torsten Roehr <troehr@php.net>
* @author Stefan Neufeind <pear.neufeind@speedpartner.de>
* @copyright 2003-2009 The PHP Group
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version Release: @package_version@
* @link http://pear.php.net/package/Image_Canvas
*/
class Image_Canvas_SWF extends Image_Canvas
{
/**
* The canvas of the graph
* @var object SWFMovie
* @access private
*/
var $_canvas;
/**
* The default Flash version
*
* Ming supports up to Flash version 6
*
* @var int
* @access private
*/
var $_version = 6;
/**
* Creates the SWF movie object
*
* Parameters available:
*
* 'width' The width of the graph
* 'height' The height of the graph
* 'version' The flash version, supports up to version 6
* 'background' An array with the background color, e.g.
* array('red' => 255,
* 'green' => 0,
* 'blue' => 0)
* Either integers between 0 and 255 or hexadecimals
* between 0x00 and 0xFF
*
* @param array $params Parameter array
*
* @return Image_Canvas_SWF
*/
function Image_Canvas_SWF($params)
{
parent::Image_Canvas($params);
$this->_reset();
$version = (isset($params['version']) && $params['version'] <= 6)
? $params['version'] : $this->_version;
$this->_canvas = new SWFMovie($version);
$this->_canvas->setDimension($this->_width, $this->_height);
if (isset($params['background'])) {
$this->setBackground($params['background']);
}
}
/**
* Sets the background color
*
* Values can be specified either as integers between 0 and 255 or as hexadecimals between 0x00 and 0xFF
*
* @param mixed $color Color
*
* @return void
* @access public
*/
function setBackground($color)
{
$color = Image_Canvas_Color::color2RGB($color);
$this->_canvas->setBackground($color[0], $color[1], $color[2]);
}
/**
* Add an object to the movie
*
* @param string $element The element
*
* @return void
* @access public
*/
function addElement($element)
{
$this->_canvas->add($element);
}
/**
* Get the color index for the RGB color
*
* @param int $color The color
*
* @return int A SVG compatible color
* @access private
*/
function _color($color = false)
{
if ($color === false) {
return array();
} else {
return Image_Canvas_Color::color2RGB($color);
}
}
/**
* Get the opacity for the RGB color
*
* @param int $color The color
*
* @return int A SWF compatible opacity value
* @access private
*/
function _opacity($color = false)
{
if ($color === false) {
return false;
} else {
$color = Image_Canvas_Color::color2RGB($color);
if ($color[3] != 255) {
return sprintf('%0.1f', $color[3]/255);
} else {
return 255;
}
}
}
/**
* Get the applicable linestyle
*
* @param mixed $lineStyle The line style to return, false if the one
* explicitly set
*
* @return mixed A compatible linestyle
* @access private
*/
function _getLineStyle($lineStyle = false)
{
if ($lineStyle === false) {
$lineStyle = $this->_lineStyle;
}
return $this->_color($lineStyle);
}
/**
* Get the applicable fillstyle
*
* @param mixed $fillStyle The fillstyle to return, false if the one
* explicitly set
*
* @return mixed A compatible fillstyle
* @access private
*/
function _getFillStyle($fillStyle = false)
{
if ($fillStyle === false) {
$fillStyle = $this->_fillStyle;
}
return $this->_color($fillStyle);
}
/**
* Sets an image that should be used for filling
*
* @param string $filename The filename of the image to fill with
*
* @todo
* @return void
*/
function setFillImage($filename)
{
}
/**
* Sets a gradient fill
*
* @param array $gradient Gradient fill options
*
* @todo
* @return void
*/
function setGradientFill($gradient)
{
}
/**
* Sets the font options.
*
* The $font array may have the following entries:
* 'type' : 'ttf' (TrueType) or omitted for default<br>
* If 'type' is 'ttf' then the following can be specified<br>
* 'size' : size in pixels<br>
* 'angle' : the angle with which to write the text
* 'file' : the .ttf file (either the basename, filename or full path)
*
* @param array $fontOptions The font options.
*
* @return void
*/
function setFont($fontOptions)
{
parent::setFont($fontOptions);
if (!isset($this->_font['size'])) {
$this->_font['size'] = 10;
}
}
/**
* Draw a line end
*
* Parameter array:
* 'x' : int X point
* 'y' : int Y point
* 'end' : string The end type of the end
* 'size' : int The size of the end
* 'color' : string The color of the end
* 'angle' : int [optional] The angle with which to draw the end
* 'url' : string [optional] Target URL
*
* @param array $params Parameter array
*
* @return void
*/
function drawEnd($params)
{
$x = $this->_getX($params['x']);
$y = $this->_getY($params['y']);
$size = $params['size'];
$angle = deg2rad((isset($params['angle']) ? $params['angle'] : 0));
$pi2 = pi() / 2;
switch ($params['end']) {
case 'lollipop':
case 'circle':
if (($fill = $this->_getFillStyle($params['color'])) !== false) {
$shapeObj = new SWFShape();
$shapeObj->setRightFill($fill[0], $fill[1], $fill[2]);
$shapeObj->movePenTo($x + $size / 2, $y);
$shapeObj->drawCircle($size / 2);
if (isset($params['url'])) {
$button = new SWFButton();
$button->addShape($shapeObj, SWFBUTTON_HIT | SWFBUTTON_UP | SWFBUTTON_DOWN | SWFBUTTON_OVER);
$button->addAction(new SWFAction("getURL('{$params['url']}');"), SWFBUTTON_MOUSEUP);
$this->_canvas->add($button);
} else {
$this->_canvas->add($shapeObj);
}
parent::drawEnd($params);
}
break;
case 'diamond':
$x0 = round($params['x'] + cos($angle) * $size * 0.65);
$y0 = round($params['y'] - sin($angle) * $size * 0.65);
$shape = array(
array($x0 + round(cos($angle) * $size * 0.65),
$y0 - round(sin($angle) * $size * 0.65)),
array($x0 + round(cos($angle + $pi2) * $size * 0.65),
$y0 - round(sin($angle + $pi2) * $size * 0.65)),
array($x0 + round(cos($angle + pi()) * $size * 0.65),
$y0 - round(sin($angle + pi()) * $size * 0.65)),
array($x0 + round(cos($angle + 3 * $pi2) * $size * 0.65),
$y0 - round(sin($angle + 3 * $pi2) * $size * 0.65))
);
break;
case 'line':
$shape = array(
array($x + round(cos($angle + $pi2) * $size / 2),
$y - round(sin($angle + $pi2) * $size / 2)),
array($x + round(cos($angle + 3 * $pi2) * $size / 2),
$y - round(sin($angle + 3 * $pi2) * $size / 2))
);
break;
case 'box':
case 'rectangle':
$x0 = round($params['x'] + cos($angle) * $size / 2);
$y0 = round($params['y'] - sin($angle) * $size / 2);
$pi4 = pi() / 4;
$shape = array(
array($x0 + round(cos($angle + $pi4) * $size / 2),
$y0 - round(sin($angle + $pi4) * $size / 2)),
array($x0 + round(cos($angle + $pi2 + $pi4) * $size / 2),
$y0 - round(sin($angle + $pi2 + $pi4) * $size / 2)),
array($x0 + round(cos($angle + pi() + $pi4) * $size / 2),
$y0 - round(sin($angle + pi() + $pi4) * $size / 2)),
array($x0 + round(cos($angle + 3 * $pi2 + $pi4) * $size / 2),
$y0 - round(sin($angle + 3 * $pi2 + $pi4) * $size / 2))
);
break;
case 'arrow':
$shape = array(
array($x + cos($angle) * $size,
$y - sin($angle) * $size),
array($x + cos($angle + $pi2) * $size * 0.4,
$y - sin($angle + $pi2) * $size * 0.4),
array($x + cos($angle + 3 * $pi2) * $size * 0.4,
$y - sin($angle + 3 * $pi2) * $size * 0.4)
);
break;
case 'arrow2':
$shape = array(
array($x + round(cos($angle) * $size),
$y - round(sin($angle) * $size)),
array($x + round(cos($angle + $pi2 + deg2rad(45)) * $size),
$y - round(sin($angle + $pi2 + deg2rad(45)) * $size)),
array($x,
$y),
array($x + round(cos($angle + 3 * $pi2 - deg2rad(45)) * $size),
$y - round(sin($angle + 3 * $pi2 - deg2rad(45)) * $size))
);
break;
}
if (isset($shape)) {
// output the shape
if (($fill = $this->_getFillStyle($params['color'])) !== false) {
$shapeObj = new SWFShape();
$shapeObj->setRightFill($fill[0], $fill[1], $fill[2]);
$shapeObj->setLine(0, $fill[0], $fill[1], $fill[2]);
$shapeObj->movePenTo($shape[0][0], $shape[0][1]);
for ($count = count($shape); $count--; $count > 0) {
$shapeObj->drawLineTo($shape[$count][0], $shape[$count][1]);
}
if (isset($params['url'])) {
$button = new SWFButton();
$button->addShape($shapeObj, SWFBUTTON_HIT | SWFBUTTON_UP | SWFBUTTON_DOWN | SWFBUTTON_OVER);
$button->addAction(new SWFAction("getURL('{$params['url']}');"), SWFBUTTON_MOUSEUP);
$this->_canvas->add($button);
} else {
$this->_canvas->add($shapeObj);
}
}
}
parent::drawEnd($params);
}
/**
* Parameter array:
* 'x0' : int X start point
* 'y0' : int Y start point
* 'x1' : int X end point
* 'y1' : int Y end point
* 'color' : mixed [optional] The line color
* 'url' : string [optional] Target URL
*
* @param array $params Parameter array
*
* @return void
*/
function line($params)
{
$x0 = $this->_getX($params['x0']);
$y0 = $this->_getY($params['y0']);
$x1 = $this->_getX($params['x1']);
$y1 = $this->_getY($params['y1']);
$color = (isset($params['color']) ? $params['color'] : false);
$color = $this->_getLineStyle($color);
$shape = new SWFShape();
$shape->setLine(1, $color[0], $color[1], $color[2]);
$shape->movePenTo($x0, $y0);
$shape->drawLine($x1 - $x0, $y1 - $y0);
if (isset($params['url'])) {
$button = new SWFButton();
$button->addShape($shape, SWFBUTTON_HIT | SWFBUTTON_UP | SWFBUTTON_DOWN | SWFBUTTON_OVER);
$button->addAction(new SWFAction("getURL('{$params['url']}');"), SWFBUTTON_MOUSEUP);
$this->_canvas->add($button);
} else {
$this->_canvas->add($shape);
}
parent::line($params);
}
/**
* Parameter array:
* 'connect': bool [optional] Specifies whether the start point should be
* connected to the endpoint (closed polygon)
* or not (connected line)
* 'fill' : mixed [optional] The fill color
* 'line' : mixed [optional] The line color
* 'url' : string [optional] Target URL
*
* @param array $params Parameter array
*
* @return void
*/
function polygon($params = array())
{
$connectEnds = (isset($params['connect']) ? $params['connect'] : false);
$fillColor = (isset($params['fill']) ? $params['fill'] : false);
$lineColor = (isset($params['line']) ? $params['line'] : false);
$lineStyle = $this->_getLineStyle($lineColor);
$fillStyle = $this->_getFillStyle($fillColor);
$shape = new SWFShape();
if ($connectEnds) {
$shape->setRightFill($fillStyle[0], $fillStyle[1], $fillStyle[2]);
}
$shape->setLine(0, $lineStyle[0], $lineStyle[1], $lineStyle[2]);
$shape->movePenTo($this->_polygon[0]['X'], $this->_polygon[0]['Y']);
foreach ($this->_polygon as $point) {
$shape->drawLineTo($point['X'], $point['Y']);
}
if ($connectEnds) {
$shape->drawLineTo($this->_polygon[0]['X'], $this->_polygon[0]['Y']);
}
if (isset($params['url'])) {
$button = new SWFButton();
$button->addShape($shape, SWFBUTTON_HIT | SWFBUTTON_UP | SWFBUTTON_DOWN | SWFBUTTON_OVER);
$button->addAction(new SWFAction("getURL('{$params['url']}');"), SWFBUTTON_MOUSEUP);
$this->_canvas->add($button);
} else {
$this->_canvas->add($shape);
}
parent::polygon($params);
}
/**
* Draw a rectangle
*
* Parameter array:
* 'x0' : int X start point
* 'y0' : int Y start point
* 'x1' : int X end point
* 'y1' : int Y end point
* 'fill' : The fill style
* 'line' : The line style
* 'url' : string [optional] Target URL
*
* @param array $params Parameter array
*
* @return void
*/
function rectangle($params)
{
$x0 = min($this->_getX($params['x0']), $this->_getX($params['x1']));
$y0 = min($this->_getY($params['y0']), $this->_getY($params['y1']));
$x1 = max($this->_getX($params['x0']), $this->_getX($params['x1']));
$y1 = max($this->_getY($params['y0']), $this->_getY($params['y1']));
$fillColor = (isset($params['fill']) ? $params['fill'] : false);
$lineColor = (isset($params['line']) ? $params['line'] : false);
$fillColor = $this->_getFillStyle($fillColor);
$lineColor = $this->_getLineStyle($lineColor);
// use fill color if no line color is set or transparent
if (count($lineColor) === 0) {
$lineColor = $fillColor;
}
$shape = new SWFShape();
$shape->setLine(1, $lineColor[0], $lineColor[1], $lineColor[2]);
if (count($fillColor)) {
$shape->setRightFill($fillColor[0], $fillColor[1], $fillColor[2]);
}
$shape->movePenTo($x0, $y0);
$shape->drawLine($x1 - $x0, 0);
$shape->drawLine(0, $y1 - $y0);
$shape->drawLine($x0 - $x1, 0);
$shape->drawLine(0, $y0 - $y1);
if (isset($params['url'])) {
$button = new SWFButton();
$button->addShape($shape, SWFBUTTON_HIT | SWFBUTTON_UP | SWFBUTTON_DOWN | SWFBUTTON_OVER);
$button->addAction(new SWFAction("getURL('{$params['url']}');"), SWFBUTTON_MOUSEUP);
$this->_canvas->add($button);
} else {
$this->_canvas->add($shape);
}
parent::rectangle($params);
}
/**
* Draw an ellipse
*
* Parameter array:
* 'x' : int X center point
* 'y' : int Y center point
* 'rx' : int X radius
* 'ry' : int Y radius
* 'fill' : mixed [optional] The fill color
* 'line' : mixed [optional] The line color
* 'url' : string [optional] Target URL
*
* @param array $params Parameter array
*
* @return void
*/
function ellipse($params)
{
$x = $this->_getX($params['x']);
$y = $this->_getY($params['y']);
$rx = $this->_getX($params['rx']);
$ry = $this->_getY($params['ry']);
// calculate scale factors
$scaleX = 1.0;
$scaleY = 1.0;
$moveX = 0;
$moveY = 0;
if ($rx > $ry) {
$scaleY = $ry / $rx;
$moveY = $ry * (1 - $scaleY);
} elseif ($rx < $ry) {
$scaleX = $rx / $ry;
$moveX = $rx * (1 - $scaleX);
}
$fillColor = (isset($params['fill']) ? $params['fill'] : false);
$lineColor = (isset($params['line']) ? $params['line'] : false);
$fillColor = $this->_getFillStyle($fillColor);
$lineColor = $this->_getLineStyle($lineColor);
$shape = new SWFShape();
$shape->setRightFill($fillColor[0], $fillColor[1], $fillColor[2]);
$shape->movePenTo($x, $y);
$shape->setLine(1, $lineColor[0], $lineColor[1], $lineColor[2]);
if (count($fillColor)) {
$shape->setRightFill($fillColor[0], $fillColor[1], $fillColor[2]);
}
$shape->drawCircle(max($rx, $ry));
if (isset($params['url'])) {
$button = new SWFButton();
$button->addShape($shape, SWFBUTTON_HIT | SWFBUTTON_UP | SWFBUTTON_DOWN | SWFBUTTON_OVER);
$button->addAction(new SWFAction("getURL('{$params['url']}');"), SWFBUTTON_MOUSEUP);
$ellipse = $this->_canvas->add($button);
} else {
$ellipse = $this->_canvas->add($shape);
}
$ellipse->move($moveX, $moveY);
$ellipse->scaleTo($scaleX, $scaleY);
parent::ellipse($params);
}
/**
* Draw a pie slice
*
* Parameter array:
* 'x' : int X center point
* 'y' : int Y center point
* 'rx' : int X radius
* 'ry' : int Y radius
* 'v1' : int The starting angle (in degrees)
* 'v2' : int The end angle (in degrees)
* 'srx' : int [optional] Starting X-radius of the pie slice (i.e. for a doughnut)
* 'sry' : int [optional] Starting Y-radius of the pie slice (i.e. for a doughnut)
* 'fill' : mixed [optional] The fill color
* 'line' : mixed [optional] The line color
*
* @param array $params Parameter array
*
* @todo
* @return void
*/
function pieslice($params)
{
}
/**
* Get the width of a text,
*
* @param string $text The text to get the width of
*
* @return int The width of the text
*/
function textWidth($text)
{
if (isset($this->_font['vertical']) && $this->_font['vertical']) {
return $this->_font['size'];
} else {
return round($this->_font['size'] * 0.5 * strlen($text));
}
}
/**
* Get the height of a text,
*
* @param string $text The text to get the height of
*
* @return int The height of the text
*/
function textHeight($text)
{
if (isset($this->_font['vertical']) && $this->_font['vertical']) {
return round($this->_font['size'] * 0.7 * strlen($text));
} else {
return $this->_font['size'];
}
}
/**
* Writes text
*
* Parameter array:
* 'x' : int X-point of text
* 'y' : int Y-point of text
* 'text' : string The text to add
* 'color' : mixed [optional] The color of the text
*
* @param array $params Parameter array
*
* @todo Vertical alignment
* @return void
*/
function addText($params)
{
$x0 = $this->_getX($params['x']);
$y0 = $this->_getY($params['y']);
$text = str_replace("\r", '', $params['text']);
$color = (isset($params['color']) ? $params['color'] : false);
$textHeight = $this->textHeight($text);
$alignment = (isset($params['alignment']) ? $params['alignment'] : false);
if (!is_array($alignment)) {
$alignment = array('vertical' => 'top', 'horizontal' => 'left');
}
if (!isset($alignment['vertical'])) {
$alignment['vertical'] = 'top';
}
if (!isset($alignment['horizontal'])) {
$alignment['horizontal'] = 'left';
}
if (($color === false) && (isset($this->_font['color']))) {
$color = $this->_font['color'];
}
if ($color == 'transparent') {
return;
}
if (strpos($this->_font['file'], '.') === false) {
$this->_font['file'] = IMAGE_CANVAS_SYSTEM_FONT_PATH . $this->_font['file'] . '.fdb';
}
$textColor = $this->_color($color);
$textOpacity = $this->_opacity($color);
$lines = explode("\n", $text);
foreach ($lines as $line) {
$x = $x0;
$y = $y0;
$y0 += $textHeight + 2;
$width = $this->textWidth($line);
$height = $this->textHeight($line);
if ($alignment['horizontal'] == 'right') {
$x -= $width;
} else if ($alignment['horizontal'] == 'center') {
$x -= $width / 2;
}
$font = new SWFFont($this->_font['file']);
$text = new SWFText();
$text->setFont($font);
$text->moveTo($x, $y + $this->_font['size']);
$text->setColor($textColor[0], $textColor[1], $textColor[2], $textOpacity);
$text->setHeight($this->_font['size']);
$text->addString($line);
$this->_canvas->add($text);
}
parent::addText($params);
}
/**
* Overlay image
*
* Parameter array:
* 'x' : int X-point of overlayed image
* 'y' : int Y-point of overlayed image
* 'filename' : string The filename of the image to overlay
* 'width' : int [optional] The width of the overlayed image (resizing if possible)
* 'height' : int [optional] The height of the overlayed image (resizing if possible)
* 'alignment' : array [optional] Alignment
* 'url' : string [optional] Target URL
*
* @param array $params Parameter array
*
* @return void
*/
function image($params)
{
parent::image($params);
}
/**
* Display the SWF
*
* @param array $param Parameter array
*
* @return void
*/
function show($param = false)
{
parent::show($param);
$this->_canvas->output();
}
/**
* Save the SWF to a file
*
* @param array $param Parameter array
* array('filename' => 'canvas.swf',
* 'compression' => 0)
*
* The compression level can be a value between 0 and 9,
* defining the SWF compression similar to gzip compression.
* This parameter is only available as of Flash MX (6).
*
* @return void
*/
function save($param = false)
{
if (!isset($param['compression'])) {
$param['compression'] = 0;
}
parent::save($param);
$this->_canvas->save($param['filename'], $param['compression']);
}
/**
* Get SWF movie object
*
* @return object
*/
function getData()
{
return $this->_canvas;
}
/**
* Set clipping to occur
*
* Parameter array:
*
* 'x0' : int X point of Upper-left corner
* 'y0' : int X point of Upper-left corner
* 'x1' : int X point of lower-right corner
* 'y1' : int Y point of lower-right corner
*
* @param array $params Parameter array (x0, y0, x1, y1)
*
* @todo
* @return void
*/
function setClipping($params = false)
{
}
/**
* Get an SWF specific HTML tag
*
* This method implicitly saves the canvas to the filename in the
* filesystem path specified and parses it as URL specified by URL path
*
* Parameter array:
* 'filename' : string
* 'filepath' : string Path to the file on the file system. Remember the final slash
* 'urlpath' : string Path to the file available through an URL. Remember the final slash
* 'width' : int The width in pixels
* 'height' : int The height in pixels
* 'quality' : Flash quality
* 'scale' : Scale
* 'menu' : Whether to display the Flash menu on mouse right-click
*
* @param array $params Parameter array
*
* @return string HTML-output
*/
function toHtml($params)
{
parent::toHtml($params);
return '<object data="' . $params['urlpath'] . $params['filename'] . '" type="application/x-shockwave-flash" width="' . $params['width'] . '" height="' . $params['height'] . '">
<param name="movie" value="' . $params['urlpath'] . $params['filename'] . '">
<param name="quality" value="' . $params['quality'] . '">
<param name="scale" value="' . $params['scale'] . '">
<param name="menu" value="' . $params['menu'] . '">
</object>';
}
}
?>