2009-01-05 00:22:54 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Image_Canvas
|
|
|
|
*
|
|
|
|
* Class for handling output in GD compatible format.
|
|
|
|
*
|
|
|
|
* Supported formats are PNG, JPEG, GIF and WBMP.
|
|
|
|
*
|
|
|
|
* Requires PHP extension GD
|
|
|
|
*
|
|
|
|
* PHP versions 4 and 5
|
|
|
|
*
|
|
|
|
* 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 Jesper Veggerby <pear.nosey@veggerby.dk>
|
|
|
|
* @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen
|
|
|
|
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
|
|
|
|
* @version CVS: $Id: GD.php,v 1.16 2007/06/22 20:19:54 nosey Exp $
|
|
|
|
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=212
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Include file Image/Canvas.php
|
|
|
|
*/
|
|
|
|
require_once 'Image/Canvas/WithMap.php';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Include file Image/Canvas/Color.php
|
|
|
|
*/
|
|
|
|
require_once 'Image/Canvas/Color.php';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Canvas class to output using PHP GD support.
|
|
|
|
*
|
|
|
|
* @category Images
|
|
|
|
* @package Image_Canvas
|
|
|
|
* @author Jesper Veggerby <pear.nosey@veggerby.dk>
|
|
|
|
* @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen
|
|
|
|
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
|
|
|
|
* @version Release: @package_version@
|
|
|
|
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=212
|
|
|
|
* @abstract
|
|
|
|
*/
|
|
|
|
class Image_Canvas_GD extends Image_Canvas_WithMap
|
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The canvas of the graph
|
|
|
|
* @var resource
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
var $_canvas;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The canvas to use for tiled filling
|
|
|
|
* @var resource
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
var $_tileImage = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Is version GD2 installed?
|
|
|
|
* @var bool
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
var $_gd2 = true;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Antialiasing?
|
|
|
|
*
|
|
|
|
* Possible values 'off', 'driver' and 'native'
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
var $_antialias = 'off';
|
|
|
|
|
|
|
|
var $_alpha = false;
|
|
|
|
|
|
|
|
var $_clipping = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create the GD canvas.
|
|
|
|
*
|
|
|
|
* Parameters available:
|
|
|
|
*
|
|
|
|
* 'width' The width of the graph on the canvas
|
|
|
|
*
|
|
|
|
* 'height' The height of the graph on the canvas
|
|
|
|
*
|
|
|
|
* 'left' The left offset of the graph on the canvas
|
|
|
|
*
|
|
|
|
* 'top' The top offset of the graph on the canvas
|
|
|
|
*
|
|
|
|
* 'antialias' = 'native' enables native GD antialiasing - this
|
|
|
|
* method has no severe impact on performance (approx +5%). Requires PHP
|
|
|
|
* 4.3.2 (with bundled GD2)
|
|
|
|
*
|
|
|
|
* 'antialias' = {true|'driver'} Image_Graph implemented method. This method
|
|
|
|
* has a severe impact on performance, drawing an antialiased line this
|
|
|
|
* way is about XX times slower, with an overall performance impact of
|
|
|
|
* about +40%. The justification for this method is that if native support
|
|
|
|
* is not available this can be used, it is also a future feature that this
|
|
|
|
* method for antialiasing will support line styles.
|
|
|
|
*
|
|
|
|
* Use antialiased for best results with a line/area chart having just a few
|
|
|
|
* datapoints. Native antialiasing does not provide a good appearance with
|
|
|
|
* short lines, as for example with smoothed charts. Antialiasing does not
|
|
|
|
* (currently) work with linestyles, neither native nor driver method!
|
|
|
|
*
|
|
|
|
* 'noalpha' = true If alpha blending is to be disabled
|
|
|
|
*
|
|
|
|
* 'filename' An image to open, on which the graph is created on
|
|
|
|
*
|
|
|
|
* 'gd' A GD resource to add the image to, use this option to continue
|
|
|
|
* working on an already existing GD resource. Make sure this is passed 'by-
|
|
|
|
* reference' (using &)
|
|
|
|
*
|
|
|
|
* 'usemap' Initialize an image map
|
|
|
|
*
|
|
|
|
* 'gd' and 'filename' are mutually exclusive with 'gd' as preference
|
|
|
|
*
|
|
|
|
* 'width' and 'height' are required unless 'filename' or 'gd' are
|
|
|
|
* specified, in which case the width and height are taken as the actual
|
|
|
|
* image width/height. If the latter is the case and 'left' and/or 'top' was
|
|
|
|
* also specified, the actual 'width'/'height' are altered so that the graph
|
|
|
|
* fits inside the canvas (i.e 'height' = actual height - top, etc.)
|
|
|
|
*
|
|
|
|
* @param array $param Parameter array
|
|
|
|
*/
|
|
|
|
function Image_Canvas_GD($param)
|
|
|
|
{
|
|
|
|
include_once 'Image/Canvas/Color.php';
|
|
|
|
|
|
|
|
parent::Image_Canvas_WithMap($param);
|
|
|
|
|
|
|
|
$this->_gd2 = ($this->_version() == 2);
|
|
|
|
$this->_font = array('font' => 1, 'color' => 'black');
|
|
|
|
|
|
|
|
if ((isset($param['gd'])) && (is_resource($param['gd']))) {
|
|
|
|
$this->_canvas =& $param['gd'];
|
|
|
|
} elseif (isset($param['filename'])) {
|
|
|
|
$this->_canvas =& $this->_getGD($param['filename']);
|
|
|
|
} else {
|
|
|
|
if ($this->_gd2) {
|
|
|
|
$this->_canvas = ImageCreateTrueColor(
|
|
|
|
$this->_width,
|
|
|
|
$this->_height
|
|
|
|
);
|
|
|
|
if ((!isset($param['noalpha'])) || ($param['noalpha'] !== true)) {
|
|
|
|
ImageAlphaBlending($this->_canvas, true);
|
|
|
|
$this->_alpha = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$this->_canvas = ImageCreate($this->_width, $this->_height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($param['antialias'])) {
|
|
|
|
$this->_antialias = $param['antialias'];
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->_antialias === true) {
|
|
|
|
$this->_antialias = 'driver';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (($this->_gd2) && ($this->_antialias === 'native') && (function_exists('ImageAntialias'))) {
|
|
|
|
ImageAntialias($this->_canvas, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get an GD image resource from a file
|
|
|
|
*
|
|
|
|
* @param string $filename
|
|
|
|
* @return mixed The GD image resource
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
function &_getGD($filename)
|
|
|
|
{
|
|
|
|
$info = getimagesize($filename);
|
|
|
|
|
|
|
|
$result = null;
|
|
|
|
switch($info[2]) {
|
|
|
|
case IMG_PNG:
|
|
|
|
$result =& ImageCreateFromPNG($filename);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IMG_JPG:
|
|
|
|
$result =& ImageCreateFromJPEG($filename);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IMG_GIF:
|
|
|
|
$result =& ImageCreateFromGIF($filename);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the color index for the RGB color
|
|
|
|
*
|
|
|
|
* @param int $color The color
|
|
|
|
* @return int The GD image index of the color
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
function _color($color = false)
|
|
|
|
{
|
|
|
|
if (($color === false) || ($color === 'opague') || ($color === 'transparent')) {
|
|
|
|
return ImageColorTransparent($this->_canvas);
|
|
|
|
} else {
|
|
|
|
return Image_Canvas_Color::allocateColor($this->_canvas, $color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the GD applicable linestyle
|
|
|
|
*
|
|
|
|
* @param mixed $lineStyle The line style to return, false if the one
|
|
|
|
* explicitly set
|
|
|
|
* @return mixed A GD compatible linestyle
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
function _getLineStyle($lineStyle = false)
|
|
|
|
{
|
|
|
|
if ($this->_gd2) {
|
|
|
|
ImageSetThickness($this->_canvas, $this->_thickness);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($lineStyle == 'transparent') {
|
|
|
|
return false;
|
|
|
|
} elseif ($lineStyle === false) {
|
|
|
|
if (is_array($this->_lineStyle)) {
|
|
|
|
$colors = array();
|
|
|
|
foreach ($this->_lineStyle as $color) {
|
|
|
|
if ($color === 'transparent') {
|
|
|
|
$color = false;
|
|
|
|
}
|
|
|
|
$colors[] = $this->_color($color);
|
|
|
|
}
|
|
|
|
ImageSetStyle($this->_canvas, $colors);
|
|
|
|
return IMG_COLOR_STYLED;
|
|
|
|
} else {
|
|
|
|
return $this->_color($this->_lineStyle);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return $this->_color($lineStyle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the GD applicable fillstyle
|
|
|
|
*
|
|
|
|
* @param mixed $fillStyle The fillstyle to return, false if the one
|
|
|
|
* explicitly set
|
|
|
|
* @return mixed A GD compatible fillstyle
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
function _getFillStyle($fillStyle = false, $x0 = 0, $y0 = 0, $x1 = 0, $y1 = 0)
|
|
|
|
{
|
|
|
|
if ($this->_tileImage != null) {
|
|
|
|
ImageDestroy($this->_tileImage);
|
|
|
|
$this->_tileImage = null;
|
|
|
|
}
|
|
|
|
if ($fillStyle == 'transparent') {
|
|
|
|
return false;
|
|
|
|
} elseif ($fillStyle === false) {
|
|
|
|
if (is_resource($this->_fillStyle)) {
|
|
|
|
$x = min($x0, $x1);
|
|
|
|
$y = min($y0, $y1);
|
|
|
|
$w = abs($x1 - $x0) + 1;
|
|
|
|
$h = abs($y1 - $y0) + 1;
|
|
|
|
if ($this->_gd2) {
|
|
|
|
$this->_tileImage = ImageCreateTrueColor(
|
|
|
|
$this->getWidth(),
|
|
|
|
$this->getHeight()
|
|
|
|
);
|
|
|
|
|
|
|
|
ImageCopyResampled(
|
|
|
|
$this->_tileImage,
|
|
|
|
$this->_fillStyle,
|
|
|
|
$x,
|
|
|
|
$y,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
$w,
|
|
|
|
$h,
|
|
|
|
ImageSX($this->_fillStyle),
|
|
|
|
ImageSY($this->_fillStyle)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
$this->_tileImage = ImageCreate(
|
|
|
|
$this->getWidth(),
|
|
|
|
$this->getHeight()
|
|
|
|
);
|
|
|
|
|
|
|
|
ImageCopyResized(
|
|
|
|
$this->_tileImage,
|
|
|
|
$this->_fillStyle,
|
|
|
|
$x,
|
|
|
|
$y,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
$w,
|
|
|
|
$h,
|
|
|
|
ImageSX($this->_fillStyle),
|
|
|
|
ImageSY($this->_fillStyle)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
ImageSetTile($this->_canvas, $this->_tileImage);
|
|
|
|
return IMG_COLOR_TILED;
|
|
|
|
} elseif ((is_array($this->_fillStyle)) && (isset($this->_fillStyle['direction']))) {
|
|
|
|
$width = abs($x1 - $x0) + 1;
|
|
|
|
$height = abs($y1 - $y0) + 1;
|
|
|
|
|
|
|
|
switch ($this->_fillStyle['direction']) {
|
|
|
|
case 'horizontal':
|
|
|
|
$count = $width;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'vertical':
|
|
|
|
$count = $height;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'horizontal_mirror':
|
|
|
|
$count = $width / 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'vertical_mirror':
|
|
|
|
$count = $height / 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'diagonal_tl_br':
|
|
|
|
case 'diagonal_bl_tr':
|
|
|
|
$count = sqrt($width * $width + $height * $height);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'radial':
|
|
|
|
$count = max($width, $height, sqrt($width * $width + $height * $height)) + 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
$count = round($count);
|
|
|
|
|
|
|
|
if ($this->_gd2) {
|
|
|
|
$this->_tileImage = ImageCreateTrueColor(
|
|
|
|
$this->getWidth(),
|
|
|
|
$this->getHeight()
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
$this->_tileImage = ImageCreate(
|
|
|
|
$this->getWidth(),
|
|
|
|
$this->getHeight()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$startColor = Image_Canvas_Color::color2RGB(
|
|
|
|
($this->_fillStyle['direction'] == 'radial' ?
|
|
|
|
$this->_fillStyle['end'] :
|
|
|
|
$this->_fillStyle['start']
|
|
|
|
)
|
|
|
|
);
|
|
|
|
$endColor = Image_Canvas_Color::color2RGB(
|
|
|
|
($this->_fillStyle['direction'] == 'radial' ?
|
|
|
|
$this->_fillStyle['start'] :
|
|
|
|
$this->_fillStyle['end']
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
$redIncrement = ($endColor[0] - $startColor[0]) / $count;
|
|
|
|
$greenIncrement = ($endColor[1] - $startColor[1]) / $count;
|
|
|
|
$blueIncrement = ($endColor[2] - $startColor[2]) / $count;
|
|
|
|
|
|
|
|
$color = false;
|
|
|
|
for ($i = 0; $i < $count; $i ++) {
|
|
|
|
unset($color);
|
|
|
|
if ($i == 0) {
|
|
|
|
$color = $startColor;
|
|
|
|
unset($color[3]);
|
|
|
|
} else {
|
|
|
|
$color[0] = round(($redIncrement * $i) +
|
|
|
|
$redIncrement + $startColor[0]);
|
|
|
|
$color[1] = round(($greenIncrement * $i) +
|
|
|
|
$greenIncrement + $startColor[1]);
|
|
|
|
$color[2] = round(($blueIncrement * $i) +
|
|
|
|
$blueIncrement + $startColor[2]);
|
|
|
|
}
|
|
|
|
$color = Image_Canvas_Color::allocateColor(
|
|
|
|
$this->_tileImage,
|
|
|
|
$color
|
|
|
|
);
|
|
|
|
|
|
|
|
switch ($this->_fillStyle['direction']) {
|
|
|
|
case 'horizontal':
|
|
|
|
ImageLine($this->_tileImage,
|
|
|
|
$x0 + $i,
|
|
|
|
$y0,
|
|
|
|
$x0 + $i,
|
|
|
|
$y1, $color);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'vertical':
|
|
|
|
ImageLine($this->_tileImage,
|
|
|
|
$x0,
|
|
|
|
$y1 - $i,
|
|
|
|
$x1,
|
|
|
|
$y1 - $i, $color);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'horizontal_mirror':
|
|
|
|
if (($x0 + $i) <= ($x1 - $i)) {
|
|
|
|
ImageLine($this->_tileImage,
|
|
|
|
$x0 + $i,
|
|
|
|
$y0,
|
|
|
|
$x0 + $i,
|
|
|
|
$y1, $color);
|
|
|
|
|
|
|
|
ImageLine($this->_tileImage,
|
|
|
|
$x1 - $i,
|
|
|
|
$y0,
|
|
|
|
$x1 - $i,
|
|
|
|
$y1, $color);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'vertical_mirror':
|
|
|
|
if (($y0 + $i) <= ($y1 - $i)) {
|
|
|
|
ImageLine($this->_tileImage,
|
|
|
|
$x0,
|
|
|
|
$y0 + $i,
|
|
|
|
$x1,
|
|
|
|
$y0 + $i, $color);
|
|
|
|
ImageLine($this->_tileImage,
|
|
|
|
$x0,
|
|
|
|
$y1 - $i,
|
|
|
|
$x1,
|
|
|
|
$y1 - $i, $color);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'diagonal_tl_br':
|
|
|
|
if (($i > $width) && ($i > $height)) {
|
|
|
|
$polygon = array (
|
|
|
|
$x1, $y0 + $i - $width - 1,
|
|
|
|
$x1, $y1,
|
|
|
|
$x0 + $i - $height - 1, $y1);
|
|
|
|
} elseif ($i > $width) {
|
|
|
|
$polygon = array (
|
|
|
|
$x0, $y0 + $i,
|
|
|
|
$x0, $y1,
|
|
|
|
$x1, $y1,
|
|
|
|
$x1, $y0 + $i - $width - 1);
|
|
|
|
} elseif ($i > $height) {
|
|
|
|
$polygon = array (
|
|
|
|
$x0 + $i - $height - 1, $y1,
|
|
|
|
$x1, $y1,
|
|
|
|
$x1, $y0,
|
|
|
|
$x0 + $i, $y0);
|
|
|
|
} else {
|
|
|
|
$polygon = array (
|
|
|
|
$x0, $y0 + $i,
|
|
|
|
$x0, $y1,
|
|
|
|
$x1, $y1,
|
|
|
|
$x1, $y0,
|
|
|
|
$x0 + $i, $y0);
|
|
|
|
}
|
|
|
|
ImageFilledPolygon(
|
|
|
|
$this->_tileImage,
|
|
|
|
$polygon,
|
|
|
|
count($polygon) / 2,
|
|
|
|
$color
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'diagonal_bl_tr':
|
|
|
|
if (($i > $width) && ($i > $height)) {
|
|
|
|
$polygon = array (
|
|
|
|
$x1, $y1 - $i + $width - 1,
|
|
|
|
$x1, $y0,
|
|
|
|
$x0 + $i - $height - 1, $y0);
|
|
|
|
} elseif ($i > $width) {
|
|
|
|
$polygon = array (
|
|
|
|
$x0, $y1 - $i,
|
|
|
|
$x0, $y0,
|
|
|
|
$x1, $y0,
|
|
|
|
$x1, $y1 - $i + $width - 1);
|
|
|
|
} elseif ($i > $height) {
|
|
|
|
$polygon = array (
|
|
|
|
$x0 + $i - $height - 1, $y0,
|
|
|
|
$x1, $y0,
|
|
|
|
$x1, $y1,
|
|
|
|
$x0 + $i, $y1);
|
|
|
|
} else {
|
|
|
|
$polygon = array (
|
|
|
|
$x0, $y1 - $i,
|
|
|
|
$x0, $y0,
|
|
|
|
$x1, $y0,
|
|
|
|
$x1, $y1,
|
|
|
|
$x0 + $i, $y1);
|
|
|
|
}
|
|
|
|
ImageFilledPolygon(
|
|
|
|
$this->_tileImage,
|
|
|
|
$polygon,
|
|
|
|
count($polygon) / 2,
|
|
|
|
$color
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'radial':
|
|
|
|
if (($this->_gd2) && ($i < $count)) {
|
|
|
|
ImageFilledEllipse(
|
|
|
|
$this->_tileImage,
|
|
|
|
$x0 + $width / 2,
|
|
|
|
$y0 + $height / 2,
|
|
|
|
$count - $i,
|
|
|
|
$count - $i,
|
|
|
|
$color
|
|
|
|
);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ImageSetTile($this->_canvas, $this->_tileImage);
|
|
|
|
return IMG_COLOR_TILED;
|
|
|
|
} else {
|
|
|
|
return $this->_color($this->_fillStyle);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return $this->_color($fillStyle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets an image that should be used for filling
|
|
|
|
*
|
|
|
|
* @param string $filename The filename of the image to fill with
|
|
|
|
*/
|
|
|
|
function setFillImage($filename)
|
|
|
|
{
|
|
|
|
$this->_fillStyle =& $this->_getGD($filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the font options.
|
|
|
|
*
|
|
|
|
* The $font array may have the following entries:
|
|
|
|
*
|
|
|
|
* 'ttf' = the .ttf file (either the basename, filename or full path)
|
|
|
|
* If 'ttf' is specified, then the following can be specified
|
|
|
|
*
|
|
|
|
* 'size' = size in pixels
|
|
|
|
*
|
|
|
|
* 'angle' = the angle with which to write the text
|
|
|
|
*
|
|
|
|
* @param array $font The font options.
|
|
|
|
*/
|
|
|
|
function setFont($fontOptions)
|
|
|
|
{
|
|
|
|
parent::setFont($fontOptions);
|
|
|
|
|
|
|
|
if (isset($this->_font['ttf'])) {
|
|
|
|
$this->_font['file'] = str_replace('\\', '/', Image_Canvas_Tool::fontMap($this->_font['ttf']));
|
|
|
|
} elseif (!isset($this->_font['font'])) {
|
|
|
|
$this->_font['font'] = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isset($this->_font['color'])) {
|
|
|
|
$this->_font['color'] = 'black';
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((isset($this->_font['angle'])) && ($this->_font['angle'] === false)) {
|
|
|
|
$this->_font['angle'] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculate pixels on a line
|
|
|
|
*
|
|
|
|
* @param int $x0 X start point
|
|
|
|
* @param int $y0 X start point
|
|
|
|
* @param int $x1 X end point
|
|
|
|
* @param int $y1 Y end point
|
|
|
|
* @return array An associated array of x,y points with all pixels on the
|
|
|
|
* line
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
function &_linePixels($x0, $y0, $x1, $y1)
|
|
|
|
{
|
|
|
|
$pixels = array();
|
|
|
|
if (abs($x0 - $x1) > abs($y0 - $y1)) {
|
|
|
|
if ($x1 != $x0) {
|
|
|
|
$m = ($y1 - $y0) / ($x1 - $x0);
|
|
|
|
} else {
|
|
|
|
$m = 0;
|
|
|
|
}
|
|
|
|
$b = $y0 - $m * $x0;
|
|
|
|
$strx = min($x0, $x1);
|
|
|
|
$endx = max($x0, $x1);
|
|
|
|
for ($x = $strx; $x <= $endx; $x++) {
|
|
|
|
$pixels[] = array('X' => $x, 'Y' => ($m * $x + $b));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ($y1 != $y0) {
|
|
|
|
$m = ($x1 - $x0) / ($y1 - $y0);
|
|
|
|
} else {
|
|
|
|
$m = 0;
|
|
|
|
}
|
|
|
|
$b = $x0 - $m * $y0;
|
|
|
|
$stry = min($y0, $y1);
|
|
|
|
$endy = max($y0, $y1);
|
|
|
|
for ($y = $stry; $y <= $endy; $y++) {
|
|
|
|
$pixels[] = array('X' => ($m * $y + $b), 'Y' => $y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $pixels;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draws an antialiased line
|
|
|
|
*
|
|
|
|
* @param int $x0 X start point
|
|
|
|
* @param int $y0 X start point
|
|
|
|
* @param int $x1 X end point
|
|
|
|
* @param int $y1 Y end point
|
|
|
|
* @param mixed $color The line color, can be omitted
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
function _antialiasedLine($x0, $y0, $x1, $y1, $color = false)
|
|
|
|
{
|
|
|
|
if (($line = $this->_getLineStyle($color)) !== false) {
|
|
|
|
if ($line >= 0) {
|
|
|
|
$line = ImageColorsForIndex($this->_canvas, $line);
|
|
|
|
$pixels = &$this->_linePixels($x0, $y0, $x1, $y1);
|
|
|
|
foreach ($pixels as $point) {
|
|
|
|
$this->_antialiasedPixel($point['X'], $point['Y'], $line);
|
|
|
|
}
|
|
|
|
unset($pixels);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draws an antialiased pixel
|
|
|
|
*
|
|
|
|
* @param int $x X point
|
|
|
|
* @param int $y Y point
|
|
|
|
* @param mixed $color The pixel color
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
function _antialiasedPixel($x, $y, $color)
|
|
|
|
{
|
|
|
|
$fx = floor($x);
|
|
|
|
$fy = floor($y);
|
|
|
|
$cx = ceil($x);
|
|
|
|
$cy = ceil($y);
|
|
|
|
$xa = $x - $fx;
|
|
|
|
$xb = $cx - $x;
|
|
|
|
$ya = $y - $fy;
|
|
|
|
$yb = $cy - $y;
|
|
|
|
if (($cx == $fx) && ($cy == $fy)) {
|
|
|
|
$this->_antialisedSubPixel($fx, $fy, 0.0, 1.0, $color);
|
|
|
|
} else {
|
|
|
|
$this->_antialisedSubPixel($fx, $fy, $xa + $ya, $xb + $yb, $color);
|
|
|
|
if ($cy != $fy) {
|
|
|
|
$this->_antialisedSubPixel($fx, $cy, $xa + $yb, $xb + $ya, $color);
|
|
|
|
}
|
|
|
|
if ($cx != $fx) {
|
|
|
|
$this->_antialisedSubPixel($cx, $fy, $xb + $ya, $xa + $yb, $color);
|
|
|
|
if ($cy != $fy) {
|
|
|
|
$this->_antialisedSubPixel($cx, $cy, $xb + $yb, $xa + $ya, $color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Antialias'es the pixel around x,y with weights a,b
|
|
|
|
*
|
|
|
|
* @param int $x X point
|
|
|
|
* @param int $y Y point
|
|
|
|
* @param int $a The weight of the current color
|
|
|
|
* @param int $b The weight of the applied/wanted color
|
|
|
|
* @param mixed $color The pixel color
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
function _antialisedSubPixel($x, $y, $a, $b, $color)
|
|
|
|
{
|
|
|
|
$x = $this->_getX($x);
|
|
|
|
$y = $this->_getX($y);
|
|
|
|
if (($x >=0 ) && ($y >= 0) && ($x < $this->getWidth()) && ($y < $this->getHeight())) {
|
|
|
|
$tempColor = ImageColorsForIndex($this->_canvas, ImageColorAt($this->_canvas, $x, $y));
|
|
|
|
|
|
|
|
$newColor[0] = min(255, round($tempColor['red'] * $a + $color['red'] * $b));
|
|
|
|
$newColor[1] = min(255, round($tempColor['green'] * $a + $color['green'] * $b));
|
|
|
|
$newColor[2] = min(255, round($tempColor['blue'] * $a + $color['blue'] * $b));
|
|
|
|
//$newColor[3] = 0;
|
|
|
|
$color = '#';
|
|
|
|
foreach ($newColor as $acolor) {
|
|
|
|
$color .= sprintf('%02s', dechex($acolor));
|
|
|
|
}
|
|
|
|
$newColor = $this->_color($color);//,'rgb(' . $newColor[0] . ',' . $newColor[1] . ',' . $newColor[2] .')';
|
|
|
|
|
|
|
|
ImageSetPixel($this->_canvas, $x, $y, $newColor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
* @param array $params Parameter array
|
|
|
|
*/
|
|
|
|
function drawEnd($params)
|
|
|
|
{
|
|
|
|
$x = $this->_getX($params['x']);
|
|
|
|
$y = $this->_getY($params['y']);
|
|
|
|
$size = $params['size'];
|
|
|
|
//var_dump($params);
|
|
|
|
$angle = deg2rad((isset($params['angle']) ? $params['angle'] : 0));
|
|
|
|
$pi2 = pi() / 2;
|
|
|
|
switch ($params['end']) {
|
|
|
|
case 'lollipop':
|
|
|
|
case 'circle':
|
|
|
|
$this->ellipse(
|
|
|
|
array(
|
|
|
|
'x' => $x,
|
|
|
|
'y' => $y,
|
|
|
|
'rx' => $size / 2,
|
|
|
|
'ry' => $size / 2,
|
|
|
|
'fill' => $params['color'],
|
|
|
|
'line' => $params['color']
|
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
case 'diamond':
|
|
|
|
$x0 = round($params['x'] + cos($angle) * $size * 0.65);
|
|
|
|
$y0 = round($params['y'] - sin($angle) * $size * 0.65);
|
|
|
|
$shape = array(
|
|
|
|
$x0 + round(cos($angle) * $size * 0.65),
|
|
|
|
$y0 - round(sin($angle) * $size * 0.65),
|
|
|
|
$x0 + round(cos($angle + $pi2) * $size * 0.65),
|
|
|
|
$y0 - round(sin($angle + $pi2) * $size * 0.65),
|
|
|
|
$x0 + round(cos($angle + pi()) * $size * 0.65),
|
|
|
|
$y0 - round(sin($angle + pi()) * $size * 0.65),
|
|
|
|
$x0 + round(cos($angle + 3 * $pi2) * $size * 0.65),
|
|
|
|
$y0 - round(sin($angle + 3 * $pi2) * $size * 0.65)
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
case 'line':
|
|
|
|
$this->line(
|
|
|
|
array(
|
|
|
|
'x0' => $x + round(cos($angle + $pi2) * $size / 2),
|
|
|
|
'y0' => $y - round(sin($angle + $pi2) * $size / 2),
|
|
|
|
'x1' => $x + round(cos($angle + 3 * $pi2) * $size / 2),
|
|
|
|
'y1' => $y - round(sin($angle + 3 * $pi2) * $size / 2),
|
|
|
|
'color' => $params['color']
|
|
|
|
)
|
|
|
|
);
|
|
|
|
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(
|
|
|
|
$x0 + round(cos($angle + $pi4) * $size / 2),
|
|
|
|
$y0 - round(sin($angle + $pi4) * $size / 2),
|
|
|
|
$x0 + round(cos($angle + $pi2 + $pi4) * $size / 2),
|
|
|
|
$y0 - round(sin($angle + $pi2 + $pi4) * $size / 2),
|
|
|
|
$x0 + round(cos($angle + pi() + $pi4) * $size / 2),
|
|
|
|
$y0 - round(sin($angle + pi() + $pi4) * $size / 2),
|
|
|
|
$x0 + round(cos($angle + 3 * $pi2 + $pi4) * $size / 2),
|
|
|
|
$y0 - round(sin($angle + 3 * $pi2 + $pi4) * $size / 2)
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
case 'arrow':
|
|
|
|
$shape = array(
|
|
|
|
$x + cos($angle) * $size,
|
|
|
|
$y - sin($angle) * $size,
|
|
|
|
$x + cos($angle + $pi2) * $size * 0.4,
|
|
|
|
$y - sin($angle + $pi2) * $size * 0.4,
|
|
|
|
$x + cos($angle + 3 * $pi2) * $size * 0.4,
|
|
|
|
$y - sin($angle + 3 * $pi2) * $size * 0.4,
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
case 'arrow2':
|
|
|
|
$shape = array(
|
|
|
|
$x + round(cos($angle) * $size),
|
|
|
|
$y - round(sin($angle) * $size),
|
|
|
|
$x + round(cos($angle + $pi2 + deg2rad(45)) * $size),
|
|
|
|
$y - round(sin($angle + $pi2 + deg2rad(45)) * $size),
|
|
|
|
$x,
|
|
|
|
$y,
|
|
|
|
$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) {
|
|
|
|
ImageFilledPolygon($this->_canvas, $shape, count($shape)/2, $fill);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
parent::drawEnd($params);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draw a line
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
* @param array $params Parameter array
|
|
|
|
*/
|
|
|
|
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);
|
|
|
|
|
|
|
|
$x0 = $this->_getX($x0);
|
|
|
|
$y0 = $this->_getY($y0);
|
|
|
|
$x1 = $this->_getX($x1);
|
|
|
|
$y1 = $this->_getY($y1);
|
|
|
|
if (($this->_antialias === 'driver') && ($x0 != $x1) && ($y0 != $y1)) {
|
|
|
|
$this->_antialiasedLine($x0, $y0, $x1, $y1, $color);
|
|
|
|
} elseif (($line = $this->_getLineStyle($color)) !== false) {
|
|
|
|
ImageLine($this->_canvas, $x0, $y0, $x1, $y1, $line);
|
|
|
|
}
|
|
|
|
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
|
|
|
|
* @param array $params Parameter array
|
|
|
|
*/
|
|
|
|
function polygon($params)
|
|
|
|
{
|
|
|
|
include_once 'Image/Canvas/Tool.php';
|
|
|
|
|
|
|
|
$connectEnds = (isset($params['connect']) ? $params['connect'] : false);
|
|
|
|
$fillColor = (isset($params['fill']) ? $params['fill'] : false);
|
|
|
|
$lineColor = (isset($params['line']) ? $params['line'] : false);
|
|
|
|
|
|
|
|
if (!$connectEnds) {
|
|
|
|
$fillColor = 'transparent';
|
|
|
|
}
|
|
|
|
$style = $this->_getLineStyle($lineColor) . $this->_getFillStyle($fillColor);
|
|
|
|
|
|
|
|
$lastPoint = false;
|
|
|
|
foreach ($this->_polygon as $point) {
|
|
|
|
if (($lastPoint) && (isset($lastPoint['P1X'])) &&
|
|
|
|
(isset($lastPoint['P1Y'])) && (isset($lastPoint['P2X'])) &&
|
|
|
|
(isset($lastPoint['P2Y'])))
|
|
|
|
{
|
|
|
|
$dx = abs($point['X'] - $lastPoint['X']);
|
|
|
|
$dy = abs($point['Y'] - $lastPoint['Y']);
|
|
|
|
$d = sqrt($dx * $dx + $dy * $dy);
|
|
|
|
if ($d > 0) {
|
|
|
|
$interval = 1 / $d;
|
|
|
|
for ($t = 0; $t <= 1; $t = $t + $interval) {
|
|
|
|
$x = Image_Canvas_Tool::bezier(
|
|
|
|
$t,
|
|
|
|
$lastPoint['X'],
|
|
|
|
$lastPoint['P1X'],
|
|
|
|
$lastPoint['P2X'],
|
|
|
|
$point['X']
|
|
|
|
);
|
|
|
|
|
|
|
|
$y = Image_Canvas_Tool::bezier(
|
|
|
|
$t,
|
|
|
|
$lastPoint['Y'],
|
|
|
|
$lastPoint['P1Y'],
|
|
|
|
$lastPoint['P2Y'],
|
|
|
|
$point['Y']
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!isset($low['X'])) {
|
|
|
|
$low['X'] = $x;
|
|
|
|
} else {
|
|
|
|
$low['X'] = min($x, $low['X']);
|
|
|
|
}
|
|
|
|
if (!isset($high['X'])) {
|
|
|
|
$high['X'] = $x;
|
|
|
|
} else {
|
|
|
|
$high['X'] = max($x, $high['X']);
|
|
|
|
}
|
|
|
|
if (!isset($low['Y'])) {
|
|
|
|
$low['Y'] = $y;
|
|
|
|
} else {
|
|
|
|
$low['Y'] = min($y, $low['Y']);
|
|
|
|
}
|
|
|
|
if (!isset($high['Y'])) {
|
|
|
|
$high['Y'] = $y;
|
|
|
|
} else {
|
|
|
|
$high['Y'] = max($y, $high['Y']);
|
|
|
|
}
|
|
|
|
$polygon[] = $x;
|
|
|
|
$polygon[] = $y;
|
|
|
|
}
|
|
|
|
if (($t - $interval) < 1) {
|
|
|
|
$x = Image_Canvas_Tool::bezier(
|
|
|
|
1,
|
|
|
|
$lastPoint['X'],
|
|
|
|
$lastPoint['P1X'],
|
|
|
|
$lastPoint['P2X'],
|
|
|
|
$point['X']
|
|
|
|
);
|
|
|
|
|
|
|
|
$y = Image_Canvas_Tool::bezier(
|
|
|
|
1,
|
|
|
|
$lastPoint['Y'],
|
|
|
|
$lastPoint['P1Y'],
|
|
|
|
$lastPoint['P2Y'],
|
|
|
|
$point['Y']
|
|
|
|
);
|
|
|
|
|
|
|
|
$polygon[] = $x;
|
|
|
|
$polygon[] = $y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!isset($low['X'])) {
|
|
|
|
$low['X'] = $point['X'];
|
|
|
|
} else {
|
|
|
|
$low['X'] = min($point['X'], $low['X']);
|
|
|
|
}
|
|
|
|
if (!isset($high['X'])) {
|
|
|
|
$high['X'] = $point['X'];
|
|
|
|
} else {
|
|
|
|
$high['X'] = max($point['X'], $high['X']);
|
|
|
|
}
|
|
|
|
if (!isset($low['Y'])) {
|
|
|
|
$low['Y'] = $point['Y'];
|
|
|
|
} else {
|
|
|
|
$low['Y'] = min($point['Y'], $low['Y']);
|
|
|
|
}
|
|
|
|
if (!isset($high['Y'])) {
|
|
|
|
$high['Y'] = $point['Y'];
|
|
|
|
} else {
|
|
|
|
$high['Y'] = max($point['Y'], $high['Y']);
|
|
|
|
}
|
|
|
|
|
|
|
|
$polygon[] = $point['X'];
|
|
|
|
$polygon[] = $point['Y'];
|
|
|
|
}
|
|
|
|
$lastPoint = $point;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((isset($polygon)) && (is_array($polygon))) {
|
|
|
|
if ($connectEnds) {
|
|
|
|
if (($fill = $this->_getFillStyle($fillColor, $low['X'], $low['Y'], $high['X'], $high['Y'])) !== false) {
|
|
|
|
ImageFilledPolygon($this->_canvas, $polygon, count($polygon)/2, $fill);
|
|
|
|
}
|
|
|
|
if ($this->_antialias === 'driver') {
|
|
|
|
$pfirst = $p0 = false;
|
|
|
|
reset($polygon);
|
|
|
|
|
|
|
|
while (list(, $x) = each($polygon)) {
|
|
|
|
list(, $y) = each($polygon);
|
|
|
|
if ($p0 !== false) {
|
|
|
|
$this->_antialiasedLine($p0['X'], $p0['Y'], $x, $y, $lineColor);
|
|
|
|
}
|
|
|
|
if ($pfirst === false) {
|
|
|
|
$pfirst = array('X' => $x, 'Y' => $y);
|
|
|
|
}
|
|
|
|
$p0 = array('X' => $x, 'Y' => $y);;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->_antialiasedLine($p0['X'], $p0['Y'], $pfirst['X'], $pfirst['Y'], $lineColor);
|
|
|
|
} elseif (($line = $this->_getLineStyle($lineColor)) !== false) {
|
|
|
|
ImagePolygon($this->_canvas, $polygon, count($polygon)/2, $line);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$prev_point = false;
|
|
|
|
if ($this->_antialias === 'driver') {
|
|
|
|
reset($polygon);
|
|
|
|
while (list(, $x) = each($polygon)) {
|
|
|
|
list(, $y) = each($polygon);
|
|
|
|
if ($prev_point) {
|
|
|
|
$this->_antialiasedLine(
|
|
|
|
$prev_point['X'],
|
|
|
|
$prev_point['Y'],
|
|
|
|
$x,
|
|
|
|
$y,
|
|
|
|
$lineColor
|
|
|
|
);
|
|
|
|
}
|
|
|
|
$prev_point = array('X' => $x, 'Y' => $y);;
|
|
|
|
}
|
|
|
|
} elseif (($line = $this->_getLineStyle($lineColor)) !== false) {
|
|
|
|
reset($polygon);
|
|
|
|
while (list(, $x) = each($polygon)) {
|
|
|
|
list(, $y) = each($polygon);
|
|
|
|
if ($prev_point) {
|
|
|
|
ImageLine(
|
|
|
|
$this->_canvas,
|
|
|
|
$prev_point['X'],
|
|
|
|
$prev_point['Y'],
|
|
|
|
$x,
|
|
|
|
$y,
|
|
|
|
$line
|
|
|
|
);
|
|
|
|
}
|
|
|
|
$prev_point = array('X' => $x, 'Y' => $y);;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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': mixed [optional] The fill color
|
|
|
|
*
|
|
|
|
* 'line': mixed [optional] The line color
|
|
|
|
*
|
|
|
|
* @param array $params Parameter array
|
|
|
|
*/
|
|
|
|
function rectangle($params)
|
|
|
|
{
|
|
|
|
$x0 = $this->_getX($params['x0']);
|
|
|
|
$y0 = $this->_getY($params['y0']);
|
|
|
|
$x1 = $this->_getX($params['x1']);
|
|
|
|
$y1 = $this->_getY($params['y1']);
|
|
|
|
$fillColor = (isset($params['fill']) ? $params['fill'] : false);
|
|
|
|
$lineColor = (isset($params['line']) ? $params['line'] : false);
|
|
|
|
|
|
|
|
if (($fill = $this->_getFillStyle($fillColor, $x0, $y0, $x1, $y1)) !== false) {
|
|
|
|
ImageFilledRectangle($this->_canvas, $x0, $y0, $x1, $y1, $fill);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (($line = $this->_getLineStyle($lineColor)) !== false) {
|
|
|
|
ImageRectangle($this->_canvas, $x0, $y0, $x1, $y1, $line);
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
*
|
|
|
|
* @param array $params Parameter array
|
|
|
|
*/
|
|
|
|
function ellipse($params)
|
|
|
|
{
|
|
|
|
$x = $this->_getX($params['x']);
|
|
|
|
$y = $this->_getY($params['y']);
|
|
|
|
$rx = $this->_getX($params['rx']);
|
|
|
|
$ry = $this->_getY($params['ry']);
|
|
|
|
$fillColor = (isset($params['fill']) ? $params['fill'] : false);
|
|
|
|
$lineColor = (isset($params['line']) ? $params['line'] : false);
|
|
|
|
|
|
|
|
if (($fill = $this->_getFillStyle($fillColor, $x - $rx, $y - $ry, $x + $rx, $y + $ry)) !== false) {
|
|
|
|
ImageFilledEllipse($this->_canvas, $x, $y, $rx * 2, $ry * 2, $fill);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (($line = $this->_getLineStyle($lineColor)) !== false) {
|
|
|
|
ImageEllipse($this->_canvas, $x, $y, $rx * 2, $ry * 2, $line);
|
|
|
|
}
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
function pieslice($params)
|
|
|
|
{
|
|
|
|
$x = $this->_getX($params['x']);
|
|
|
|
$y = $this->_getY($params['y']);
|
|
|
|
$rx = $params['rx'];
|
|
|
|
$ry = $params['ry'];
|
|
|
|
$v1 = $params['v1'];
|
|
|
|
$v2 = $params['v2'];
|
|
|
|
$srx = (isset($params['srx']) ? $params['srx'] : 0);
|
|
|
|
$sry = (isset($params['sry']) ? $params['sry'] : 0);
|
|
|
|
$fillColor = (isset($params['fill']) ? $params['fill'] : false);
|
|
|
|
$lineColor = (isset($params['line']) ? $params['line'] : false);
|
|
|
|
|
|
|
|
$dA = 0.1;
|
|
|
|
|
|
|
|
if (($srx !== false) && ($sry !== false)) {
|
|
|
|
$angle = max($v1, $v2);
|
|
|
|
while ($angle >= min($v1, $v2)) {
|
|
|
|
$polygon[] = ($x + $srx * cos(deg2rad($angle % 360)));
|
|
|
|
$polygon[] = ($y + $sry * sin(deg2rad($angle % 360)));
|
|
|
|
$angle -= $dA;
|
|
|
|
}
|
|
|
|
if (($angle + $dA) > min($v1, $v2)) {
|
|
|
|
$polygon[] = ($x + $srx * cos(deg2rad(min($v1, $v2) % 360)));
|
|
|
|
$polygon[] = ($y + $sry * sin(deg2rad(min($v1, $v2) % 360)));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$polygon[] = $x;
|
|
|
|
$polygon[] = $y;
|
|
|
|
}
|
|
|
|
|
|
|
|
$angle = min($v1, $v2);
|
|
|
|
while ($angle <= max($v1, $v2)) {
|
|
|
|
$polygon[] = ($x + $rx * cos(deg2rad($angle % 360)));
|
|
|
|
$polygon[] = ($y + $ry * sin(deg2rad($angle % 360)));
|
|
|
|
$angle += $dA;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (($angle - $dA) < max($v1, $v2)) {
|
|
|
|
$polygon[] = ($x + $rx * cos(deg2rad(max($v1, $v2) % 360)));
|
|
|
|
$polygon[] = ($y + $ry * sin(deg2rad(max($v1, $v2) % 360)));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((($fill = $this->_getFillStyle($fillColor, $x - $rx - 1, $y - $ry - 1, $x + $rx + 1, $y + $ry + 1)) !== false) && (count($polygon) > 2)) {
|
|
|
|
ImageFilledPolygon($this->_canvas, $polygon, count($polygon) / 2, $fill);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (($line = $this->_getLineStyle($lineColor)) !== false) {
|
|
|
|
ImagePolygon($this->_canvas, $polygon, count($polygon) / 2, $line);
|
|
|
|
}
|
|
|
|
|
|
|
|
parent::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['file'])) {
|
|
|
|
$angle = 0;
|
|
|
|
if (isset($this->_font['angle'])) {
|
|
|
|
$angle = $this->_font['angle'];
|
|
|
|
}
|
|
|
|
|
|
|
|
$width = 0;
|
|
|
|
$lines = explode("\n", $text);
|
|
|
|
foreach ($lines as $line) {
|
|
|
|
$bounds = ImageTTFBBox(
|
|
|
|
$this->_font['size'],
|
|
|
|
$angle,
|
|
|
|
$this->_font['file'],
|
|
|
|
$text
|
|
|
|
);
|
|
|
|
|
|
|
|
$x0 = min($bounds[0], $bounds[2], $bounds[4], $bounds[6]);
|
|
|
|
$x1 = max($bounds[0], $bounds[2], $bounds[4], $bounds[6]);
|
|
|
|
$width = max(abs($x0 - $x1), $width);
|
|
|
|
}
|
|
|
|
return $width;
|
|
|
|
} else {
|
|
|
|
if ((isset($this->_font['vertical'])) && ($this->_font['vertical'])) {
|
|
|
|
return ImageFontHeight($this->_font['font']) * (substr_count($text, "\n") + 1);
|
|
|
|
} else {
|
|
|
|
$width = 0;
|
|
|
|
$lines = explode("\n", $text);
|
|
|
|
foreach ($lines as $line) {
|
|
|
|
$width = max($width, ImageFontWidth($this->_font['font']) * strlen($line));
|
|
|
|
}
|
|
|
|
return $width;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the height of a text.
|
|
|
|
*
|
|
|
|
* Note! This method can give some peculiar results, since ImageTTFBBox() returns the total
|
|
|
|
* bounding box of a text, where ImageTTF() writes the text on the baseline of the text, that
|
|
|
|
* is 'g', 'p', 'q' and other letters that dig under the baseline will appear to have a larger
|
|
|
|
* height than they actually do. Have a look at the tests/text.php test case - the first two
|
|
|
|
* columns, 'left and 'center', both look alright, whereas the last column, 'right', appear
|
|
|
|
* with a larger space between the first text and the second. This is because the total height
|
|
|
|
* is actually smaller by exactly the number of pixels that the 'g' digs under the baseline.
|
|
|
|
* Remove the 'g' from the text and they appear correct.
|
|
|
|
*
|
|
|
|
* @param string $text The text to get the height of
|
|
|
|
* @param bool $force Force the method to calculate the size
|
|
|
|
* @return int The height of the text
|
|
|
|
*/
|
|
|
|
function textHeight($text, $force = false)
|
|
|
|
{
|
|
|
|
if (isset($this->_font['file'])) {
|
|
|
|
$angle = 0;
|
|
|
|
if (isset($this->_font['angle'])) {
|
|
|
|
$angle = $this->_font['angle'];
|
|
|
|
}
|
|
|
|
|
|
|
|
$linebreaks = substr_count($text, "\n");
|
|
|
|
if (($angle == 0) && ($force === false)) {
|
|
|
|
/*
|
|
|
|
* if the angle is 0 simply return the size, due to different
|
|
|
|
* heights for example for x-axis labels, making the labels
|
|
|
|
* _not_ appear as written on the same baseline
|
|
|
|
*/
|
|
|
|
return $this->_font['size'] + ($this->_font['size'] + 2) * $linebreaks;
|
|
|
|
}
|
|
|
|
|
|
|
|
$height = 0;
|
|
|
|
$lines = explode("\n", $text);
|
|
|
|
foreach ($lines as $line) {
|
|
|
|
$bounds = ImageTTFBBox(
|
|
|
|
$this->_font['size'],
|
|
|
|
$angle,
|
|
|
|
$this->_font['file'],
|
|
|
|
$line
|
|
|
|
);
|
|
|
|
|
|
|
|
$y0 = min($bounds[1], $bounds[3], $bounds[5], $bounds[7]);
|
|
|
|
$y1 = max($bounds[1], $bounds[3], $bounds[5], $bounds[7]);
|
|
|
|
$height += abs($y0 - $y1);
|
|
|
|
}
|
|
|
|
return $height + $linebreaks * 2;
|
|
|
|
} else {
|
|
|
|
if ((isset($this->_font['vertical'])) && ($this->_font['vertical'])) {
|
|
|
|
$width = 0;
|
|
|
|
$lines = explode("\n", $text);
|
|
|
|
foreach ($lines as $line) {
|
|
|
|
$width = max($width, ImageFontWidth($this->_font['font']) * strlen($line));
|
|
|
|
}
|
|
|
|
return $width;
|
|
|
|
} else {
|
|
|
|
return ImageFontHeight($this->_font['font']) * (substr_count($text, "\n") + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculated the absolute bottom-left position of the text, by simulating
|
|
|
|
* the calculation of the baseline drop.
|
|
|
|
* @param int $x The relative x position to write the text
|
|
|
|
* @param int $y The relative y position to write the text
|
|
|
|
* @param string $text The text to write
|
|
|
|
* @param array $align The alignment of the text relative to (x, y)
|
|
|
|
* @returns array An array containing the absolute x and y positions
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
function _getAbsolutePosition($x, $y, $text, $align)
|
|
|
|
{
|
|
|
|
if ($this->_font['angle'] > 0) {
|
|
|
|
$w0 = $this->textWidth($text);
|
|
|
|
$h0 = $this->textHeight($text);
|
|
|
|
|
|
|
|
if ($align['vertical'] == 'bottom') {
|
|
|
|
$dy = $y - $h0;
|
|
|
|
}
|
|
|
|
else if ($align['vertical'] == 'center') {
|
|
|
|
$dy = $y - $h0 / 2;
|
|
|
|
}
|
|
|
|
else if ($align['vertical'] == 'top') {
|
|
|
|
$dy = $y;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($align['horizontal'] == 'right') {
|
|
|
|
$dx = $x - $w0;
|
|
|
|
}
|
|
|
|
else if ($align['horizontal'] == 'center') {
|
|
|
|
$dx = $x - $w0 / 2;
|
|
|
|
}
|
|
|
|
else if ($align['horizontal'] == 'left') {
|
|
|
|
$dx = $x;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (($this->_font['angle'] < 180) && ($this->_font['angle'] >= 0)) {
|
|
|
|
$dy += $h0;
|
|
|
|
}
|
|
|
|
if (($this->_font['angle'] >= 90) && ($this->_font['angle'] < 270)) {
|
|
|
|
$dx += $w0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// get the maximum size of normal text above base line - sampled by 'Al'
|
|
|
|
$size1 = imagettfbbox($this->_font['size'], 0, $this->_font['file'], 'Al');
|
|
|
|
$height1 = abs($size1[7] - $size1[1]);
|
|
|
|
|
|
|
|
// get the maximum size of all text above base and below line - sampled by 'AlgjpqyQ'
|
|
|
|
$size2 = imagettfbbox($this->_font['size'], 0, $this->_font['file'], 'AlgjpqyQ');
|
|
|
|
$height2 = abs($size2[7] - $size2[1]);
|
|
|
|
|
|
|
|
// get the size of the text, simulating height above baseline beinh max, by sampling using 'Al'
|
|
|
|
$size = imagettfbbox($this->_font['size'], 0, $this->_font['file'], 'Al' . $text);
|
|
|
|
$height = abs($size[7] - $size[1]);
|
|
|
|
|
|
|
|
// if all text is above baseline, i.e. height of text compares to max height above (within 10%)
|
|
|
|
if (abs($height - $height1)/$height1 < 0.1) {
|
|
|
|
$dHeight = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$dHeight = abs($height2 - $height1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// specifies the bottom-left corner!
|
|
|
|
$dx = $x + sin(deg2rad($this->_font['angle'])) * $dHeight;
|
|
|
|
$dy = $y - cos(deg2rad($this->_font['angle'])) * $dHeight;
|
|
|
|
|
|
|
|
if ($align['vertical'] == 'top') {
|
|
|
|
$dy += $height;
|
|
|
|
}
|
|
|
|
else if ($align['vertical'] == 'center') {
|
|
|
|
$dy += ($height + $dHeight) / 2;
|
|
|
|
}
|
|
|
|
else if ($align['vertical'] == 'bottom') {
|
|
|
|
$dy += $dHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($align['horizontal'] == 'center') {
|
|
|
|
$factor = 0.5;
|
|
|
|
}
|
|
|
|
else if ($align['horizontal'] == 'right') {
|
|
|
|
$factor = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$factor = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($factor != 0) {
|
|
|
|
$size = imagettfbbox($this->_font['size'], 0, $this->_font['file'], $text);
|
|
|
|
$w0 = abs($size[2] - $size[0]);
|
|
|
|
$dx -= cos(deg2rad($this->_font['angle'])) * $w0 * $factor;
|
|
|
|
$dy += sin(deg2rad($this->_font['angle'])) * $w0 * $factor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return array('x' => $dx, 'y' => $dy);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Writes text
|
|
|
|
*
|
|
|
|
* Parameter array:
|
|
|
|
*
|
|
|
|
* 'x': int X-point of text
|
|
|
|
*
|
|
|
|
* 'y': int Y-point of text
|
|
|
|
*
|
|
|
|
* 'text': string The text to add
|
|
|
|
*
|
|
|
|
* 'alignment': array [optional] Alignment
|
|
|
|
*
|
|
|
|
* 'color': mixed [optional] The color of the text
|
|
|
|
*/
|
|
|
|
function addText($params)
|
|
|
|
{
|
|
|
|
$x0 = $this->_getX($params['x']);
|
|
|
|
$y0 = $this->_getY($params['y']);
|
|
|
|
$text = $params['text'];
|
|
|
|
$color = (isset($params['color']) ? $params['color'] : false);
|
|
|
|
$alignment = (isset($params['alignment']) ? $params['alignment'] : false);
|
|
|
|
|
|
|
|
$text = str_replace("\r", '', $text);
|
|
|
|
|
|
|
|
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 (isset($this->_font['size'])) {
|
|
|
|
$textHeight = $this->_font['size'] + 2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$textHeight = $this->textHeight('A');
|
|
|
|
}
|
|
|
|
$lines = explode("\n", $text);
|
|
|
|
foreach ($lines as $line) {
|
|
|
|
$x = $x0;
|
|
|
|
$y = $y0;
|
|
|
|
|
|
|
|
$y0 += $textHeight + 2;
|
|
|
|
|
|
|
|
if (($color === false) && (isset($this->_font['color']))) {
|
|
|
|
$color = $this->_font['color'];
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($color != 'transparent') {
|
|
|
|
if (isset($this->_font['file'])) {
|
|
|
|
$result = $this->_getAbsolutePosition($x, $y, $line, $alignment);
|
|
|
|
ImageTTFText(
|
|
|
|
$this->_canvas,
|
|
|
|
$this->_font['size'],
|
|
|
|
$this->_font['angle'],
|
|
|
|
$result['x'],
|
|
|
|
$result['y'],
|
|
|
|
$this->_color($color),
|
|
|
|
$this->_font['file'],
|
|
|
|
$line
|
|
|
|
);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
$width = $this->textWidth($line);
|
|
|
|
$height = $this->textHeight($line);
|
|
|
|
if ($alignment['horizontal'] == 'right') {
|
|
|
|
$x -= $width;
|
|
|
|
}
|
|
|
|
else if ($alignment['horizontal'] == 'center') {
|
|
|
|
$x -= $width / 2;
|
|
|
|
}
|
|
|
|
if ($alignment['vertical'] == 'bottom') {
|
|
|
|
$y -= $height;
|
|
|
|
}
|
|
|
|
else if ($alignment['vertical'] == 'center') {
|
|
|
|
$y -= $height / 2;
|
|
|
|
}
|
|
|
|
if ((isset($this->_font['vertical'])) && ($this->_font['vertical'])) {
|
|
|
|
ImageStringUp(
|
|
|
|
$this->_canvas,
|
|
|
|
$this->_font['font'],
|
|
|
|
$x,
|
|
|
|
$y + $this->textHeight($text),
|
|
|
|
$line,
|
|
|
|
$this->_color($color)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
ImageString(
|
|
|
|
$this->_canvas,
|
|
|
|
$this->_font['font'],
|
|
|
|
$x,
|
|
|
|
$y,
|
|
|
|
$line,
|
|
|
|
$this->_color($color)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
function image($params)
|
|
|
|
{
|
|
|
|
$x = $this->_getX($params['x']);
|
|
|
|
$y = $this->_getY($params['y']);
|
|
|
|
$filename = $params['filename'];
|
|
|
|
$width = (isset($params['width']) ? $params['width'] : false);
|
|
|
|
$height = (isset($params['height']) ? $params['height'] : false);
|
|
|
|
$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 (file_exists($filename)) {
|
|
|
|
if (strtolower(substr($filename, -4)) == '.png') {
|
|
|
|
$image = ImageCreateFromPNG($filename);
|
|
|
|
} elseif (strtolower(substr($filename, -4)) == '.gif') {
|
|
|
|
$image = ImageCreateFromGIF($filename);
|
|
|
|
} else {
|
|
|
|
$image = ImageCreateFromJPEG($filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
$imgWidth = ImageSX($image);
|
|
|
|
$imgHeight = ImageSY($image);
|
|
|
|
|
|
|
|
$outputWidth = ($width !== false ? $width : $imgWidth);
|
|
|
|
$outputHeight = ($height !== false ? $height : $imgHeight);
|
|
|
|
|
|
|
|
if ($alignment['horizontal'] == 'right') {
|
|
|
|
$x -= $outputWidth;
|
|
|
|
} elseif ($alignment['horizontal'] == 'center') {
|
|
|
|
$x -= $outputWidth / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($alignment['vertical'] == 'bottom') {
|
|
|
|
$y -= $outputHeight;
|
|
|
|
} elseif ($alignment['vertical'] == 'center') {
|
|
|
|
$y -= $outputHeight / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((($width !== false) && ($width != $imgWidth)) ||
|
|
|
|
(($height !== false) && ($height != $imgHeight)))
|
|
|
|
{
|
|
|
|
if ($this->_gd2) {
|
|
|
|
ImageCopyResampled(
|
|
|
|
$this->_canvas,
|
|
|
|
$image,
|
|
|
|
$x,
|
|
|
|
$y,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
$width,
|
|
|
|
$height,
|
|
|
|
$imgWidth,
|
|
|
|
$imgHeight
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
ImageCopyResized(
|
|
|
|
$this->_canvas,
|
|
|
|
$image,
|
|
|
|
$x,
|
|
|
|
$y,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
$width,
|
|
|
|
$height,
|
|
|
|
$imgWidth,
|
|
|
|
$imgHeight
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ImageCopy(
|
|
|
|
$this->_canvas,
|
|
|
|
$image,
|
|
|
|
$x,
|
|
|
|
$y,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
$imgWidth,
|
|
|
|
$imgHeight
|
|
|
|
);
|
|
|
|
}
|
|
|
|
ImageDestroy($image);
|
|
|
|
}
|
|
|
|
parent::image($params);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
function setClipping($params = false)
|
|
|
|
{
|
|
|
|
if ($params === false) {
|
|
|
|
$index = count($this->_clipping) - 1;
|
|
|
|
if (isset($this->_clipping[$index])) {
|
|
|
|
$params = $this->_clipping[$index];
|
|
|
|
$canvas = $params['canvas'];
|
|
|
|
ImageCopy(
|
|
|
|
$canvas,
|
|
|
|
$this->_canvas,
|
|
|
|
min($params['x0'], $params['x1']),
|
|
|
|
min($params['y0'], $params['y1']),
|
|
|
|
min($params['x0'], $params['x1']),
|
|
|
|
min($params['y0'], $params['y1']),
|
|
|
|
abs($params['x1'] - $params['x0'] + 1),
|
|
|
|
abs($params['y1'] - $params['y0'] + 1)
|
|
|
|
);
|
|
|
|
$this->_canvas = $canvas;
|
|
|
|
unset($this->_clipping[$index]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$params['canvas'] = $this->_canvas;
|
|
|
|
|
|
|
|
if ($this->_gd2) {
|
|
|
|
$this->_canvas = ImageCreateTrueColor(
|
|
|
|
$this->_width,
|
|
|
|
$this->_height
|
|
|
|
);
|
|
|
|
if ($this->_alpha) {
|
|
|
|
ImageAlphaBlending($this->_canvas, true);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$this->_canvas = ImageCreate($this->_width, $this->_height);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (($this->_gd2) && ($this->_antialias === 'native')) {
|
|
|
|
ImageAntialias($this->_canvas, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
ImageCopy($this->_canvas, $params['canvas'], 0, 0, 0, 0, $this->_width, $this->_height);
|
|
|
|
|
|
|
|
$this->_clipping[count($this->_clipping)] = $params;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a canvas 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
|
|
|
|
*
|
|
|
|
* 'alt': string [optional] Alternative text on image
|
|
|
|
*
|
|
|
|
* 'cssclass': string [optional] The CSS Stylesheet class
|
|
|
|
*
|
|
|
|
* 'border': int [optional] The border width on the image
|
|
|
|
*/
|
|
|
|
function toHtml($params)
|
|
|
|
{
|
|
|
|
parent::toHtml($params);
|
|
|
|
return '<img src="' . $params['urlpath'] . $params['filename'] . '"' .
|
|
|
|
(isset($params['alt']) ? ' alt="' . $params['alt'] . '"' : '') .
|
|
|
|
(isset($params['cssclass']) ? ' class="' . $params['cssclass'] . '"' : '') .
|
|
|
|
(isset($params['border']) ? ' border="' . $params['border'] . '"' : '') .
|
|
|
|
(isset($this->_imageMap) ? ' usemap="#' . $params['filename'] . '"' : '') . '>' .
|
|
|
|
(isset($this->_imageMap) ? "\n" . $this->_imageMap->toHtml(array('name' => $params['filename'])) : '');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resets the canvas.
|
|
|
|
*
|
|
|
|
* Include fillstyle, linestyle, thickness and polygon
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
function _reset()
|
|
|
|
{
|
|
|
|
if ($this->_gd2) {
|
|
|
|
ImageSetThickness($this->_canvas, 1);
|
|
|
|
}
|
|
|
|
if ($this->_tileImage != null) {
|
|
|
|
ImageDestroy($this->_tileImage);
|
|
|
|
$this->_tileImage = null;
|
|
|
|
}
|
|
|
|
parent::_reset();
|
|
|
|
$this->_font = array('font' => 1, 'color' => 'black');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check which version of GD is installed
|
|
|
|
*
|
|
|
|
* @return int 0 if GD isn't installed, 1 if GD 1.x is installed and 2 if GD
|
|
|
|
* 2.x is installed
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
function _version()
|
|
|
|
{
|
|
|
|
$result = false;
|
|
|
|
if (function_exists('gd_info')) {
|
|
|
|
$info = gd_info();
|
|
|
|
$version = $info['GD Version'];
|
|
|
|
} else {
|
|
|
|
ob_start();
|
|
|
|
phpinfo(8);
|
|
|
|
$php_info = ob_get_contents();
|
|
|
|
ob_end_clean();
|
|
|
|
|
|
|
|
if (ereg("<td[^>]*>GD Version *<\/td><td[^>]*>([^<]*)<\/td>",
|
|
|
|
$php_info, $result))
|
|
|
|
{
|
|
|
|
$version = $result[1];
|
|
|
|
} else {
|
|
|
|
$version = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ereg('1\.[0-9]{1,2}', $version)) {
|
|
|
|
return 1;
|
|
|
|
} elseif (ereg('2\.[0-9]{1,2}', $version)) {
|
|
|
|
return 2;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-11-26 22:50:40 +00:00
|
|
|
?>
|