1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7 8/* This library is LGPL 9 * written by Louis-Philippe Huberdeau 10 * 11 * vim: fdm=marker tabstop=4 shiftwidth=4 noet: 12 * 13 * This file contains the GD graphic renderer. 14 */ 15require_once('lib/graph-engine/core.php'); 16 17class GD_GRenderer extends GRenderer // {{{1 18{ 19 var $gd; 20 var $styles; 21 var $colors; 22 var $fonts; 23 24 var $format; 25 var $width; 26 var $height; 27 28 var $imageMap; 29 30 function __construct($width = 0, $height = 0, $format = 'png') // {{{2 31 { 32 // Null size does not create a graphic. 33 $this->styles = []; 34 $this->colors = []; 35 $this->fonts = []; 36 37 if ($width !== 0 && $height !== 0) { 38 $this->gd = imagecreate($width, $height); 39 $this->_getColor('white'); 40 } 41 42 $this->format = $format; 43 $this->width = $width; 44 $this->height = $height; 45 } 46 47 function addLink($target, $left, $top, $right, $bottom, $title = null) // {{{2 48 { 49 $this->_convertPosition($left, $top); 50 $this->_convertPosition($right, $bottom); 51 $target = htmlspecialchars($target); 52 $title = htmlspecialchars($title); 53 54 $this->imageMap .= "<area shape=\"rect\" coords=\"$left,$top,$right,$bottom\" href=\"$target\" alt=\"$title\" title=\"$title\"/>\n"; 55 } 56 57 function drawLine($x1, $y1, $x2, $y2, $style) // {{{2 58 { 59 $this->_convertPosition($x1, $y1); 60 $this->_convertPosition($x2, $y2); 61 imagesetthickness($this->gd, $style['line-width']); 62 imageline($this->gd, $x1, $y1, $x2, $y2, $style['line']); 63 } 64 65 function drawRectangle($left, $top, $right, $bottom, $style) // {{{2 66 { 67 if ($top > $bottom) { 68 // Filled rect has a problem when coordinates are inverted. 69 $a = $top; 70 $top = $bottom; 71 $bottom = $a; 72 } 73 if ($left > $right) { 74 // Filled rect has a problem when coordinates are inverted. 75 $a = $left; 76 $left = $right; 77 $right = $a; 78 } 79 80 $this->_convertPosition($left, $top); 81 $this->_convertPosition($right, $bottom); 82 83 if (isset($style['fill'])) { 84 imagefilledrectangle($this->gd, $left, $top, $right, $bottom, $style['fill']); 85 } 86 87 imagesetthickness($this->gd, $style['line-width']); 88 imagerectangle($this->gd, $left, $top, $right, $bottom, $style['line']); 89 } 90 91 function drawPie($centerX, $centerY, $radius, $begin, $end, $style) // {{{2 92 { 93 $radius = $radius * 2; 94 if ($begin != 0 || $end != 360) { 95 $tmp = -$begin; 96 $begin = -$end; 97 $end = $tmp; 98 } 99 100 $this->_convertPosition($centerX, $centerY); 101 $radius = $radius * min($this->width, $this->height); 102 imagefilledarc($this->gd, $centerX, $centerY, $radius, $radius, $begin, $end, $style['fill'], IMG_ARC_PIE); 103 104 imagesetthickness($this->gd, $style['line-width']); 105 imagefilledarc($this->gd, $centerX, $centerY, $radius, $radius, $begin, $end, $style['line'], IMG_ARC_NOFILL | IMG_ARC_EDGED); 106 } 107 108 function drawText($text, $left, $right, $height, $style) // {{{2 109 { 110 $h = $height; // Creating duplicate (temp) 111 $this->_convertPosition($left, $height); 112 $this->_convertPosition($right, $h); 113 switch ($style['align']) { 114 case 'left': 115 $this->_drawLeftText($text, $left, $height, $style); 116 break; 117 case 'center': 118 $this->_drawCenterText($text, $left, $right, $height, $style); 119 break; 120 case 'right': 121 $this->_drawRightText($text, $right, $height, $style); 122 break; 123 } 124 } 125 126 function getTextWidth($text, $style) // {{{2 127 { 128 return imagefontwidth($style['font']) * strlen($text) / $this->width; 129 } 130 131 function getTextHeight($style) // {{{2 132 { 133 return imagefontheight($style['font']) / $this->height; 134 } 135 136 function getStyle($name) // {{{2 137 { 138 if (isset($this->styles[$name])) { 139 return $this->styles[$name]; 140 } 141 142 return $this->styles[$name] = $this->_findStyle($name); 143 } 144 145 function httpOutput($filename) // {{{2 146 { 147 switch ($this->format) { 148 case 'png': 149 header("Content-type: image/png"); 150 imagepng($this->gd); 151 break; 152 case 'jpg': 153 header("Content-type: image/jpeg"); 154 imagejpeg($this->gd); 155 break; 156 default: 157 echo "Unknown Format: {$this->format}\n"; 158 } 159 160 imagedestroy($this->gd); 161 } 162 163 function writeToStream($stream) // {{{2 164 { 165 ob_start(); 166 switch ($this->format) { 167 case 'png': 168 imagepng($this->gd); 169 break; 170 case 'jpg': 171 imagejpeg($this->gd); 172 break; 173 default: 174 echo "Unknown Format: {$this->format}\n"; 175 } 176 fwrite($stream, ob_get_contents()); 177 ob_end_clean(); 178 imagedestroy($this->gd); 179 } 180 181 function getMapContent() // {{{2 182 { 183 return $this->imageMap; 184 } 185 186 function _convertLength($value, $type) // {{{2 187 { 188 // $type is either 'width' or 'height' 189 // $value is a 0-1 float 190 return floor($value * $this->$type); 191 } 192 193 function _convertPosition(&$x, &$y) // {{{2 194 { 195 // Parameters passed by ref! 196 $x = $this->_convertLength($x, 'width'); 197 $y = $this->_convertLength($y, 'height'); 198 } 199 200 function _findStyle($name) // {{{2 201 { 202 $parts = explode('-', $name); 203 $style = []; 204 205 switch ($parts[0]) { 206 case 'Thin': 207 $style['line-width'] = 1; 208 array_shift($parts); 209 break; 210 case 'Bold': 211 $style['line-width'] = 2; 212 array_shift($parts); 213 break; 214 case 'Bolder': 215 $style['line-width'] = 3; 216 array_shift($parts); 217 break; 218 case 'Large': 219 $style['font'] = 5; 220 array_shift($parts); 221 break; 222 case 'Small': 223 $style['font'] = 2; 224 array_shift($parts); 225 break; 226 case 'Normal': 227 array_shift($parts); 228 default: 229 if ($parts[0] == 'Text') { 230 $style['font'] = 4; 231 } else { 232 $style['line-width'] = 1; 233 } 234 break; 235 } 236 237 switch ($parts[0]) { 238 case 'LineStroke': 239 $style['line'] = $this->_getColor($parts[1]); 240 break; 241 case 'FillStroke': 242 $style['fill'] = $this->_getColor($parts[1]); 243 $style['line'] = $this->_getColor('Black'); 244 break; 245 case 'Text': 246 if (! isset($parts[1])) { 247 $parts[1] = null; 248 } 249 switch ($parts[1]) { 250 case 'Center': 251 $style['align'] = 'center'; 252 break; 253 case 'Right': 254 $style['align'] = 'right'; 255 break; 256 case 'Left': 257 default: 258 $style['align'] = 'left'; 259 break; 260 } 261 break; 262 default: 263 return GRenderer::getStyle($name); 264 } 265 266 return $style; 267 } 268 269 function _getColor($name) // {{{2 270 { 271 $name = strtolower($name); 272 273 if (isset($this->colors[$name])) { 274 return $this->colors[$name]; 275 } 276 277 return $this->colors[$name] = $this->_findColor($name); 278 } 279 280 function _findColor($name) // {{{2 281 { 282 $color = $this->_getRawColor($name); 283 return imagecolorallocate($this->gd, (int)$color['r'], (int)$color['g'], (int)$color['b']); 284 } 285 286 function _drawLeftText($string, $left, $height, $style) // {{{2 287 { 288 imagestring($this->gd, $style['font'], $left, $height, $string, $this->_getColor('Black')); 289 } 290 291 function _drawCenterText($string, $left, $right, $height, $style) // {{{2 292 { 293 $width = imagefontwidth($style['font']) * strlen($string); 294 $x = ( $right - $left ) / 2 + $left - $width / 2; 295 296 imagestring($this->gd, $style['font'], $x, $height, $string, $this->_getColor('Black')); 297 } 298 299 function _drawRightText($string, $right, $height, $style) // {{{2 300 { 301 $width = imagefontwidth($style['font']) * strlen($string); 302 $x = $right - $width; 303 304 imagestring($this->gd, $style['font'], $x, $height, $string, $this->_getColor('Black')); 305 } 306} // }}}1 307