| [ Index ] |
|
Code source de Cr@wltr@ck 2.2.1 |
1 <?php 2 /* 3 * This work is hereby released into the Public Domain. 4 * To view a copy of the public domain dedication, 5 * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to 6 * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. 7 * 8 */ 9 10 require_once dirname(__FILE__)."/../Driver.class.php"; 11 12 /** 13 * Draw your objects 14 * 15 * @package Artichow 16 */ 17 18 class awGDDriver extends Driver { 19 20 /** 21 * A GD resource 22 * 23 * @var $resource 24 */ 25 public $resource; 26 27 public function __construct() { 28 parent::__construct(); 29 30 $this->driverString = 'gd'; 31 } 32 33 public function init(awImage $image) { 34 35 if($this->resource === NULL) { 36 37 $this->setImageSize($image->width, $image->height); 38 39 // Create image 40 $this->resource = imagecreatetruecolor($this->imageWidth, $this->imageHeight); 41 if(!$this->resource) { 42 awImage::drawError("Class Image: Unable to create a graph."); 43 } 44 45 imagealphablending($this->resource, TRUE); 46 47 // Antialiasing is now handled by the Driver object 48 $this->setAntiAliasing($image->getAntiAliasing()); 49 50 // Original color 51 $this->filledRectangle( 52 new awWhite, 53 new awLine( 54 new awPoint(0, 0), 55 new awPoint($this->imageWidth, $this->imageHeight) 56 ) 57 ); 58 59 $shadow = $image->shadow; 60 if($shadow !== NULL) { 61 $shadow = $shadow->getSpace(); 62 $p1 = new awPoint($shadow->left, $shadow->top); 63 $p2 = new awPoint($this->imageWidth - $shadow->right - 1, $this->imageHeight - $shadow->bottom - 1); 64 65 66 // Draw image background 67 $this->filledRectangle($image->getBackground(), new awLine($p1, $p2)); 68 69 // Draw image border 70 $image->border->rectangle($this, $p1, $p2); 71 } 72 73 } 74 } 75 76 public function initFromFile(awFileImage $fileImage, $file) { 77 78 $image = @getimagesize((string)$file); 79 80 if($image and in_array($image[2], array(2, 3))) { 81 82 $fileImage->setSize($image[0], $image[1]); 83 84 switch($image[2]) { 85 86 case 2 : 87 $this->resource = imagecreatefromjpeg($file); 88 break; 89 90 case 3 : 91 $this->resource = imagecreatefrompng($file); 92 break; 93 94 } 95 96 $this->setImageSize($fileImage->width, $fileImage->height); 97 } else { 98 awImage::drawError("Class FileImage: Artichow does not support the format of this image (must be in PNG or JPEG)"); 99 } 100 } 101 102 public function setImageSize($width, $height) { 103 104 $this->imageWidth = $width; 105 $this->imageHeight = $height; 106 107 } 108 109 public function setPosition($x, $y) { 110 111 // Calculate absolute position 112 $this->x = round($x * $this->imageWidth - $this->w / 2); 113 $this->y = round($y * $this->imageHeight - $this->h / 2); 114 115 } 116 117 public function setAbsPosition($x, $y) { 118 119 $this->x = $x; 120 $this->y = $y; 121 122 } 123 124 public function movePosition($x, $y) { 125 126 $this->x += (int)$x; 127 $this->y += (int)$y; 128 129 } 130 131 public function setSize($w, $h) { 132 133 // Calcul absolute size 134 $this->w = round($w * $this->imageWidth); 135 $this->h = round($h * $this->imageHeight); 136 137 return $this->getSize(); 138 139 } 140 141 public function setAbsSize($w, $h) { 142 143 $this->w = $w; 144 $this->h = $h; 145 146 return $this->getSize(); 147 148 } 149 150 public function getSize() { 151 152 return array($this->w, $this->h); 153 154 } 155 156 public function setAntiAliasing($bool) { 157 158 if(function_exists('imageantialias')) { 159 imageantialias($this->resource, (bool)$bool); 160 161 $this->antiAliasing = (bool)$bool; 162 } else { 163 awImage::drawErrorFile('missing-anti-aliasing'); 164 } 165 } 166 167 public function getColor(awColor $color) { 168 169 if($color->alpha === 0 or function_exists('imagecolorallocatealpha') === FALSE) { 170 $gdColor = imagecolorallocate($this->resource, $color->red, $color->green, $color->blue); 171 } else { 172 $gdColor = imagecolorallocatealpha($this->resource, $color->red, $color->green, $color->blue, $color->alpha); 173 } 174 175 return $gdColor; 176 } 177 178 public function copyImage(awImage $image, awPoint $p1, awPoint $p2) { 179 180 list($x1, $y1) = $p1->getLocation(); 181 list($x2, $y2) = $p2->getLocation(); 182 183 $driver = $image->getDriver(); 184 imagecopy($this->resource, $driver->resource, $this->x + $x1, $this->y + $y1, 0, 0, $x2 - $x1, $y2 - $y1); 185 186 } 187 188 public function copyResizeImage(awImage $image, awPoint $d1, awPoint $d2, awPoint $s1, awPoint $s2, $resample = TRUE) { 189 190 if($resample) { 191 $function = 'imagecopyresampled'; 192 } else { 193 $function = 'imagecopyresized'; 194 } 195 196 $driver = $image->getDriver(); 197 198 $function( 199 $this->resource, 200 $driver->resource, 201 $this->x + $d1->x, $this->y + $d1->y, 202 $s1->x, $s1->y, 203 $d2->x - $d1->x, $d2->y - $d1->y, 204 $s2->x - $s1->x, $s2->y - $s1->y 205 ); 206 207 } 208 209 public function string(awText $text, awPoint $point, $width = NULL) { 210 211 $font = $text->getFont(); 212 213 // Can we deal with that font? 214 if($this->isCompatibleWithFont($font) === FALSE) { 215 awImage::drawError('Class GDDriver: Incompatible font type (\''.get_class($font).'\')'); 216 } 217 218 // Check which FontDriver to use 219 if($font instanceof awPHPFont) { 220 $fontDriver = $this->phpFontDriver; 221 } else { 222 $fontDriver = $this->fileFontDriver; 223 } 224 225 if($text->getBackground() !== NULL or $text->border->visible()) { 226 227 list($left, $right, $top, $bottom) = $text->getPadding(); 228 229 $textWidth = $fontDriver->getTextWidth($text, $this); 230 $textHeight = $fontDriver->getTextHeight($text, $this); 231 232 $x1 = floor($point->x - $left); 233 $y1 = floor($point->y - $top); 234 $x2 = $x1 + $textWidth + $left + $right; 235 $y2 = $y1 + $textHeight + $top + $bottom; 236 237 $this->filledRectangle( 238 $text->getBackground(), 239 awLine::build($x1, $y1, $x2, $y2) 240 ); 241 242 $text->border->rectangle( 243 $this, 244 new awPoint($x1 - 1, $y1 - 1), 245 new awPoint($x2 + 1, $y2 + 1) 246 ); 247 248 } 249 250 $fontDriver->string($this, $text, $point, $width); 251 252 } 253 254 public function point(awColor $color, awPoint $p) { 255 256 if($p->isHidden() === FALSE) { 257 $rgb = $this->getColor($color); 258 imagesetpixel($this->resource, $this->x + round($p->x), $this->y + round($p->y), $rgb); 259 } 260 261 } 262 263 public function line(awColor $color, awLine $line) { 264 265 if($line->thickness > 0 and $line->isHidden() === FALSE) { 266 267 $rgb = $this->getColor($color); 268 $thickness = $line->thickness; 269 270 list($p1, $p2) = $line->getLocation(); 271 272 $this->startThickness($thickness); 273 274 switch($line->getStyle()) { 275 276 case awLine::SOLID : 277 imageline($this->resource, $this->x + round($p1->x), $this->y + round($p1->y), $this->x + round($p2->x), $this->y + round($p2->y), $rgb); 278 break; 279 280 case awLine::DOTTED : 281 $size = sqrt(pow($p2->y - $p1->y, 2) + pow($p2->x - $p1->x, 2)); 282 $cos = ($p2->x - $p1->x) / $size; 283 $sin = ($p2->y - $p1->y) / $size; 284 for($i = 0; $i <= $size; $i += 2) { 285 $p = new awPoint( 286 round($i * $cos + $p1->x), 287 round($i * $sin + $p1->y) 288 ); 289 $this->point($color, $p); 290 } 291 break; 292 293 case awLine::DASHED : 294 $width = $p2->x - $p1->x; 295 $height = $p2->y - $p1->y; 296 $size = sqrt(pow($height, 2) + pow($width, 2)); 297 298 if($size == 0) { 299 return; 300 } 301 302 $cos = $width / $size; 303 $sin = $height / $size; 304 305 $functionX = ($width > 0) ? 'min' : 'max'; 306 $functionY = ($height > 0) ? 'min' : 'max'; 307 308 for($i = 0; $i <= $size; $i += 6) { 309 310 $t1 = new awPoint( 311 round($i * $cos + $p1->x), 312 round($i * $sin + $p1->y) 313 ); 314 315 $t2 = new awPoint( 316 round($functionX(($i + 3) * $cos, $width) + $p1->x), 317 round($functionY(($i + 3) * $sin, $height) + $p1->y) 318 ); 319 320 $this->line($color, new awLine($t1, $t2)); 321 322 } 323 break; 324 325 } 326 327 $this->stopThickness($thickness); 328 329 } 330 331 } 332 333 public function arc(awColor $color, awPoint $center, $width, $height, $from, $to) { 334 335 imagefilledarc( 336 $this->resource, 337 $this->x + $center->x, $this->y + $center->y, 338 $width, $height, 339 $from, $to, 340 $this->getColor($color), 341 IMG_ARC_EDGED | IMG_ARC_NOFILL 342 ); 343 344 } 345 346 public function filledArc(awColor $color, awPoint $center, $width, $height, $from, $to) { 347 348 imagefilledarc( 349 $this->resource, 350 $this->x + $center->x, $this->y + $center->y, 351 $width, $height, 352 $from, $to, 353 $this->getColor($color), 354 IMG_ARC_PIE 355 ); 356 357 } 358 359 public function ellipse(awColor $color, awPoint $center, $width, $height) { 360 361 list($x, $y) = $center->getLocation(); 362 363 $rgb = $this->getColor($color); 364 imageellipse( 365 $this->resource, 366 $this->x + $x, 367 $this->y + $y, 368 $width, 369 $height, 370 $rgb 371 ); 372 373 } 374 375 public function filledEllipse($background, awPoint $center, $width, $height) { 376 377 if($background instanceof awColor) { 378 379 list($x, $y) = $center->getLocation(); 380 381 $rgb = $this->getColor($background); 382 383 imagefilledellipse( 384 $this->resource, 385 $this->x + $x, 386 $this->y + $y, 387 $width, 388 $height, 389 $rgb 390 ); 391 392 } else if($background instanceof awGradient) { 393 394 list($x, $y) = $center->getLocation(); 395 396 $x1 = $x - round($width / 2); 397 $y1 = $y - round($height / 2); 398 $x2 = $x1 + $width; 399 $y2 = $y1 + $height; 400 401 $gradientDriver = new awGDGradientDriver($this); 402 $gradientDriver->filledEllipse( 403 $background, 404 $x1, $y1, 405 $x2, $y2 406 ); 407 408 } 409 410 } 411 412 public function rectangle(awColor $color, awLine $line) { 413 414 list($p1, $p2) = $line->getLocation(); 415 416 switch($line->getStyle()) { 417 418 case awLine::SOLID : 419 $thickness = $line->getThickness(); 420 $this->startThickness($thickness); 421 $rgb = $this->getColor($color); 422 imagerectangle($this->resource, $this->x + $p1->x, $this->y + $p1->y, $this->x + $p2->x, $this->y + $p2->y, $rgb); 423 $this->stopThickness($thickness); 424 break; 425 426 default : 427 /* <php5> */ 428 $side = clone $line; 429 /* </php5> */ 430 431 /* <php4> -- 432 $side = new Line($p1, $p2); 433 -- </php4> */ 434 435 // Top side 436 $side->setLocation( 437 new awPoint($p1->x, $p1->y), 438 new awPoint($p2->x, $p1->y) 439 ); 440 $this->line($color, $side); 441 442 // Right side 443 $side->setLocation( 444 new awPoint($p2->x, $p1->y), 445 new awPoint($p2->x, $p2->y) 446 ); 447 $this->line($color, $side); 448 449 // Bottom side 450 $side->setLocation( 451 new awPoint($p1->x, $p2->y), 452 new awPoint($p2->x, $p2->y) 453 ); 454 $this->line($color, $side); 455 456 // Left side 457 $side->setLocation( 458 new awPoint($p1->x, $p1->y), 459 new awPoint($p1->x, $p2->y) 460 ); 461 $this->line($color, $side); 462 463 break; 464 465 } 466 467 } 468 469 public function filledRectangle($background, awLine $line) { 470 471 $p1 = $line->p1; 472 $p2 = $line->p2; 473 474 if($background instanceof awColor) { 475 $rgb = $this->getColor($background); 476 imagefilledrectangle($this->resource, $this->x + $p1->x, $this->y + $p1->y, $this->x + $p2->x, $this->y + $p2->y, $rgb); 477 } else if($background instanceof awGradient) { 478 $gradientDriver = new awGDGradientDriver($this); 479 $gradientDriver->filledRectangle($background, $p1, $p2); 480 } 481 482 } 483 484 public function polygon(awColor $color, awPolygon $polygon) { 485 486 switch($polygon->getStyle()) { 487 488 case awPolygon::SOLID : 489 $thickness = $polygon->getThickness(); 490 $this->startThickness($thickness); 491 $points = $this->getPolygonPoints($polygon); 492 $rgb = $this->getColor($color); 493 imagepolygon($this->resource, $points, $polygon->count(), $rgb); 494 $this->stopThickness($thickness); 495 break; 496 497 default : 498 499 if($polygon->count() > 1) { 500 501 $prev = $polygon->get(0); 502 503 $line = new awLine; 504 $line->setStyle($polygon->getStyle()); 505 $line->setThickness($polygon->getThickness()); 506 507 for($i = 1; $i < $polygon->count(); $i++) { 508 $current = $polygon->get($i); 509 $line->setLocation($prev, $current); 510 $this->line($color, $line); 511 $prev = $current; 512 } 513 514 // Close the polygon 515 $line->setLocation($prev, $polygon->get(0)); 516 $this->line($color, $line); 517 518 } 519 520 } 521 522 } 523 524 public function filledPolygon($background, awPolygon $polygon) { 525 526 if($background instanceof awColor) { 527 528 $points = $this->getPolygonPoints($polygon); 529 $rgb = $this->getColor($background); 530 531 imagefilledpolygon($this->resource, $points, $polygon->count(), $rgb); 532 533 } else if($background instanceof awGradient) { 534 535 $gradientDriver = new awGDGradientDriver($this); 536 $gradientDriver->filledPolygon($background, $polygon); 537 538 } 539 540 } 541 542 public function send(awImage $image) { 543 544 $this->drawImage($image); 545 546 } 547 548 public function get(awImage $image) { 549 550 return $this->drawImage($image, TRUE, FALSE); 551 552 } 553 554 public function getTextWidth(awText $text) { 555 $font = $text->getFont(); 556 557 if($font instanceof awPHPFont) { 558 $fontDriver = $this->phpFontDriver; 559 } else { 560 $fontDriver = $this->fileFontDriver; 561 } 562 563 return $fontDriver->getTextWidth($text, $this); 564 } 565 566 public function getTextHeight(awText $text) { 567 $font = $text->getFont(); 568 569 if($font instanceof awPHPFont) { 570 $fontDriver = $this->phpFontDriver; 571 } else { 572 $fontDriver = $this->fileFontDriver; 573 } 574 575 return $fontDriver->getTextHeight($text, $this); 576 } 577 578 protected function isCompatibleWithFont(awFont $font) { 579 if($font instanceof awFDBFont) { 580 return FALSE; 581 } else { 582 return TRUE; 583 } 584 } 585 586 private function drawImage(awImage $image, $return = FALSE, $header = TRUE) { 587 588 $format = $image->getFormatString(); 589 590 // Test if format is available 591 if((imagetypes() & $image->getFormat()) === FALSE) { 592 awImage::drawError("Class Image: Format '".$format."' is not available on your system. Check that your PHP has been compiled with the good libraries."); 593 } 594 595 // Get some infos about this image 596 switch($format) { 597 case 'jpeg' : 598 $function = 'imagejpeg'; 599 break; 600 case 'png' : 601 $function = 'imagepng'; 602 break; 603 case 'gif' : 604 $function = 'imagegif'; 605 break; 606 } 607 608 // Send headers to the browser 609 if($header === TRUE) { 610 $image->sendHeaders(); 611 } 612 613 if($return) { 614 ob_start(); 615 } 616 617 $function($this->resource); 618 619 if($return) { 620 return ob_get_clean(); 621 } 622 } 623 624 private function getPolygonPoints(awPolygon $polygon) { 625 626 $points = array(); 627 628 foreach($polygon->all() as $point) { 629 $points[] = $point->x + $this->x; 630 $points[] = $point->y + $this->y; 631 } 632 633 return $points; 634 635 } 636 637 private function startThickness($thickness) { 638 639 if($thickness > 1) { 640 641 // Beurk :'( 642 if($this->antiAliasing and function_exists('imageantialias')) { 643 imageantialias($this->resource, FALSE); 644 } 645 imagesetthickness($this->resource, $thickness); 646 647 } 648 649 } 650 651 private function stopThickness($thickness) { 652 653 if($thickness > 1) { 654 655 if($this->antiAliasing and function_exists('imageantialias')) { 656 imageantialias($this->resource, TRUE); 657 } 658 imagesetthickness($this->resource, 1); 659 660 } 661 662 } 663 664 665 } 666 667 registerClass('GDDriver'); 668 669 /** 670 * To your gradients 671 * 672 * @package Artichow 673 */ 674 675 class awGDGradientDriver { 676 677 /** 678 * A driver 679 * 680 * @var awGDDriver 681 */ 682 protected $driver; 683 684 /** 685 * Build your GDGradientDriver 686 * 687 * @var awGDDriver $driver 688 */ 689 public function __construct(awGDDriver $driver) { 690 691 $this->driver = $driver; 692 693 } 694 695 public function drawFilledFlatTriangle(awGradient $gradient, awPoint $a, awPoint $b, awPoint $c) { 696 697 if($gradient->angle !== 0) { 698 awImage::drawError("Class GDGradientDriver: Flat triangles can only be used with 0 degree gradients."); 699 } 700 701 // Look for right-angled triangle 702 if($a->x !== $b->x and $b->x !== $c->x) { 703 awImage::drawError("Class GDGradientDriver: Not right-angled flat triangles are not supported yet."); 704 } 705 706 if($a->x === $b->x) { 707 $d = $a; 708 $e = $c; 709 } else { 710 $d = $c; 711 $e = $a; 712 } 713 714 $this->init($gradient, $b->y - $d->y); 715 716 for($i = $c->y + 1; $i < $b->y; $i++) { 717 718 $color = $this->color($i - $d->y); 719 $pos = ($i - $d->y) / ($b->y - $d->y); 720 721 $p1 = new awPoint($e->x, $i); 722 $p2 = new awPoint(1 + floor($e->x - $pos * ($e->x - $d->x)), $i); 723 724 $this->driver->filledRectangle($color, new awLine($p1, $p2)); 725 726 unset($color); 727 728 } 729 730 } 731 732 protected function drawFilledTriangle(awGradient $gradient, awPolygon $polygon) { 733 734 if($gradient->angle === 0) { 735 $this->drawFilledTriangleVertically($gradient, $polygon); 736 } elseif($gradient->angle === 90) { 737 $this->drawFilledTriangleHorizontally($gradient, $polygon); 738 } 739 740 } 741 742 private function drawFilledTriangleVertically(awGradient $gradient, awPolygon $polygon) { 743 list($yMin, $yMax) = $polygon->getBoxYRange(); 744 745 $this->init($gradient, $yMax - $yMin); 746 747 // Get the triangle line we will draw our lines from 748 $fromLine = NULL; 749 $lines = $polygon->getLines(); 750 751 $count = count($lines); 752 753 // Pick the side of the triangle going from the top 754 // to the bottom of the surrounding box 755 for($i = 0; $i < $count; $i++) { 756 if($lines[$i]->isTopToBottom($polygon)) { 757 list($fromLine) = array_splice($lines, $i, 1); 758 break; 759 } 760 } 761 762 // If for some reason the three points are aligned, 763 // $fromLine will still be NULL 764 if($fromLine === NULL) { 765 return; 766 } 767 768 $fillLine = NULL; 769 for($y = round($yMin); $y < round($yMax); $y++) { 770 771 $fromX = $fromLine->getXFrom($y); 772 773 $toX = array(); 774 foreach($lines as $line) { 775 $xValue = $line->getXFrom($y); 776 777 if(!is_null($xValue)) { 778 $toX[] = $xValue; 779 } 780 } 781 782 if(count($toX) === 1) { 783 $fillLine = new Line( 784 new Point($fromX, $y), 785 new Point($toX[0], $y) 786 ); 787 } else { 788 789 $line1 = new Line( 790 new Point($fromX, $y), 791 new Point($toX[0], $y) 792 ); 793 $line2 = new Line( 794 new Point($fromX, $y), 795 new Point($toX[1], $y) 796 ); 797 798 if($line1->getSize() < $line2->getSize()) { 799 $fillLine = $line1; 800 } else { 801 $fillLine = $line2; 802 } 803 } 804 805 if(!$fillLine->isPoint()) { 806 $color = $this->color($y - $yMin); 807 $this->driver->line($color, $fillLine); 808 809 unset($color); 810 } 811 } 812 813 } 814 815 private function drawFilledTriangleHorizontally(awGradient $gradient, awPolygon $polygon) { 816 list($xMin, $xMax) = $polygon->getBoxXRange(); 817 818 $this->init($gradient, $xMax - $xMin); 819 820 // Get the triangle line we will draw our lines from 821 $fromLine = NULL; 822 $lines = $polygon->getLines(); 823 824 $count = count($lines); 825 826 // Pick the side of the triangle going all the way 827 // from the left side to the right side of the surrounding box 828 for($i = 0; $i < $count; $i++) { 829 if($lines[$i]->isLeftToRight($polygon)) { 830 list($fromLine) = array_splice($lines, $i, 1); 831 break; 832 } 833 } 834 835 // If for some reason the three points are aligned, 836 // $fromLine will still be NULL 837 if($fromLine === NULL) { 838 return; 839 } 840 841 $fillLine = NULL; 842 for($x = round($xMin); $x < round($xMax); $x++) { 843 844 $fromY = floor($fromLine->getYFrom($x)); 845 846 $toY = array(); 847 foreach($lines as $line) { 848 $yValue = $line->getYFrom($x); 849 850 if(!is_null($yValue)) { 851 $toY[] = floor($yValue); 852 } 853 } 854 855 if(count($toY) === 1) { 856 $fillLine = new Line( 857 new Point($x, $fromY), 858 new Point($x, $toY[0]) 859 ); 860 } else { 861 862 $line1 = new Line( 863 new Point($x, $fromY), 864 new Point($x, $toY[0]) 865 ); 866 $line2 = new Line( 867 new Point($x, $fromY), 868 new Point($x, $toY[1]) 869 ); 870 871 if($line1->getSize() < $line2->getSize()) { 872 $fillLine = $line1; 873 } else { 874 $fillLine = $line2; 875 } 876 } 877 878 $color = $this->color($x - $xMin); 879 if($fillLine->isPoint()) { 880 $this->driver->point($color, $fillLine->p1); 881 } elseif($fillLine->getSize() >= 1) { 882 $this->driver->line($color, $fillLine); 883 } 884 unset($color); 885 } 886 887 } 888 889 public function filledRectangle(awGradient $gradient, awPoint $p1, awPoint $p2) { 890 891 list($x1, $y1) = $p1->getLocation(); 892 list($x2, $y2) = $p2->getLocation(); 893 894 if($y1 < $y2) { 895 $y1 ^= $y2 ^= $y1 ^= $y2; 896 } 897 898 if($x2 < $x1) { 899 $x1 ^= $x2 ^= $x1 ^= $x2; 900 } 901 902 if($gradient instanceof awLinearGradient) { 903 $this->rectangleLinearGradient($gradient, new awPoint($x1, $y1), new awPoint($x2, $y2)); 904 } else { 905 awImage::drawError("Class GDGradientDriver: This gradient is not supported by rectangles."); 906 } 907 908 } 909 910 public function filledPolygon(awGradient $gradient, awPolygon $polygon) { 911 912 if($gradient instanceof awLinearGradient) { 913 $this->polygonLinearGradient($gradient, $polygon); 914 } else { 915 awImage::drawError("Class GDGradientDriver: This gradient is not supported by polygons."); 916 } 917 918 } 919 920 protected function rectangleLinearGradient(awLinearGradient $gradient, awPoint $p1, awPoint $p2) { 921 922 list($x1, $y1) = $p1->getLocation(); 923 list($x2, $y2) = $p2->getLocation(); 924 925 if($y1 - $y2 > 0) { 926 927 if($gradient->angle === 0) { 928 929 $this->init($gradient, $y1 - $y2); 930 931 for($i = $y2; $i <= $y1; $i++) { 932 933 $color = $this->color($i - $y2); 934 935 $p1 = new awPoint($x1, $i); 936 $p2 = new awPoint($x2, $i); 937 938 $this->driver->filledRectangle($color, new awLine($p1, $p2)); 939 940 unset($color); 941 942 } 943 944 } else if($gradient->angle === 90) { 945 946 $this->init($gradient, $x2 - $x1); 947 948 for($i = $x1; $i <= $x2; $i++) { 949 950 $color = $this->color($i - $x1); 951 952 $p1 = new awPoint($i, $y2); 953 $p2 = new awPoint($i, $y1); 954 955 $this->driver->filledRectangle($color, new awLine($p1, $p2)); 956 957 unset($color); 958 959 } 960 961 } 962 963 } 964 965 } 966 967 public function filledEllipse(awGradient $gradient, $x1, $y1, $x2, $y2) { 968 969 if($y1 < $y2) { 970 $y1 ^= $y2 ^= $y1 ^= $y2; 971 } 972 973 if($x2 < $x1) { 974 $x1 ^= $x2 ^= $x1 ^= $x2; 975 } 976 977 if($gradient instanceof awRadialGradient) { 978 $this->ellipseRadialGradient($gradient, $x1, $y1, $x2, $y2); 979 } else if($gradient instanceof awLinearGradient) { 980 $this->ellipseLinearGradient($gradient, $x1, $y1, $x2, $y2); 981 } else { 982 awImage::drawError("Class GDGradientDriver: This gradient is not supported by ellipses."); 983 } 984 985 } 986 987 protected function ellipseRadialGradient(awGradient $gradient, $x1, $y1, $x2, $y2) { 988 989 if($y1 - $y2 > 0) { 990 991 if($y1 - $y2 != $x2 - $x1) { 992 awImage::drawError("Class GDGradientDriver: Radial gradients are only implemented on circle, not ellipses."); 993 } 994 995 $c = new awPoint($x1 + ($x2 - $x1) / 2, $y1 + ($y2 - $y1) / 2); 996 $r = ($x2 - $x1) / 2; 997 $ok = array(); 998 999 // Init gradient 1000 $this->init($gradient, $r); 1001 1002 for($i = 0; $i <= $r; $i += 0.45) { 1003 1004 $p = ceil((2 * M_PI * $i)); 1005 1006 if($p > 0) { 1007 $interval = 360 / $p; 1008 } else { 1009 $interval = 360; 1010 } 1011 1012 $color = $this->color($i); 1013 1014 for($j = 0; $j < 360; $j += $interval) { 1015 1016 $rad = ($j / 360) * (2 * M_PI); 1017 1018 $x = round($i * cos($rad)); 1019 $y = round($i * sin($rad)); 1020 1021 $l = sqrt($x * $x + $y * $y); 1022 1023 if($l <= $r) { 1024 1025 if( 1026 array_key_exists((int)$x, $ok) === FALSE or 1027 array_key_exists((int)$y, $ok[$x]) === FALSE 1028 ) { 1029 1030 // Print the point 1031 $this->driver->point($color, new awPoint($c->x + $x, $c->y + $y)); 1032 1033 $ok[(int)$x][(int)$y] = TRUE; 1034 1035 } 1036 1037 } 1038 1039 } 1040 1041 unset($color); 1042 1043 } 1044 1045 } 1046 1047 } 1048 1049 protected function ellipseLinearGradient(awGradient $gradient, $x1, $y1, $x2, $y2) { 1050 1051 // Gauche->droite : 90° 1052 1053 if($y1 - $y2 > 0) { 1054 1055 if($y1 - $y2 != $x2 - $x1) { 1056 awImage::drawError("Class GDGradientDriver: Linear gradients are only implemented on circle, not ellipses."); 1057 } 1058 1059 $r = ($x2 - $x1) / 2; 1060 1061 // Init gradient 1062 $this->init($gradient, $x2 - $x1); 1063 1064 for($i = -$r; $i <= $r; $i++) { 1065 1066 $h = sin(acos($i / $r)) * $r; 1067 1068 $color = $this->color($i + $r); 1069 1070 if($gradient->angle === 90) { 1071 1072 // Print the line 1073 $p1 = new awPoint( 1074 $x1 + $i + $r, 1075 round(max($y2 + $r - $h + 1, $y2)) 1076 ); 1077 1078 $p2 = new awPoint( 1079 $x1 + $i + $r, 1080 round(min($y1 - $r + $h - 1, $y1)) 1081 ); 1082 1083 } else { 1084 1085 // Print the line 1086 $p1 = new awPoint( 1087 round(max($x1 + $r - $h + 1, $x1)), 1088 $y2 + $i + $r 1089 ); 1090 1091 $p2 = new awPoint( 1092 round(min($x2 - $r + $h - 1, $x2)), 1093 $y2 + $i + $r 1094 ); 1095 1096 } 1097 1098 $this->driver->filledRectangle($color, new awLine($p1, $p2)); 1099 1100 unset($color); 1101 1102 } 1103 1104 } 1105 1106 } 1107 1108 protected function polygonLinearGradient(awLinearGradient $gradient, awPolygon $polygon) { 1109 1110 $count = $polygon->count(); 1111 1112 if($count >= 4) { 1113 1114 $left = $polygon->get(0); 1115 $right = $polygon->get($count - 1); 1116 1117 if($gradient->angle === 0) { 1118 1119 // Get polygon maximum and minimum 1120 $offset = $polygon->get(0); 1121 $max = $min = $offset->y; 1122 for($i = 1; $i < $count - 1; $i++) { 1123 $offset = $polygon->get($i); 1124 $max = max($max, $offset->y); 1125 $min = min($min, $offset->y); 1126 } 1127 1128 $this->init($gradient, $max - $min); 1129 1130 $prev = $polygon->get(1); 1131 1132 $sum = 0; 1133 1134 for($i = 2; $i < $count - 1; $i++) { 1135 1136 $current = $polygon->get($i); 1137 1138 $interval = 1; 1139 1140 if($i !== $count - 2) { 1141 $current->x -= $interval; 1142 } 1143 1144 if($current->x - $prev->x > 0) { 1145 1146 // Draw rectangle 1147 $x1 = $prev->x; 1148 $x2 = $current->x; 1149 $y1 = max($prev->y, $current->y); 1150 $y2 = $left->y; 1151 1152 $gradient = new awLinearGradient( 1153 $this->color($max - $min - ($y2 - $y1)), 1154 $this->color($max - $min), 1155 0 1156 ); 1157 1158 if($y1 > $y2) { 1159 $y2 = $y1; 1160 } 1161 1162 $this->driver->filledRectangle( 1163 $gradient, 1164 awLine::build($x1, $y1, $x2, $y2) 1165 ); 1166 1167 $top = ($prev->y < $current->y) ? $current : $prev; 1168 $bottom = ($prev->y >= $current->y) ? $current : $prev; 1169 1170 $gradient = new awLinearGradient( 1171 $this->color($bottom->y - $min), 1172 $this->color($max - $min - ($y2 - $y1)), 1173 0 1174 ); 1175 1176 1177 $gradientDriver = new awGDGradientDriver($this->driver); 1178 $gradientDriver->drawFilledFlatTriangle( 1179 $gradient, 1180 new awPoint($prev->x, min($prev->y, $current->y)), 1181 $top, 1182 new awPoint($current->x, min($prev->y, $current->y)) 1183 ); 1184 unset($gradientDriver); 1185 1186 $sum += $current->x - $prev->x; 1187 1188 } 1189 1190 $prev = $current; 1191 $prev->x += $interval; 1192 1193 } 1194 1195 } else if($gradient->angle === 90) { 1196 1197 $width = $right->x - $left->x; 1198 $this->init($gradient, $width); 1199 1200 $pos = 1; 1201 $next = $polygon->get($pos++); 1202 1203 $this->next($polygon, $pos, $prev, $next); 1204 1205 for($i = 0; $i <= $width; $i++) { 1206 1207 $x = $left->x + $i; 1208 1209 $y1 = round($prev->y + ($next->y - $prev->y) * (($i + $left->x - $prev->x) / ($next->x - $prev->x))); 1210 $y2 = $left->y; 1211 1212 // Draw line 1213 $color = $this->color($i); 1214 // YaPB : PHP does not handle alpha on lines 1215 $this->driver->filledRectangle($color, awLine::build($x, $y1, $x, $y2)); 1216 1217 unset($color); 1218 1219 // Jump to next point 1220 if($next->x == $i + $left->x) { 1221 1222 $this->next($polygon, $pos, $prev, $next); 1223 1224 } 1225 1226 } 1227 1228 } 1229 1230 } else if($count === 3) { 1231 $this->drawFilledTriangle( 1232 $gradient, 1233 $polygon 1234 ); 1235 } 1236 1237 } 1238 1239 private function next($polygon, &$pos, &$prev, &$next) { 1240 1241 do { 1242 $prev = $next; 1243 $next = $polygon->get($pos++); 1244 } 1245 while($next->x - $prev->x == 0 and $pos < $polygon->count()); 1246 1247 } 1248 1249 /** 1250 * Start colors 1251 * 1252 * @var int 1253 */ 1254 private $r1, $g1, $b1, $a1; 1255 1256 /** 1257 * Stop colors 1258 * 1259 * @var int 1260 */ 1261 private $r2, $g2, $b2, $a2; 1262 1263 /** 1264 * Gradient size in pixels 1265 * 1266 * @var int 1267 */ 1268 private $size; 1269 1270 1271 private function init(awGradient $gradient, $size) { 1272 1273 list( 1274 $this->r1, $this->g1, $this->b1, $this->a1 1275 ) = $gradient->from->rgba(); 1276 1277 list( 1278 $this->r2, $this->g2, $this->b2, $this->a2 1279 ) = $gradient->to->rgba(); 1280 1281 $this->size = $size; 1282 } 1283 1284 private function color($pos) { 1285 1286 return new awColor( 1287 $this->getRed($pos), 1288 $this->getGreen($pos), 1289 $this->getBlue($pos), 1290 $this->getAlpha($pos) 1291 ); 1292 1293 } 1294 1295 1296 private function getRed($pos) { 1297 if((float)$this->size !== 0.0) { 1298 return (int)round($this->r1 + ($pos / $this->size) * ($this->r2 - $this->r1)); 1299 } else { 1300 return 0; 1301 } 1302 } 1303 1304 private function getGreen($pos) { 1305 if((float)$this->size !== 0.0) { 1306 return (int)round($this->g1 + ($pos / $this->size) * ($this->g2 - $this->g1)); 1307 } else { 1308 return 0; 1309 } 1310 } 1311 1312 private function getBlue($pos) { 1313 if((float)$this->size !== 0.0) { 1314 return (int)round($this->b1 + ($pos / $this->size) * ($this->b2 - $this->b1)); 1315 } else { 1316 return 0; 1317 } 1318 } 1319 1320 private function getAlpha($pos) { 1321 if((float)$this->size !== 0.0) { 1322 return (int)round(($this->a1 + ($pos / $this->size) * ($this->a2 - $this->a1)) / 127 * 100); 1323 } else { 1324 return 0; 1325 } 1326 } 1327 1328 } 1329 1330 registerClass('GDGradientDriver'); 1331 1332 /* 1333 * Check for GD2 1334 */ 1335 if(function_exists('imagecreatetruecolor') === FALSE) { 1336 awImage::drawErrorFile('missing-gd2'); 1337 } 1338 1339 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Thu Sep 6 14:14:11 2007 | par Balluche grâce à PHPXref 0.7 |