Source for file gd.class.php
Documentation is available at gd.class.php
* This work is hereby released into the Public Domain.
* To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
require_once dirname(__FILE__ ). "/../Driver.class.php";
* @package linea21.externals
$this->driverString = 'gd';
public function init(awImage $image) {
// Antialiasing is now handled by the Driver object
new awPoint($this->imageWidth, $this->imageHeight)
$shadow = $image->shadow;
$shadow = $shadow->getSpace();
$p1 = new awPoint($shadow->left, $shadow->top);
$p2 = new awPoint($this->imageWidth - $shadow->right - 1, $this->imageHeight - $shadow->bottom - 1);
$image->border->rectangle($this, $p1, $p2);
public function initFromFile(awFileImage $fileImage, $file) {
if($image and in_array($image[2], array(2, 3))) {
$fileImage->setSize($image[0], $image[1]);
awImage::drawError("Class FileImage: Artichow does not support the format of this image (must be in PNG or JPEG)");
$this->imageWidth = $width;
$this->imageHeight = $height;
// Calculate absolute position
$this->x = round($x * $this->imageWidth - $this->w / 2);
$this->y = round($y * $this->imageHeight - $this->h / 2);
$this->w = round($w * $this->imageWidth);
$this->h = round($h * $this->imageHeight);
return array($this->w, $this->h);
imageantialias($this->resource, (bool) $bool);
$this->antiAliasing = (bool) $bool;
} elseif($bool == true) {
public function getColor(awColor $color) {
if($color->alpha === 0 or function_exists('imagecolorallocatealpha') === FALSE) {
public function copyImage(awImage $image, awPoint $p1, awPoint $p2) {
list ($x1, $y1) = $p1->getLocation();
list ($x2, $y2) = $p2->getLocation();
$driver = $image->getDriver();
imagecopy($this->resource, $driver->resource, $this->x + $x1, $this->y + $y1, 0, 0, $x2 - $x1, $y2 - $y1);
public function copyResizeImage(awImage $image, awPoint $d1, awPoint $d2, awPoint $s1, awPoint $s2, $resample = TRUE) {
$function = 'imagecopyresampled';
$function = 'imagecopyresized';
$driver = $image->getDriver();
$this->x + $d1->x, $this->y + $d1->y,
$d2->x - $d1->x, $d2->y - $d1->y,
$s2->x - $s1->x, $s2->y - $s1->y
public function string(awText $text, awPoint $point, $width = NULL) {
$font = $text->getFont();
// Can we deal with that font?
if($this->isCompatibleWithFont($font) === FALSE) {
awImage::drawError('Class GDDriver: Incompatible font type (\''.get_class($font).'\')');
// Check which FontDriver to use
$fontDriver = $this->phpFontDriver;
$fontDriver = $this->fileFontDriver;
if($text->getBackground() !== NULL or $text->border->visible()) {
list ($left, $right, $top, $bottom) = $text->getPadding();
$textWidth = $fontDriver->getTextWidth($text, $this);
$textHeight = $fontDriver->getTextHeight($text, $this);
$x1 = floor($point->x - $left);
$y1 = floor($point->y - $top);
$x2 = $x1 + $textWidth + $left + $right;
$y2 = $y1 + $textHeight + $top + $bottom;
$text->border->rectangle(
$fontDriver->string($this, $text, $point, $width);
public function point(awColor $color, awPoint $p) {
if($p->isHidden() === FALSE) {
public function line(awColor $color, awLine $line) {
if($line->thickness > 0 and $line->isHidden() === FALSE) {
$thickness = $line->thickness;
list ($p1, $p2) = $line->getLocation();
$this->startThickness($thickness);
switch($line->getStyle()) {
$size = sqrt(pow($p2->y - $p1->y, 2) + pow($p2->x - $p1->x, 2));
$cos = ($p2->x - $p1->x) / $size;
$sin = ($p2->y - $p1->y) / $size;
for($i = 0; $i <= $size; $i += 2) {
round($i * $cos + $p1->x),
round($i * $sin + $p1->y)
$this->point($color, $p);
$width = $p2->x - $p1->x;
$height = $p2->y - $p1->y;
$functionX = ($width > 0) ? 'min' : 'max';
$functionY = ($height > 0) ? 'min' : 'max';
for($i = 0; $i <= $size; $i += 6) {
round($i * $cos + $p1->x),
round($i * $sin + $p1->y)
round($functionX(($i + 3) * $cos, $width) + $p1->x),
round($functionY(($i + 3) * $sin, $height) + $p1->y)
$this->stopThickness($thickness);
public function arc(awColor $color, awPoint $center, $width, $height, $from, $to) {
$this->x + $center->x, $this->y + $center->y,
IMG_ARC_EDGED | IMG_ARC_NOFILL
public function filledArc(awColor $color, awPoint $center, $width, $height, $from, $to) {
$this->x + $center->x, $this->y + $center->y,
public function ellipse(awColor $color, awPoint $center, $width, $height) {
list ($x, $y) = $center->getLocation();
public function filledEllipse($background, awPoint $center, $width, $height) {
if($background instanceof awColor) {
list ($x, $y) = $center->getLocation();
list ($x, $y) = $center->getLocation();
$x1 = $x - round($width / 2);
$y1 = $y - round($height / 2);
$gradientDriver->filledEllipse(
public function rectangle(awColor $color, awLine $line) {
list ($p1, $p2) = $line->getLocation();
switch($line->getStyle()) {
$thickness = $line->getThickness();
$this->startThickness($thickness);
imagerectangle($this->resource, $this->x + $p1->x, $this->y + $p1->y, $this->x + $p2->x, $this->y + $p2->y, $rgb);
$this->stopThickness($thickness);
$side = new Line($p1, $p2);
$this->line($color, $side);
$this->line($color, $side);
$this->line($color, $side);
$this->line($color, $side);
if($background instanceof awColor) {
$gradientDriver->filledRectangle($background, $p1, $p2);
public function polygon(awColor $color, awPolygon $polygon) {
switch($polygon->getStyle()) {
$thickness = $polygon->getThickness();
$this->startThickness($thickness);
$points = $this->getPolygonPoints($polygon);
$this->stopThickness($thickness);
if($polygon->count() > 1) {
$prev = $polygon->get(0);
$line->setStyle($polygon->getStyle());
$line->setThickness($polygon->getThickness());
for($i = 1; $i < $polygon->count(); $i++ ) {
$current = $polygon->get($i);
$line->setLocation($prev, $current);
$this->line($color, $line);
$line->setLocation($prev, $polygon->get(0));
$this->line($color, $line);
if($background instanceof awColor) {
$points = $this->getPolygonPoints($polygon);
$gradientDriver->filledPolygon($background, $polygon);
public function send(awImage $image) {
$this->drawImage($image);
public function get(awImage $image) {
return $this->drawImage($image, TRUE, FALSE);
$font = $text->getFont();
$fontDriver = $this->phpFontDriver;
$fontDriver = $this->fileFontDriver;
return $fontDriver->getTextWidth($text, $this);
$font = $text->getFont();
$fontDriver = $this->phpFontDriver;
$fontDriver = $this->fileFontDriver;
return $fontDriver->getTextHeight($text, $this);
if($font instanceof awFDBFont) {
private function drawImage(awImage $image, $return = FALSE, $header = TRUE) {
$format = $image->getFormatString();
// Test if format is available
if((imagetypes() & $image->getFormat()) === FALSE) {
awImage::drawError("Class Image: Format '". $format. "' is not available on your system. Check that your PHP has been compiled with the good libraries.");
// Get some infos about this image
// Send headers to the browser
private function getPolygonPoints(awPolygon $polygon) {
foreach($polygon->all() as $point) {
$points[] = $point->x + $this->x;
$points[] = $point->y + $this->y;
private function startThickness($thickness) {
private function stopThickness($thickness) {
* @package linea21.externals
* Build your GDGradientDriver
* @var awGDDriver $driver
if($gradient->angle !== 0) {
awImage::drawError("Class GDGradientDriver: Flat triangles can only be used with 0 degree gradients.");
// Look for right-angled triangle
if($a->x !== $b->x and $b->x !== $c->x) {
awImage::drawError("Class GDGradientDriver: Not right-angled flat triangles are not supported yet.");
$this->init($gradient, $b->y - $d->y);
for($i = $c->y + 1; $i < $b->y; $i++ ) {
$color = $this->color($i - $d->y);
$pos = ($i - $d->y) / ($b->y - $d->y);
$p2 = new awPoint(1 + floor($e->x - $pos * ($e->x - $d->x)), $i);
if($gradient->angle === 0) {
$this->drawFilledTriangleVertically($gradient, $polygon);
} elseif($gradient->angle === 90) {
$this->drawFilledTriangleHorizontally($gradient, $polygon);
private function drawFilledTriangleVertically(awGradient $gradient, awPolygon $polygon) {
list ($yMin, $yMax) = $polygon->getBoxYRange();
$this->init($gradient, $yMax - $yMin);
// Get the triangle line we will draw our lines from
$lines = $polygon->getLines();
// Pick the side of the triangle going from the top
// to the bottom of the surrounding box
for($i = 0; $i < $count; $i++ ) {
if($lines[$i]->isTopToBottom($polygon)) {
// If for some reason the three points are aligned,
// $fromLine will still be NULL
$fromX = $fromLine->getXFrom($y);
foreach($lines as $line) {
$xValue = $line->getXFrom($y);
if($line1->getSize() < $line2->getSize()) {
if(!$fillLine->isPoint()) {
$color = $this->color($y - $yMin);
private function drawFilledTriangleHorizontally(awGradient $gradient, awPolygon $polygon) {
list ($xMin, $xMax) = $polygon->getBoxXRange();
$this->init($gradient, $xMax - $xMin);
// Get the triangle line we will draw our lines from
$lines = $polygon->getLines();
// Pick the side of the triangle going all the way
// from the left side to the right side of the surrounding box
for($i = 0; $i < $count; $i++ ) {
if($lines[$i]->isLeftToRight($polygon)) {
// If for some reason the three points are aligned,
// $fromLine will still be NULL
$fromY = floor($fromLine->getYFrom($x));
foreach($lines as $line) {
$yValue = $line->getYFrom($x);
if($line1->getSize() < $line2->getSize()) {
$color = $this->color($x - $xMin);
if($fillLine->isPoint()) {
} elseif($fillLine->getSize() >= 1) {
public function filledRectangle(awGradient $gradient, awPoint $p1, awPoint $p2) {
list ($x1, $y1) = $p1->getLocation();
list ($x2, $y2) = $p2->getLocation();
$y1 ^= $y2 ^= $y1 ^= $y2;
$x1 ^= $x2 ^= $x1 ^= $x2;
awImage::drawError("Class GDGradientDriver: This gradient is not supported by rectangles.");
public function filledPolygon(awGradient $gradient, awPolygon $polygon) {
awImage::drawError("Class GDGradientDriver: This gradient is not supported by polygons.");
list ($x1, $y1) = $p1->getLocation();
list ($x2, $y2) = $p2->getLocation();
if($gradient->angle === 0) {
$this->init($gradient, $y1 - $y2);
for($i = $y2; $i <= $y1; $i++ ) {
$color = $this->color($i - $y2);
} else if($gradient->angle === 90) {
$this->init($gradient, $x2 - $x1);
for($i = $x1; $i <= $x2; $i++ ) {
$color = $this->color($i - $x1);
public function filledEllipse(awGradient $gradient, $x1, $y1, $x2, $y2) {
$y1 ^= $y2 ^= $y1 ^= $y2;
$x1 ^= $x2 ^= $x1 ^= $x2;
awImage::drawError("Class GDGradientDriver: This gradient is not supported by ellipses.");
if($y1 - $y2 != $x2 - $x1) {
awImage::drawError("Class GDGradientDriver: Radial gradients are only implemented on circle, not ellipses.");
$c = new awPoint($x1 + ($x2 - $x1) / 2, $y1 + ($y2 - $y1) / 2);
$this->init($gradient, $r);
for($i = 0; $i <= $r; $i += 0.45) {
$p = ceil((2 * M_PI * $i));
$color = $this->color($i);
for($j = 0; $j < 360; $j += $interval) {
$rad = ($j / 360) * (2 * M_PI);
$l = sqrt($x * $x + $y * $y);
$ok[(int) $x][(int) $y] = TRUE;
if($y1 - $y2 != $x2 - $x1) {
awImage::drawError("Class GDGradientDriver: Linear gradients are only implemented on circle, not ellipses.");
$this->init($gradient, $x2 - $x1);
for($i = - $r; $i <= $r; $i++ ) {
$color = $this->color($i + $r);
if($gradient->angle === 90) {
$count = $polygon->count();
$left = $polygon->get(0);
$right = $polygon->get($count - 1);
if($gradient->angle === 0) {
// Get polygon maximum and minimum
$offset = $polygon->get(0);
$max = $min = $offset->y;
for($i = 1; $i < $count - 1; $i++ ) {
$offset = $polygon->get($i);
$max = max($max, $offset->y);
$min = min($min, $offset->y);
$this->init($gradient, $max - $min);
$prev = $polygon->get(1);
for($i = 2; $i < $count - 1; $i++ ) {
$current = $polygon->get($i);
$current->x -= $interval;
if($current->x - $prev->x > 0) {
$y1 = max($prev->y, $current->y);
$this->color($max - $min - ($y2 - $y1)),
$this->color($max - $min),
$top = ($prev->y < $current->y) ? $current : $prev;
$bottom = ($prev->y >= $current->y) ? $current : $prev;
$this->color($bottom->y - $min),
$this->color($max - $min - ($y2 - $y1)),
$gradientDriver->drawFilledFlatTriangle(
new awPoint($prev->x, min($prev->y, $current->y)),
new awPoint($current->x, min($prev->y, $current->y))
$sum += $current->x - $prev->x;
} else if($gradient->angle === 90) {
$width = $right->x - $left->x;
$this->init($gradient, $width);
$next = $polygon->get($pos++ );
$this->next($polygon, $pos, $prev, $next);
for($i = 0; $i <= $width; $i++ ) {
$y1 = round($prev->y + ($next->y - $prev->y) * (($i + $left->x - $prev->x) / ($next->x - $prev->x)));
$color = $this->color($i);
// YaPB : PHP does not handle alpha on lines
if($next->x == $i + $left->x) {
$this->next($polygon, $pos, $prev, $next);
} else if($count === 3) {
private function next($polygon, &$pos, &$prev, &$next) {
$next = $polygon->get($pos++ );
while($next->x - $prev->x == 0 and $pos < $polygon->count());
private $r1, $g1, $b1, $a1;
private $r2, $g2, $b2, $a2;
* Gradient size in pixels
private function init(awGradient $gradient, $size) {
$this->r1, $this->g1, $this->b1, $this->a1
) = $gradient->from->rgba();
$this->r2, $this->g2, $this->b2, $this->a2
) = $gradient->to->rgba();
private function color($pos) {
private function getRed($pos) {
if((float) $this->size !== 0.0) {
return (int) round($this->r1 + ($pos / $this->size) * ($this->r2 - $this->r1));
private function getGreen($pos) {
if((float) $this->size !== 0.0) {
return (int) round($this->g1 + ($pos / $this->size) * ($this->g2 - $this->g1));
private function getBlue($pos) {
if((float) $this->size !== 0.0) {
return (int) round($this->b1 + ($pos / $this->size) * ($this->b2 - $this->b1));
private function getAlpha($pos) {
if((float) $this->size !== 0.0) {
return (int) round(($this->a1 + ($pos / $this->size) * ($this->a2 - $this->a1)) / 127 * 100);
|