1<?php 2 3/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 4 5/** 6 * Class for handling output in Postscript format. 7 * 8 * Requires PHP extension pslib 9 * 10 * PHP versions 4 and 5 11 * 12 * LICENSE: This library is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU Lesser General Public License as published by 14 * the Free Software Foundation; either version 2.1 of the License, or (at your 15 * option) any later version. This library is distributed in the hope that it 16 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 17 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 18 * General Public License for more details. You should have received a copy of 19 * the GNU Lesser General Public License along with this library; if not, write 20 * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 21 * 02111-1307 USA 22 * 23 * @category Images 24 * @package Image_Canvas 25 * @author Jesper Veggerby <pear.nosey@veggerby.dk> 26 * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen 27 * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 28 * @version CVS: $Id: PS.php 287471 2009-08-18 23:12:01Z clockwerx $ 29 * @link http://pear.php.net/package/Image_Canvas 30 */ 31 32/** 33 * Include file Image/Canvas.php 34 */ 35require_once 'Image/Canvas.php'; 36 37/** 38 * Include file Image/Canvas/Color.php 39 */ 40require_once 'Image/Canvas/Color.php'; 41 42/** 43 * PostScript Canvas class. 44 * 45 * @category Images 46 * @package Image_Canvas 47 * @author Jesper Veggerby <pear.nosey@veggerby.dk> 48 * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen 49 * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 50 * @version Release: @package_version@ 51 * @link http://pear.php.net/package/Image_Canvas 52 */ 53class Image_Canvas_PS extends Image_Canvas 54{ 55 56 /** 57 * The PostScript document 58 * @var resource 59 * @access private 60 */ 61 var $_ps; 62 63 /** 64 * The major version of pslib 65 * @var int 66 * @access private 67 */ 68 var $_pslib; 69 70 /** 71 * The font 72 * @var mixed 73 * @access private 74 */ 75 var $_psFont = false; 76 77 /** 78 * The width of the page 79 * @var int 80 * @access private 81 */ 82 var $_pageWidth; 83 84 /** 85 * The height of the page 86 * @var int 87 * @access private 88 */ 89 var $_pageHeight; 90 91 /** 92 * Create the PostScript canvas. 93 * 94 * Parameters available: 95 * 96 * 'page' Specify the page/paper format for the graph's page, available 97 * formats are: A0, A1, A2, A3, A4, A5, A6, B5, letter, legal, ledger, 98 * 11x17, cd_front, inlay, inlay_nosides 99 * 100 * 'align' Alignment of the graph on the page, available options are: 101 * topleft, topcenter, topright, leftcenter, center, rightcenter, 102 * leftbottom, centerbottom, rightbottom 103 * 104 * 'orientation' Specifies the paper orientation, default is 'portrait' and 105 * 'landscape' is also supported. 106 * 107 * 'creator' The creator tag of the PostScript/graph 108 * 109 * 'author' The author tag of the PostScript/graph 110 * 111 * 'title' The title tag of the PostScript/graph 112 * 113 * 'width' The width of the graph on the page 114 * 115 * 'height' The height of the graph on the page 116 * 117 * 'left' The left offset of the graph on the page 118 * 119 * 'top' The top offset of the graph on the page 120 * 121 * 'filename' The PostScript file to open/add page to, using 'filename' requires 122 * 'ps' An existing pslib PostScript document to add the page to 123 * 124 * 'add_page' (true/false) Used together with 'ps', to specify whether the 125 * canvas should add a new graph page (true) or create the graph on the 126 * current page (false), default is 'true' 127 * 128 * The 'page' and 'width' & 'height' can be mutually omitted, if 'page' is 129 * omitted the page is created using dimensions of width x height, and if 130 * width and height are omitted the page dimensions are used for the graph. 131 * 132 * If 'ps' is specified, 'filename', 'creator', 'author' and 'title' has no 133 * effect. 134 * 135 * 'left' and 'top' are overridden by 'align' 136 * 137 * It is required either to specify 'width' & 'height' or 'page'. 138 * 139 * The PostScript format/pslib has some limitations on the capabilities, 140 * which means some functionality available using other canvass (fx. alpha 141 * blending and gradient fills) are not supported with PostScript 142 * (see Canvas.txt in the docs/ folder for further details) 143 * 144 * @param array $param Parameter array 145 */ 146 function Image_Canvas_PS($param) 147 { 148 if (isset($param['page'])) { 149 switch (strtoupper($param['page'])) { 150 case 'A0': 151 $this->_pageWidth = 2380; 152 $this->_pageHeight = 3368; 153 break; 154 155 case 'A1': 156 $this->_pageWidth = 1684; 157 $this->_pageHeight = 2380; 158 break; 159 160 case 'A2': 161 $this->_pageWidth = 1190; 162 $this->_pageHeight = 1684; 163 break; 164 165 case 'A3': 166 $this->_pageWidth = 842; 167 $this->_pageHeight = 1190; 168 break; 169 170 case 'A4': 171 $this->_pageWidth = 595; 172 $this->_pageHeight = 842; 173 break; 174 175 case 'A5': 176 $this->_pageWidth = 421; 177 $this->_pageHeight = 595; 178 break; 179 180 case 'A6': 181 $this->_pageWidth = 297; 182 $this->_pageHeight = 421; 183 break; 184 185 case 'B5': 186 $this->_pageWidth = 501; 187 $this->_pageHeight = 709; 188 break; 189 190 case 'LETTER': 191 $this->_pageWidth = 612; 192 $this->_pageHeight = 792; 193 break; 194 195 case 'LEGAL': 196 $this->_pageWidth = 612; 197 $this->_pageHeight = 1008; 198 break; 199 200 case 'LEDGER': 201 $this->_pageWidth = 1224; 202 $this->_pageHeight = 792; 203 break; 204 205 case '11X17': 206 $this->_pageWidth = 792; 207 $this->_pageHeight = 1224; 208 break; 209 210 case 'CD_FRONT': 211 $this->_pageWidth = 337; 212 $this->_pageHeight = 337; 213 break; 214 215 case 'INLAY': 216 $this->_pageWidth = 425; 217 $this->_pageHeight = 332; 218 break; 219 220 case 'INLAY_NOSIDES': 221 $this->_pageWidth = 390; 222 $this->_pageHeight = 332; 223 break; 224 } 225 } 226 227 $this->setDefaultFont(array('name' => 'Helvetica', 'color' => 'black', 'size' => 9)); 228 229 if ((isset($param['orientation'])) && (strtoupper($param['orientation']) == 'LANDSCAPE')) { 230 $w = $this->_pageWidth; 231 $this->_pageWidth = $this->_pageHeight; 232 $this->_pageHeight = $w; 233 } 234 235 parent::Image_Canvas($param); 236 237 if (!$this->_pageWidth) { 238 $this->_pageWidth = $this->_width; 239 } elseif (!$this->_width) { 240 $this->_width = $this->_pageWidth; 241 } 242 243 if (!$this->_pageHeight) { 244 $this->_pageHeight = $this->_height; 245 } elseif (!$this->_height) { 246 $this->_height = $this->_pageHeight; 247 } 248 249 $this->_width = min($this->_width, $this->_pageWidth); 250 $this->_height = min($this->_height, $this->_pageHeight); 251 252 if ((isset($param['align'])) && 253 (($this->_width != $this->_pageWidth) || ($this->_height != $this->_pageHeight)) 254 ) { 255 switch (strtoupper($param['align'])) { 256 case 'TOPLEFT': 257 $this->_top = 0; 258 $this->_left = 0; 259 break; 260 261 case 'TOPCENTER': 262 $this->_top = 0; 263 $this->_left = ($this->_pageWidth - $this->_width) / 2; 264 break; 265 266 case 'TOPRIGHT': 267 $this->_top = 0; 268 $this->_left = $this->_pageWidth - $this->_width; 269 break; 270 271 case 'LEFTCENTER': 272 $this->_top = ($this->_pageHeight - $this->_height) / 2; 273 $this->_left = 0; 274 break; 275 276 case 'CENTER': 277 $this->_top = ($this->_pageHeight - $this->_height) / 2; 278 $this->_left = ($this->_pageWidth - $this->_width) / 2; 279 break; 280 281 case 'RIGHTCENTER': 282 $this->_top = ($this->_pageHeight - $this->_height) / 2; 283 $this->_left = $this->_pageWidth - $this->_width; 284 break; 285 286 case 'LEFTBOTTOM': 287 $this->_top = $this->_pageHeight - $this->_height; 288 $this->_left = 0; 289 break; 290 291 case 'CENTERBOTTOM': 292 $this->_top = $this->_pageHeight - $this->_height; 293 $this->_left = ($this->_pageWidth - $this->_width) / 2; 294 break; 295 296 case 'RIGHTBOTTOM': 297 $this->_top = $this->_pageHeight - $this->_height; 298 $this->_left = $this->_pageWidth - $this->_width; 299 break; 300 } 301 } 302 303 $addPage = true; 304 if ((isset($param['ps'])) && (is_resource($param['ps']))) { 305 $this->_ps =& $param['ps']; 306 if ((isset($param['add_page'])) && ($param['add_page'] === false)) { 307 $addPage = false; 308 } 309 } else { 310 $this->_ps = ps_new(); 311 312 if (isset($param['filename'])) { 313 ps_open_file($this->_ps, $param['filename']); 314 } else { 315 ps_open_file($this->_ps); 316 } 317 318 ps_set_parameter($this->_ps, 'warning', 'true'); 319 320 ps_set_info($this->_ps, 'Creator', (isset($param['creator']) ? $param['creator'] : 'PEAR::Image_Canvas')); 321 ps_set_info($this->_ps, 'Author', (isset($param['author']) ? $param['author'] : 'Jesper Veggerby')); 322 ps_set_info($this->_ps, 'Title', (isset($param['title']) ? $param['title'] : 'Image_Canvas')); 323 } 324 325 if ($addPage) { 326 ps_begin_page($this->_ps, $this->_pageWidth, $this->_pageHeight); 327 } 328 $this->_reset(); 329 330 $this->_pslib = $this->_version(); 331 } 332 333 /** 334 * Get the x-point from the relative to absolute coordinates 335 * 336 * @param float $x The relative x-coordinate (in percentage of total width) 337 * @return float The x-coordinate as applied to the canvas 338 * @access private 339 */ 340 function _getX($x) 341 { 342 return $this->_left + $x; 343 } 344 345 /** 346 * Get the y-point from the relative to absolute coordinates 347 * 348 * @param float $y The relative y-coordinate (in percentage of total width) 349 * @return float The y-coordinate as applied to the canvas 350 * @access private 351 */ 352 function _getY($y) 353 { 354 return $this->_pageHeight - ($this->_top + $y); 355 } 356 357 /** 358 * Get the color index for the RGB color 359 * 360 * @param int $color The color 361 * @return int The GD image index of the color 362 * @access private 363 */ 364 function _color($color = false) 365 { 366 if (($color === false) || ($color === 'opague') || ($color === 'transparent')) { 367 return false; 368 } else { 369 $color = Image_Canvas_Color::color2RGB($color); 370 $color[0] = $color[0]/255; 371 $color[1] = $color[1]/255; 372 $color[2] = $color[2]/255; 373 return $color; 374 } 375 } 376 377 /** 378 * Get the PostScript linestyle 379 * 380 * @param mixed $lineStyle The line style to return, false if the one 381 * explicitly set 382 * @return bool True if set (so that a line should be drawn) 383 * @access private 384 */ 385 function _setLineStyle($lineStyle = false) 386 { 387 if ($lineStyle === false) { 388 $lineStyle = $this->_lineStyle; 389 } 390 391 if (($lineStyle == 'transparent') || ($lineStyle === false)) { 392 return false; 393 } 394 395 if (is_array($lineStyle)) { 396 // TODO Implement linestyles in pslib (using ps_setcolor(.., 'pattern'...); ? 397 reset($lineStyle); 398 $lineStyle = current($lineStyle); 399 } 400 401 $color = $this->_color($lineStyle); 402 403 ps_setlinewidth($this->_ps, $this->_thickness); 404 ps_setcolor($this->_ps, 'stroke', 'rgb', $color[0], $color[1], $color[2], 0); 405 return true; 406 } 407 408 /** 409 * Set the PostScript fill style 410 * 411 * @param mixed $fillStyle The fillstyle to return, false if the one 412 * explicitly set 413 * @return bool True if set (so that a line should be drawn) 414 * @access private 415 */ 416 function _setFillStyle($fillStyle = false) 417 { 418 if ($fillStyle === false) { 419 $fillStyle = $this->_fillStyle; 420 } 421 422 if (($fillStyle == 'transparent') || ($fillStyle === false)) { 423 return false; 424 } 425 426 $color = $this->_color($fillStyle); 427 428 ps_setcolor($this->_ps, 'fill', 'rgb', $color[0], $color[1], $color[2], 0); 429 return true; 430 } 431 432 /** 433 * Set the PostScript font 434 * 435 * @access private 436 */ 437 function _setFont() 438 { 439 $this->_psFont = false; 440 if (isset($this->_font['name'])) { 441 ps_set_parameter($this->_ps, 'FontOutline', $this->_font['name'] . '=' . $this->_font['file']); 442 $this->_psFont = ps_findfont($this->_ps, $this->_font['name'], $this->_font['encoding'], $this->_font['embed']); 443 444 if ($this->_psFont) { 445 ps_setfont($this->_ps, $this->_psFont, $this->_font['size']); 446 $this->_setFillStyle($this->_font['color']); 447 } 448 } else { 449 $this->_setFillStyle('black'); 450 } 451 } 452 453 /** 454 * Sets an image that should be used for filling. 455 * 456 * Image filling is not supported with PostScript, filling 'transparent' 457 * 458 * @param string $filename The filename of the image to fill with 459 */ 460 function setFillImage($filename) 461 { 462 $this->_fillStyle = 'transparent'; 463 } 464 465 /** 466 * Sets a gradient fill 467 * 468 * Gradient filling is not supported with PostScript, end color used as solid fill. 469 * 470 * @param array $gradient Gradient fill options 471 */ 472 function setGradientFill($gradient) 473 { 474 $this->_fillStyle = $gradient['end']; 475 } 476 477 /** 478 * Sets the font options. 479 * 480 * The $font array may have the following entries: 481 * 482 * 'ttf' = the .ttf file (either the basename, filename or full path) 483 * If 'ttf' is specified, then the following can be specified 484 * 485 * 'size' = size in pixels 486 * 487 * 'angle' = the angle with which to write the text 488 * 489 * @param array $font The font options. 490 */ 491 function setFont($fontOptions) 492 { 493 parent::setFont($fontOptions); 494 495 if (!isset($this->_font['size'])) { 496 $this->_font['size'] = 12; 497 } 498 499 if (!isset($this->_font['encoding'])) { 500 $this->_font['encoding'] = null; 501 } 502 503 if ($this->_font['name'] == 'Helvetica') { 504 $this->_font['embed'] = 0; 505 } 506 507 if (!isset($this->_font['color'])) { 508 $this->_font['color'] = 'black'; 509 } 510 } 511 512 /** 513 * Resets the canvas. 514 * 515 * Includes fillstyle, linestyle, thickness and polygon 516 * 517 * @access private 518 */ 519 function _reset() 520 { 521// ps_initgraphics($this->_ps); 522 parent::_reset(); 523 } 524 525 /** 526 * Draw a line 527 * 528 * Parameter array: 529 * 'x0': int X start point 530 * 'y0': int Y start point 531 * 'x1': int X end point 532 * 'y1': int Y end point 533 * 'color': mixed [optional] The line color 534 * @param array $params Parameter array 535 */ 536 function line($params) 537 { 538 $color = (isset($params['color']) ? $params['color'] : false); 539 if ($this->_setLineStyle($color)) { 540 ps_moveto($this->_ps, $this->_getX($params['x0']), $this->_getY($params['y0'])); 541 ps_lineto($this->_ps, $this->_getX($params['x1']), $this->_getY($params['y1'])); 542 ps_stroke($this->_ps); 543 } 544 parent::line($params); 545 } 546 547 /** 548 * Parameter array: 549 * 'connect': bool [optional] Specifies whether the start point should be 550 * connected to the endpoint (closed polygon) or not (connected line) 551 * 'fill': mixed [optional] The fill color 552 * 'line': mixed [optional] The line color 553 * @param array $params Parameter array 554 */ 555 function polygon($params = array()) 556 { 557 $connectEnds = (isset($params['connect']) ? $params['connect'] : false); 558 $fillColor = (isset($params['fill']) ? $params['fill'] : false); 559 $lineColor = (isset($params['line']) ? $params['line'] : false); 560 561 $line = $this->_setLineStyle($lineColor); 562 $fill = false; 563 if ($connectEnds) { 564 $fill = $this->_setFillStyle($fillColor); 565 } 566 567 $first = true; 568 foreach ($this->_polygon as $point) { 569 if ($first === true) { 570 ps_moveto($this->_ps, $point['X'], $point['Y']); 571 $first = $point; 572 } else { 573 if (isset($last['P1X'])) { 574 ps_curveto($this->_ps, 575 $last['P1X'], 576 $last['P1Y'], 577 $last['P2X'], 578 $last['P2Y'], 579 $point['X'], 580 $point['Y'] 581 ); 582 } else { 583 ps_lineto($this->_ps, 584 $point['X'], 585 $point['Y'] 586 ); 587 } 588 } 589 $last = $point; 590 } 591 592 if ($connectEnds) { 593 if (isset($last['P1X'])) { 594 ps_curveto($this->_ps, 595 $last['P1X'], 596 $last['P1Y'], 597 $last['P2X'], 598 $last['P2Y'], 599 $first['X'], 600 $first['Y'] 601 ); 602 } else { 603 ps_lineto($this->_ps, 604 $first['X'], 605 $first['Y'] 606 ); 607 } 608 } 609 610 if (($line) && ($fill)) { 611 ps_fill_stroke($this->_ps); 612 } elseif ($line) { 613 ps_stroke($this->_ps); 614 } elseif ($fill) { 615 ps_fill($this->_ps); 616 } 617 parent::polygon($params); 618 } 619 620 /** 621 * Draw a rectangle 622 * 623 * Parameter array: 624 * 'x0': int X start point 625 * 'y0': int Y start point 626 * 'x1': int X end point 627 * 'y1': int Y end point 628 * 'fill': mixed [optional] The fill color 629 * 'line': mixed [optional] The line color 630 * @param array $params Parameter array 631 */ 632 function rectangle($params) 633 { 634 $x0 = $this->_getX($params['x0']); 635 $y0 = $this->_getY($params['y0']); 636 $x1 = $this->_getX($params['x1']); 637 $y1 = $this->_getY($params['y1']); 638 $fillColor = (isset($params['fill']) ? $params['fill'] : false); 639 $lineColor = (isset($params['line']) ? $params['line'] : false); 640 641 $line = $this->_setLineStyle($lineColor); 642 $fill = $this->_setFillStyle($fillColor); 643 if (($line) || ($fill)) { 644 ps_rect($this->_ps, min($x0, $x1), min($y0, $y1), abs($x1 - $x0), abs($y1 - $y0)); 645 if (($line) && ($fill)) { 646 ps_fill_stroke($this->_ps); 647 } elseif ($line) { 648 ps_stroke($this->_ps); 649 } elseif ($fill) { 650 ps_fill($this->_ps); 651 } 652 } 653 parent::rectangle($params); 654 } 655 656 /** 657 * Draw an ellipse 658 * 659 * Parameter array: 660 * 'x': int X center point 661 * 'y': int Y center point 662 * 'rx': int X radius 663 * 'ry': int Y radius 664 * 'fill': mixed [optional] The fill color 665 * 'line': mixed [optional] The line color 666 * @param array $params Parameter array 667 */ 668 function ellipse($params) 669 { 670 $x = $params['x']; 671 $y = $params['y']; 672 $rx = $params['rx']; 673 $ry = $params['ry']; 674 $fillColor = (isset($params['fill']) ? $params['fill'] : false); 675 $lineColor = (isset($params['line']) ? $params['line'] : false); 676 677 $line = $this->_setLineStyle($lineColor); 678 $fill = $this->_setFillStyle($fillColor); 679 if (($line) || ($fill)) { 680 if ($rx == $ry) { 681 ps_circle($this->_ps, $this->_getX($x), $this->_getY($y), $rx); 682 } else { 683 ps_moveto($this->_ps, $this->_getX($x - $rx), $this->_getY($y)); 684 ps_curveto($this->_ps, 685 $this->_getX($x - $rx), $this->_getY($y), 686 $this->_getX($x - $rx), $this->_getY($y - $ry), 687 $this->_getX($x), $this->_getY($y - $ry) 688 ); 689 ps_curveto($this->_ps, 690 $this->_getX($x), $this->_getY($y - $ry), 691 $this->_getX($x + $rx), $this->_getY($y - $ry), 692 $this->_getX($x + $rx), $this->_getY($y) 693 ); 694 ps_curveto($this->_ps, 695 $this->_getX($x + $rx), $this->_getY($y), 696 $this->_getX($x + $rx), $this->_getY($y + $ry), 697 $this->_getX($x), $this->_getY($y + $ry) 698 ); 699 ps_curveto($this->_ps, 700 $this->_getX($x), $this->_getY($y + $ry), 701 $this->_getX($x - $rx), $this->_getY($y + $ry), 702 $this->_getX($x - $rx), $this->_getY($y) 703 ); 704 } 705 706 if (($line) && ($fill)) { 707 ps_fill_stroke($this->_ps); 708 } elseif ($line) { 709 ps_stroke($this->_ps); 710 } elseif ($fill) { 711 ps_fill($this->_ps); 712 } 713 } 714 parent::ellipse($params); 715 } 716 717 /** 718 * Draw a pie slice 719 * 720 * Parameter array: 721 * 'x': int X center point 722 * 'y': int Y center point 723 * 'rx': int X radius 724 * 'ry': int Y radius 725 * 'v1': int The starting angle (in degrees) 726 * 'v2': int The end angle (in degrees) 727 * 'srx': int [optional] Starting X-radius of the pie slice (i.e. for a doughnut) 728 * 'sry': int [optional] Starting Y-radius of the pie slice (i.e. for a doughnut) 729 * 'fill': mixed [optional] The fill color 730 * 'line': mixed [optional] The line color 731 * @param array $params Parameter array 732 */ 733 function pieslice($params) 734 { 735 $x = $this->_getX($params['x']); 736 $y = $this->_getY($params['y']); 737 $rx = $this->_getX($params['rx']); 738 $ry = $this->_getY($params['ry']); 739 $v1 = $this->_getX($params['v1']); 740 $v2 = $this->_getY($params['v2']); 741 $srx = $this->_getX($params['srx']); 742 $sry = $this->_getY($params['sry']); 743 $fillColor = (isset($params['fill']) ? $params['fill'] : false); 744 $lineColor = (isset($params['line']) ? $params['line'] : false); 745 746 // TODO Implement pslib::pieSlice() 747 parent::pieslice($params); 748 } 749 750 /** 751 * Get the width of a text, 752 * 753 * @param string $text The text to get the width of 754 * @return int The width of the text 755 */ 756 function textWidth($text) 757 { 758 if ($this->_psFont === false) { 759 return $this->_font['size'] * 0.7 * strlen($text); 760 } else { 761 return ps_stringwidth($this->_ps, $text, $this->_psFont, $this->_font['size']); 762 } 763 } 764 765 /** 766 * Get the height of a text, 767 * 768 * @param string $text The text to get the height of 769 * @return int The height of the text 770 */ 771 function textHeight($text) 772 { 773 if (isset($this->_font['size'])) { 774 return $this->_font['size']; 775 } else { 776 return 12; 777 } 778 } 779 780 /** 781 * Writes text 782 * 783 * Parameter array: 784 * 'x': int X-point of text 785 * 'y': int Y-point of text 786 * 'text': string The text to add 787 * 'alignment': array [optional] Alignment 788 * 'color': mixed [optional] The color of the text 789 */ 790 function addText($params) 791 { 792 $x = $this->_getX($params['x']); 793 $y = $this->_getY($params['y']); 794 $text = $params['text']; 795 $color = (isset($params['color']) ? $params['color'] : false); 796 $alignment = (isset($params['alignment']) ? $params['alignment'] : false); 797 798 $this->_setFont(); 799 800 $textWidth = $this->textWidth($text); 801 $textHeight = $this->textHeight($text); 802 803 if (!is_array($alignment)) { 804 $alignment = array('vertical' => 'top', 'horizontal' => 'left'); 805 } 806 807 if (!isset($alignment['vertical'])) { 808 $alignment['vertical'] = 'top'; 809 } 810 811 if (!isset($alignment['horizontal'])) { 812 $alignment['horizontal'] = 'left'; 813 } 814 815 if ($alignment['horizontal'] == 'right') { 816 $x = $x - $textWidth; 817 } elseif ($alignment['horizontal'] == 'center') { 818 $x = $x - ($textWidth / 2); 819 } 820 821 $y -= $textHeight; 822 823 if ($alignment['vertical'] == 'bottom') { 824 $y = $y + $textHeight; 825 } elseif ($alignment['vertical'] == 'center') { 826 $y = $y + ($textHeight / 2); 827 } 828 829 if (($color === false) && (isset($this->_font['color']))) { 830 $color = $this->_font['color']; 831 } 832 833 ps_show_xy($this->_ps, $text, $x, $y); 834 835 parent::addText($params); 836 } 837 838 /** 839 * Overlay image 840 * 841 * Parameter array: 842 * 'x': int X-point of overlayed image 843 * 'y': int Y-point of overlayed image 844 * 'filename': string The filename of the image to overlay 845 * 'width': int [optional] The width of the overlayed image (resizing if possible) 846 * 'height': int [optional] The height of the overlayed image (resizing if possible) 847 * 'alignment': array [optional] Alignment 848 */ 849 function image($params) 850 { 851 $x = $this->_getX($params['x']); 852 $y = $this->_getY($params['y']); 853 $filename = $params['filename']; 854 $width = (isset($params['width']) ? $params['width'] : false); 855 $height = (isset($params['height']) ? $params['height'] : false); 856 $alignment = (isset($params['alignment']) ? $params['alignment'] : false); 857 858 if (substr($filename, -4) == '.png') { 859 $type = 'png'; 860 } elseif (substr($filename, -4) == '.jpg') { 861 $type = 'jpeg'; 862 } 863 864 $image = ps_open_image_file($this->_ps, $type, realpath($filename), ''); 865 $width_ = ps_get_value($this->_ps, 'imagewidth', $image); 866 $height_ = ps_get_value($this->_ps, 'imageheight', $image); 867 868 $outputWidth = ($width !== false ? $width : $width_); 869 $outputHeight = ($height !== false ? $height : $height_); 870 871 if (!is_array($alignment)) { 872 $alignment = array('vertical' => 'top', 'horizontal' => 'left'); 873 } 874 875 if (!isset($alignment['vertical'])) { 876 $alignment['vertical'] = 'top'; 877 } 878 879 if (!isset($alignment['horizontal'])) { 880 $alignment['horizontal'] = 'left'; 881 } 882 883 if ($alignment['horizontal'] == 'right') { 884 $x -= $outputWidth; 885 } elseif ($alignment['horizontal'] == 'center') { 886 $x -= $outputWidth / 2; 887 } 888 889 if ($alignment['vertical'] == 'top') { 890 $y += $outputHeight; 891 } elseif ($alignment['vertical'] == 'center') { 892 $y += $outputHeight / 2; 893 } 894 895 if (($width === false) && ($height === false)) { 896 $scale = 1; 897 } else { 898 $scale = max(($height/$height_), ($width/$width_)); 899 } 900 901 ps_place_image($this->_ps, $image, $x, $y, $scale); 902 ps_close_image($this->_ps, $image); 903 904 parent::image($params); 905 } 906 907 /** 908 * Output the result of the canvas 909 * 910 * @param array $param Parameter array 911 * @abstract 912 */ 913 function show($param = false) 914 { 915 parent::show($param); 916 ps_end_page($this->_ps); 917 ps_close($this->_ps); 918 919 $buf = ps_get_buffer($this->_ps); 920 $len = strlen($buf); 921 922 header('Content-type: application/postscript'); 923 header('Content-Length: ' . $len); 924 header('Content-Disposition: inline; filename=image_graph.ps'); 925 print $buf; 926 927 ps_delete($this->_ps); 928 } 929 930 /** 931 * Output the result of the canvas 932 * 933 * @param array $param Parameter array 934 * @abstract 935 */ 936 function save($param = false) 937 { 938 parent::save($param); 939 ps_end_page($this->_ps); 940 ps_close($this->_ps); 941 942 if($param['filename'] == "") { 943 $buf = ps_get_buffer($this->_ps); 944 $len = strlen($buf); 945 946 $fp = @fopen($param['filename'], 'wb'); 947 if ($fp) { 948 fwrite($fp, $buf, strlen($buf)); 949 fclose($fp); 950 } 951 } 952 953 ps_delete($this->_ps); 954 } 955 956 /** 957 * Get a canvas specific HTML tag. 958 * 959 * This method implicitly saves the canvas to the filename in the 960 * filesystem path specified and parses it as URL specified by URL path 961 * 962 * Parameter array: 963 * 'filename': string 964 * 'filepath': string Path to the file on the file system. Remember the final slash 965 * 'urlpath': string Path to the file available through an URL. Remember the final slash 966 * 'title': string The url title 967 */ 968 function toHtml($params) 969 { 970 parent::toHtml($params); 971 return '<a href="' . $params['urlpath'] . $params['filename'] . '">' . $params['title'] . '</a>'; 972 } 973 974 /** 975 * Check which major version of pslib is installed 976 * 977 * @return int The mahor version number of pslib 978 * @access private 979 */ 980 function _version() 981 { 982 $result = false; 983 $version = ''; 984 if (function_exists('ps_get_majorversion')) { 985 $version = ps_get_majorversion(); 986 } else if (function_exists('ps_get_value')) { 987 $version = ps_get_value($this->_ps, 'major', 0); 988 } else { 989 ob_start(); 990 phpinfo(8); 991 $php_info = ob_get_contents(); 992 ob_end_clean(); 993 994 if (preg_match("/<td[^>]*>pslib Version *<\/td><td[^>]*>([^<]*)<\/td>/", 995 $php_info, $result)) 996 { 997 $version = $result[1]; 998 } 999 } 1000 1001 if (preg_match('/([0-9]{1,2})\.[0-9]{1,2}(\.[0-9]{1,2})?/', trim($version), $result)) { 1002 return $result[1]; 1003 } else { 1004 return $version; 1005 } 1006 } 1007 1008} 1009 1010?> 1011