BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Painter - A PHP GD Library.
* @author Nnamdi Onyeyiri
* @version 1.1
* @package Painter
*/
/* Geometric Primitives ----------------------------------------------------- */
/**
* Encapsulates a point in 2-dimensional space.
* @package Painter
*/
class Point
{
/**
* X co-ordinate.
* @var number
*/
var $X;
/**
* Y co-ordinate.
* @var number
*/
var $Y;
/**
* Creates a new Point object.
* @param number $x The X co-ordinate.
* @param number $y The Y co-ordinate.
*/
function Point ($x, $y)
{
painter_enforce_type ($x, "number");
painter_enforce_type ($y, "number");
$this->X = $x;
$this->Y = $y;
}
}
/**
* Encapsulates a rectangle.
* @package Painter
*/
class Rect
{
/**
* X co-ordinate of upper left corner.
* @var number
*/
var $X;
/**
* Y co-ordinate of upper left corner.
* @var number
*/
var $Y;
/**
* Rectangle width.
* @var number
*/
var $Width;
/**
* Rectangle height.
* @var number
*/
var $Height;
/**
* Creates a new Rect object.
* @param number $x The upper left corner X co-ordinate.
* @param number $y The upper left corner Y co-ordinate.
* @param number $w The width of the Rect.
* @param number $h The height of the Rect.
*/
function Rect ($x, $y, $w, $h)
{
painter_enforce_type ($x, "number");
painter_enforce_type ($y, "number");
painter_enforce_type ($w, "number");
painter_enforce_type ($h, "number");
$this->X = $x;
$this->Y = $y;
$this->Width = $w;
$this->Height = $h;
}
/**
* Srinks the Rect by the specified number of pixels.
* @param int $v The number of pixels to shrink the Rect by.
* @return Rect
*/
function Shrink ($v = 1)
{
painter_enforce_type ($v, "number");
$x = $this->X + $v;
$y = $this->Y + $v;
$w = $this->Width - ($v * 2);
$h = $this->Height - ($v * 2);
return new Rect ($x, $y, $w, $h);
}
/**
* Expands the Rect by the specified number of pixels.
* @param int $v The number of pixels to expand the Rect by.
* @return Rect
*/
function Grow ($v = 1)
{
painter_enforce_type ($v, "number");
$x = $this->X - $v;
$y = $this->Y - $v;
$w = $this->Width + ($v * 2);
$h = $this->Height + ($v * 2);
return new Rect ($x, $y, $w, $h);
}
}
/**
* Encapsulates an ellipse.
* @package Painter
*/
class Ellipse
{
/**
* The X co-ordinate of the center of the ellipse.
* @var number
*/
var $X;
/**
* The Y co-ordinate of the center of the ellipse.
* @var number
*/
var $Y;
/**
* Ellipse width.
* @var number
*/
var $Width;
/**
* Ellipse height.
* @var number
*/
var $Height;
/**
* Creates a new Ellipse object.
* @param number $x The upper left corner X co-ordinate.
* @param number $y The upper left corner Y co-ordinate.
* @param number $w The width of the Ellipse.
* @param number $h The height of the Ellipse.
*/
function Ellipse ($x, $y, $w, $h)
{
painter_enforce_type ($x, "number");
painter_enforce_type ($y, "number");
painter_enforce_type ($w, "number");
painter_enforce_type ($h, "number");
$this->X = $x;
$this->Y = $y;
$this->Width = $w;
$this->Height = $h;
}
/**
* Srinks the Ellipse by the specified number of pixels.
* @param int $v The number of pixels to shrink the Ellipse by.
* @return Ellipse
*/
function Shrink ($v = 1)
{
painter_enforce_type ($v, "number");
$w = $this->Width - ($v * 2);
$h = $this->Height - ($v * 2);
return new Ellipse ($this->X, $this->Y, $w, $h);
}
/**
* Expands the Ellipse by the specified number of pixels.
* @param int $v The number of pixels to expand the Ellipse by.
* @return Ellipse
*/
function Grow ($v = 1)
{
painter_enforce_type ($v, "number");
$w = $this->Width + ($v * 2);
$h = $this->Height + ($v * 2);
return new Ellipse ($this->X, $this->Y, $w, $h);
}
}
/**
* Encapsulates an arc.
* @package Painter
*/
class Arc
{
/**
* The X co-ordinate of the ellipse the arc is a part of.
* @var number
*/
var $X;
/**
* The Y co-ordinate of the ellipse the arc is a part of.
* @var number
*/
var $Y;
/**
* The width of the ellipse the arc is a part of.
* @var number
*/
var $Width;
/**
* The height of the ellipse the arc is a part of.
* @var number
*/
var $Height;
/**
* The start angle of the arc.
* @var number
*/
var $Start;
/**
* The end angle of the arc.
* @var number
*/
var $End;
/**
* Creates a new Arc object.
* @param number $x The upper left corner X co-ordinate.
* @param number $y The upper left corner Y co-ordinate.
* @param number $w The width of the Arc.
* @param number $h The height of the Arc.
* @param number $s The start angle.
* @param number $e The end angle.
*/
function Arc ($x, $y, $w, $h, $s, $e)
{
painter_enforce_type ($x, "number");
painter_enforce_type ($y, "number");
painter_enforce_type ($w, "number");
painter_enforce_type ($h, "number");
painter_enforce_type ($s, "number");
painter_enforce_type ($e, "number");
$this->X = $x;
$this->Y = $y;
$this->Width = $w;
$this->Height = $h;
$this->Start = $s;
$this->End = $e;
}
/**
* Srinks the Arc by the specified number of pixels.
* @param int $v The number of pixels to shrink the Arc by.
* @return Arc
*/
function Shrink ($v = 1)
{
painter_enforce_type ($v, "number");
$w = $this->Width - ($v * 2);
$h = $this->Height - ($v * 2);
return new Arc ($this->X, $this->Y, $w, $h, $this->Start, $this->End);
}
/**
* Expands the Arc by the specified number of pixels.
* @param int $v The number of pixels to expand the Arc by.
* @return Arc
*/
function Grow ($v = 1)
{
painter_enforce_type ($v, "number");
$w = $this->Width + ($v * 2);
$h = $this->Height + ($v * 2);
return new Arc ($this->X, $this->Y, $w, $h, $this->Start, $this->End);
}
}
/**
* Encapsulates a polygon.
* @package Painter
*/
class Polygon
{
/**
* An array of the points that form the polygon.
* @var number
*/
var $Points;
/**
* Expands the Arc by the specified number of pixels.
* @param array $pts An array of Point objects that form the polygon.
*/
function Polygon ($pts = null)
{
$this->Points = array ();
if ($pts != null)
{
painter_enforce_type ($pts, "array");
$this->Points = $pts;
}
}
/**
* Adds a new Point to the polygon.
* @param Point $pt The Point to add.
*/
function AddPoint ($pt)
{
painter_enforce_type ($pt, "Point");
$this->Points[] = $pt;
}
/**
* Makes this Polygon the same as the specified Rect $r.
* @param Rect $r The Rect to model.
*/
function FromRect ($r)
{
painter_enforce_type ($r, "Rect");
$this->Points = array ();
$this->AddPoint (new Point ($r->X, $r->Y));
$this->AddPoint (new Point ($r->X + $r->Width, $r->Y));
$this->AddPoint (new Point ($r->X + $r->Width, $r->Y + $r->Height));
$this->AddPoint (new Point ($r->X, $r->Y + $r->Height));
$this->AddPoint (new Point ($r->X, $r->Y));
}
/**
* Makes this Polygon the same as the specified Ellipse $el.
* @param Ellipse $el The Ellipse to model.
* @param int $step Smoothness of the generated curve.
*/
function FromEllipse ($el, $step = 10)
{
painter_enforce_type ($step, "int");
$arc = new Arc ($el->X, $el->Y, $el->Width, $el->Height, 0, 360);
$this->Points = $this->_Arc2Polygon ($arc, $step);
}
/**
* Makes this Polygon the same as the specified Arc $arc.
* @param Arc $arc The Arc to model.
* @param int $step Smoothness of the generated curve.
*/
function FromArc ($arc, $step = 10)
{
painter_enforce_type ($step, "int");
$this->Points = $this->_Arc2Polygon ($arc, $step);
}
/**
* Returns the center point of the polygon.
* @return Point
*/
function GetCenter ()
{
$len = count ($this->Points);
$x = 0;
$y = 0;
for ($i = 0; $i < $len; $i++)
{
$x += $this->Points[$i]->X;
$y += $this->Points[$i]->Y;
}
$x = round ($x / $len);
$y = round ($y / $len);
return new Point ($x, $y);
}
/**
* @access private
*/
function _Arc2Polygon ($arc, $step)
{
$pts = array ();
$beta = -deg2rad (90);
$sinbeta = sin ($beta);
$cosbeta = cos ($beta);
$a = $arc->Height / 2;
$b = $arc->Width / 2;
for ($i = $arc->Start + 90; $i < $arc->End + 90; $i += $step)
{
$alpha = deg2rad ($i);
$sinalpha = sin ($alpha);
$cosalpha = cos ($alpha);
$cc = $cosalpha * $costbeta;
$ss = $sinalpha * $sinbeta;
$cas = $cosalpha * $sinbeta;
$sac = $sinalpha * $cosbeta;
$x = $arc->X + (($a * $cc) - ($b * $ss));
$y = $arc->Y + (($a * $cas) + ($b * $sac));
$pts[] = new Point (round ($x), round ($y));
}
if ($arc->End - $arc->Start < 360)
{
$pts[] = new Point ($arc->X, $arc->Y);
}
return $pts;
}
}
/* Geometric Transformations ------------------------------------------------ */
/**
* Encapsulates transformations for Polygon objects.
* @package Painter
*/
class Transform
{
/**
* @access private
*/
var $matrix;
/**
* Creates a new Transform object.
*/
function Transform ()
{
$this->Clear ();
}
/**
* Restores the transformation matrix to the identity matrix.
*/
function Clear ()
{
$this->matrix = array ( 1, 0, 0,
0, 1, 0,
0, 0, 1 );
}
/**
* Adds a translation operation.
* @param number $x Translation along X axis.
* @param number $y Translation along Y axis.
*/
function Translate ($x, $y)
{
painter_enforce_type ($x, "int");
painter_enforce_type ($y, "int");
$trans = array ( 1, 0, $x,
0, 1, $y,
0, 0, 1);
$this->matrix = $this->_Mult ($this->matrix, $trans);
}
/**
* Adds a rotation operation.
* @param number $theta The angle of rotation.
*/
function Rotate ($theta)
{
painter_enforce_type ($theta, "number");
$t = deg2rad ($theta);
$rotate = array ( cos ($t), -sin ($t), 0,
sin ($t), cos ($t), 0,
0, 0, 1);
$this->matrix = $this->_Mult ($this->matrix, $rotate);
}
/**
* Adds a sheering operation.
* @param number $x The sheering value along the X axis.
* @param number $y The sheering value along the Y axis.
*/
function Sheer ($x = 0, $y = 0)
{
painter_enforce_type ($x, "number");
painter_enforce_type ($y, "number");
$sheer = array ( 1, $x, 0,
$y, 1, 0,
0, 0, 1);
$this->matrix = $this->_Mult ($this->matrix, $sheer);
}
/**
* Adds a scaling operation.
* @param number $x The value to scale in along the X axis.
* @param number $y The value to scale in along the Y axis.
*/
function Scale ($x = 1, $y = 1)
{
painter_enforce_type ($x, "number");
painter_enforce_type ($y, "number");
$scale = array ( $x, 0, 0,
0, $y, 0,
0, 0, 1);
$this->matrix = $this->_Mult ($this->matrix, $scale);
}
/**
* Adds a custom transformation.
* @param array $trans A 3x3 transformation matrix to include.
*/
function CustomTransform ($trans)
{
painter_enforce_type ($trans, "array");
if (count ($trans) != 9)
{
painter_error ("Specified transform array must contain 9 elements");
}
$this->matrix = $this->_Mult ($this->matrix, $trans);
}
/**
* Performs the stored transformation on $poly. $cx = $y = -1 will set the
* centre of the Polygon as origin.
* @param Polygon $poly The Polygon to transform.
* @param int $cx The X co-ordinate to act as origin.
* @param int $cy The Y co-ordinate to act as origin.
* @return Polygon
*/
function Trans ($poly, $cx = -1, $cy = -1)
{
painter_enforce_type ($poly, "Polygon");
painter_enforce_type ($cx, "int");
painter_enforce_type ($cy, "int");
if ($cx < 0 || $cy < 0)
{
$cpt = $poly->GetCenter ();
$cx = $cpt->X;
$cy = $cpt->Y;
}
$trans = $this->_CentreOrigin ($cx, $cy);
$len = count ($poly->Points);
$npoly = new Polygon ();
for ($i = 0; $i < $len; $i++)
{
$pt = $poly->Points[$i];
$v = array (0 => $pt->X, 3 => $pt->Y, 6 => 1);
$v = $this->_Mult ($trans, $v);
$npoly->AddPoint (new Point (round ($v[0]), round ($v[3])));
}
return $npoly;
}
/**
* @access private
*/
function _CentreOrigin ($cx, $cy)
{
$origin = array ( 1, 0, -$cx,
0, 1, -$cy,
0, 0, 1);
$iorigin = array ( 1, 0, $cx,
0, 1, $cy,
0, 0, 1);
$trans = $this->_Mult ($this->matrix, $origin);
$trans = $this->_Mult ($iorigin, $trans);
return $trans;
}
/**
* @access private
*/
function _Mult ($a, $b)
{
$c = array ();
$p = count ($b) / 3;
for ($j = 0; $j < $p; $j++)
{
for ($i = 0; $i < 3; $i++)
{
for ($k = 0; $k < 3; $k++)
{
$c[($i * 3) + $j] += $a[($i * 3) + $k] * $b[($k * 3) + $j];
}
}
}
return $c;
}
}
/* Colour Representation ---------------------------------------------------- */
/**
* Encapsulates a colour.
* @package Painter
*/
class Colour
{
/**
* Red colour value.
* @var int
*/
var $R;
/**
* Green colour value.
* @var int
*/
var $G;
/**
* Blue colour value.
* @var int
*/
var $B;
/**
* Alpha colour value.
* @var int
*/
var $A;
/**
* Creates a new Colour object.
* @param int $r Red.
* @param int $g Green.
* @param int $b Blue.
* @param int $a Alpha.
*/
function Colour ($r = -1, $g = -1, $b = -1, $a = 0)
{
painter_enforce_type ($r, "number");
painter_enforce_type ($g, "number");
painter_enforce_type ($b, "number");
painter_enforce_type ($a, "number");
if ($r < 0) $r = rand (0, 255);
if ($g < 0) $g = rand (0, 255);
if ($b < 0) $b = rand (0, 255);
$this->R = $r;
$this->G = $g;
$this->B = $b;
$this->A = $a;
}
/**
* Lightens the colour by the percent specified by $d.
* @param int $d The percentage to lighten the colour by.
*/
function Lighten ($d = 10)
{
list ($h, $s, $v) = $this->_Rgb2Hsv ();
$v += $v * ($d / 100);
list ($r, $g, $b) = $this->_Hsv2Rgb ($h, $s, $v);
$this->R = min ($r, 255);
$this->G = min ($g, 255);
$this->B = min ($b, 255);
}
/**
* Darkens the colour by the percent specified by $d.
* @param int $d The percentage to darken the colour by.
*/
function Darken ($d = 10)
{
list ($h, $s, $v) = $this->_Rgb2Hsv ();
$v -= $v * ($d / 100);
list ($r, $g, $b) = $this->_Hsv2Rgb ($h, $s, $v);
$this->R = max ($r, 0);
$this->G = max ($g, 0);
$this->B = max ($b, 0);
}
/**
* @access private
*/
function _Rgb2Hsv ()
{
$r = $this->R / 255;
$g = $this->G / 255;
$b = $this->B / 255;
$max = max ($r, max ($g, $b));
$min = min ($r, min ($g, $b));
$dif = $max - $min;
if ($max == $min)
{
$h = 0;
}
else if ($max == $r && $g >= $b)
{
$h = 60 * (($g - $b) / $dif);
}
else if ($max == $r && $g < $b)
{
$h = (60 * (($g - $b) / $dif)) + 360;
}
else if ($max == $g)
{
$h = (60 * (($b - $r) / $dif)) + 120;
}
else
{
$h = (60 * (($r - $g) / $dif)) + 240;
}
$v = $max;
if ($max == 0)
{
$s = 0;
}
else
{
$s = ($max - $min) / $max;
}
return array ($h, $s, $v);
}
/**
* @access private
*/
function _Hsv2Rgb ($h, $s, $v)
{
$hi = floor (($h / 60) % 6);
$f = ($h / 60) - floor ($h / 60);
$p = $v * (1 - $s);
$q = $v * (1 - ($f * $s));
$t = $v * ((1 - (1 - $f) * $s));
switch ($hi)
{
case 0: $r = $v; $g = $t; $b = $p; break;
case 1: $r = $q; $g = $v; $b = $p; break;
case 2: $r = $p; $g = $v; $b = $t; break;
case 3: $r = $p; $g = $q; $b = $v; break;
case 4: $r = $t; $g = $p; $b = $v; break;
case 5: $r = $v; $g = $p; $b = $q; break;
}
return array (round ($r * 255), round ($g * 255), round ($b * 255));
}
}
/* Gradient Brush ----------------------------------------------------------- */
/**
* Encapsulates a gradient.
* @package Painter
*/
class Gradient
{
/**
* @access private
*/
var $Colours;
/**
* Creates a new Gradient object.
* @param Colour $start The start colour.
* @param Colour $end The end colour.
*/
function Gradient ($start, $end)
{
painter_enforce_type ($start, "Colour");
painter_enforce_type ($end, "Colour");
$this->Colours = array ();
$this->Colours[0] = $start;
$this->Colours[100] = $end;
}
/**
* Inserts a colour to be used at $percent percent of the way through
* the gradient.
* @param Colour $clr The colour to add.
* @param int $percent The percent of the way through.
*/
function Add ($clr, $percent)
{
painter_enforce_type ($clr, "Colour");
painter_enforce_type ($percent, "int");
$this->Colours[$percent] = $clr;
ksort ($this->Colours);
}
/**
* Returns the colour to use at a point in a gradient.
* @param int $pos The position in the rendering.
* @param int $w The width of the gradient area.
* @return Colour
*/
function GetColour ($pos, $w)
{
list ($c1, $c2) = $this->_GetBoudingColours ($pos, $w);
$dist = (($c2 - $c1) / 100) * $w;
$i = $pos - (($c1 / 100) * $w);
$clr1 = $this->Colours[$c1];
$clr2 = $this->Colours[$c2];
$r1 = $clr1->R;
$g1 = $clr1->G;
$b1 = $clr1->B;
$r2 = $clr2->R;
$g2 = $clr2->G;
$b2 = $clr2->B;
$r = ($r2 - $r1 != 0) ? intval ($r1 + ($r2 - $r1) * ($i / $dist)) : $r1;
$g = ($g2 - $g1 != 0) ? intval ($g1 + ($g2 - $g1) * ($i / $dist)) : $g1;
$b = ($b2 - $b1 != 0) ? intval ($b1 + ($b2 - $b1) * ($i / $dist)) : $b1;
return new Colour ($r, $g, $b);
}
/**
* @access private
*/
function _GetBoudingColours ($pos, $w)
{
$percent = round (($pos / $w) * 100);
$keys = array_keys ($this->Colours);
$clr1 = $keys[0];
$clr2 = $keys[1];
for ($i = 0; $i < count ($keys); $i++)
{
if ($keys[$i] < $percent)
{
$clr1 = $keys[$i];
$clr2 = $keys[$i + 1];
}
else
break;
}
return array ($clr1, $clr2);
}
}
/* Font Handling ------------------------------------------------------------ */
/**
* Encapsulates a font.
* @package Painter
*/
class Font
{
/**#@+
* @access private
*/
var $Handle;
var $Size;
var $Type;
var $Path;
/**#@-*/
/**
* Creates a new Font object.
* @param int $sz The size of a built-in font.
*/
function Font ($sz = -1)
{
if ($sz > 0)
{
$this->LoadDefault ($sz);
}
}
/**
* Loads a built-in font.
* @param int $sz The size of the built-in font.
*/
function LoadDefault ($sz)
{
$this->Type = "default";
$this->Size = $sz;
}
/**
* Loads a TTF font.
* @param string $path The path to the font file.
* @param int $sz The font size.
*/
function LoadTtfFont ($path, $sz)
{
painter_enforce_type ($path, "string");
painter_enforce_type ($sz, "number");
$this->Type = "ttf";
$this->Path = $path;
$this->Size = $sz;
}
/**
* Loads a PS font.
* @param string $path The path to the font file.
* @param int $sz The font size.
*/
function LoadPsFont ($path, $sz)
{
painter_enforce_type ($path, "string");
painter_enforce_type ($sz, "number");
$this->Type = "ps";
$this->Path = $path;
$this->Size = $sz;
$this->Handle = imagepsloadfont ($path);
}
/**
* Loads a GD font.
* @param string $path The path to the font file.
* @param int $sz The font size.
*/
function LoadGdFont ($path, $sz)
{
painter_enforce_type ($path, "string");
painter_enforce_type ($sz, "number");
$this->Type = "gd";
$this->Path = $path;
$this->Handle = imageloadfont ($path);
$this->Size = $sz;
}
/**
* Frees the resources used by a font.
*/
function Free ()
{
switch ($this->Type)
{
case "ps": imagepsfreefont ($this->Handle); break;
case "gd": imagefreefont ($this->Handle); break;
}
}
}
/* The Painter Class -------------------------------------------------------- */
/**
* Wrapper class for some GD operations.
* @package Painter
*/
class Painter
{
/**#@+
* @access private
*/
var $img;
var $width;
var $height;
/**#@+*/
/**
* Creates a new Painter object.
* @param int $w The image width.
* @param int $h The image height.
*/
function Painter ($w, $h)
{
painter_enforce_type ($w, "int");
painter_enforce_type ($h, "int");
$this->img = imagecreatetruecolor ($w, $h);
$this->width = $w;
$this->height = $h;
$this->Antialias ();
}
/**
* Fills the image with a single colour.
* @param Colour $clr The colour to use, or null for white.
*/
function Clear ($clr = null)
{
if ($clr == null)
{
$clr = new Colour (255, 255, 255);
}
else
{
painter_enforce_type ($clr, "Colour");
}
$this->FillRect (new Rect (0, 0, $this->width, $this->height), $clr);
}
/**
* Returns the underlying image handle.
* @return image
*/
function GetImage ()
{
return $this->img;
}
/**
* Returns the size of the image.
* @return array
*/
function GetSize ()
{
return array ($this->width, $this->height);
}
/**
* Turns on/off antialiasing.
* @param bool $on Set alias state.
*/
function Antialias ($on = true)
{
painter_enforce_type ($on, "bool");
if (function_exists ("imageantialias"))
{
imageantialias ($this->img, $on);
}
}
/**
* Sets the thickness of the lines used by drawing functions.
* @param int $thickness The line thickness.
*/
function SetThickness ($thickness)
{
painter_enforce_type ($thickness, "int");
imagesetthickness ($this->img, $thickness);
}
/**
* Draws a line between $pt1 and $pt2.
* @param Point $pt1 Start point.
* @param Point $pt2 End point.
* @param Colour $clr The colour to use.
*/
function DrawLine ($pt1, $pt2, $clr)
{
painter_enforce_type ($pt1, "Point");
painter_enforce_type ($pt2, "Point");
painter_enforce_type ($clr, "Colour");
$img = $this->img;
$c = imagecolorallocatealpha ($img, $clr->R, $clr->G, $clr->B, $clr->A);
imageline ($img, $pt1->X, $pt1->Y, $pt2->X, $pt2->Y, $c);
imagecolordeallocate ($img, $c);
}
/**
* Draw a Rect.
* @param Rect $rect The Rect to draw.
* @param Colour $clr The colour to use.
*/
function DrawRect ($rect, $clr)
{
$this->_Rect ($rect, $clr, false);
}
/**
* Fill a Rect.
* @param Rect $rect The Rect to fill.
* @param Colour $clr The colour to use.
*/
function FillRect ($rect, $clr)
{
$this->_Rect ($rect, $clr, true);
}
/**
* Gradient fill a Rect.
* @param Rect $rect The Rect to fill.
* @param Gradient $grad The gradient to use.
* @param bool $vert True for vertical gradient, otherwise false.
*/
function GradFillRect ($rect, $grad, $vert = false)
{
painter_enforce_type ($rect, "Rect");
painter_enforce_type ($grad, "Gradient");
painter_enforce_type ($vert, "bool");
$lines = $this->_BoxGradLines ($rect, $vert);
$this->_GradFill ($lines, $grad);
}
/**
* Draw an Ellipse.
* @param Ellipse $el The Ellipse to draw.
* @param Colour $clr The colour to use.
*/
function DrawEllipse ($el, $clr)
{
$this->_Ellipse ($el, $clr, false);
}
/**
* Fill an Ellipse.
* @param Rect $el The Ellipse to fill.
* @param Colour $clr The colour to use.
*/
function FillEllipse ($el, $clr)
{
$this->_Ellipse ($el, $clr, true);
}
/**
* Gradient fill an Ellipse.
* @param Ellipse $el The Ellipse to fill.
* @param Gradient $grad The gradient to use.
* @param bool $vert True for vertical gradient, otherwise false.
*/
function GradFillEllipse ($el, $grad, $vert = false)
{
painter_enforce_type ($el, "Ellipse");
painter_enforce_type ($grad, "Gradient");
painter_enforce_type ($vert, "bool");
$arc = new Arc ($el->X, $el->Y, $el->Width, $el->Height, 0, 360);
$lines = $this->_ArcGradLines ($arc, $vert);
$this->_GradFill ($lines, $grad);
}
/**
* Draw a Polygon.
* @param Polygon $poly The Polygon to draw.
* @param Colour $clr The colour to use.
*/
function DrawPolygon ($poly, $clr)
{
$this->_Polygon ($poly, $clr, false);
}
/**
* Fill a Polygon.
* @param Polygon $poly The Polygon to fill.
* @param Colour $clr The colour to use.
*/
function FillPolygon ($poly, $clr)
{
$this->_Polygon ($poly, $clr, true);
}
/**
* Draw an Arc.
* @param Arc $arc The Arc to draw.
* @param Colour $clr The colour to use.
*/
function DrawArc ($arc, $clr)
{
$this->_Arc ($arc, $clr, false, 0);
}
/**
* Fill an Arc.
* @param Arc $arc The Arc to draw.
* @param Colour $clr The colour to use.
* @param int $style A bitwise OR of the style options or filling arcs.
*/
function FillArc ($arc, $clr, $style = 0)
{
$this->_Arc ($arc, $clr, true, $style);
}
/**
* Gradient fill an Arc.
* @param Arc $arc The Arc to fill.
* @param Gradient $grad The gradient to use.
* @param bool $vert True for vertical gradient, otherwise false.
*/
function GradFillArc ($arc, $grad, $vert = false)
{
painter_enforce_type ($arc, "Arc");
painter_enforce_type ($grad, "Gradient");
painter_enforce_type ($vert, "bool");
if ($arc->Start != 0 || $vert)
{
$msg = "Vertical gradients or arcs that do not start at angle 0";
$msg .= " are not currently supported";
painter_error ($msg);
}
$lines = $this->_ArcGradLines ($arc, $vert);
$this->_GradFill ($lines, $grad);
}
/**
* Writes text.
* @param Font $font The font to write.
* @param Point $pt The Point to draw the text.
* @param string $txt The string to write.
* @param Colour $clr The Colour to use.
* @param int $angle The angle to draw the text at.
*/
function WriteText ($font, $pt, $txt, $clr, $angle = 0)
{
painter_enforce_type ($font, "Font");
painter_enforce_type ($pt, "Point");
painter_enforce_type ($txt, "string");
painter_enforce_type ($clr, "Colour");
painter_enforce_type ($angle, "number");
$img = $this->img;
$c = imagecolorallocatealpha ($img, $clr->R, $clr->G, $clr->B, $clr->A);
$sz = $font->Size;
$p = $font->Path;
switch ($font->Type)
{
case "ttf":
imagettftext ($img, $sz, $angle, $pt->X, $pt->Y, $c, $p, $txt);
break;
case "ps":
imagepstext ($img, $txt, $font->Handle, $sz, $c, $c, $pt->X,
$pt->Y, null, null, $angle, null);
break;
default:
imagestring ($img, $sz, $pt->X, $pt->Y, $txt, $c);
break;
}
imagecolordeallocate ($img, $c);
}
/**
* Calculate the bounding box of some text.
* @param Font $font The font to write.
* @param string $txt The string to write.
* @param int $angle The angle to draw the text at.
* @return Rect
*/
function MeasureText ($font, $txt, $angle = 0)
{
painter_enforce_type ($font, "Font");
painter_enforce_type ($txt, "string");
painter_enforce_type ($angle, "number");
$img = $this->img;
$c = imagecolorallocatealpha ($img, $clr->R, $clr->G, $clr->B, $clr->A);
$sz = $font->Size;
$p = $font->Path;
$ret = null;
switch ($font->Type)
{
case "ttf":
$bb = imagettfbbox ($sz, $angle, $p, $txt);
$ret = new Rect (0, 0, $bb[2]-$bb[0], $bb[1]-$bb[7]);
break;
case "ps":
$bb =imagepsbbox ($txt, $font->Handle, $sz, null, null, $angle);
$ret = new Rect (0, 0, $bb[2] - $bb[0], $bb[3] - $bb[1]);
break;
default:
$ret = new Rect (0, 0, 0, 0);
break;
}
imagecolordeallocate ($img, $c);
return $ret;
}
/**
* Destroys the image.
*/
function Free ()
{
imagedestroy ($this->img);
}
/**
* @access private
*/
function _Rect ($rect, $clr, $fill)
{
painter_enforce_type ($rect, "Rect");
painter_enforce_type ($clr, "Colour");
$x = $rect->X;
$y = $rect->Y;
$w = $rect->Width - 1;
$h = $rect->Height - 1;
$img = $this->img;
$c = imagecolorallocatealpha ($img, $clr->R, $clr->G, $clr->B, $clr->A);
if ($fill)
{
imagefilledrectangle ($img, $x, $y, $x + $w, $y + $h, $c);
}
else
{
imagerectangle ($img, $x, $y, $x + $w, $y + $h, $c);
}
imagecolordeallocate ($img, $c);
}
/**
* @access private
*/
function _Ellipse ($el, $clr, $fill)
{
painter_enforce_type ($el, "Ellipse");
painter_enforce_type ($clr, "Colour");
$x = $el->X;
$y = $el->Y;
$w = $el->Width;
$h = $el->Height;
$img = $this->img;
$c = imagecolorallocatealpha ($img, $clr->R, $clr->G, $clr->B, $clr->A);
if ($fill)
{
imagefilledellipse ($img, $x, $y, $w, $h, $c);
}
else
{
imageellipse ($img, $x, $y, $w, $h, $c);
}
imagecolordeallocate ($img, $c);
}
/**
* @access private
*/
function _Polygon ($poly, $clr, $fill)
{
painter_enforce_type ($poly, "Polygon");
painter_enforce_type ($clr, "Colour");
$cnt = count ($poly->Points);
$pts = array ();
for ($i = 0; $i < $cnt; $i++)
{
$pts[] = $poly->Points[$i]->X;
$pts[] = $poly->Points[$i]->Y;
}
$img = $this->img;
$c = imagecolorallocatealpha ($img, $clr->R, $clr->G, $clr->B, $clr->A);
if ($fill)
{
imagefilledpolygon ($img, $pts, $cnt, $c);
}
else
{
imagepolygon ($img, $pts, $cnt, $c);
}
imagecolordeallocate ($img, $c);
}
/**
* @access private
*/
function _Arc ($arc, $clr, $fill, $style)
{
painter_enforce_type ($arc, "Arc");
painter_enforce_type ($clr, "Colour");
$x = $arc->X;
$y = $arc->Y;
$w = $arc->Width;
$h = $arc->Height;
$s = $arc->Start;
$e = $arc->End;
$img = $this->img;
$c = imagecolorallocatealpha ($img, $clr->R, $clr->G, $clr->B, $clr->A);
if ($fill)
{
imagefilledarc ($img, $x, $y, $w, $h, $s, $e, $c, $style);
}
else
{
imagearc ($img, $x, $y, $w, $h, $s, $e, $c);
}
imagecolordeallocate ($img, $c);
}
/**
* @access private
*/
function _BoxGradLines ($r, $vert)
{
$lines = array ();
$w = $r->Width - 1;
$h = $r->Height;
$len = (!$vert) ? $h : $w;
for ($i = 0; $i < $len; $i++)
{
if (!$vert)
{
$lines[] = array ($r->X, $r->Y + $i, $r->X + $w, $r->Y + $i);
}
else
{
$lines[] = array ($r->X + $i, $r->Y, $r->X + $i, $r->Y + $h);
}
}
return $lines;
}
/**
* @access private
*/
function _PlotLine ($pt1, $pt2, $vert)
{
$dx = ($pt2->X - $pt1->X);
$m = $c = null;
if ($dx != 0)
{
$m = ($pt2->Y - $pt1->Y) / $dx;
$c = $pt1->Y - ($m * $pt1->X);
}
if ($vert)
{
$min = min ($pt1->X, $pt2->X);
$max = max ($pt1->X, $pt2->X);
for ($i = $min; $i < $max; $i++)
{
$line[$i] = round (($m * $i) + $c);
}
}
else
{
$min = min ($pt1->Y, $pt2->Y);
$max = max ($pt1->Y, $pt2->Y);
for ($i = $min; $i < $max; $i++)
{
if ($m != null)
{
$line[$i] = round (($i - $c) / $m);
}
else
{
$line[$i] = $pt1->X;
}
}
}
return $line;
}
/**
* @access private
*/
function _ArcGradLines($arc, $vert)
{
$p = new Polygon ();
$p->FromArc ($arc, 1);
$pts = $p->Points;
$len = count ($pts);
if ($arc->End - $arc->Start < 360)
{
$line = $this->_PlotLine ($pts[$len - 2], $pts[$len - 1], $vert);
}
$bds = array ();
for ($i = 0; $i < $len; $i++)
{
if (!$vert)
{
$y = $pts[$i]->Y;
$x = array ($pts[$i]->X);
$bds[$y] = (isset ($bds[$y])) ? array_merge ($bds[$y], $x) : $x;
if ($arc->End - $arc->Start < 360 && isset ($line[$y]))
{
$bds[$y] = array_merge ($bds[$y], array ($line[$y]));
}
}
else
{
$x = $pts[$i]->X;
$y = array ($pts[$i]->Y);
$bds[$x] = (isset ($bds[$x])) ? array_merge ($bds[$x], $y) : $y;
}
}
$len = count ($bds);
ksort ($bds);
$lines = array ();
$keys = array_keys ($bds);
for ($i = 0; $i < $len; $i++)
{
$sl = $bds[$keys[$i]];
$min = null;
$max = null;
for ($j = 0; $j < count ($sl); $j++)
{
if ($min == null || $sl[$j] < $min) $min = $sl[$j];
if ($max == null || $sl[$j] > $max) $max = $sl[$j];
}
if (!$vert)
{
$lines[] = array ($min, $keys[$i], $max, $keys[$i]);
}
else
{
$lines[] = array ($keys[$i], $min, $keys[$i], $max);
}
}
return $lines;
}
/**
* @access private
*/
function _GradFill ($lines, $grad)
{
$img = $this->img;
$l = count ($lines);
for ($i = 0; $i < $l; $i++)
{
$oldr = $r;
$oldg = $g;
$oldb = $b;
$c = $grad->GetColour ($i, $l);
$r = $c->R;
$g = $c->G;
$b = $c->B;
if ("$oldr,$oldg,$oldb" != "$r,$g,$b")
{
if ($fill) imagecolordeallocate ($img, $fill);
$fill = imagecolorallocate ($img, $r, $g, $b);
}
$ln = $lines[$i];
$lx1 = $ln[0];
$ly1 = $ln[1];
$lx2 = $ln[2];
$ly2 = $ln[3];
imagefilledrectangle($img, $lx1, $ly1, $lx2, $ly2, $fill);
}
}
}
/* Global functions --------------------------------------------------------- */
/**
* @access private
*/
function painter_enforce_type ($obj, $type)
{
switch ($type)
{
case "string": $valid = is_string ($obj); break;
case "int": $valid = is_int ($obj); break;
case "float": $valid = is_float ($obj); break;
case "double": $valid = is_double ($obj); break;
case "number": $valid = is_numeric($obj); break;
case "array": $valid = is_array($obj); break;
case "bool": $valid = is_bool($obj); break;
default: $valid = ($type == get_class ($obj));
}
if (!$valid)
{
$trace = debug_backtrace ();
$func = $trace[1]['function'];
$err = "Invalid argument to function '".$func;
$err .= "', required type '".$type."'";
painter_error ($err);
}
}
/**
* @access private
*/
function painter_error ($msg, $trace = true)
{
echo "Painter Error: ".$msg."
";
if ($trace)
{
var_dump (debug_backtrace ());
}
die ();
}
?>