[ Index ] |
|
Code source de Horde 3.1.3 |
1 <?php 2 3 require_once dirname(__FILE__) . '/../Image.php'; 4 5 /** 6 * This class implements the Horde_Image:: API for the PHP GD 7 * extension. It mainly provides some utility functions, such as the 8 * ability to make pixels, for now. 9 * 10 * $Horde: framework/Image/Image/gd.php,v 1.48.10.14 2006/01/01 21:28:22 jan Exp $ 11 * 12 * Copyright 2002-2006 Chuck Hagenbuch <chuck@horde.org> 13 * 14 * See the enclosed file COPYING for license information (LGPL). If you 15 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. 16 * 17 * @author Chuck Hagenbuch <chuck@horde.org> 18 * @since Horde 3.0 19 * @package Horde_Image 20 */ 21 class Horde_Image_gd extends Horde_Image { 22 23 /** 24 * Capabilites of this driver. 25 * 26 * @var array 27 */ 28 var $_capabilities = array('resize', 29 'crop', 30 'rotate', 31 'flip', 32 'mirror', 33 'grayscale', 34 'sepia', 35 'yellowize', 36 'watermark', 37 'canvas', 38 ); 39 40 /** 41 * What kind of images should GD generate? Defaults to 'png'. 42 * 43 * @var string 44 */ 45 var $_type = 'png'; 46 47 /** 48 * GD Image resource for the current image data. 49 * 50 * @var resource 51 */ 52 var $_im; 53 54 /** 55 * String identifier of the current image. New image data will not be 56 * loaded if the same id is already loaded. 57 * 58 * @var string 59 */ 60 var $_id = ''; 61 62 function Horde_Image_gd($params) 63 { 64 parent::Horde_Image($params); 65 if (!empty($params['type'])) { 66 $this->_type = $params['type']; 67 } 68 69 if (!empty($params['width'])) { 70 $this->_im = &$this->_create($this->_width, $this->_height); 71 $this->_call('imageFill', array($this->_im, 0, 0, $this->allocateColor($this->_background))); 72 } 73 } 74 75 function getContentType() 76 { 77 return 'image/' . $this->_type; 78 } 79 80 /** 81 * Display the current image. 82 */ 83 function display() 84 { 85 $this->headers(); 86 return $this->_call('image' . $this->_type, array($this->_im)); 87 } 88 89 /** 90 * Returns the raw data for this image. 91 * 92 * @param boolean $convert If true, the image data will be returned in the 93 * target format, independently from any image 94 * operations. 95 * 96 * @return string The raw image data. 97 */ 98 function raw($convert = false) 99 { 100 return Util::bufferOutput('image' . $this->_type, $this->_im); 101 } 102 103 /** 104 * Reset the image data. 105 */ 106 function reset() 107 { 108 parent::reset(); 109 if (is_resource($this->_im)) { 110 return $this->_call('imageDestroy', array($this->_im)); 111 } 112 return true; 113 } 114 115 /** 116 * Get the height and width of the current image. 117 * 118 * @return array An hash with 'width' containing the width, 119 * 'height' containing the height of the image. 120 */ 121 function getDimensions() 122 { 123 if (is_a($this->_im, 'PEAR_Error')) { 124 return $this->_im; 125 } elseif (is_resource($this->_im)) { 126 return array('width' => $this->_call('imageSX', array($this->_im)), 127 'height' => $this->_call('imageSY', array($this->_im))); 128 } else { 129 return array('width' => 0, 'height' => 0); 130 } 131 } 132 133 /** 134 * Creates a color that can be accessed in this object. When a 135 * color is set, the integer resource of it is returned. 136 * 137 * @param string $name The name of the color. 138 * 139 * @return integer The resource of the color that can be passed to GD. 140 */ 141 function allocateColor($name) 142 { 143 static $colors = array(); 144 145 if (empty($colors[$name])) { 146 list($r, $g, $b) = $this->getRGB($name); 147 $colors[$name] = $this->_call('imageColorAllocate', array($this->_im, $r, $g, $b)); 148 } 149 150 return $colors[$name]; 151 } 152 153 function getFont($font) 154 { 155 switch ($font) { 156 case 'tiny': 157 return 1; 158 159 case 'medium': 160 return 3; 161 162 case 'large': 163 return 4; 164 165 case 'giant': 166 return 5; 167 168 case 'small': 169 default: 170 return 2; 171 } 172 } 173 174 /** 175 * Load the image data from a string. 176 * 177 * @param string $id An arbitrary id for the image. 178 * @param string $image_data The data to use for the image. 179 */ 180 function loadString($id, $image_data) 181 { 182 if ($id != $this->_id) { 183 if ($this->_im) { 184 if (is_a($result = $this->reset(), 'PEAR_Error')) { 185 return $result; 186 } 187 } 188 $this->_im = &$this->_call('imageCreateFromString', array($image_data)); 189 $this->_id = $id; 190 if (is_a($this->_im, 'PEAR_Error')) { 191 return $this->_im; 192 } 193 } 194 } 195 196 /** 197 * Load the image data from a file. 198 * 199 * @param string $filename The full path and filename to the file to load 200 * the image data from. The filename will also be 201 * used for the image id. 202 * 203 * @return mixed PEAR Error if file does not exist or could not be loaded 204 * otherwise NULL if successful or already loaded. 205 */ 206 function loadFile($filename) 207 { 208 if (is_a($result = $this->reset(), 'PEAR_Error')) { 209 return $result; 210 } 211 212 if (is_a($info = $this->_call('getimagesize', array($filename)), 'PEAR_Error')) { 213 return $info; 214 } 215 216 if (is_array($info)) { 217 switch ($info[2]) { 218 case 1: 219 if (function_exists('imagecreatefromgif')) { 220 $this->_im = &$this->_call('imagecreatefromgif', array($filename)); 221 } 222 break; 223 case 2: 224 $this->_im = &$this->_call('imagecreatefromjpeg', array($filename)); 225 break; 226 case 3: 227 $this->_im = &$this->_call('imagecreatefrompng', array($filename)); 228 break; 229 case 15: 230 if (function_exists('imagecreatefromgwbmp')) { 231 $this->_im = &$this->_call('imagecreatefromgwbmp', array($filename)); 232 } 233 break; 234 case 16: 235 $this->_im = &$this->_call('imagecreatefromxbm', array($filename)); 236 break; 237 } 238 } 239 240 if (is_a($this->_im, 'PEAR_Error')) { 241 return $this->_im; 242 } 243 244 if (is_resource($this->_im)) { 245 return; 246 } 247 248 $result = parent::loadFile($filename); 249 if (is_a($result, 'PEAR_Error')) { 250 return $result; 251 } 252 return $this->_im = &$this->_call('imageCreateFromString', array($this->_data)); 253 } 254 255 /** 256 * Resize the current image. 257 * 258 * @param integer $width The new width. 259 * @param integer $height The new height. 260 * @param boolean $ratio Maintain original aspect ratio. 261 */ 262 function resize($width, $height, $ratio = true) 263 { 264 /* Abort if we're asked to divide by zero, or truncate the 265 * image completely in either direction. */ 266 if (!$width || !$height) { 267 return; 268 } 269 270 if ($ratio) { 271 if ($width / $height > $this->_call('imageSX', array($this->_im)) / $this->_call('imageSY', array($this->_im))) { 272 $width = $height * $this->_call('imageSX', array($this->_im)) / $this->_call('imageSY', array($this->_im)); 273 } else { 274 $height = $width * $this->_call('imageSY', array($this->_im)) / $this->_call('imageSX', array($this->_im)); 275 } 276 } 277 278 $im = $this->_im; 279 $this->_im = &$this->_create($width, $height); 280 if (is_a($this->_im, 'PEAR_Error')) { 281 return $this->_im; 282 } 283 if (is_a($result = $this->_call('imageFill', array($this->_im, 0, 0, $this->_call('imageColorAllocate', array($this->_im, 255, 255, 255)))), 'PEAR_Error')) { 284 return $result; 285 } 286 if (is_a($this->_call('imageCopyResampled', array($this->_im, $im, 0, 0, 0, 0, $width, $height, $this->_call('imageSX', array($im)), $this->_call('imageSY', array($im)))), 'PEAR_Error')) { 287 return $this->_call('imageCopyResized', array($this->_im, $im, 0, 0, 0, 0, $width, $height, $this->_call('imageSX', array($im)), $this->_call('imageSY', array($im)))); 288 } 289 } 290 291 /** 292 * Crop the current image. 293 * 294 * @param integer $x1 The top left corner of the cropped image. 295 * @param integer $y1 The top right corner of the cropped image. 296 * @param integer $x2 The bottom left corner of the cropped image. 297 * @param integer $y2 The bottom right corner of the cropped image. 298 */ 299 function crop($x1, $y1, $x2, $y2) 300 { 301 $im = $this->_im; 302 $this->_im = &$this->_create($x2 - $x1, $y2 - $y1); 303 if (is_a($this->_im, 'PEAR_Error')) { 304 return $this->_im; 305 } 306 return $this->_call('imageCopy', array($this->_im, $im, 0, 0, $x1, $y1, $x2 - $x1, $y2 - $y1)); 307 } 308 309 /** 310 * Rotate the current image. 311 * 312 * @param integer $angle The angle to rotate the image by, 313 * in the clockwise direction 314 * @param integer $background The background color to fill any triangles 315 */ 316 function rotate($angle, $background = 'white') 317 { 318 if (!function_exists('imagerotate')) { 319 return; 320 } 321 322 $background = $this->allocateColor($background); 323 if (is_a($background, 'PEAR_Error')) { 324 return $background; 325 } 326 327 switch ($angle) { 328 case '90': 329 $x = $this->_call('imageSX', array($this->_im)); 330 $y = $this->_call('imageSY', array($this->_im)); 331 $xymax = max($x, $y); 332 333 $im = &$this->_create($xymax, $xymax); 334 if (is_a($im, 'PEAR_Error')) { 335 return $im; 336 } 337 if (is_a($result = $this->_call('imageCopy', array($im, $this->_im, 0, 0, 0, 0, $x, $y)), 'PEAR_Error')) { 338 return $result; 339 } 340 $im = &$this->_call('imageRotate', array($im, 270, $background)); 341 if (is_a($im, 'PEAR_Error')) { 342 return $im; 343 } 344 $this->_im = $im; 345 $im = &$this->_create($y, $x); 346 if (is_a($im, 'PEAR_Error')) { 347 return $im; 348 } 349 if ($x < $y) { 350 if (is_a($result = $this->_call('imageCopy', array($im, $this->_im, 0, 0, 0, 0, $xymax, $xymax)), 'PEAR_Error')) { 351 return $result; 352 } 353 } elseif ($x > $y) { 354 if (is_a($result = $this->_call('imageCopy', array($im, $this->_im, 0, 0, $xymax - $y, $xymax - $x, $xymax, $xymax)), 'PEAR_Error')) { 355 return $result; 356 } 357 } 358 $this->_im = $im; 359 break; 360 361 default: 362 $this->_im = &$this->_call('imageRotate', array($this->_im, 360 - $angle, $background)); 363 if (is_a($this->_im, 'PEAR_Error')) { 364 return $this->_im; 365 } 366 break; 367 } 368 } 369 370 /** 371 * Flip the current image. 372 */ 373 function flip() 374 { 375 $x = $this->_call('imageSX', array($this->_im)); 376 $y = $this->_call('imageSY', array($this->_im)); 377 378 $im = &$this->_create($x, $y); 379 if (is_a($im, 'PEAR_Error')) { 380 return $im; 381 } 382 for ($curY = 0; $curY < $y; $curY++) { 383 if (is_a($result = $this->_call('imageCopy', array($im, $this->_im, 0, $y - ($curY + 1), 0, $curY, $x, 1)), 'PEAR_Error')) { 384 return $result; 385 } 386 } 387 388 $this->_im = $im; 389 } 390 391 /** 392 * Mirror the current image. 393 */ 394 function mirror() 395 { 396 $x = $this->_call('imageSX', array($this->_im)); 397 $y = $this->_call('imageSY', array($this->_im)); 398 399 $im = &$this->_create($x, $y); 400 if (is_a($im, 'PEAR_Error')) { 401 return $im; 402 } 403 for ($curX = 0; $curX < $x; $curX++) { 404 if (is_a($result = $this->_call('imageCopy', array($im, $this->_im, $x - ($curX + 1), 0, $curX, 0, 1, $y)), 'PEAR_Error')) { 405 return $result; 406 } 407 } 408 409 $this->_im = $im; 410 } 411 412 /** 413 * Convert the current image to grayscale. 414 */ 415 function grayscale() 416 { 417 $rateR = .229; 418 $rateG = .587; 419 $rateB = .114; 420 $whiteness = 3; 421 422 if (function_exists('imageistruecolor') && $this->_call('imageIsTrueColor', array($this->_im)) === true) { 423 if (is_a($result = $this->_call('imageTrueColorToPalette', array($this->_im, true, 256)), 'PEAR_Error')) { 424 return $result; 425 } 426 } 427 428 $colors = min(256, $this->_call('imageColorsTotal', array($this->_im))); 429 for ($x = 0; $x < $colors; $x++) { 430 $src = $this->_call('imageColorsForIndex', array($this->_im, $x)); 431 if (is_a($src, 'PEAR_Error')) { 432 return $src; 433 } 434 $new = min(255, abs($src['red'] * $rateR + $src['green'] * $rateG + $src['blue'] * $rateB) + $whiteness); 435 if (is_a($result = $this->_call('imageColorSet', array($this->_im, $x, $new, $new, $new)), 'PEAR_Error')) { 436 return $result; 437 } 438 } 439 } 440 441 /** 442 * Sepia filter. 443 * 444 * Basically turns the image to grayscale and then adds some 445 * defined tint on it (R += 30, G += 43, B += -23) so it will 446 * appear to be a very old picture. 447 */ 448 function sepia() 449 { 450 $tintR = 80; 451 $tintG = 43; 452 $tintB = -23; 453 $rateR = .229; 454 $rateG = .587; 455 $rateB = .114; 456 $whiteness = 3; 457 458 if ($this->_call('imageIsTrueColor', array($this->_im)) === true) { 459 if (is_a($result = $this->_call('imageTrueColorToPalette', array($this->_im, true, 256)), 'PEAR_Error')) { 460 return $result; 461 } 462 } 463 464 $colors = max(256, $this->_call('imageColorsTotal', array($this->_im))); 465 for ($x = 0; $x < $colors; $x++) { 466 $src = $this->_call('imageColorsForIndex', array($this->_im, $x)); 467 if (is_a($src, 'PEAR_Error')) { 468 return $src; 469 } 470 $new = min(255, abs($src['red'] * $rateR + $src['green'] * $rateG + $src['blue'] * $rateB) + $whiteness); 471 $r = min(255, $new + $tintR); 472 $g = min(255, $new + $tintG); 473 $b = min(255, $new + $tintB); 474 if (is_a($result = $this->_call('imageColorSet', array($this->_im, $x, $r, $g, $b)), 'PEAR_Error')) { 475 return $result; 476 } 477 } 478 } 479 480 /** 481 * Yellowize filter. 482 * 483 * Adds a layer of yellow that can be transparent or solid. If 484 * $intensityA is 255 the image will be 0% transparent (solid). 485 * 486 * @param integer $intensityY How strong should the yellow (red and green) be? (0-255) 487 * @param integer $intensityB How weak should the blue be? (>= 2, in the positive limit it will be make BLUE 0) 488 */ 489 function yellowize($intensityY = 50, $intensityB = 3) 490 { 491 if ($this->_call('imageIsTrueColor', array($this->_im)) === true) { 492 if (is_a($result = $this->_call('imageTrueColorToPalette', array($this->_im, true, 256)), 'PEAR_Error')) { 493 return $result; 494 } 495 } 496 497 $colors = max(256, $this->_call('imageColorsTotal', array($this->_im))); 498 for ($x = 0; $x < $colors; $x++) { 499 $src = $this->_call('imageColorsForIndex', array($this->_im, $x)); 500 if (is_a($src, 'PEAR_Error')) { 501 return $src; 502 } 503 $r = min($src['red'] + $intensityY, 255); 504 $g = min($src['green'] + $intensityY, 255); 505 $b = max(($r + $g) / max($intensityB, 2), 0); 506 if (is_a($result = $this->_call('imageColorSet', array($this->_im, $x, $r, $g, $b)), 'PEAR_Error')) { 507 return $result; 508 } 509 } 510 } 511 512 function watermark($text, $halign = 'right', $valign = 'bottom', $font = 'small') 513 { 514 $color = $this->_call('imageColorClosest', array($this->_im, 255, 255, 255)); 515 if (is_a($color, 'PEAR_Error')) { 516 return $color; 517 } 518 $shadow = $this->_call('imageColorClosest', array($this->_im, 0, 0, 0)); 519 if (is_a($shadow, 'PEAR_Error')) { 520 return $shadow; 521 } 522 523 // Shadow offset in pixels. 524 $drop = 1; 525 526 // Maximum text width. 527 $maxwidth = 200; 528 529 // Amount of space to leave between the text and the image 530 // border. 531 $padding = 10; 532 533 $f = $this->getFont($font); 534 $fontwidth = $this->_call('imageFontWidth', array($f)); 535 if (is_a($fontwidth, 'PEAR_Error')) { 536 return $fontwidth; 537 } 538 $fontheight = $this->_call('imageFontHeight', array($f)); 539 if (is_a($fontheight, 'PEAR_Error')) { 540 return $fontheight; 541 } 542 543 // So that shadow is not off the image with right align and 544 // bottom valign. 545 $margin = floor($padding + $drop) / 2; 546 547 if ($maxwidth) { 548 $maxcharsperline = floor(($maxwidth - ($margin * 2)) / $fontwidth); 549 $text = wordwrap($text, $maxcharsperline, "\n", 1); 550 } 551 552 // Split $text into individual lines. 553 $lines = explode("\n", $text); 554 555 switch ($valign) { 556 case 'center': 557 $y = ($this->_call('imageSY', array($this->_im)) - ($fontheight * count($lines))) / 2; 558 break; 559 560 case 'bottom': 561 $y = $this->_call('imageSY', array($this->_im)) - (($fontheight * count($lines)) + $margin); 562 break; 563 564 default: 565 $y = $margin; 566 break; 567 } 568 569 switch ($halign) { 570 case 'right': 571 foreach ($lines as $line) { 572 if (is_a($result = $this->_call('imageString', array($this->_im, $f, ($this->_call('imageSX', array($this->_im)) - $fontwidth * strlen($line)) - $margin + $drop, ($y + $drop), $line, $shadow)), 'PEAR_Error')) { 573 return $result; 574 } 575 $result = $this->_call('imageString', array($this->_im, $f, ($this->_call('imageSX', array($this->_im)) - $fontwidth * strlen($line)) - $margin, $y, $line, $color)); 576 $y += $fontheight; 577 } 578 break; 579 580 case 'center': 581 foreach ($lines as $line) { 582 if (is_a($result = $this->_call('imageString', array($this->_im, $f, floor(($this->_call('imageSX', array($this->_im)) - $fontwidth * strlen($line)) / 2) + $drop, ($y + $drop), $line, $shadow)), 'PEAR_Error')) { 583 return $result; 584 } 585 $result = $this->_call('imageString', array($this->_im, $f, floor(($this->_call('imageSX', array($this->_im)) - $fontwidth * strlen($line)) / 2), $y, $line, $color)); 586 $y += $fontheight; 587 } 588 break; 589 590 default: 591 foreach ($lines as $line) { 592 if (is_a($result = $this->_call('imageString', array($this->_im, $f, $margin + $drop, ($y + $drop), $line, $shadow)), 'PEAR_Error')) { 593 return $result; 594 } 595 $result = $this->_call('imageString', array($this->_im, $f, $margin, $y, $line, $color)); 596 $y += $fontheight; 597 } 598 break; 599 } 600 601 if (is_a($result, 'PEAR_Error')) { 602 return $result; 603 } 604 } 605 606 /** 607 * Draws a text string on the image in a specified location, with 608 * the specified style information. 609 * 610 * @param string $text The text to draw. 611 * @param integer $x The left x coordinate of the start of the 612 * text string. 613 * @param integer $y The top y coordinate of the start of the text 614 * string. 615 * @param string $font The font identifier you want to use for the 616 * text. 617 * @param string $color The color that you want the text displayed in. 618 * @param integer $direction An integer that specifies the orientation of 619 * the text. 620 */ 621 function text($string, $x, $y, $font = 'monospace', $color = 'black', $direction = 0) 622 { 623 $c = $this->allocateColor($color); 624 if (is_a($c, 'PEAR_Error')) { 625 return $c; 626 } 627 $f = $this->getFont($font); 628 switch ($direction) { 629 case -90: 630 case 270: 631 $result = $this->_call('imageStringUp', array($this->_im, $f, $x, $y, $string, $c)); 632 break; 633 634 case 0: 635 default: 636 $result = $this->_call('imageString', array($this->_im, $f, $x, $y, $string, $c)); 637 } 638 639 return $result; 640 } 641 642 /** 643 * Draw a circle. 644 * 645 * @param integer $x The x co-ordinate of the centre. 646 * @param integer $y The y co-ordinate of the centre. 647 * @param integer $r The radius of the circle. 648 * @param string $color The line color of the circle. 649 * @param string $fill The color to fill the circle. 650 */ 651 function circle($x, $y, $r, $color, $fill = null) 652 { 653 $c = $this->allocateColor($color); 654 if (is_a($c, 'PEAR_Error')) { 655 return $c; 656 } 657 if (is_null($fill)) { 658 $result = $this->_call('imageEllipse', array($this->_im, $x, $y, $r * 2, $r * 2, $c)); 659 } else { 660 if ($fill !== $color) { 661 $fillColor = $this->allocateColor($fill); 662 if (is_a($fillColor, 'PEAR_Error')) { 663 return $fillColor; 664 } 665 if (is_a($result = $this->_call('imageFilledEllipse', array($this->_im, $x, $y, $r * 2, $r * 2, $fillColor)), 'PEAR_Error')) { 666 return $result; 667 } 668 $result = $this->_call('imageEllipse', array($this->_im, $x, $y, $r * 2, $r * 2, $c)); 669 } else { 670 $result = $this->_call('imageFilledEllipse', array($this->_im, $x, $y, $r * 2, $r * 2, $c)); 671 } 672 } 673 if (is_a($result, 'PEAR_Error')) { 674 return $result; 675 } 676 } 677 678 /** 679 * Draw a polygon based on a set of vertices. 680 * 681 * @param array $vertices An array of x and y labeled arrays 682 * (eg. $vertices[0]['x'], $vertices[0]['y'], ...). 683 * @param string $color The color you want to draw the polygon with. 684 * @param string $fill The color to fill the polygon. 685 */ 686 function polygon($verts, $color, $fill = 'none') 687 { 688 $vertices = array(); 689 foreach ($verts as $vert) { 690 $vertices[] = $vert['x']; 691 $vertices[] = $vert['y']; 692 } 693 694 if ($fill != 'none') { 695 $f = $this->allocateColor($fill); 696 if (is_a($f, 'PEAR_Error')) { 697 return $f; 698 } 699 if (is_a($result = $this->_call('imageFilledPolygon', array($this->_im, $vertices, count($verts), $f)), 'PEAR_Error')) { 700 return $result; 701 } 702 } 703 704 if ($fill == 'none' || $fill != $color) { 705 $c = $this->allocateColor($color); 706 if (is_a($c, 'PEAR_Error')) { 707 return $c; 708 } 709 if (is_a($result = $this->_call('imagePolygon', array($this->_im, $vertices, count($verts), $c)), 'PEAR_Error')) { 710 return $result; 711 } 712 } 713 } 714 715 /** 716 * Draw a rectangle. 717 * 718 * @param integer $x The left x-coordinate of the rectangle. 719 * @param integer $y The top y-coordinate of the rectangle. 720 * @param integer $width The width of the rectangle. 721 * @param integer $height The height of the rectangle. 722 * @param string $color The line color of the rectangle. 723 * @param string $fill The color to fill the rectangle with. 724 */ 725 function rectangle($x, $y, $width, $height, $color = 'black', $fill = 'none') 726 { 727 if ($fill != 'none') { 728 $f = $this->allocateColor($fill); 729 if (is_a($f, 'PEAR_Error')) { 730 return $f; 731 } 732 if (is_a($result = $this->_call('imageFilledRectangle', array($this->_im, $x, $y, $x + $width, $y + $height, $f)), 'PEAR_Error')) { 733 return $result; 734 } 735 } 736 737 if ($fill == 'none' || $fill != $color) { 738 $c = $this->allocateColor($color); 739 if (is_a($c, 'PEAR_Error')) { 740 return $c; 741 } 742 if (is_a($result = $this->_call('imageRectangle', array($this->_im, $x, $y, $x + $width, $y + $height, $c)), 'PEAR_Error')) { 743 return $result; 744 } 745 } 746 } 747 748 /** 749 * Draw a rounded rectangle. 750 * 751 * @param integer $x The left x-coordinate of the rectangle. 752 * @param integer $y The top y-coordinate of the rectangle. 753 * @param integer $width The width of the rectangle. 754 * @param integer $height The height of the rectangle. 755 * @param integer $round The width of the corner rounding. 756 * @param string $color The line color of the rectangle. 757 * @param string $fill The color to fill the rounded rectangle with. 758 */ 759 function roundedRectangle($x, $y, $width, $height, $round, $color = 'black', $fill = 'none') 760 { 761 if ($round <= 0) { 762 // Optimize out any calls with no corner rounding. 763 return $this->rectangle($x, $y, $width, $height, $color, $fill); 764 } 765 766 $c = $this->allocateColor($color); 767 if (is_a($c, 'PEAR_Error')) { 768 return $c; 769 } 770 771 // Set corner points to avoid lots of redundant math. 772 $x1 = $x + $round; 773 $y1 = $y + $round; 774 775 $x2 = $x + $width - $round; 776 $y2 = $y + $round; 777 778 $x3 = $x + $width - $round; 779 $y3 = $y + $height - $round; 780 781 $x4 = $x + $round; 782 $y4 = $y + $height - $round; 783 784 $r = $round * 2; 785 786 // Calculate the upper left arc. 787 $p1 = $this->_arcPoints($round, 180, 225); 788 $p2 = $this->_arcPoints($round, 225, 270); 789 790 // Calculate the upper right arc. 791 $p3 = $this->_arcPoints($round, 270, 315); 792 $p4 = $this->_arcPoints($round, 315, 360); 793 794 // Calculate the lower right arc. 795 $p5 = $this->_arcPoints($round, 0, 45); 796 $p6 = $this->_arcPoints($round, 45, 90); 797 798 // Calculate the lower left arc. 799 $p7 = $this->_arcPoints($round, 90, 135); 800 $p8 = $this->_arcPoints($round, 135, 180); 801 802 // Draw the corners - upper left, upper right, lower right, 803 // lower left. 804 if (is_a($result = $this->_call('imageArc', array($this->_im, $x1, $y1, $r, $r, 180, 270, $c)), 'PEAR_Error')) { 805 return $result; 806 } 807 if (is_a($result = $this->_call('imageArc', array($this->_im, $x2, $y2, $r, $r, 270, 360, $c)), 'PEAR_Error')) { 808 return $result; 809 } 810 if (is_a($result = $this->_call('imageArc', array($this->_im, $x3, $y3, $r, $r, 0, 90, $c)), 'PEAR_Error')) { 811 return $result; 812 } 813 if (is_a($result = $this->_call('imageArc', array($this->_im, $x4, $y4, $r, $r, 90, 180, $c)), 'PEAR_Error')) { 814 return $result; 815 } 816 817 // Draw the connecting sides - top, right, bottom, left. 818 if (is_a($result = $this->_call('imageLine', array($this->_im, $x1 + $p2['x2'], $y1 + $p2['y2'], $x2 + $p3['x1'], $y2 + $p3['y1'], $c)), 'PEAR_Error')) { 819 return $result; 820 } 821 if (is_a($result = $this->_call('imageLine', array($this->_im, $x2 + $p4['x2'], $y2 + $p4['y2'], $x3 + $p5['x1'], $y3 + $p5['y1'], $c)), 'PEAR_Error')) { 822 return $result; 823 } 824 if (is_a($result = $this->_call('imageLine', array($this->_im, $x3 + $p6['x2'], $y3 + $p6['y2'], $x4 + $p7['x1'], $y4 + $p7['y1'], $c)), 'PEAR_Error')) { 825 return $result; 826 } 827 if (is_a($result = $this->_call('imageLine', array($this->_im, $x4 + $p8['x2'], $y4 + $p8['y2'], $x1 + $p1['x1'], $y1 + $p1['y1'], $c)), 'PEAR_Error')) { 828 return $result; 829 } 830 831 if ($fill != 'none') { 832 $f = $this->allocateColor($fill); 833 if (is_a($f, 'PEAR_Error')) { 834 return $f; 835 } 836 if (is_a($result = $this->_call('imageFillToBorder', array($this->_im, $x + ($width / 2), $y + ($height / 2), $c, $f)), 'PEAR_Error')) { 837 return $result; 838 } 839 } 840 } 841 842 /** 843 * Draw a line. 844 * 845 * @param integer $x0 The x co-ordinate of the start. 846 * @param integer $y0 The y co-ordinate of the start. 847 * @param integer $x1 The x co-ordinate of the end. 848 * @param integer $y1 The y co-ordinate of the end. 849 * @param string $color The line color. 850 * @param string $width The width of the line. 851 */ 852 function line($x1, $y1, $x2, $y2, $color = 'black', $width = 1) 853 { 854 $c = $this->allocateColor($color); 855 if (is_a($c, 'PEAR_Error')) { 856 return $c; 857 } 858 859 // Don't need to do anything special for single-width lines. 860 if ($width == 1) { 861 $result = $this->_call('imageLine', array($this->_im, $x1, $y1, $x2, $y2, $c)); 862 } elseif ($x1 == $x2) { 863 // For vertical lines, we can just draw a vertical 864 // rectangle. 865 $left = $x1 - floor(($width - 1) / 2); 866 $right = $x1 + floor($width / 2); 867 $result = $this->_call('imageFilledRectangle', array($this->_im, $left, $y1, $right, $y2, $c)); 868 } elseif ($y1 == $y2) { 869 // For horizontal lines, we can just draw a horizontal 870 // filled rectangle. 871 $top = $y1 - floor($width / 2); 872 $bottom = $y1 + floor(($width - 1) / 2); 873 $result = $this->_call('imageFilledRectangle', array($this->_im, $x1, $top, $x2, $bottom, $c)); 874 } else { 875 // Angled lines. 876 877 // Make sure that the end points of the line are 878 // perpendicular to the line itself. 879 $a = atan2($y1 - $y2, $x2 - $x1); 880 $dx = (sin($a) * $width / 2); 881 $dy = (cos($a) * $width / 2); 882 883 $verts = array($x2 + $dx, $y2 + $dy, $x2 - $dx, $y2 - $dy, $x1 - $dx, $y1 - $dy, $x1 + $dx, $y1 + $dy); 884 $result = $this->_call('imageFilledPolygon', array($this->_im, $verts, count($verts) / 2, $c)); 885 } 886 887 return $result; 888 } 889 890 /** 891 * Draw a dashed line. 892 * 893 * @param integer $x0 The x co-ordinate of the start. 894 * @param integer $y0 The y co-ordinate of the start. 895 * @param integer $x1 The x co-ordinate of the end. 896 * @param integer $y1 The y co-ordinate of the end. 897 * @param string $color The line color. 898 * @param string $width The width of the line. 899 * @param integer $dash_length The length of a dash on the dashed line 900 * @param integer $dash_space The length of a space in the dashed line 901 */ 902 function dashedLine($x0, $y0, $x1, $y1, $color = 'black', $width = 1, $dash_length = 2, $dash_space = 2) 903 { 904 $c = $this->allocateColor($color); 905 if (is_a($c, 'PEAR_Error')) { 906 return $c; 907 } 908 $w = $this->allocateColor('white'); 909 if (is_a($w, 'PEAR_Error')) { 910 return $w; 911 } 912 913 // Set up the style array according to the $dash_* parameters. 914 $style = array(); 915 for ($i = 0; $i < $dash_length; $i++) { 916 $style[] = $c; 917 } 918 for ($i = 0; $i < $dash_space; $i++) { 919 $style[] = $w; 920 } 921 922 if (is_a($result = $this->_call('imageSetStyle', array($this->_im, $style)), 'PEAR_Error')) { 923 return $result; 924 } 925 if (is_a($result = $this->_call('imageSetThickness', array($this->_im, $width)), 'PEAR_Error')) { 926 return $result; 927 } 928 return $this->_call('imageLine', array($this->_im, $x0, $y0, $x1, $y1, IMG_COLOR_STYLED)); 929 } 930 931 /** 932 * Draw a polyline (a non-closed, non-filled polygon) based on a 933 * set of vertices. 934 * 935 * @param array $vertices An array of x and y labeled arrays 936 * (eg. $vertices[0]['x'], $vertices[0]['y'], ...). 937 * @param string $color The color you want to draw the line with. 938 * @param string $width The width of the line. 939 */ 940 function polyline($verts, $color, $width = 1) 941 { 942 $first = true; 943 foreach ($verts as $vert) { 944 if (!$first) { 945 if (is_a($result = $this->line($lastX, $lastY, $vert['x'], $vert['y'], $color, $width), 'PEAR_Error')) { 946 return $result; 947 } 948 } else { 949 $first = false; 950 } 951 $lastX = $vert['x']; 952 $lastY = $vert['y']; 953 } 954 } 955 956 /** 957 * Draw an arc. 958 * 959 * @param integer $x The x co-ordinate of the centre. 960 * @param integer $y The y co-ordinate of the centre. 961 * @param integer $r The radius of the arc. 962 * @param integer $start The start angle of the arc. 963 * @param integer $end The end angle of the arc. 964 * @param string $color The line color of the arc. 965 * @param string $fill The fill color of the arc (defaults to none). 966 */ 967 function arc($x, $y, $r, $start, $end, $color = 'black', $fill = null) 968 { 969 $c = $this->allocateColor($color); 970 if (is_a($c, 'PEAR_Error')) { 971 return $c; 972 } 973 if (is_null($fill)) { 974 $result = $this->_call('imageArc', array($this->_im, $x, $y, $r * 2, $r * 2, $start, $end, $c)); 975 } else { 976 if ($fill !== $color) { 977 $f = $this->allocateColor($fill); 978 if (is_a($f, 'PEAR_Error')) { 979 return $f; 980 } 981 if (is_a($result = $this->_call('imageFilledArc', array($this->_im, $x, $y, $r * 2, $r * 2, $start, $end, $f, IMG_ARC_PIE)), 'PEAR_Error')) { 982 return $result; 983 } 984 $result = $this->_call('imageFilledArc', array($this->_im, $x, $y, $r * 2, $r * 2, $start, $end, $c, IMG_ARC_EDGED | IMG_ARC_NOFILL)); 985 } else { 986 $result = $this->_call('imageFilledArc', array($this->_im, $x, $y, $r * 2, $r * 2, $start, $end, $c, IMG_ARC_PIE)); 987 } 988 } 989 return $result; 990 } 991 992 /** 993 * Creates an image of the given size. 994 * If possible the function returns a true color image. 995 * 996 * @param integer $width The image width. 997 * @param integer $height The image height. 998 * 999 * @return resource|object PEAR Error The image handler or a PEAR_Error on 1000 * error. 1001 */ 1002 function &_create($width, $height) 1003 { 1004 $result = &$this->_call('imageCreateTrueColor', array($width, $height)); 1005 if (!is_resource($result)) { 1006 $result = &$this->_call('imageCreate', array($width, $height)); 1007 } 1008 return $result; 1009 } 1010 1011 /** 1012 * Wraps a call to a function of the gd extension. 1013 * If the call produces an error, a PEAR_Error is returned, the function 1014 * result otherwise. 1015 * 1016 * @param string $function The name of the function to wrap. 1017 * @param array $params An array with all parameters for that function. 1018 * 1019 * @return mixed Either the function result or a PEAR_Error if an error 1020 * occured when executing the function. 1021 */ 1022 function &_call($function, $params = null) 1023 { 1024 unset($php_errormsg); 1025 $track = ini_set('track_errors', 1); 1026 $result = @call_user_func_array($function, $params); 1027 if ($track !== false) { 1028 ini_set('track_errors', $track); 1029 } 1030 if (!empty($php_errormsg)) { 1031 require_once 'PEAR.php'; 1032 $result = PEAR::raiseError($function . ': ' . $php_errormsg); 1033 } 1034 return $result; 1035 } 1036 1037 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 18:01:28 2007 | par Balluche grâce à PHPXref 0.7 |