Changeset 267 for trunk/client/modules/Elezioni/grafici/gd_image.inc.php
- Timestamp:
- Apr 14, 2019, 2:31:40 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/client/modules/Elezioni/grafici/gd_image.inc.php
r265 r267 1 1 <?php 2 2 //======================================================================= 3 // File: 4 // Description: 5 // Created: 6 // Ver: $Id: gd_image.inc.php 1922 2010-01-11 11:42:50Z ljp$3 // File: GD_IMAGE.INC.PHP 4 // Description: PHP Graph Plotting library. Low level image drawing routines 5 // Created: 2001-01-08, refactored 2008-03-29 6 // Ver: $Id$ 7 7 // 8 // Copyright (c) A sial Corporation. All rights reserved.8 // Copyright (c) Aditus Consulting. All rights reserved. 9 9 //======================================================================== 10 10 11 require_once 'jpgraph_rgb.inc.php'; 12 require_once 'jpgraph_ttf.inc.php'; 13 require_once 'imageSmoothArc.php'; 14 require_once 'jpgraph_errhandler.inc.php'; 15 16 // Line styles 17 define('LINESTYLE_SOLID',1); 18 define('LINESTYLE_DOTTED',2); 19 define('LINESTYLE_DASHED',3); 20 define('LINESTYLE_LONGDASH',4); 21 22 // The DEFAULT_GFORMAT sets the default graphic encoding format, i.e. 23 // PNG, JPG or GIF depending on what is installed on the target system 24 // in that order. 25 if( !DEFINED("DEFAULT_GFORMAT") ) { 26 define("DEFAULT_GFORMAT","auto"); 27 } 28 29 //======================================================================== 11 12 //=================================================== 30 13 // CLASS Image 31 // Description: The very coor image drawing class that encapsulates all 32 // calls to the GD library 33 // Note: The class used by the library is the decendant 34 // class RotImage which extends the Image class with transparent 35 // rotation. 36 //========================================================================= 14 // Description: Wrapper class with some goodies to form the 15 // Interface to low level image drawing routines. 16 //=================================================== 37 17 class Image { 18 public $left_margin=30,$right_margin=30,$top_margin=20,$bottom_margin=30; 38 19 public $img=null; 20 public $plotwidth=0,$plotheight=0; 21 public $width=0, $height=0; 39 22 public $rgb=null; 23 public $current_color,$current_color_name; 24 public $line_weight=1, $line_style=LINESTYLE_SOLID; 40 25 public $img_format; 41 26 public $ttf=null; 42 public $line_style=LINESTYLE_SOLID;43 public $current_color,$current_color_name;44 public $original_width=0, $original_height=0;45 public $plotwidth=0,$plotheight=0;46 47 // for __get, __set48 private $_left_margin=30,$_right_margin=30,$_top_margin=20,$_bottom_margin=30;49 //private $_plotwidth=0,$_plotheight=0;50 private $_width=0, $_height=0;51 private $_line_weight=1;52 53 27 protected $expired=true; 54 28 protected $lastx=0, $lasty=0; 55 29 protected $obs_list=array(); 56 protected $font_size=12,$font_family=FF_ DEFAULT, $font_style=FS_NORMAL;30 protected $font_size=12,$font_family=FF_FONT1, $font_style=FS_NORMAL; 57 31 protected $font_file=''; 58 32 protected $text_halign="left",$text_valign="bottom"; … … 63 37 protected $langconv = null ; 64 38 protected $iInterlace=false; 65 protected $bbox_cache = array(); // STore the last found tetx bounding box66 protected $ff_font0;67 protected $ff_font0_bold;68 protected $ff_font1;69 protected $ff_font1_bold;70 protected $ff_font2;71 protected $ff_font2_bold;72 73 74 39 //--------------- 75 40 // CONSTRUCTOR 76 function __construct($aWidth=0,$aHeight=0,$aFormat=DEFAULT_GFORMAT,$aSetAutoMargin=true) { 77 78 $this->original_width = $aWidth; 79 $this->original_height = $aHeight; 80 $this->CreateImgCanvas($aWidth, $aHeight); 81 82 if( $aSetAutoMargin ) { 83 $this->SetAutoMargin(); 84 } 85 86 if( !$this->SetImgFormat($aFormat) ) { 87 JpGraphError::RaiseL(25081,$aFormat);//("JpGraph: Selected graphic format is either not supported or unknown [$aFormat]"); 88 } 89 $this->ttf = new TTF(); 90 $this->langconv = new LanguageConv(); 91 92 $this->ff_font0 = imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT0.gdf"); 93 $this->ff_font1 = imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT1.gdf"); 94 $this->ff_font2 = imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT2.gdf"); 95 $this->ff_font1_bold = imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT1-Bold.gdf"); 96 $this->ff_font2_bold = imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT2-Bold.gdf"); 41 function Image($aWidth,$aHeight,$aFormat=DEFAULT_GFORMAT,$aSetAutoMargin=true) { 42 $this->CreateImgCanvas($aWidth,$aHeight); 43 if( $aSetAutoMargin ) 44 $this->SetAutoMargin(); 45 46 if( !$this->SetImgFormat($aFormat) ) { 47 JpGraphError::RaiseL(25081,$aFormat);//("JpGraph: Selected graphic format is either not supported or unknown [$aFormat]"); 48 } 49 $this->ttf = new TTF(); 50 $this->langconv = new LanguageConv(); 97 51 } 98 52 99 53 // Enable interlacing in images 100 54 function SetInterlace($aFlg=true) { 101 55 $this->iInterlace=$aFlg; 102 56 } 103 57 104 58 // Should we use anti-aliasing. Note: This really slows down graphics! 105 59 function SetAntiAliasing($aFlg=true) { 106 $this->use_anti_aliasing = $aFlg; 107 if( function_exists('imageantialias') ) { 108 imageantialias($this->img,$aFlg); 109 } 110 else { 111 JpGraphError::RaiseL(25128);//('The function imageantialias() is not available in your PHP installation. Use the GD version that comes with PHP and not the standalone version.') 112 } 113 } 114 115 function GetAntiAliasing() { 116 return $this->use_anti_aliasing ; 60 $this->use_anti_aliasing = $aFlg; 61 if( function_exists('imageantialias') ) { 62 imageantialias($this->img,$aFlg); 63 } 64 else { 65 JpGraphError::RaiseL(25128);//('The function imageantialias() is not available in your PHP installation. Use the GD version that comes with PHP and not the standalone version.') 66 } 117 67 } 118 68 119 69 function CreateRawCanvas($aWidth=0,$aHeight=0) { 120 121 $aWidth *= SUPERSAMPLING_SCALE; 122 $aHeight *= SUPERSAMPLING_SCALE; 123 124 if( $aWidth <= 1 || $aHeight <= 1 ) { 125 JpGraphError::RaiseL(25082,$aWidth,$aHeight);//("Illegal sizes specified for width or height when creating an image, (width=$aWidth, height=$aHeight)"); 126 } 127 128 $this->img = @imagecreatetruecolor($aWidth, $aHeight); 129 if( $this->img < 1 ) { 130 JpGraphError::RaiseL(25126); 131 //die("Can't create truecolor image. Check that you really have GD2 library installed."); 132 } 133 $this->SetAlphaBlending(); 134 135 if( $this->iInterlace ) { 136 imageinterlace($this->img,1); 137 } 138 if( $this->rgb != null ) { 139 $this->rgb->img = $this->img ; 140 } 141 else { 142 $this->rgb = new RGB($this->img); 143 } 70 if( $aWidth <= 1 || $aHeight <= 1 ) { 71 JpGraphError::RaiseL(25082,$aWidth,$aHeight);//("Illegal sizes specified for width or height when creating an image, (width=$aWidth, height=$aHeight)"); 72 } 73 74 if( USE_TRUECOLOR ) { 75 $this->img = @imagecreatetruecolor($aWidth, $aHeight); 76 if( $this->img < 1 ) { 77 JpGraphError::RaiseL(25126); 78 //die("Can't create truecolor image. Check that you really have GD2 library installed."); 79 } 80 $this->SetAlphaBlending(); 81 } else { 82 $this->img = @imagecreate($aWidth, $aHeight); 83 if( $this->img < 1 ) { 84 JpGraphError::RaiseL(25126); 85 //die("<b>JpGraph Error:</b> Can't create image. Check that you really have the GD library installed."); 86 } 87 } 88 89 if( $this->iInterlace ) { 90 imageinterlace($this->img,1); 91 } 92 if( $this->rgb != null ) 93 $this->rgb->img = $this->img ; 94 else 95 $this->rgb = new RGB($this->img); 144 96 } 145 97 146 98 function CloneCanvasH() { 147 148 149 150 151 } 152 99 $oldimage = $this->img; 100 $this->CreateRawCanvas($this->width,$this->height); 101 imagecopy($this->img,$oldimage,0,0,0,0,$this->width,$this->height); 102 return $oldimage; 103 } 104 153 105 function CreateImgCanvas($aWidth=0,$aHeight=0) { 154 106 155 156 157 158 159 160 161 $this->height=$aHeight; 162 163 164 165 // We will set the final size later. 166 167 168 169 170 171 172 173 174 // Set canvas color (will also be the background color for a 175 176 $this->SetColor($this->canvascolor); 177 $this->FilledRectangle(0,0,$this->width-1,$this->height-1);178 179 107 $old = array($this->img,$this->width,$this->height); 108 109 $aWidth = round($aWidth); 110 $aHeight = round($aHeight); 111 112 $this->width=$aWidth; 113 $this->height=$aHeight; 114 115 116 if( $aWidth==0 || $aHeight==0 ) { 117 // We will set the final size later. 118 // Note: The size must be specified before any other 119 // img routines that stroke anything are called. 120 $this->img = null; 121 $this->rgb = null; 122 return $old; 123 } 124 125 $this->CreateRawCanvas($aWidth,$aHeight); 126 // Set canvas color (will also be the background color for a 127 // a pallett image 128 $this->SetColor($this->canvascolor); 129 $this->FilledRectangle(0,0,$aWidth,$aHeight); 130 131 return $old ; 180 132 } 181 133 182 134 function CopyCanvasH($aToHdl,$aFromHdl,$aToX,$aToY,$aFromX,$aFromY,$aWidth,$aHeight,$aw=-1,$ah=-1) { 183 184 185 186 187 188 189 190 191 135 if( $aw === -1 ) { 136 $aw = $aWidth; 137 $ah = $aHeight; 138 $f = 'imagecopyresized'; 139 } 140 else { 141 $f = 'imagecopyresampled'; 142 } 143 $f($aToHdl,$aFromHdl,$aToX,$aToY,$aFromX,$aFromY, $aWidth,$aHeight,$aw,$ah); 192 144 } 193 145 194 146 function Copy($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1) { 195 $this->CopyCanvasH($this->img,$fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight); 147 $this->CopyCanvasH($this->img,$fromImg,$toX,$toY,$fromX,$fromY, 148 $toWidth,$toHeight,$fromWidth,$fromHeight); 196 149 } 197 150 198 151 function CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1,$aMix=100) { 199 if( $aMix == 100 ) { 200 $this->CopyCanvasH($this->img,$fromImg, 201 $toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight); 202 } 203 else { 204 if( ($fromWidth != -1 && ($fromWidth != $toWidth)) || ($fromHeight != -1 && ($fromHeight != $fromHeight)) ) { 205 // Create a new canvas that will hold the re-scaled original from image 206 if( $toWidth <= 1 || $toHeight <= 1 ) { 207 JpGraphError::RaiseL(25083);//('Illegal image size when copying image. Size for copied to image is 1 pixel or less.'); 208 } 209 210 $tmpimg = @imagecreatetruecolor($toWidth, $toHeight); 211 212 if( $tmpimg < 1 ) { 213 JpGraphError::RaiseL(25084);//('Failed to create temporary GD canvas. Out of memory ?'); 214 } 215 $this->CopyCanvasH($tmpimg,$fromImg,0,0,0,0, 216 $toWidth,$toHeight,$fromWidth,$fromHeight); 217 $fromImg = $tmpimg; 218 } 219 imagecopymerge($this->img,$fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$aMix); 220 } 152 if( $aMix == 100 ) { 153 $this->CopyCanvasH($this->img,$fromImg, 154 $toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight); 155 } 156 else { 157 if( ($fromWidth != -1 && ($fromWidth != $toWidth)) || 158 ($fromHeight != -1 && ($fromHeight != $fromHeight)) ) { 159 // Create a new canvas that will hold the re-scaled original from image 160 if( $toWidth <= 1 || $toHeight <= 1 ) { 161 JpGraphError::RaiseL(25083);//('Illegal image size when copying image. Size for copied to image is 1 pixel or less.'); 162 } 163 if( USE_TRUECOLOR ) { 164 $tmpimg = @imagecreatetruecolor($toWidth, $toHeight); 165 } else { 166 $tmpimg = @imagecreate($toWidth, $toHeight); 167 } 168 if( $tmpimg < 1 ) { 169 JpGraphError::RaiseL(25084);//('Failed to create temporary GD canvas. Out of memory ?'); 170 } 171 $this->CopyCanvasH($tmpimg,$fromImg,0,0,0,0, 172 $toWidth,$toHeight,$fromWidth,$fromHeight); 173 $fromImg = $tmpimg; 174 } 175 imagecopymerge($this->img,$fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$aMix); 176 } 221 177 } 222 178 223 179 static function GetWidth($aImg=null) { 224 if( $aImg === null ) { 225 $aImg = $this->img; 226 } 227 return imagesx($aImg); 180 if( $aImg === null ) 181 $aImg = $this->img; 182 return imagesx($aImg); 228 183 } 229 184 230 185 static function GetHeight($aImg=null) { 231 if( $aImg === null ) { 232 $aImg = $this->img; 233 } 234 return imagesy($aImg); 235 } 236 186 if( $aImg === null ) 187 $aImg = $this->img; 188 return imagesy($aImg); 189 } 190 237 191 static function CreateFromString($aStr) { 238 $img = imagecreatefromstring($aStr); 239 if( $img === false ) { 240 JpGraphError::RaiseL(25085); 241 //('An image can not be created from the supplied string. It is either in a format not supported or the string is representing an corrupt image.'); 242 } 243 return $img; 192 $img = imagecreatefromstring($aStr); 193 if( $img === false ) { 194 JpGraphError::RaiseL(25085);//('An image can not be created from the supplied string. It is either in a format not supported or the string is representing an corrupt image.'); 195 } 196 return $img; 244 197 } 245 198 246 199 function SetCanvasH($aHdl) { 247 248 200 $this->img = $aHdl; 201 $this->rgb->img = $aHdl; 249 202 } 250 203 251 204 function SetCanvasColor($aColor) { 252 205 $this->canvascolor = $aColor ; 253 206 } 254 207 255 208 function SetAlphaBlending($aFlg=true) { 256 ImageAlphaBlending($this->img,$aFlg); 257 } 258 259 function SetAutoMargin() { 260 $min_bm=5; 261 $lm = min(40,$this->width/7); 262 $rm = min(20,$this->width/10); 263 $tm = max(5,$this->height/7); 264 $bm = max($min_bm,$this->height/6); 265 $this->SetMargin($lm,$rm,$tm,$bm); 266 } 267 209 ImageAlphaBlending($this->img,$aFlg); 210 } 211 212 213 function SetAutoMargin() { 214 GLOBAL $gJpgBrandTiming; 215 $min_bm=5; 216 /* 217 if( $gJpgBrandTiming ) 218 $min_bm=15; 219 */ 220 $lm = min(40,$this->width/7); 221 $rm = min(20,$this->width/10); 222 $tm = max(5,$this->height/7); 223 $bm = max($min_bm,$this->height/7); 224 $this->SetMargin($lm,$rm,$tm,$bm); 225 } 226 227 268 228 //--------------- 269 // PUBLIC METHODS 270 229 // PUBLIC METHODS 230 271 231 function SetFont($family,$style=FS_NORMAL,$size=10) { 272 $this->font_family=$family; 273 $this->font_style=$style; 274 $this->font_size=$size*SUPERSAMPLING_SCALE; 275 $this->font_file=''; 276 if( ($this->font_family==FF_FONT1 || $this->font_family==FF_FONT2) && $this->font_style==FS_BOLD ){ 277 ++$this->font_family; 278 } 279 if( $this->font_family > FF_FONT2+1 ) { // A TTF font so get the font file 280 281 // Check that this PHP has support for TTF fonts 282 if( !function_exists('imagettfbbox') ) { 283 // use internal font when php is configured without '--with-ttf' 284 $this->font_family = FF_FONT1; 285 // JpGraphError::RaiseL(25087);//('This PHP build has not been configured with TTF support. You need to recompile your PHP installation with FreeType support.'); 286 } else { 287 $this->font_file = $this->ttf->File($this->font_family,$this->font_style); 288 } 289 } 232 $this->font_family=$family; 233 $this->font_style=$style; 234 $this->font_size=$size; 235 $this->font_file=''; 236 if( ($this->font_family==FF_FONT1 || $this->font_family==FF_FONT2) && $this->font_style==FS_BOLD ){ 237 ++$this->font_family; 238 } 239 if( $this->font_family > FF_FONT2+1 ) { // A TTF font so get the font file 240 241 // Check that this PHP has support for TTF fonts 242 if( !function_exists('imagettfbbox') ) { 243 JpGraphError::RaiseL(25087);//('This PHP build has not been configured with TTF support. You need to recompile your PHP installation with FreeType support.'); 244 } 245 $this->font_file = $this->ttf->File($this->font_family,$this->font_style); 246 } 290 247 } 291 248 292 249 // Get the specific height for a text string 293 250 function GetTextHeight($txt="",$angle=0) { 294 $tmp = preg_split('/\n/',$txt); 295 $n = count($tmp); 296 $m=0; 297 for($i=0; $i< $n; ++$i) { 298 $m = max($m,strlen($tmp[$i])); 299 } 300 301 if( $this->font_family <= FF_FONT2+1 ) { 302 if( $angle==0 ) { 303 $h = imagefontheight($this->font_family); 304 if( $h === false ) { 305 JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); 306 } 307 308 return $n*$h; 309 } 310 else { 311 $w = @imagefontwidth($this->font_family); 312 if( $w === false ) { 313 JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); 314 } 315 316 return $m*$w; 317 } 318 } 319 else { 320 $bbox = $this->GetTTFBBox($txt,$angle); 321 return $bbox[1]-$bbox[5]+1; 322 } 323 } 324 251 $tmp = split("\n",$txt); 252 $n = count($tmp); 253 $m=0; 254 for($i=0; $i< $n; ++$i) 255 $m = max($m,strlen($tmp[$i])); 256 257 if( $this->font_family <= FF_FONT2+1 ) { 258 if( $angle==0 ) { 259 $h = imagefontheight($this->font_family); 260 if( $h === false ) { 261 JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); 262 } 263 264 return $n*$h; 265 } 266 else { 267 $w = @imagefontwidth($this->font_family); 268 if( $w === false ) { 269 JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); 270 } 271 272 return $m*$w; 273 } 274 } 275 else { 276 $bbox = $this->GetTTFBBox($txt,$angle); 277 return $bbox[1]-$bbox[5]; 278 } 279 } 280 325 281 // Estimate font height 326 282 function GetFontHeight($angle=0) { 327 328 329 } 330 283 $txt = "XOMg"; 284 return $this->GetTextHeight($txt,$angle); 285 } 286 331 287 // Approximate font width with width of letter "O" 332 288 function GetFontWidth($angle=0) { 333 $txt = 'O'; 334 return $this->GetTextWidth($txt,$angle); 335 } 336 337 // Get actual width of text in absolute pixels. Note that the width is the 338 // texts projected with onto the x-axis. Call with angle=0 to get the true 339 // etxt width. 289 $txt = 'O'; 290 return $this->GetTextWidth($txt,$angle); 291 } 292 293 // Get actual width of text in absolute pixels 340 294 function GetTextWidth($txt,$angle=0) { 341 295 342 $tmp = preg_split('/\n/',$txt); 343 $n = count($tmp); 344 if( $this->font_family <= FF_FONT2+1 ) { 345 346 $m=0; 347 for($i=0; $i < $n; ++$i) { 348 $l=strlen($tmp[$i]); 349 if( $l > $m ) { 350 $m = $l; 351 } 352 } 353 354 if( $angle==0 ) { 355 $w = @imagefontwidth($this->font_family); 356 if( $w === false ) { 357 JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); 358 } 359 return $m*$w; 360 } 361 else { 362 // 90 degrees internal so height becomes width 363 $h = @imagefontheight($this->font_family); 364 if( $h === false ) { 365 JpGraphError::RaiseL(25089);//('You have a misconfigured GD font support. The call to imagefontheight() fails.'); 366 } 367 return $n*$h; 368 } 369 } 370 else { 371 // For TTF fonts we must walk through a lines and find the 372 // widest one which we use as the width of the multi-line 373 // paragraph 374 $m=0; 375 for( $i=0; $i < $n; ++$i ) { 376 $bbox = $this->GetTTFBBox($tmp[$i],$angle); 377 $mm = $bbox[2] - $bbox[0]; 378 if( $mm > $m ) 379 $m = $mm; 380 } 381 return $m; 382 } 383 } 384 385 296 $tmp = split("\n",$txt); 297 $n = count($tmp); 298 if( $this->font_family <= FF_FONT2+1 ) { 299 300 $m=0; 301 for($i=0; $i < $n; ++$i) { 302 $l=strlen($tmp[$i]); 303 if( $l > $m ) { 304 $m = $l; 305 } 306 } 307 308 if( $angle==0 ) { 309 $w = @imagefontwidth($this->font_family); 310 if( $w === false ) { 311 JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); 312 } 313 return $m*$w; 314 } 315 else { 316 // 90 degrees internal so height becomes width 317 $h = @imagefontheight($this->font_family); 318 if( $h === false ) { 319 JpGraphError::RaiseL(25089);//('You have a misconfigured GD font support. The call to imagefontheight() fails.'); 320 } 321 return $n*$h; 322 } 323 } 324 else { 325 // For TTF fonts we must walk through a lines and find the 326 // widest one which we use as the width of the multi-line 327 // paragraph 328 $m=0; 329 for( $i=0; $i < $n; ++$i ) { 330 $bbox = $this->GetTTFBBox($tmp[$i],$angle); 331 $mm = $bbox[2] - $bbox[0]; 332 if( $mm > $m ) 333 $m = $mm; 334 } 335 return $m; 336 } 337 } 338 386 339 // Draw text with a box around it 387 340 function StrokeBoxedText($x,$y,$txt,$dir=0,$fcolor="white",$bcolor="black", 388 $shadowcolor=false,$paragraph_align="left", 389 $xmarg=6,$ymarg=4,$cornerradius=0,$dropwidth=3) { 390 391 $oldx = $this->lastx; 392 $oldy = $this->lasty; 393 394 if( !is_numeric($dir) ) { 395 if( $dir=="h" ) $dir=0; 396 elseif( $dir=="v" ) $dir=90; 397 else JpGraphError::RaiseL(25090,$dir);//(" Unknown direction specified in call to StrokeBoxedText() [$dir]"); 398 } 399 400 if( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) { 401 $width=$this->GetTextWidth($txt,$dir) ; 402 $height=$this->GetTextHeight($txt,$dir) ; 403 } 404 else { 405 $width=$this->GetBBoxWidth($txt,$dir) ; 406 $height=$this->GetBBoxHeight($txt,$dir) ; 407 } 408 409 $height += 2*$ymarg; 410 $width += 2*$xmarg; 411 412 if( $this->text_halign=="right" ) $x -= $width; 413 elseif( $this->text_halign=="center" ) $x -= $width/2; 414 415 if( $this->text_valign=="bottom" ) $y -= $height; 416 elseif( $this->text_valign=="center" ) $y -= $height/2; 417 418 $olda = $this->SetAngle(0); 419 420 if( $shadowcolor ) { 421 $this->PushColor($shadowcolor); 422 $this->FilledRoundedRectangle($x-$xmarg+$dropwidth,$y-$ymarg+$dropwidth, 423 $x+$width+$dropwidth,$y+$height-$ymarg+$dropwidth, 424 $cornerradius); 425 $this->PopColor(); 426 $this->PushColor($fcolor); 427 $this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg, 428 $x+$width,$y+$height-$ymarg, 429 $cornerradius); 430 $this->PopColor(); 431 $this->PushColor($bcolor); 432 $this->RoundedRectangle($x-$xmarg,$y-$ymarg, 433 $x+$width,$y+$height-$ymarg,$cornerradius); 434 $this->PopColor(); 435 } 436 else { 437 if( $fcolor ) { 438 $oc=$this->current_color; 439 $this->SetColor($fcolor); 440 $this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius); 441 $this->current_color=$oc; 341 $shadowcolor=false,$paragraph_align="left", 342 $xmarg=6,$ymarg=4,$cornerradius=0,$dropwidth=3) { 343 344 if( !is_numeric($dir) ) { 345 if( $dir=="h" ) $dir=0; 346 elseif( $dir=="v" ) $dir=90; 347 else JpGraphError::RaiseL(25090,$dir);//(" Unknown direction specified in call to StrokeBoxedText() [$dir]"); 348 } 349 350 if( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) { 351 $width=$this->GetTextWidth($txt,$dir) ; 352 $height=$this->GetTextHeight($txt,$dir) ; 353 } 354 else { 355 $width=$this->GetBBoxWidth($txt,$dir) ; 356 $height=$this->GetBBoxHeight($txt,$dir) ; 357 } 358 359 $height += 2*$ymarg; 360 $width += 2*$xmarg; 361 362 if( $this->text_halign=="right" ) $x -= $width; 363 elseif( $this->text_halign=="center" ) $x -= $width/2; 364 if( $this->text_valign=="bottom" ) $y -= $height; 365 elseif( $this->text_valign=="center" ) $y -= $height/2; 366 367 $olda = $this->SetAngle(0); 368 369 if( $shadowcolor ) { 370 $this->PushColor($shadowcolor); 371 $this->FilledRoundedRectangle($x-$xmarg+$dropwidth,$y-$ymarg+$dropwidth, 372 $x+$width+$dropwidth,$y+$height-$ymarg+$dropwidth, 373 $cornerradius); 374 $this->PopColor(); 375 $this->PushColor($fcolor); 376 $this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg, 377 $x+$width,$y+$height-$ymarg, 378 $cornerradius); 379 $this->PopColor(); 380 $this->PushColor($bcolor); 381 $this->RoundedRectangle($x-$xmarg,$y-$ymarg, 382 $x+$width,$y+$height-$ymarg,$cornerradius); 383 $this->PopColor(); 384 } 385 else { 386 if( $fcolor ) { 387 $oc=$this->current_color; 388 $this->SetColor($fcolor); 389 $this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius); 390 $this->current_color=$oc; 391 } 392 if( $bcolor ) { 393 $oc=$this->current_color; 394 $this->SetColor($bcolor); 395 $this->RoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius); 396 $this->current_color=$oc; 397 } 398 } 399 400 $h=$this->text_halign; 401 $v=$this->text_valign; 402 $this->SetTextAlign("left","top"); 403 $this->StrokeText($x, $y, $txt, $dir, $paragraph_align); 404 $bb = array($x-$xmarg,$y+$height-$ymarg,$x+$width,$y+$height-$ymarg, 405 $x+$width,$y-$ymarg,$x-$xmarg,$y-$ymarg); 406 $this->SetTextAlign($h,$v); 407 408 $this->SetAngle($olda); 409 410 return $bb; 411 } 412 413 // Set text alignment 414 function SetTextAlign($halign,$valign="bottom") { 415 $this->text_halign=$halign; 416 $this->text_valign=$valign; 417 } 418 419 420 function _StrokeBuiltinFont($x,$y,$txt,$dir=0,$paragraph_align="left",&$aBoundingBox,$aDebug=false) { 421 422 if( is_numeric($dir) && $dir!=90 && $dir!=0) 423 JpGraphError::RaiseL(25091);//(" Internal font does not support drawing text at arbitrary angle. Use TTF fonts instead."); 424 425 $h=$this->GetTextHeight($txt); 426 $fh=$this->GetFontHeight(); 427 $w=$this->GetTextWidth($txt); 428 429 if( $this->text_halign=="right") 430 $x -= $dir==0 ? $w : $h; 431 elseif( $this->text_halign=="center" ) { 432 // For center we subtract 1 pixel since this makes the middle 433 // be prefectly in the middle 434 $x -= $dir==0 ? $w/2-1 : $h/2; 435 } 436 if( $this->text_valign=="top" ) 437 $y += $dir==0 ? $h : $w; 438 elseif( $this->text_valign=="center" ) 439 $y += $dir==0 ? $h/2 : $w/2; 440 441 if( $dir==90 ) { 442 imagestringup($this->img,$this->font_family,$x,$y,$txt,$this->current_color); 443 $aBoundingBox = array(round($x),round($y),round($x),round($y-$w),round($x+$h),round($y-$w),round($x+$h),round($y)); 444 if( $aDebug ) { 445 // Draw bounding box 446 $this->PushColor('green'); 447 $this->Polygon($aBoundingBox,true); 448 $this->PopColor(); 449 } 450 } 451 else { 452 if( preg_match('/\n/',$txt) ) { 453 $tmp = split("\n",$txt); 454 for($i=0; $i < count($tmp); ++$i) { 455 $w1 = $this->GetTextWidth($tmp[$i]); 456 if( $paragraph_align=="left" ) { 457 imagestring($this->img,$this->font_family,$x,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); 458 } 459 elseif( $paragraph_align=="right" ) { 460 imagestring($this->img,$this->font_family,$x+($w-$w1), 461 $y-$h+1+$i*$fh,$tmp[$i],$this->current_color); 462 } 463 else { 464 imagestring($this->img,$this->font_family,$x+$w/2-$w1/2, 465 $y-$h+1+$i*$fh,$tmp[$i],$this->current_color); 466 } 467 } 468 } 469 else { 470 //Put the text 471 imagestring($this->img,$this->font_family,$x,$y-$h+1,$txt,$this->current_color); 472 } 473 if( $aDebug ) { 474 // Draw the bounding rectangle and the bounding box 475 $p1 = array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y)); 476 477 // Draw bounding box 478 $this->PushColor('green'); 479 $this->Polygon($p1,true); 480 $this->PopColor(); 481 442 482 } 443 if( $bcolor ) { 444 $oc=$this->current_color; 445 $this->SetColor($bcolor); 446 $this->RoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius); 447 $this->current_color=$oc; 483 $aBoundingBox=array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y)); 484 } 485 } 486 487 function AddTxtCR($aTxt) { 488 // If the user has just specified a '\n' 489 // instead of '\n\t' we have to add '\r' since 490 // the width will be too muchy otherwise since when 491 // we print we stroke the individually lines by hand. 492 $e = explode("\n",$aTxt); 493 $n = count($e); 494 for($i=0; $i<$n; ++$i) { 495 $e[$i]=str_replace("\r","",$e[$i]); 496 } 497 return implode("\n\r",$e); 498 } 499 500 function GetTTFBBox($aTxt,$aAngle=0) { 501 $bbox = @ImageTTFBBox($this->font_size,$aAngle,$this->font_file,$aTxt); 502 if( $bbox === false ) { 503 JpGraphError::RaiseL(25092,$this->font_file); 504 //("There is either a configuration problem with TrueType or a problem reading font file (".$this->font_file."). Make sure file exists and is in a readable place for the HTTP process. (If 'basedir' restriction is enabled in PHP then the font file must be located in the document root.). It might also be a wrongly installed FreeType library. Try uppgrading to at least FreeType 2.1.13 and recompile GD with the correct setup so it can find the new FT library."); 505 } 506 return $bbox; 507 } 508 509 function GetBBoxTTF($aTxt,$aAngle=0) { 510 // Normalize the bounding box to become a minimum 511 // enscribing rectangle 512 513 $aTxt = $this->AddTxtCR($aTxt); 514 515 if( !is_readable($this->font_file) ) { 516 JpGraphError::RaiseL(25093,$this->font_file); 517 //('Can not read font file ('.$this->font_file.') in call to Image::GetBBoxTTF. Please make sure that you have set a font before calling this method and that the font is installed in the TTF directory.'); 518 } 519 $bbox = $this->GetTTFBBox($aTxt,$aAngle); 520 521 if( $aAngle==0 ) 522 return $bbox; 523 if( $aAngle >= 0 ) { 524 if( $aAngle <= 90 ) { //<=0 525 $bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1], 526 $bbox[2],$bbox[5],$bbox[6],$bbox[5]); 527 } 528 elseif( $aAngle <= 180 ) { //<= 2 529 $bbox = array($bbox[4],$bbox[7],$bbox[0],$bbox[7], 530 $bbox[0],$bbox[3],$bbox[4],$bbox[3]); 531 } 532 elseif( $aAngle <= 270 ) { //<= 3 533 $bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5], 534 $bbox[6],$bbox[1],$bbox[2],$bbox[1]); 535 } 536 else { 537 $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], 538 $bbox[4],$bbox[7],$bbox[0],$bbox[7]); 539 } 540 } 541 elseif( $aAngle < 0 ) { 542 if( $aAngle <= -270 ) { // <= -3 543 $bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1], 544 $bbox[2],$bbox[5],$bbox[6],$bbox[5]); 545 } 546 elseif( $aAngle <= -180 ) { // <= -2 547 $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], 548 $bbox[4],$bbox[7],$bbox[0],$bbox[7]); 549 } 550 elseif( $aAngle <= -90 ) { // <= -1 551 $bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5], 552 $bbox[6],$bbox[1],$bbox[2],$bbox[1]); 553 } 554 else { 555 $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], 556 $bbox[4],$bbox[7],$bbox[0],$bbox[7]); 557 } 558 } 559 return $bbox; 560 } 561 562 function GetBBoxHeight($aTxt,$aAngle=0) { 563 $box = $this->GetBBoxTTF($aTxt,$aAngle); 564 return $box[1]-$box[7]+1; 565 } 566 567 function GetBBoxWidth($aTxt,$aAngle=0) { 568 $box = $this->GetBBoxTTF($aTxt,$aAngle); 569 return $box[2]-$box[0]+1; 570 } 571 572 function _StrokeTTF($x,$y,$txt,$dir=0,$paragraph_align="left",&$aBoundingBox,$debug=false) { 573 574 // Setupo default inter line margin for paragraphs to 575 // 25% of the font height. 576 $ConstLineSpacing = 0.25 ; 577 578 // Remember the anchor point before adjustment 579 if( $debug ) { 580 $ox=$x; 581 $oy=$y; 582 } 583 584 if( !preg_match('/\n/',$txt) || ($dir>0 && preg_match('/\n/',$txt)) ) { 585 // Format a single line 586 587 $txt = $this->AddTxtCR($txt); 588 589 $bbox=$this->GetBBoxTTF($txt,$dir); 590 591 // Align x,y ot lower left corner of bbox 592 $x -= $bbox[0]; 593 $y -= $bbox[1]; 594 595 // Note to self: "topanchor" is deprecated after we changed the 596 // bopunding box stuff. 597 if( $this->text_halign=="right" || $this->text_halign=="topanchor" ) 598 $x -= $bbox[2]-$bbox[0]; 599 elseif( $this->text_halign=="center" ) $x -= ($bbox[2]-$bbox[0])/2; 600 601 if( $this->text_valign=="top" ) $y += abs($bbox[5])+$bbox[1]; 602 elseif( $this->text_valign=="center" ) $y -= ($bbox[5]-$bbox[1])/2; 603 604 ImageTTFText ($this->img, $this->font_size, $dir, $x, $y, 605 $this->current_color,$this->font_file,$txt); 606 607 // Calculate and return the co-ordinates for the bounding box 608 $box=@ImageTTFBBox($this->font_size,$dir,$this->font_file,$txt); 609 $p1 = array(); 610 611 612 for($i=0; $i < 4; ++$i) { 613 $p1[] = round($box[$i*2]+$x); 614 $p1[] = round($box[$i*2+1]+$y); 615 } 616 $aBoundingBox = $p1; 617 618 // Debugging code to highlight the bonding box and bounding rectangle 619 // For text at 0 degrees the bounding box and bounding rectangle are the 620 // same 621 if( $debug ) { 622 // Draw the bounding rectangle and the bounding box 623 $box=@ImageTTFBBox($this->font_size,$dir,$this->font_file,$txt); 624 $p = array(); 625 $p1 = array(); 626 for($i=0; $i < 4; ++$i) { 627 $p[] = $bbox[$i*2]+$x; 628 $p[] = $bbox[$i*2+1]+$y; 629 $p1[] = $box[$i*2]+$x; 630 $p1[] = $box[$i*2+1]+$y; 631 } 632 633 // Draw bounding box 634 $this->PushColor('green'); 635 $this->Polygon($p1,true); 636 $this->PopColor(); 637 638 // Draw bounding rectangle 639 $this->PushColor('darkgreen'); 640 $this->Polygon($p,true); 641 $this->PopColor(); 642 643 // Draw a cross at the anchor point 644 $this->PushColor('red'); 645 $this->Line($ox-15,$oy,$ox+15,$oy); 646 $this->Line($ox,$oy-15,$ox,$oy+15); 647 $this->PopColor(); 448 648 } 449 } 450 451 $h=$this->text_halign; 452 $v=$this->text_valign; 453 $this->SetTextAlign("left","top"); 454 455 $debug=false; 456 $this->StrokeText($x, $y, $txt, $dir, $paragraph_align,$debug); 457 458 $bb = array($x-$xmarg,$y+$height-$ymarg,$x+$width,$y+$height-$ymarg, 459 $x+$width,$y-$ymarg,$x-$xmarg,$y-$ymarg); 460 $this->SetTextAlign($h,$v); 461 462 $this->SetAngle($olda); 463 $this->lastx = $oldx; 464 $this->lasty = $oldy; 465 466 return $bb; 467 } 468 469 // Draw text with a box around it. This time the box will be rotated 470 // with the text. The previous method will just make a larger enough non-rotated 471 // box to hold the text inside. 472 function StrokeBoxedText2($x,$y,$txt,$dir=0,$fcolor="white",$bcolor="black", 473 $shadowcolor=false,$paragraph_align="left", 474 $xmarg=6,$ymarg=4,$cornerradius=0,$dropwidth=3) { 475 476 // This version of boxed text will stroke a rotated box round the text 477 // thta will follow the angle of the text. 478 // This has two implications: 479 // 1) This methos will only support TTF fonts 480 // 2) The only two alignment that makes sense are centered or baselined 481 482 if( $this->font_family <= FF_FONT2+1 ) { 483 JpGraphError::RaiseL(25131);//StrokeBoxedText2() Only support TTF fonts and not built in bitmap fonts 484 } 485 486 $oldx = $this->lastx; 487 $oldy = $this->lasty; 488 $dir = $this->NormAngle($dir); 489 490 if( !is_numeric($dir) ) { 491 if( $dir=="h" ) $dir=0; 492 elseif( $dir=="v" ) $dir=90; 493 else JpGraphError::RaiseL(25090,$dir);//(" Unknown direction specified in call to StrokeBoxedText() [$dir]"); 494 } 495 496 $width=$this->GetTextWidth($txt,0) + 2*$xmarg; 497 $height=$this->GetTextHeight($txt,0) + 2*$ymarg ; 498 $rect_width=$this->GetBBoxWidth($txt,$dir) ; 499 $rect_height=$this->GetBBoxHeight($txt,$dir) ; 500 501 $baseline_offset = $this->bbox_cache[1]-1; 502 503 if( $this->text_halign=="center" ) { 504 if( $dir >= 0 && $dir <= 90 ) { 505 506 $x -= $rect_width/2; 507 $x += sin($dir*M_PI/180)*$height; 508 $y += $rect_height/2; 509 510 } elseif( $dir >= 270 && $dir <= 360 ) { 511 512 $x -= $rect_width/2; 513 $y -= $rect_height/2; 514 $y += cos($dir*M_PI/180)*$height; 515 516 } elseif( $dir >= 90 && $dir <= 180 ) { 517 518 $x += $rect_width/2; 519 $y += $rect_height/2; 520 $y += cos($dir*M_PI/180)*$height; 521 522 } 523 else { 524 // $dir > 180 && $dir < 270 525 $x += $rect_width/2; 526 $x += sin($dir*M_PI/180)*$height; 527 $y -= $rect_height/2; 528 } 529 } 530 531 // Rotate the box around this point 532 $this->SetCenter($x,$y); 533 $olda = $this->SetAngle(-$dir); 534 535 // We need to use adjusted coordinats for the box to be able 536 // to draw the box below the baseline. This cannot be done before since 537 // the rotating point must be the original x,y since that is arounbf the 538 // point where the text will rotate and we cannot change this since 539 // that is where the GD/GreeType will rotate the text 540 541 542 // For smaller <14pt font we need to do some additional 543 // adjustments to make it look good 544 if( $this->font_size < 14 ) { 545 $x -= 2; 546 $y += 2; 547 } 548 else { 549 // $y += $baseline_offset; 550 } 551 552 if( $shadowcolor ) { 553 $this->PushColor($shadowcolor); 554 $this->FilledRectangle($x-$xmarg+$dropwidth,$y+$ymarg+$dropwidth-$height, 555 $x+$width+$dropwidth,$y+$ymarg+$dropwidth); 556 //$cornerradius); 557 $this->PopColor(); 558 $this->PushColor($fcolor); 559 $this->FilledRectangle($x-$xmarg, $y+$ymarg-$height, 560 $x+$width, $y+$ymarg); 561 //$cornerradius); 562 $this->PopColor(); 563 $this->PushColor($bcolor); 564 $this->Rectangle($x-$xmarg,$y+$ymarg-$height, 565 $x+$width,$y+$ymarg); 566 //$cornerradius); 567 $this->PopColor(); 568 } 569 else { 570 if( $fcolor ) { 571 $oc=$this->current_color; 572 $this->SetColor($fcolor); 573 $this->FilledRectangle($x-$xmarg,$y+$ymarg-$height,$x+$width,$y+$ymarg);//,$cornerradius); 574 $this->current_color=$oc; 575 } 576 if( $bcolor ) { 577 $oc=$this->current_color; 578 $this->SetColor($bcolor); 579 $this->Rectangle($x-$xmarg,$y+$ymarg-$height,$x+$width,$y+$ymarg);//,$cornerradius); 580 $this->current_color=$oc; 581 } 582 } 583 584 if( $this->font_size < 14 ) { 585 $x += 2; 586 $y -= 2; 587 } 588 else { 589 590 // Restore the original y before we stroke the text 591 // $y -= $baseline_offset; 592 593 } 594 595 $this->SetCenter(0,0); 596 $this->SetAngle($olda); 597 598 $h=$this->text_halign; 599 $v=$this->text_valign; 600 if( $this->text_halign == 'center') { 601 $this->SetTextAlign('center','basepoint'); 602 } 603 else { 604 $this->SetTextAlign('basepoint','basepoint'); 605 } 606 607 $debug=false; 608 $this->StrokeText($x, $y, $txt, $dir, $paragraph_align,$debug); 609 610 $bb = array($x-$xmarg, $y+$height-$ymarg, 611 $x+$width, $y+$height-$ymarg, 612 $x+$width, $y-$ymarg, 613 $x-$xmarg, $y-$ymarg); 614 615 $this->SetTextAlign($h,$v); 616 $this->SetAngle($olda); 617 618 $this->lastx = $oldx; 619 $this->lasty = $oldy; 620 621 return $bb; 622 } 623 624 // Set text alignment 625 function SetTextAlign($halign,$valign="bottom") { 626 $this->text_halign=$halign; 627 $this->text_valign=$valign; 628 } 629 630 function _StrokeBuiltinFont($x,$y,$txt,$dir,$paragraph_align,&$aBoundingBox,$aDebug=false) { 631 632 if( is_numeric($dir) && $dir!=90 && $dir!=0) 633 JpGraphError::RaiseL(25091);//(" Internal font does not support drawing text at arbitrary angle. Use TTF fonts instead."); 634 635 $h=$this->GetTextHeight($txt); 636 $fh=$this->GetFontHeight(); 637 $w=$this->GetTextWidth($txt); 638 639 if( $this->text_halign=="right") { 640 $x -= $dir==0 ? $w : $h; 641 } 642 elseif( $this->text_halign=="center" ) { 643 // For center we subtract 1 pixel since this makes the middle 644 // be prefectly in the middle 645 $x -= $dir==0 ? $w/2-1 : $h/2; 646 } 647 if( $this->text_valign=="top" ) { 648 $y += $dir==0 ? $h : $w; 649 } 650 elseif( $this->text_valign=="center" ) { 651 $y += $dir==0 ? $h/2 : $w/2; 652 } 653 654 $use_font = $this->font_family; 655 656 if( $dir==90 ) { 657 imagestringup($this->img,$use_font,$x,$y,$txt,$this->current_color); 658 $aBoundingBox = array(round($x),round($y),round($x),round($y-$w),round($x+$h),round($y-$w),round($x+$h),round($y)); 659 if( $aDebug ) { 660 // Draw bounding box 661 $this->PushColor('green'); 662 $this->Polygon($aBoundingBox,true); 663 $this->PopColor(); 664 } 665 } 666 else { 667 if( preg_match('/\n/',$txt) ) { 668 $tmp = preg_split('/\n/',$txt); 669 for($i=0; $i < count($tmp); ++$i) { 670 $w1 = $this->GetTextWidth($tmp[$i]); 671 if( $paragraph_align=="left" ) { 672 imagestring($this->img,$use_font,$x,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); 673 } 674 elseif( $paragraph_align=="right" ) { 675 imagestring($this->img,$use_font,$x+($w-$w1),$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); 676 } 677 else { 678 imagestring($this->img,$use_font,$x+$w/2-$w1/2,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); 679 } 680 } 681 } 682 else { 683 //Put the text 684 imagestring($this->img,$use_font,$x,$y-$h+1,$txt,$this->current_color); 685 } 686 if( $aDebug ) { 687 // Draw the bounding rectangle and the bounding box 688 $p1 = array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y)); 689 690 // Draw bounding box 691 $this->PushColor('green'); 692 $this->Polygon($p1,true); 693 $this->PopColor(); 694 695 } 696 $aBoundingBox=array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y)); 697 } 698 } 699 700 function AddTxtCR($aTxt) { 701 // If the user has just specified a '\n' 702 // instead of '\n\t' we have to add '\r' since 703 // the width will be too muchy otherwise since when 704 // we print we stroke the individually lines by hand. 705 $e = explode("\n",$aTxt); 706 $n = count($e); 707 for($i=0; $i<$n; ++$i) { 708 $e[$i]=str_replace("\r","",$e[$i]); 709 } 710 return implode("\n\r",$e); 711 } 712 713 function NormAngle($a) { 714 // Normalize angle in degrees 715 // Normalize angle to be between 0-360 716 while( $a > 360 ) 717 $a -= 360; 718 while( $a < -360 ) 719 $a += 360; 720 if( $a < 0 ) 721 $a = 360 + $a; 722 return $a; 723 } 724 725 function imagettfbbox_fixed($size, $angle, $fontfile, $text) { 726 727 728 if( ! USE_LIBRARY_IMAGETTFBBOX ) { 729 730 $bbox = @imagettfbbox($size, $angle, $fontfile, $text); 731 if( $bbox === false ) { 732 JpGraphError::RaiseL(25092,$this->font_file); 733 //("There is either a configuration problem with TrueType or a problem reading font file (".$this->font_file."). Make sure file exists and is in a readable place for the HTTP process. (If 'basedir' restriction is enabled in PHP then the font file must be located in the document root.). It might also be a wrongly installed FreeType library. Try uppgrading to at least FreeType 2.1.13 and recompile GD with the correct setup so it can find the new FT library."); 734 } 735 $this->bbox_cache = $bbox; 736 return $bbox; 737 } 738 739 // The built in imagettfbbox is buggy for angles != 0 so 740 // we calculate this manually by getting the bounding box at 741 // angle = 0 and then rotate the bounding box manually 742 $bbox = @imagettfbbox($size, 0, $fontfile, $text); 743 if( $bbox === false ) { 744 JpGraphError::RaiseL(25092,$this->font_file); 745 //("There is either a configuration problem with TrueType or a problem reading font file (".$this->font_file."). Make sure file exists and is in a readable place for the HTTP process. (If 'basedir' restriction is enabled in PHP then the font file must be located in the document root.). It might also be a wrongly installed FreeType library. Try uppgrading to at least FreeType 2.1.13 and recompile GD with the correct setup so it can find the new FT library."); 746 } 747 748 $angle = $this->NormAngle($angle); 749 750 $a = $angle*M_PI/180; 751 $ca = cos($a); 752 $sa = sin($a); 753 $ret = array(); 754 755 // We always add 1 pixel to the left since the left edge of the bounding 756 // box is sometimes coinciding with the first pixel of the text 757 //$bbox[0] -= 1; 758 //$bbox[6] -= 1; 759 760 // For roatated text we need to add extra width for rotated 761 // text since the kerning and stroking of the TTF is not the same as for 762 // text at a 0 degree angle 763 764 if( $angle > 0.001 && abs($angle-360) > 0.001 ) { 765 $h = abs($bbox[7]-$bbox[1]); 766 $w = abs($bbox[2]-$bbox[0]); 767 768 $bbox[0] -= 2; 769 $bbox[6] -= 2; 770 // The width is underestimated so compensate for that 771 $bbox[2] += round($w*0.06); 772 $bbox[4] += round($w*0.06); 773 774 // and we also need to compensate with increased height 775 $bbox[5] -= round($h*0.1); 776 $bbox[7] -= round($h*0.1); 777 778 if( $angle > 90 ) { 779 // For angles > 90 we also need to extend the height further down 780 // by the baseline since that is also one more problem 781 $bbox[1] += round($h*0.15); 782 $bbox[3] += round($h*0.15); 783 784 // and also make it slighty less height 785 $bbox[7] += round($h*0.05); 786 $bbox[5] += round($h*0.05); 787 788 // And we need to move the box slightly top the rright (from a tetx perspective) 789 $bbox[0] += round($w*0.02); 790 $bbox[6] += round($w*0.02); 791 792 if( $angle > 180 ) { 793 // And we need to move the box slightly to the left (from a text perspective) 794 $bbox[0] -= round($w*0.02); 795 $bbox[6] -= round($w*0.02); 796 $bbox[2] -= round($w*0.02); 797 $bbox[4] -= round($w*0.02); 798 799 } 800 801 } 802 for($i = 0; $i < 7; $i += 2) { 803 $ret[$i] = round($bbox[$i] * $ca + $bbox[$i+1] * $sa); 804 $ret[$i+1] = round($bbox[$i+1] * $ca - $bbox[$i] * $sa); 805 } 806 $this->bbox_cache = $ret; 807 return $ret; 808 } 809 else { 810 $this->bbox_cache = $bbox; 811 return $bbox; 812 } 813 } 814 815 // Deprecated 816 function GetTTFBBox($aTxt,$aAngle=0) { 817 $bbox = $this->imagettfbbox_fixed($this->font_size,$aAngle,$this->font_file,$aTxt); 818 return $bbox; 819 } 820 821 function GetBBoxTTF($aTxt,$aAngle=0) { 822 // Normalize the bounding box to become a minimum 823 // enscribing rectangle 824 825 $aTxt = $this->AddTxtCR($aTxt); 826 827 if( !is_readable($this->font_file) ) { 828 JpGraphError::RaiseL(25093,$this->font_file); 829 //('Can not read font file ('.$this->font_file.') in call to Image::GetBBoxTTF. Please make sure that you have set a font before calling this method and that the font is installed in the TTF directory.'); 830 } 831 $bbox = $this->imagettfbbox_fixed($this->font_size,$aAngle,$this->font_file,$aTxt); 832 833 if( $aAngle==0 ) return $bbox; 834 835 if( $aAngle >= 0 ) { 836 if( $aAngle <= 90 ) { //<=0 837 $bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1], 838 $bbox[2],$bbox[5],$bbox[6],$bbox[5]); 839 } 840 elseif( $aAngle <= 180 ) { //<= 2 841 $bbox = array($bbox[4],$bbox[7],$bbox[0],$bbox[7], 842 $bbox[0],$bbox[3],$bbox[4],$bbox[3]); 843 } 844 elseif( $aAngle <= 270 ) { //<= 3 845 $bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5], 846 $bbox[6],$bbox[1],$bbox[2],$bbox[1]); 847 } 848 else { 849 $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], 850 $bbox[4],$bbox[7],$bbox[0],$bbox[7]); 851 } 852 } 853 elseif( $aAngle < 0 ) { 854 if( $aAngle <= -270 ) { // <= -3 855 $bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1], 856 $bbox[2],$bbox[5],$bbox[6],$bbox[5]); 857 } 858 elseif( $aAngle <= -180 ) { // <= -2 859 $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], 860 $bbox[4],$bbox[7],$bbox[0],$bbox[7]); 861 } 862 elseif( $aAngle <= -90 ) { // <= -1 863 $bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5], 864 $bbox[6],$bbox[1],$bbox[2],$bbox[1]); 865 } 866 else { 867 $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], 868 $bbox[4],$bbox[7],$bbox[0],$bbox[7]); 869 } 870 } 871 return $bbox; 872 } 873 874 function GetBBoxHeight($aTxt,$aAngle=0) { 875 $box = $this->GetBBoxTTF($aTxt,$aAngle); 876 return abs($box[7]-$box[1]); 877 } 878 879 function GetBBoxWidth($aTxt,$aAngle=0) { 880 $box = $this->GetBBoxTTF($aTxt,$aAngle); 881 return $box[2]-$box[0]+1; 882 } 883 884 885 function _StrokeTTF($x,$y,$txt,$dir,$paragraph_align,&$aBoundingBox,$debug=false) { 886 887 // Setup default inter line margin for paragraphs to be 888 // 3% of the font height. 889 $ConstLineSpacing = 0.03 ; 890 891 // Remember the anchor point before adjustment 892 if( $debug ) { 893 $ox=$x; 894 $oy=$y; 895 } 896 897 if( !preg_match('/\n/',$txt) || ($dir>0 && preg_match('/\n/',$txt)) ) { 898 // Format a single line 899 900 $txt = $this->AddTxtCR($txt); 901 $bbox=$this->GetBBoxTTF($txt,$dir); 902 $width = $this->GetBBoxWidth($txt,$dir); 903 $height = $this->GetBBoxHeight($txt,$dir); 904 905 // The special alignment "basepoint" is mostly used internally 906 // in the library. This will put the anchor position at the left 907 // basepoint of the tetx. This is the default anchor point for 908 // TTF text. 909 910 if( $this->text_valign != 'basepoint' ) { 911 // Align x,y ot lower left corner of bbox 912 913 914 if( $this->text_halign=='right' ) { 915 $x -= $width; 916 $x -= $bbox[0]; 917 } 918 elseif( $this->text_halign=='center' ) { 919 $x -= $width/2; 920 $x -= $bbox[0]; 921 } 922 elseif( $this->text_halign=='baseline' ) { 923 // This is only support for text at 90 degree !! 924 // Do nothing the text is drawn at baseline by default 925 } 926 927 if( $this->text_valign=='top' ) { 928 $y -= $bbox[1]; // Adjust to bottom of text 929 $y += $height; 930 } 931 elseif( $this->text_valign=='center' ) { 932 $y -= $bbox[1]; // Adjust to bottom of text 933 $y += $height/2; 934 } 935 elseif( $this->text_valign=='baseline' ) { 936 // This is only support for text at 0 degree !! 937 // Do nothing the text is drawn at baseline by default 938 } 939 } 940 ImageTTFText ($this->img, $this->font_size, $dir, $x, $y, 941 $this->current_color,$this->font_file,$txt); 942 943 // Calculate and return the co-ordinates for the bounding box 944 $box = $this->imagettfbbox_fixed($this->font_size,$dir,$this->font_file,$txt); 945 $p1 = array(); 946 947 for($i=0; $i < 4; ++$i) { 948 $p1[] = round($box[$i*2]+$x); 949 $p1[] = round($box[$i*2+1]+$y); 950 } 951 $aBoundingBox = $p1; 952 953 // Debugging code to highlight the bonding box and bounding rectangle 954 // For text at 0 degrees the bounding box and bounding rectangle are the 955 // same 956 if( $debug ) { 957 // Draw the bounding rectangle and the bounding box 958 959 $p = array(); 960 $p1 = array(); 961 962 for($i=0; $i < 4; ++$i) { 963 $p[] = $bbox[$i*2]+$x ; 964 $p[] = $bbox[$i*2+1]+$y; 965 $p1[] = $box[$i*2]+$x ; 966 $p1[] = $box[$i*2+1]+$y ; 967 } 968 969 // Draw bounding box 970 $this->PushColor('green'); 971 $this->Polygon($p1,true); 972 $this->PopColor(); 973 974 // Draw bounding rectangle 975 $this->PushColor('darkgreen'); 976 $this->Polygon($p,true); 977 $this->PopColor(); 978 979 // Draw a cross at the anchor point 980 $this->PushColor('red'); 981 $this->Line($ox-15,$oy,$ox+15,$oy); 982 $this->Line($ox,$oy-15,$ox,$oy+15); 983 $this->PopColor(); 984 } 985 } 986 else { 987 // Format a text paragraph 988 $fh=$this->GetFontHeight(); 989 990 // Line margin is 25% of font height 991 $linemargin=round($fh*$ConstLineSpacing); 992 $fh += $linemargin; 993 $w=$this->GetTextWidth($txt); 994 995 $y -= $linemargin/2; 996 $tmp = preg_split('/\n/',$txt); 997 $nl = count($tmp); 998 $h = $nl * $fh; 999 1000 if( $this->text_halign=='right') { 1001 $x -= $dir==0 ? $w : $h; 1002 } 1003 elseif( $this->text_halign=='center' ) { 1004 $x -= $dir==0 ? $w/2 : $h/2; 1005 } 1006 1007 if( $this->text_valign=='top' ) { 1008 $y += $dir==0 ? $h : $w; 1009 } 1010 elseif( $this->text_valign=='center' ) { 1011 $y += $dir==0 ? $h/2 : $w/2; 1012 } 1013 1014 // Here comes a tricky bit. 1015 // Since we have to give the position for the string at the 1016 // baseline this means thaht text will move slightly up 1017 // and down depending on any of it's character descend below 1018 // the baseline, for example a 'g'. To adjust the Y-position 1019 // we therefore adjust the text with the baseline Y-offset 1020 // as used for the current font and size. This will keep the 1021 // baseline at a fixed positoned disregarding the actual 1022 // characters in the string. 1023 $standardbox = $this->GetTTFBBox('Gg',$dir); 1024 $yadj = $standardbox[1]; 1025 $xadj = $standardbox[0]; 1026 $aBoundingBox = array(); 1027 for($i=0; $i < $nl; ++$i) { 1028 $wl = $this->GetTextWidth($tmp[$i]); 1029 $bbox = $this->GetTTFBBox($tmp[$i],$dir); 1030 if( $paragraph_align=='left' ) { 1031 $xl = $x; 1032 } 1033 elseif( $paragraph_align=='right' ) { 1034 $xl = $x + ($w-$wl); 1035 } 1036 else { 1037 // Center 1038 $xl = $x + $w/2 - $wl/2 ; 1039 } 1040 1041 // In theory we should adjust with full pre-lead to get the lines 1042 // lined up but this doesn't look good so therfore we only adjust with 1043 // half th pre-lead 1044 $xl -= $bbox[0]/2; 1045 $yl = $y - $yadj; 1046 //$xl = $xl- $xadj; 1047 ImageTTFText($this->img, $this->font_size, $dir, $xl, $yl-($h-$fh)+$fh*$i, 1048 $this->current_color,$this->font_file,$tmp[$i]); 1049 1050 // echo "xl=$xl,".$tmp[$i]." <br>"; 1051 if( $debug ) { 1052 // Draw the bounding rectangle around each line 1053 $box=@ImageTTFBBox($this->font_size,$dir,$this->font_file,$tmp[$i]); 1054 $p = array(); 1055 for($j=0; $j < 4; ++$j) { 1056 $p[] = $bbox[$j*2]+$xl; 1057 $p[] = $bbox[$j*2+1]+$yl-($h-$fh)+$fh*$i; 1058 } 1059 1060 // Draw bounding rectangle 1061 $this->PushColor('darkgreen'); 1062 $this->Polygon($p,true); 1063 $this->PopColor(); 1064 } 1065 } 1066 1067 // Get the bounding box 1068 $bbox = $this->GetBBoxTTF($txt,$dir); 1069 for($j=0; $j < 4; ++$j) { 1070 $bbox[$j*2]+= round($x); 1071 $bbox[$j*2+1]+= round($y - ($h-$fh) - $yadj); 1072 } 1073 $aBoundingBox = $bbox; 1074 1075 if( $debug ) { 1076 // Draw a cross at the anchor point 1077 $this->PushColor('red'); 1078 $this->Line($ox-25,$oy,$ox+25,$oy); 1079 $this->Line($ox,$oy-25,$ox,$oy+25); 1080 $this->PopColor(); 1081 } 1082 1083 } 1084 } 1085 649 } 650 else { 651 // Format a text paragraph 652 $fh=$this->GetFontHeight(); 653 654 // Line margin is 25% of font height 655 $linemargin=round($fh*$ConstLineSpacing); 656 $fh += $linemargin; 657 $w=$this->GetTextWidth($txt); 658 659 $y -= $linemargin/2; 660 $tmp = split("\n",$txt); 661 $nl = count($tmp); 662 $h = $nl * $fh; 663 664 if( $this->text_halign=="right") 665 $x -= $dir==0 ? $w : $h; 666 elseif( $this->text_halign=="center" ) { 667 $x -= $dir==0 ? $w/2 : $h/2; 668 } 669 670 if( $this->text_valign=="top" ) 671 $y += $dir==0 ? $h : $w; 672 elseif( $this->text_valign=="center" ) 673 $y += $dir==0 ? $h/2 : $w/2; 674 675 // Here comes a tricky bit. 676 // Since we have to give the position for the string at the 677 // baseline this means thaht text will move slightly up 678 // and down depending on any of it's character descend below 679 // the baseline, for example a 'g'. To adjust the Y-position 680 // we therefore adjust the text with the baseline Y-offset 681 // as used for the current font and size. This will keep the 682 // baseline at a fixed positoned disregarding the actual 683 // characters in the string. 684 $standardbox = $this->GetTTFBBox('Gg',$dir); 685 $yadj = $standardbox[1]; 686 $xadj = $standardbox[0]; 687 $aBoundingBox = array(); 688 for($i=0; $i < $nl; ++$i) { 689 $wl = $this->GetTextWidth($tmp[$i]); 690 $bbox = $this->GetTTFBBox($tmp[$i],$dir); 691 if( $paragraph_align=="left" ) { 692 $xl = $x; 693 } 694 elseif( $paragraph_align=="right" ) { 695 $xl = $x + ($w-$wl); 696 } 697 else { 698 // Center 699 $xl = $x + $w/2 - $wl/2 ; 700 } 701 702 $xl -= $bbox[0]; 703 $yl = $y - $yadj; 704 $xl = $xl - $xadj; 705 ImageTTFText ($this->img, $this->font_size, $dir, 706 $xl, $yl-($h-$fh)+$fh*$i, 707 $this->current_color,$this->font_file,$tmp[$i]); 708 709 if( $debug ) { 710 // Draw the bounding rectangle around each line 711 $box=@ImageTTFBBox($this->font_size,$dir,$this->font_file,$tmp[$i]); 712 $p = array(); 713 for($j=0; $j < 4; ++$j) { 714 $p[] = $bbox[$j*2]+$xl; 715 $p[] = $bbox[$j*2+1]+$yl-($h-$fh)+$fh*$i; 716 } 717 718 // Draw bounding rectangle 719 $this->PushColor('darkgreen'); 720 $this->Polygon($p,true); 721 $this->PopColor(); 722 } 723 } 724 725 // Get the bounding box 726 $bbox = $this->GetBBoxTTF($txt,$dir); 727 for($j=0; $j < 4; ++$j) { 728 $bbox[$j*2]+= round($x); 729 $bbox[$j*2+1]+= round($y - ($h-$fh) - $yadj); 730 } 731 $aBoundingBox = $bbox; 732 733 if( $debug ) { 734 // Draw a cross at the anchor point 735 $this->PushColor('red'); 736 $this->Line($ox-25,$oy,$ox+25,$oy); 737 $this->Line($ox,$oy-25,$ox,$oy+25); 738 $this->PopColor(); 739 } 740 741 } 742 } 743 1086 744 function StrokeText($x,$y,$txt,$dir=0,$paragraph_align="left",$debug=false) { 1087 745 1088 $x = round($x); 1089 $y = round($y); 1090 1091 // Do special language encoding 1092 $txt = $this->langconv->Convert($txt,$this->font_family); 1093 1094 if( !is_numeric($dir) ) { 1095 JpGraphError::RaiseL(25094);//(" Direction for text most be given as an angle between 0 and 90."); 1096 } 1097 1098 if( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) { 1099 $this->_StrokeBuiltinFont($x,$y,$txt,$dir,$paragraph_align,$boundingbox,$debug); 1100 } 1101 elseif( $this->font_family >= _FIRST_FONT && $this->font_family <= _LAST_FONT) { 1102 $this->_StrokeTTF($x,$y,$txt,$dir,$paragraph_align,$boundingbox,$debug); 1103 } 1104 else { 1105 JpGraphError::RaiseL(25095);//(" Unknown font font family specification. "); 1106 } 1107 return $boundingbox; 1108 } 1109 746 $x = round($x); 747 $y = round($y); 748 749 // Do special language encoding 750 $txt = $this->langconv->Convert($txt,$this->font_family); 751 752 if( !is_numeric($dir) ) 753 JpGraphError::RaiseL(25094);//(" Direction for text most be given as an angle between 0 and 90."); 754 755 if( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) { 756 $this->_StrokeBuiltinFont($x,$y,$txt,$dir,$paragraph_align,$boundingbox,$debug); 757 } 758 elseif($this->font_family >= _FIRST_FONT && $this->font_family <= _LAST_FONT) { 759 $this->_StrokeTTF($x,$y,$txt,$dir,$paragraph_align,$boundingbox,$debug); 760 } 761 else 762 JpGraphError::RaiseL(25095);//(" Unknown font font family specification. "); 763 return $boundingbox; 764 } 765 1110 766 function SetMargin($lm,$rm,$tm,$bm) { 1111 1112 $this->left_margin=$lm; 1113 $this->right_margin=$rm; 1114 $this->top_margin=$tm; 1115 $this->bottom_margin=$bm; 1116 1117 $this->plotwidth = $this->width - $this->left_margin - $this->right_margin; 1118 $this->plotheight = $this->height - $this->top_margin - $this->bottom_margin; 1119 1120 if( $this->width > 0 && $this->height > 0 ) { 1121 if( $this->plotwidth < 0 || $this->plotheight < 0 ) { 1122 JpGraphError::RaiseL(25130, $this->plotwidth, $this->plotheight); 1123 //JpGraphError::raise("To small plot area. ($lm,$rm,$tm,$bm : $this->plotwidth x $this->plotheight). With the given image size and margins there is to little space left for the plot. Increase the plot size or reduce the margins."); 1124 } 1125 } 767 $this->left_margin=$lm; 768 $this->right_margin=$rm; 769 $this->top_margin=$tm; 770 $this->bottom_margin=$bm; 771 $this->plotwidth=$this->width - $this->left_margin-$this->right_margin ; 772 $this->plotheight=$this->height - $this->top_margin-$this->bottom_margin ; 773 if( $this->width > 0 && $this->height > 0 ) { 774 if( $this->plotwidth < 0 || $this->plotheight < 0 ) 775 JpGraphError::raise("To small plot area. ($lm,$rm,$tm,$bm : $this->plotwidth x $this->plotheight). With the given image size and margins there is to little space left for the plot. Increase the plot size or reduce the margins."); 776 } 1126 777 } 1127 778 1128 779 function SetTransparent($color) { 1129 1130 } 1131 780 imagecolortransparent ($this->img,$this->rgb->allocate($color)); 781 } 782 1132 783 function SetColor($color,$aAlpha=0) { 1133 1134 1135 1136 1137 1138 //("Can't allocate any more colors. Image has already allocated maximum of <b>$tc colors</b>. This might happen if you have anti-aliasing turned on together with a background image or perhaps gradient fill since this requires many, many colors. Try to turn off anti-aliasing. If there is still a problem try downgrading the quality of the background image to use a smaller pallete to leave some entries for your graphs. You should try to limit the number of colors in your background image to 64. If there is still problem set the constant DEFINE(\"USE_APPROX_COLORS\",true); in jpgraph.php This will use approximative colors when the palette is full. Unfortunately there is not much JpGraph can do about this since the palette size is a limitation of current graphic format and what the underlying GD library suppports."); 1139 1140 1141 } 1142 784 $this->current_color_name = $color; 785 $this->current_color=$this->rgb->allocate($color,$aAlpha); 786 if( $this->current_color == -1 ) { 787 $tc=imagecolorstotal($this->img); 788 JpGraphError::RaiseL(25096); 789 //("Can't allocate any more colors. Image has already allocated maximum of <b>$tc colors</b>. This might happen if you have anti-aliasing turned on together with a background image or perhaps gradient fill since this requires many, many colors. Try to turn off anti-aliasing. If there is still a problem try downgrading the quality of the background image to use a smaller pallete to leave some entries for your graphs. You should try to limit the number of colors in your background image to 64. If there is still problem set the constant DEFINE(\"USE_APPROX_COLORS\",true); in jpgraph.php This will use approximative colors when the palette is full. Unfortunately there is not much JpGraph can do about this since the palette size is a limitation of current graphic format and what the underlying GD library suppports."); 790 } 791 return $this->current_color; 792 } 793 1143 794 function PushColor($color) { 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 } 1154 795 if( $color != "" ) { 796 $this->colorstack[$this->colorstackidx]=$this->current_color_name; 797 $this->colorstack[$this->colorstackidx+1]=$this->current_color; 798 $this->colorstackidx+=2; 799 $this->SetColor($color); 800 } 801 else { 802 JpGraphError::RaiseL(25097);//("Color specified as empty string in PushColor()."); 803 } 804 } 805 1155 806 function PopColor() { 1156 if( $this->colorstackidx < 1 ) { 1157 JpGraphError::RaiseL(25098);//(" Negative Color stack index. Unmatched call to PopColor()"); 1158 } 1159 $this->current_color=$this->colorstack[--$this->colorstackidx]; 1160 $this->current_color_name=$this->colorstack[--$this->colorstackidx]; 1161 } 1162 1163 807 if($this->colorstackidx<1) 808 JpGraphError::RaiseL(25098);//(" Negative Color stack index. Unmatched call to PopColor()"); 809 $this->current_color=$this->colorstack[--$this->colorstackidx]; 810 $this->current_color_name=$this->colorstack[--$this->colorstackidx]; 811 } 812 813 1164 814 function SetLineWeight($weight) { 1165 $old = $this->line_weight; 1166 imagesetthickness($this->img,$weight); 1167 $this->line_weight = $weight; 1168 return $old; 1169 } 1170 815 imagesetthickness($this->img,$weight); 816 $this->line_weight = $weight; 817 } 818 1171 819 function SetStartPoint($x,$y) { 1172 1173 1174 } 1175 820 $this->lastx=round($x); 821 $this->lasty=round($y); 822 } 823 1176 824 function Arc($cx,$cy,$w,$h,$s,$e) { 1177 // GD Arc doesn't like negative angles 1178 while( $s < 0) $s += 360; 1179 while( $e < 0) $e += 360; 1180 imagearc($this->img,round($cx),round($cy),round($w),round($h),$s,$e,$this->current_color); 1181 } 1182 825 // GD Arc doesn't like negative angles 826 while( $s < 0) $s += 360; 827 while( $e < 0) $e += 360; 828 829 imagearc($this->img,round($cx),round($cy),round($w),round($h), 830 $s,$e,$this->current_color); 831 } 832 1183 833 function FilledArc($xc,$yc,$w,$h,$s,$e,$style='') { 1184 $s = round($s); 1185 $e = round($e); 1186 while( $s < 0 ) $s += 360; 1187 while( $e < 0 ) $e += 360; 1188 if( $style=='' ) 1189 $style=IMG_ARC_PIE; 1190 if( abs($s-$e) > 0 ) { 1191 imagefilledarc($this->img,round($xc),round($yc),round($w),round($h),$s,$e,$this->current_color,$style); 1192 // $this->DrawImageSmoothArc($this->img,round($xc),round($yc),round($w),round($h),$s,$e,$this->current_color,$style); 1193 } 834 while( $s < 0 ) $s += 360; 835 while( $e < 0 ) $e += 360; 836 if( $style=='' ) 837 $style=IMG_ARC_PIE; 838 if( abs($s-$e) > 0.001 ) { 839 imagefilledarc($this->img,round($xc),round($yc),round($w),round($h), 840 round($s),round($e),$this->current_color,$style); 841 } 1194 842 } 1195 843 1196 844 function FilledCakeSlice($cx,$cy,$w,$h,$s,$e) { 1197 845 $this->CakeSlice($cx,$cy,$w,$h,$s,$e,$this->current_color_name); 1198 846 } 1199 847 1200 848 function CakeSlice($xc,$yc,$w,$h,$s,$e,$fillcolor="",$arccolor="") { 1201 $s = round($s); $e = round($e); 1202 $w = round($w); $h = round($h); 1203 $xc = round($xc); $yc = round($yc); 1204 if( $s == $e ) { 1205 // A full circle. We draw this a plain circle 1206 $this->PushColor($fillcolor); 1207 imagefilledellipse($this->img,$xc,$yc,2*$w,2*$h,$this->current_color); 1208 1209 // If antialiasing is used then we often don't have any color no the surrounding 1210 // arc. So, we need to check for this special case so we don't send an empty 1211 // color to the push function. In this case we use the fill color for the arc as well 1212 if( $arccolor != '' ) { 1213 $this->PopColor(); 1214 $this->PushColor($arccolor); 1215 } 1216 imageellipse($this->img,$xc,$yc,2*$w,2*$h,$this->current_color); 1217 $this->Line($xc,$yc,cos($s*M_PI/180)*$w+$xc,$yc+sin($s*M_PI/180)*$h); 1218 $this->PopColor(); 1219 } 1220 else { 1221 $this->PushColor($fillcolor); 1222 $this->FilledArc($xc,$yc,2*$w,2*$h,$s,$e); 1223 $this->PopColor(); 1224 if( $arccolor != "" ) { 1225 $this->PushColor($arccolor); 1226 // We add 2 pixels to make the Arc() better aligned with 1227 // the filled arc. 1228 imagefilledarc($this->img,$xc,$yc,2*$w,2*$h,$s,$e,$this->current_color,IMG_ARC_NOFILL | IMG_ARC_EDGED ) ; 1229 $this->PopColor(); 1230 } 1231 } 849 $s = round($s); $e = round($e); 850 $w = round($w); $h = round($h); 851 $xc = round($xc); $yc = round($yc); 852 if( $s ==$e ) { 853 // A full circle. We draw this a plain circle 854 $this->PushColor($fillcolor); 855 imagefilledellipse($this->img,$xc,$yc,2*$w,2*$h,$this->current_color); 856 $this->PopColor(); 857 $this->PushColor($arccolor); 858 imageellipse($this->img,$xc,$yc,2*$w,2*$h,$this->current_color); 859 $this->Line($xc,$yc,cos($s*M_PI/180)*$w+$xc,$yc+sin($s*M_PI/180)*$h); 860 $this->PopColor(); 861 } 862 else { 863 $this->PushColor($fillcolor); 864 $this->FilledArc($xc,$yc,2*$w,2*$h,$s,$e); 865 $this->PopColor(); 866 if( $arccolor != "" ) { 867 $this->PushColor($arccolor); 868 // We add 2 pixels to make the Arc() better aligned with 869 // the filled arc. 870 imagefilledarc($this->img,$xc,$yc,2*$w,2*$h,$s,$e,$this->current_color,IMG_ARC_NOFILL | IMG_ARC_EDGED ) ; 871 $this->PopColor(); 872 } 873 } 1232 874 } 1233 875 1234 876 function Ellipse($xc,$yc,$w,$h) { 1235 1236 } 1237 877 $this->Arc($xc,$yc,$w,$h,0,360); 878 } 879 1238 880 function Circle($xc,$yc,$r) { 1239 imageellipse($this->img,round($xc),round($yc),$r*2,$r*2,$this->current_color); 1240 // $this->DrawImageSmoothArc($this->img,round($xc),round($yc),$r*2+1,$r*2+1,0,360,$this->current_color); 1241 // $this->imageSmoothCircle($this->img, round($xc),round($yc), $r*2+1, $this->current_color); 1242 } 1243 881 imageellipse($this->img,round($xc),round($yc),$r*2,$r*2,$this->current_color); 882 } 883 1244 884 function FilledCircle($xc,$yc,$r) { 1245 imagefilledellipse($this->img,round($xc),round($yc),2*$r,2*$r,$this->current_color); 1246 // $this->DrawImageSmoothArc($this->img, round($xc), round($yc), 2*$r, 2*$r, 0, 360, $this->current_color); 1247 } 1248 885 imagefilledellipse($this->img,round($xc),round($yc),2*$r,2*$r,$this->current_color); 886 } 887 1249 888 // Linear Color InterPolation 1250 889 function lip($f,$t,$p) { 1251 1252 1253 1254 1255 890 $p = round($p,1); 891 $r = $f[0] + ($t[0]-$f[0])*$p; 892 $g = $f[1] + ($t[1]-$f[1])*$p; 893 $b = $f[2] + ($t[2]-$f[2])*$p; 894 return array($r,$g,$b); 1256 895 } 1257 896 1258 897 // Set line style dashed, dotted etc 1259 898 function SetLineStyle($s) { 1260 if( is_numeric($s) ) { 1261 if( $s<1 || $s>4 ) { 1262 JpGraphError::RaiseL(25101,$s);//(" Illegal numeric argument to SetLineStyle(): ($s)"); 1263 } 1264 } 1265 elseif( is_string($s) ) { 1266 if( $s == "solid" ) $s=1; 1267 elseif( $s == "dotted" ) $s=2; 1268 elseif( $s == "dashed" ) $s=3; 1269 elseif( $s == "longdashed" ) $s=4; 1270 else { 1271 JpGraphError::RaiseL(25102,$s);//(" Illegal string argument to SetLineStyle(): $s"); 1272 } 1273 } 1274 else { 1275 JpGraphError::RaiseL(25103,$s);//(" Illegal argument to SetLineStyle $s"); 1276 } 1277 $old = $this->line_style; 1278 $this->line_style=$s; 1279 return $old; 1280 } 1281 899 if( is_numeric($s) ) { 900 if( $s<1 || $s>4 ) 901 JpGraphError::RaiseL(25101,$s);//(" Illegal numeric argument to SetLineStyle(): ($s)"); 902 } 903 elseif( is_string($s) ) { 904 if( $s == "solid" ) $s=1; 905 elseif( $s == "dotted" ) $s=2; 906 elseif( $s == "dashed" ) $s=3; 907 elseif( $s == "longdashed" ) $s=4; 908 else JpGraphError::RaiseL(25102,$s);//(" Illegal string argument to SetLineStyle(): $s"); 909 } 910 else { 911 JpGraphError::RaiseL(25103,$s);//(" Illegal argument to SetLineStyle $s"); 912 } 913 $old = $this->line_style; 914 $this->line_style=$s; 915 return $old; 916 } 917 1282 918 // Same as Line but take the line_style into account 1283 function StyleLine($x1,$y1,$x2,$y2,$aStyle='', $from_grid_class = false) { 1284 if( $this->line_weight <= 0 ) return; 1285 1286 if( $aStyle === '' ) { 1287 $aStyle = $this->line_style; 1288 } 1289 1290 $dashed_line_method = 'DashedLine'; 1291 if ($from_grid_class) { 1292 $dashed_line_method = 'DashedLineForGrid'; 1293 } 1294 1295 // Add error check since dashed line will only work if anti-alias is disabled 1296 // this is a limitation in GD 1297 1298 if( $aStyle == 1 ) { 1299 // Solid style. We can handle anti-aliasing for this 1300 $this->Line($x1,$y1,$x2,$y2); 1301 } 1302 else { 1303 // Since the GD routines doesn't handle AA for styled line 1304 // we have no option than to turn it off to get any lines at 1305 // all if the weight > 1 1306 $oldaa = $this->GetAntiAliasing(); 1307 if( $oldaa && $this->line_weight > 1 ) { 1308 $this->SetAntiAliasing(false); 1309 } 1310 1311 switch( $aStyle ) { 1312 case 2: // Dotted 1313 $this->$dashed_line_method($x1,$y1,$x2,$y2,2,6); 1314 break; 1315 case 3: // Dashed 1316 $this->$dashed_line_method($x1,$y1,$x2,$y2,5,9); 1317 break; 1318 case 4: // Longdashes 1319 $this->$dashed_line_method($x1,$y1,$x2,$y2,9,13); 1320 break; 1321 default: 1322 JpGraphError::RaiseL(25104,$this->line_style);//(" Unknown line style: $this->line_style "); 1323 break; 1324 } 1325 if( $oldaa ) { 1326 $this->SetAntiAliasing(true); 1327 } 1328 } 1329 } 1330 919 function StyleLine($x1,$y1,$x2,$y2,$aStyle='') { 920 if( $this->line_weight <= 0 ) 921 return; 922 923 if( $aStyle === '' ) { 924 $aStyle = $this->line_style; 925 } 926 927 // Add error check since dashed line will only work if anti-alias is disabled 928 // this is a limitation in GD 929 930 switch( $aStyle ) { 931 case 1:// Solid 932 $this->Line($x1,$y1,$x2,$y2); 933 break; 934 case 2: // Dotted 935 $this->DashedLine($x1,$y1,$x2,$y2,2,6); 936 break; 937 case 3: // Dashed 938 $this->DashedLine($x1,$y1,$x2,$y2,5,9); 939 break; 940 case 4: // Longdashes 941 $this->DashedLine($x1,$y1,$x2,$y2,9,13); 942 break; 943 default: 944 JpGraphError::RaiseL(25104,$this->line_style);//(" Unknown line style: $this->line_style "); 945 break; 946 } 947 } 948 1331 949 function DashedLine($x1,$y1,$x2,$y2,$dash_length=1,$dash_space=4) { 1332 950 1333 if( $this->line_weight <= 0 ) return; 1334 1335 // Add error check to make sure anti-alias is not enabled. 1336 // Dashed line does not work with anti-alias enabled. This 1337 // is a limitation in GD. 1338 if( $this->use_anti_aliasing ) { 1339 // JpGraphError::RaiseL(25129); // Anti-alias can not be used with dashed lines. Please disable anti-alias or use solid lines. 1340 } 1341 1342 $x1 = round($x1); 1343 $x2 = round($x2); 1344 $y1 = round($y1); 1345 $y2 = round($y2); 1346 1347 $dash_length *= SUPERSAMPLING_SCALE; 1348 $dash_space *= SUPERSAMPLING_SCALE; 1349 1350 $style = array_fill(0,$dash_length,$this->current_color); 1351 $style = array_pad($style,$dash_space,IMG_COLOR_TRANSPARENT); 1352 imagesetstyle($this->img, $style); 1353 imageline($this->img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); 1354 1355 $this->lastx = $x2; 1356 $this->lasty = $y2; 1357 } 1358 1359 function DashedLineForGrid($x1,$y1,$x2,$y2,$dash_length=1,$dash_space=4) { 1360 1361 if( $this->line_weight <= 0 ) return; 1362 1363 // Add error check to make sure anti-alias is not enabled. 1364 // Dashed line does not work with anti-alias enabled. This 1365 // is a limitation in GD. 1366 if( $this->use_anti_aliasing ) { 1367 // JpGraphError::RaiseL(25129); // Anti-alias can not be used with dashed lines. Please disable anti-alias or use solid lines. 1368 } 1369 1370 $x1 = round($x1); 1371 $x2 = round($x2); 1372 $y1 = round($y1); 1373 $y2 = round($y2); 1374 1375 /* 1376 $dash_length *= $this->scale; 1377 $dash_space *= $this->scale; 1378 */ 1379 1380 $dash_length = 2; 1381 $dash_length = 4; 1382 imagesetthickness($this->img, 1); 1383 $style = array_fill(0,$dash_length, $this->current_color); //hexdec('CCCCCC')); 1384 $style = array_pad($style,$dash_space,IMG_COLOR_TRANSPARENT); 1385 imagesetstyle($this->img, $style); 1386 imageline($this->img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); 1387 1388 $this->lastx = $x2; 1389 $this->lasty = $y2; 1390 } 951 if( $this->line_weight <= 0 ) 952 return; 953 954 // Add error check to make sure anti-alias is not enabled. 955 // Dashed line does not work with anti-alias enabled. This 956 // is a limitation in GD. 957 if( $this->use_anti_aliasing ) { 958 JpGraphError::RaiseL(25129); // Anti-alias can not be used with dashed lines. Please disable anti-alias or use solid lines. 959 } 960 961 962 $x1 = round($x1); 963 $x2 = round($x2); 964 $y1 = round($y1); 965 $y2 = round($y2); 966 967 $style = array_fill(0,$dash_length,$this->current_color); 968 $style = array_pad($style,$dash_space,IMG_COLOR_TRANSPARENT); 969 imagesetstyle($this->img, $style); 970 imageline($this->img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); 971 $this->lastx=$x2; $this->lasty=$y2; 972 } 1391 973 1392 974 function Line($x1,$y1,$x2,$y2) { 1393 975 1394 if( $this->line_weight <= 0 ) return; 1395 1396 $x1 = round($x1); 1397 $x2 = round($x2); 1398 $y1 = round($y1); 1399 $y2 = round($y2); 1400 1401 imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); 1402 // $this->DrawLine($this->img, $x1, $y1, $x2, $y2, $this->line_weight, $this->current_color); 1403 $this->lastx=$x2; 1404 $this->lasty=$y2; 976 if( $this->line_weight <= 0 ) 977 return; 978 979 $x1 = round($x1); 980 $x2 = round($x2); 981 $y1 = round($y1); 982 $y2 = round($y2); 983 984 imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); 985 $this->lastx=$x2; $this->lasty=$y2; 1405 986 } 1406 987 1407 988 function Polygon($p,$closed=FALSE,$fast=FALSE) { 1408 989 1409 if( $this->line_weight <= 0 ) return; 1410 1411 $n=count($p); 1412 $oldx = $p[0];1413 $oldy = $p[1];1414 if( $fast ) { 1415 for( $i=2; $i < $n; $i+=2) {1416 imageline($this->img,$oldx,$oldy,$p[$i],$p[$i+1],$this->current_color); 1417 $oldx = $p[$i];1418 $oldy = $p[$i+1];1419 } 1420 if( $closed ) { 1421 imageline($this->img,$p[$n*2-2],$p[$n*2-1],$p[0],$p[1],$this->current_color); 1422 } 1423 1424 else { 1425 for( $i=2; $i < $n; $i+=2 ){1426 $this->StyleLine($oldx,$oldy,$p[$i],$p[$i+1]); 1427 $oldx = $p[$i];1428 $oldy = $p[$i+1];1429 } 1430 if( $closed ) { 1431 $this->StyleLine($oldx,$oldy,$p[0],$p[1]); 1432 } 1433 1434 } 1435 990 if( $this->line_weight <= 0 ) 991 return; 992 993 $n=count($p); 994 $oldx = $p[0]; 995 $oldy = $p[1]; 996 if( $fast ) { 997 for( $i=2; $i < $n; $i+=2 ) { 998 imageline($this->img,$oldx,$oldy,$p[$i],$p[$i+1],$this->current_color); 999 $oldx = $p[$i]; 1000 $oldy = $p[$i+1]; 1001 } 1002 if( $closed ) { 1003 imageline($this->img,$p[$n*2-2],$p[$n*2-1],$p[0],$p[1],$this->current_color); 1004 } 1005 } 1006 else { 1007 for( $i=2; $i < $n; $i+=2 ) { 1008 $this->StyleLine($oldx,$oldy,$p[$i],$p[$i+1]); 1009 $oldx = $p[$i]; 1010 $oldy = $p[$i+1]; 1011 } 1012 if( $closed ) 1013 $this->StyleLine($oldx,$oldy,$p[0],$p[1]); 1014 } 1015 } 1016 1436 1017 function FilledPolygon($pts) { 1437 $n=count($pts); 1438 if( $n == 0 ) { 1439 JpGraphError::RaiseL(25105);//('NULL data specified for a filled polygon. Check that your data is not NULL.'); 1440 } 1441 for($i=0; $i < $n; ++$i) { 1442 $pts[$i] = round($pts[$i]); 1443 } 1444 $old = $this->line_weight; 1445 imagesetthickness($this->img,1); 1446 imagefilledpolygon($this->img,$pts,count($pts)/2,$this->current_color); 1447 $this->line_weight = $old; 1448 imagesetthickness($this->img,$old); 1449 } 1450 1018 $n=count($pts); 1019 if( $n == 0 ) { 1020 JpGraphError::RaiseL(25105);//('NULL data specified for a filled polygon. Check that your data is not NULL.'); 1021 } 1022 for($i=0; $i < $n; ++$i) 1023 $pts[$i] = round($pts[$i]); 1024 imagefilledpolygon($this->img,$pts,count($pts)/2,$this->current_color); 1025 } 1026 1451 1027 function Rectangle($xl,$yu,$xr,$yl) { 1452 1453 } 1454 1028 $this->Polygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl,$xl,$yu)); 1029 } 1030 1455 1031 function FilledRectangle($xl,$yu,$xr,$yl) { 1456 1032 $this->FilledPolygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl)); 1457 1033 } 1458 1034 1459 1035 function FilledRectangle2($xl,$yu,$xr,$yl,$color1,$color2,$style=1) { 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 } 1487 1488 function ShadowRectangle($xl,$yu,$xr,$yl,$fcolor=false,$shadow_width= 4,$shadow_color='darkgray',$useAlpha=true) {1489 1036 // Fill a rectangle with lines of two colors 1037 if( $style===1 ) { 1038 // Horizontal stripe 1039 if( $yl < $yu ) { 1040 $t = $yl; $yl=$yu; $yu=$t; 1041 } 1042 for( $y=$yu; $y <= $yl; ++$y) { 1043 $this->SetColor($color1); 1044 $this->Line($xl,$y,$xr,$y); 1045 ++$y; 1046 $this->SetColor($color2); 1047 $this->Line($xl,$y,$xr,$y); 1048 } 1049 } 1050 else { 1051 if( $xl < $xl ) { 1052 $t = $xl; $xl=$xr; $xr=$t; 1053 } 1054 for( $x=$xl; $x <= $xr; ++$x) { 1055 $this->SetColor($color1); 1056 $this->Line($x,$yu,$x,$yl); 1057 ++$x; 1058 $this->SetColor($color2); 1059 $this->Line($x,$yu,$x,$yl); 1060 } 1061 } 1062 } 1063 1064 function ShadowRectangle($xl,$yu,$xr,$yl,$fcolor=false,$shadow_width=3,$shadow_color=array(102,102,102)) { 1065 // This is complicated by the fact that we must also handle the case where 1490 1066 // the reactangle has no fill color 1491 $xl = floor($xl); 1492 $yu = floor($yu); 1493 $xr = floor($xr); 1494 $yl = floor($yl); 1495 $this->PushColor($shadow_color); 1496 $shadowAlpha=0; 1497 $this->SetLineWeight(1); 1498 $this->SetLineStyle('solid'); 1499 $basecolor = $this->rgb->Color($shadow_color); 1500 $shadow_color = array($basecolor[0],$basecolor[1],$basecolor[2],); 1501 for( $i=0; $i < $shadow_width; ++$i ) { 1502 $this->SetColor($shadow_color,$shadowAlpha); 1503 $this->Line($xr-$shadow_width+$i, $yu+$shadow_width, 1504 $xr-$shadow_width+$i, $yl-$shadow_width-1+$i); 1505 $this->Line($xl+$shadow_width, $yl-$shadow_width+$i, 1506 $xr-$shadow_width+$i, $yl-$shadow_width+$i); 1507 if( $useAlpha ) $shadowAlpha += 1.0/$shadow_width; 1508 } 1509 1510 $this->PopColor(); 1511 if( $fcolor==false ) { 1512 $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); 1513 } 1514 else { 1515 $this->PushColor($fcolor); 1516 $this->FilledRectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); 1517 $this->PopColor(); 1518 $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); 1519 } 1067 $this->PushColor($shadow_color); 1068 $this->FilledRectangle($xr-$shadow_width,$yu+$shadow_width,$xr,$yl-$shadow_width-1); 1069 $this->FilledRectangle($xl+$shadow_width,$yl-$shadow_width,$xr,$yl); 1070 //$this->FilledRectangle($xl+$shadow_width,$yu+$shadow_width,$xr,$yl); 1071 $this->PopColor(); 1072 if( $fcolor==false ) 1073 $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); 1074 else { 1075 $this->PushColor($fcolor); 1076 $this->FilledRectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); 1077 $this->PopColor(); 1078 $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); 1079 } 1520 1080 } 1521 1081 1522 1082 function FilledRoundedRectangle($xt,$yt,$xr,$yl,$r=5) { 1523 1524 1525 1526 1527 1528 1529 // when alphablending is enabled) we have no choice but 1530 1531 1532 1533 1534 1535 $this->FilledRectangle($xt+$r,$yt,$xr-$r,$yt+$r);1536 1537 $this->FilledRectangle($xt+$r,$yl-$r,$xr-$r,$yl);1538 1539 $this->FilledRectangle($xt,$yt+$r,$xt+$r,$yl-$r);1540 1541 $this->FilledRectangle($xr-$r,$yt+$r,$xr,$yl-$r);1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 } 1552 1553 function RoundedRectangle($xt,$yt,$xr,$yl,$r=5) { 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1083 if( $r==0 ) { 1084 $this->FilledRectangle($xt,$yt,$xr,$yl); 1085 return; 1086 } 1087 1088 // To avoid overlapping fillings (which will look strange 1089 // when alphablending is enabled) we have no choice but 1090 // to fill the five distinct areas one by one. 1091 1092 // Center square 1093 $this->FilledRectangle($xt+$r,$yt+$r,$xr-$r,$yl-$r); 1094 // Top band 1095 $this->FilledRectangle($xt+$r,$yt,$xr-$r,$yt+$r-1); 1096 // Bottom band 1097 $this->FilledRectangle($xt+$r,$yl-$r+1,$xr-$r,$yl); 1098 // Left band 1099 $this->FilledRectangle($xt,$yt+$r+1,$xt+$r-1,$yl-$r); 1100 // Right band 1101 $this->FilledRectangle($xr-$r+1,$yt+$r,$xr,$yl-$r); 1102 1103 // Topleft & Topright arc 1104 $this->FilledArc($xt+$r,$yt+$r,$r*2,$r*2,180,270); 1105 $this->FilledArc($xr-$r,$yt+$r,$r*2,$r*2,270,360); 1106 1107 // Bottomleft & Bottom right arc 1108 $this->FilledArc($xt+$r,$yl-$r,$r*2,$r*2,90,180); 1109 $this->FilledArc($xr-$r,$yl-$r,$r*2,$r*2,0,90); 1110 1111 } 1112 1113 function RoundedRectangle($xt,$yt,$xr,$yl,$r=5) { 1114 1115 if( $r==0 ) { 1116 $this->Rectangle($xt,$yt,$xr,$yl); 1117 return; 1118 } 1119 1120 // Top & Bottom line 1121 $this->Line($xt+$r,$yt,$xr-$r,$yt); 1122 $this->Line($xt+$r,$yl,$xr-$r,$yl); 1123 1124 // Left & Right line 1125 $this->Line($xt,$yt+$r,$xt,$yl-$r); 1126 $this->Line($xr,$yt+$r,$xr,$yl-$r); 1127 1128 // Topleft & Topright arc 1129 $this->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); 1130 $this->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); 1131 1132 // Bottomleft & Bottomright arc 1133 $this->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); 1134 $this->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); 1575 1135 } 1576 1136 1577 1137 function FilledBevel($x1,$y1,$x2,$y2,$depth=2,$color1='white@0.4',$color2='darkgray@0.4') { 1578 1579 1138 $this->FilledRectangle($x1,$y1,$x2,$y2); 1139 $this->Bevel($x1,$y1,$x2,$y2,$depth,$color1,$color2); 1580 1140 } 1581 1141 1582 1142 function Bevel($x1,$y1,$x2,$y2,$depth=2,$color1='white@0.4',$color2='black@0.5') { 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1143 $this->PushColor($color1); 1144 for( $i=0; $i < $depth; ++$i ) { 1145 $this->Line($x1+$i,$y1+$i,$x1+$i,$y2-$i); 1146 $this->Line($x1+$i,$y1+$i,$x2-$i,$y1+$i); 1147 } 1148 $this->PopColor(); 1149 1150 $this->PushColor($color2); 1151 for( $i=0; $i < $depth; ++$i ) { 1152 $this->Line($x1+$i,$y2-$i,$x2-$i,$y2-$i); 1153 $this->Line($x2-$i,$y1+$i,$x2-$i,$y2-$i-1); 1154 } 1155 $this->PopColor(); 1596 1156 } 1597 1157 1598 1158 function StyleLineTo($x,$y) { 1599 1600 1601 1602 } 1603 1159 $this->StyleLine($this->lastx,$this->lasty,$x,$y); 1160 $this->lastx=$x; 1161 $this->lasty=$y; 1162 } 1163 1604 1164 function LineTo($x,$y) { 1605 1606 1607 1608 } 1609 1165 $this->Line($this->lastx,$this->lasty,$x,$y); 1166 $this->lastx=$x; 1167 $this->lasty=$y; 1168 } 1169 1610 1170 function Point($x,$y) { 1611 1612 } 1613 1171 imagesetpixel($this->img,round($x),round($y),$this->current_color); 1172 } 1173 1614 1174 function Fill($x,$y) { 1615 1175 imagefill($this->img,round($x),round($y),$this->current_color); 1616 1176 } 1617 1177 1618 1178 function FillToBorder($x,$y,$aBordColor) { 1619 1620 1621 1622 1623 1179 $bc = $this->rgb->allocate($aBordColor); 1180 if( $bc == -1 ) { 1181 JpGraphError::RaiseL(25106);//('Image::FillToBorder : Can not allocate more colors'); 1182 } 1183 imagefilltoborder($this->img,round($x),round($y),$bc,$this->current_color); 1624 1184 } 1625 1185 1626 1186 function SetExpired($aFlg=true) { 1627 1628 } 1629 1187 $this->expired = $aFlg; 1188 } 1189 1630 1190 // Generate image header 1631 1191 function Headers() { 1632 1633 // In case we are running from the command line with the client version of 1634 // PHP we can't send any headers. 1635 $sapi = php_sapi_name(); 1636 if( $sapi == 'cli' ) return; 1637 1638 // These parameters are set by headers_sent() but they might cause 1639 // an undefined variable error unless they are initilized 1640 $file=''; 1641 $lineno=''; 1642 if( headers_sent($file,$lineno) ) { 1643 $file=basename($file); 1644 $t = new ErrMsgText(); 1645 $msg = $t->Get(10,$file,$lineno); 1646 die($msg); 1647 } 1648 1649 if ($this->expired) { 1650 header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); 1651 header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT"); 1652 header("Cache-Control: no-cache, must-revalidate"); 1653 header("Pragma: no-cache"); 1654 } 1655 header("Content-type: image/$this->img_format"); 1192 1193 // In case we are running from the command line with the client version of 1194 // PHP we can't send any headers. 1195 $sapi = php_sapi_name(); 1196 if( $sapi == 'cli' ) 1197 return; 1198 1199 // These parameters are set by headers_sent() but they might cause 1200 // an undefined variable error unless they are initilized 1201 $file=''; 1202 $lineno=''; 1203 if( headers_sent($file,$lineno) ) { 1204 $file=basename($file); 1205 $t = new ErrMsgText(); 1206 $msg = $t->Get(10,$file,$lineno); 1207 die($msg); 1208 } 1209 1210 if ($this->expired) { 1211 header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); 1212 header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT"); 1213 header("Cache-Control: no-cache, must-revalidate"); 1214 header("Pragma: no-cache"); 1215 } 1216 header("Content-type: image/$this->img_format"); 1656 1217 } 1657 1218 1658 1219 // Adjust image quality for formats that allow this 1659 1220 function SetQuality($q) { 1660 1661 } 1662 1221 $this->quality = $q; 1222 } 1223 1663 1224 // Stream image to browser or to file 1664 function Stream($aFile=NULL) { 1665 $this->DoSupersampling(); 1666 1667 $func="image".$this->img_format; 1668 if( $this->img_format=="jpeg" && $this->quality != null ) { 1669 $res = @$func($this->img,$aFile,$this->quality); 1670 1671 if(!$res){ 1672 if($aFile != NULL){ 1673 JpGraphError::RaiseL(25107,$aFile);//("Can't write to file '$aFile'. Check that the process running PHP has enough permission."); 1674 }else{ 1675 JpGraphError::RaiseL(25108);//("Can't stream image. This is most likely due to a faulty PHP/GD setup. Try to recompile PHP and use the built-in GD library that comes with PHP."); 1676 } 1225 function Stream($aFile="") { 1226 $func="image".$this->img_format; 1227 if( $this->img_format=="jpeg" && $this->quality != null ) { 1228 $res = @$func($this->img,$aFile,$this->quality); 1229 } 1230 else { 1231 if( $aFile != "" ) { 1232 $res = @$func($this->img,$aFile); 1233 if( !$res ) 1234 JpGraphError::RaiseL(25107,$aFile);//("Can't write to file '$aFile'. Check that the process running PHP has enough permission."); 1235 } 1236 else { 1237 $res = @$func($this->img); 1238 if( !$res ) 1239 JpGraphError::RaiseL(25108);//("Can't stream image. This is most likely due to a faulty PHP/GD setup. Try to recompile PHP and use the built-in GD library that comes with PHP."); 1677 1240 1678 } 1679 } 1680 else { 1681 if( $aFile != NULL ) { 1682 $res = @$func($this->img,$aFile); 1683 if( !$res ) { 1684 JpGraphError::RaiseL(25107,$aFile);//("Can't write to file '$aFile'. Check that the process running PHP has enough permission."); 1685 } 1686 } 1687 else { 1688 $res = @$func($this->img); 1689 if( !$res ) { 1690 JpGraphError::RaiseL(25108);//("Can't stream image. This is most likely due to a faulty PHP/GD setup. Try to recompile PHP and use the built-in GD library that comes with PHP."); 1691 } 1692 1693 } 1694 } 1695 } 1696 1697 // Do SuperSampling using $scale 1698 function DoSupersampling() { 1699 if (SUPERSAMPLING_SCALE <= 1) { 1700 return $this->img; 1701 } 1702 1703 $dst_img = @imagecreatetruecolor($this->original_width, $this->original_height); 1704 imagecopyresampled($dst_img, $this->img, 0, 0, 0, 0, $this->original_width, $this->original_height, $this->width, $this->height); 1705 $this->Destroy(); 1706 return $this->img = $dst_img; 1707 } 1708 1709 // Clear resources used by image (this is normally not used since all resources are/should be 1710 // returned when the script terminates 1241 } 1242 } 1243 } 1244 1245 // Clear resource tide up by image 1711 1246 function Destroy() { 1712 1713 } 1714 1247 imagedestroy($this->img); 1248 } 1249 1715 1250 // Specify image format. Note depending on your installation 1716 1251 // of PHP not all formats may be supported. 1717 function SetImgFormat($aFormat,$aQuality=75) { 1718 $this->quality = $aQuality; 1719 $aFormat = strtolower($aFormat); 1720 $tst = true; 1721 $supported = imagetypes(); 1722 if( $aFormat=="auto" ) { 1723 if( $supported & IMG_PNG ) $this->img_format="png"; 1724 elseif( $supported & IMG_JPG ) $this->img_format="jpeg"; 1725 elseif( $supported & IMG_GIF ) $this->img_format="gif"; 1726 elseif( $supported & IMG_WBMP ) $this->img_format="wbmp"; 1727 elseif( $supported & IMG_XPM ) $this->img_format="xpm"; 1728 else { 1729 JpGraphError::RaiseL(25109);//("Your PHP (and GD-lib) installation does not appear to support any known graphic formats. You need to first make sure GD is compiled as a module to PHP. If you also want to use JPEG images you must get the JPEG library. Please see the PHP docs for details."); 1730 } 1731 return true; 1732 } 1733 else { 1734 if( $aFormat=="jpeg" || $aFormat=="png" || $aFormat=="gif" ) { 1735 if( $aFormat=="jpeg" && !($supported & IMG_JPG) ) $tst=false; 1736 elseif( $aFormat=="png" && !($supported & IMG_PNG) ) $tst=false; 1737 elseif( $aFormat=="gif" && !($supported & IMG_GIF) ) $tst=false; 1738 elseif( $aFormat=="wbmp" && !($supported & IMG_WBMP) ) $tst=false; 1739 elseif( $aFormat=="xpm" && !($supported & IMG_XPM) ) $tst=false; 1740 else { 1741 $this->img_format=$aFormat; 1742 return true; 1743 } 1744 } 1745 else { 1746 $tst=false; 1747 } 1748 if( !$tst ) { 1749 JpGraphError::RaiseL(25110,$aFormat);//(" Your PHP installation does not support the chosen graphic format: $aFormat"); 1750 } 1751 } 1752 } 1753 1754 /** 1755 * Draw Line 1756 */ 1757 function DrawLine($im, $x1, $y1, $x2, $y2, $weight, $color) { 1758 if ($weight == 1) { 1759 return imageline($im,$x1,$y1,$x2,$y2,$color); 1760 } 1761 1762 $angle=(atan2(($y1 - $y2), ($x2 - $x1))); 1763 1764 $dist_x = $weight * (sin($angle)) / 2; 1765 $dist_y = $weight * (cos($angle)) / 2; 1766 1767 $p1x=ceil(($x1 + $dist_x)); 1768 $p1y=ceil(($y1 + $dist_y)); 1769 $p2x=ceil(($x2 + $dist_x)); 1770 $p2y=ceil(($y2 + $dist_y)); 1771 $p3x=ceil(($x2 - $dist_x)); 1772 $p3y=ceil(($y2 - $dist_y)); 1773 $p4x=ceil(($x1 - $dist_x)); 1774 $p4y=ceil(($y1 - $dist_y)); 1775 1776 $array=array($p1x,$p1y,$p2x,$p2y,$p3x,$p3y,$p4x,$p4y); 1777 imagefilledpolygon ( $im, $array, (count($array)/2), $color ); 1778 1779 // for antialias 1780 imageline($im, $p1x, $p1y, $p2x, $p2y, $color); 1781 imageline($im, $p3x, $p3y, $p4x, $p4y, $color); 1782 return; 1783 1784 1785 1786 return imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); 1787 $weight = 8; 1788 if ($weight <= 1) { 1789 return imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); 1790 } 1791 1792 $pts = array(); 1793 1794 $weight /= 2; 1795 1796 if ($y2 - $y1 == 0) { 1797 // x line 1798 $pts = array(); 1799 $pts[] = $x1; $pts[] = $y1 - $weight; 1800 $pts[] = $x1; $pts[] = $y1 + $weight; 1801 $pts[] = $x2; $pts[] = $y2 + $weight; 1802 $pts[] = $x2; $pts[] = $y2 - $weight; 1803 1804 } elseif ($x2 - $x1 == 0) { 1805 // y line 1806 $pts = array(); 1807 $pts[] = $x1 - $weight; $pts[] = $y1; 1808 $pts[] = $x1 + $weight; $pts[] = $y1; 1809 $pts[] = $x2 + $weight; $pts[] = $y2; 1810 $pts[] = $x2 - $weight; $pts[] = $y2; 1811 1812 } else { 1813 1814 var_dump($x1, $x2, $y1, $y2); 1815 $length = sqrt(pow($x2 - $x1, 2) + pow($y2 - $y1, 2)); 1816 var_dump($length);exit; 1817 exit; 1818 1819 /* 1820 $lean = ($y2 - $y1) / ($x2 - $x1); 1821 $lean2 = -1 / $lean; 1822 $sin = $lean / ($y2 - $y1); 1823 $cos = $lean / ($x2 - $x1); 1824 1825 $pts[] = $x1 + (-$weight * $sin); $pts[] = $y1 + (-$weight * $cos); 1826 $pts[] = $x1 + (+$weight * $sin); $pts[] = $y1 + (+$weight * $cos); 1827 $pts[] = $x2 + (+$weight * $sin); $pts[] = $y2 + (+$weight * $cos); 1828 $pts[] = $x2 + (-$weight * $sin); $pts[] = $y2 + (-$weight * $cos); 1829 */ 1830 } 1831 1832 //print_r($pts);exit; 1833 if (count($pts)/2 < 3) { 1834 return; 1835 } 1836 1837 imagesetthickness($im, 1); 1838 imagefilledpolygon($im, $pts,count($pts)/2, $color); 1839 1840 1841 $weight *= 2; 1842 1843 // $this->DrawImageSmoothArc($im, $x1, $y1, $weight, $weight, 0, 360, $color); 1844 // $this->DrawImageSmoothArc($im, $x2, $y2, $weight, $weight, 0, 360, $color); 1845 } 1846 1847 1848 function DrawImageSmoothArc($im, $xc, $yc, $w, $h, $s, $e, $color, $style = null) { 1849 $tmp = $s; 1850 $s = (360 - $e) / 180 * M_PI; 1851 $e = (360 - $tmp) / 180 * M_PI; 1852 return imageSmoothArc($im, round($xc), round($yc), round($w), round($h), $this->CreateColorForImageSmoothArc($color), $s, $e); 1853 } 1854 1855 function CreateColorForImageSmoothArc($color) { 1856 $alpha = $color >> 24 & 0xFF; 1857 $red = $color >> 16 & 0xFF; 1858 $green = $color >> 8 & 0xFF; 1859 $blue = $color & 0xFF; 1860 1861 //var_dump($alpha, $red, $green, $blue);exit; 1862 1863 return array($red, $green, $blue, $alpha); 1864 } 1865 1866 function imageSmoothCircle( &$img, $cx, $cy, $cr, $color ) { 1867 $ir = $cr; 1868 $ix = 0; 1869 $iy = $ir; 1870 $ig = 2 * $ir - 3; 1871 $idgr = -6; 1872 $idgd = 4 * $ir - 10; 1873 $fill = imageColorExactAlpha( $img, $color[ 'R' ], $color[ 'G' ], $color[ 'B' ], 0 ); 1874 imageLine( $img, $cx + $cr - 1, $cy, $cx, $cy, $fill ); 1875 imageLine( $img, $cx - $cr + 1, $cy, $cx - 1, $cy, $fill ); 1876 imageLine( $img, $cx, $cy + $cr - 1, $cx, $cy + 1, $fill ); 1877 imageLine( $img, $cx, $cy - $cr + 1, $cx, $cy - 1, $fill ); 1878 $draw = imageColorExactAlpha( $img, $color[ 'R' ], $color[ 'G' ], $color[ 'B' ], 42 ); 1879 imageSetPixel( $img, $cx + $cr, $cy, $draw ); 1880 imageSetPixel( $img, $cx - $cr, $cy, $draw ); 1881 imageSetPixel( $img, $cx, $cy + $cr, $draw ); 1882 imageSetPixel( $img, $cx, $cy - $cr, $draw ); 1883 while ( $ix <= $iy - 2 ) { 1884 if ( $ig < 0 ) { 1885 $ig += $idgd; 1886 $idgd -= 8; 1887 $iy--; 1888 } else { 1889 $ig += $idgr; 1890 $idgd -= 4; 1891 } 1892 $idgr -= 4; 1893 $ix++; 1894 imageLine( $img, $cx + $ix, $cy + $iy - 1, $cx + $ix, $cy + $ix, $fill ); 1895 imageLine( $img, $cx + $ix, $cy - $iy + 1, $cx + $ix, $cy - $ix, $fill ); 1896 imageLine( $img, $cx - $ix, $cy + $iy - 1, $cx - $ix, $cy + $ix, $fill ); 1897 imageLine( $img, $cx - $ix, $cy - $iy + 1, $cx - $ix, $cy - $ix, $fill ); 1898 imageLine( $img, $cx + $iy - 1, $cy + $ix, $cx + $ix, $cy + $ix, $fill ); 1899 imageLine( $img, $cx + $iy - 1, $cy - $ix, $cx + $ix, $cy - $ix, $fill ); 1900 imageLine( $img, $cx - $iy + 1, $cy + $ix, $cx - $ix, $cy + $ix, $fill ); 1901 imageLine( $img, $cx - $iy + 1, $cy - $ix, $cx - $ix, $cy - $ix, $fill ); 1902 $filled = 0; 1903 for ( $xx = $ix - 0.45; $xx < $ix + 0.5; $xx += 0.2 ) { 1904 for ( $yy = $iy - 0.45; $yy < $iy + 0.5; $yy += 0.2 ) { 1905 if ( sqrt( pow( $xx, 2 ) + pow( $yy, 2 ) ) < $cr ) $filled += 4; 1906 } 1907 } 1908 $draw = imageColorExactAlpha( $img, $color[ 'R' ], $color[ 'G' ], $color[ 'B' ], ( 100 - $filled ) ); 1909 imageSetPixel( $img, $cx + $ix, $cy + $iy, $draw ); 1910 imageSetPixel( $img, $cx + $ix, $cy - $iy, $draw ); 1911 imageSetPixel( $img, $cx - $ix, $cy + $iy, $draw ); 1912 imageSetPixel( $img, $cx - $ix, $cy - $iy, $draw ); 1913 imageSetPixel( $img, $cx + $iy, $cy + $ix, $draw ); 1914 imageSetPixel( $img, $cx + $iy, $cy - $ix, $draw ); 1915 imageSetPixel( $img, $cx - $iy, $cy + $ix, $draw ); 1916 imageSetPixel( $img, $cx - $iy, $cy - $ix, $draw ); 1917 } 1918 } 1919 1920 function __get($name) { 1921 1922 if (strpos($name, 'raw_') !== false) { 1923 // if $name == 'raw_left_margin' , return $this->_left_margin; 1924 $variable_name = '_' . str_replace('raw_', '', $name); 1925 return $this->$variable_name; 1926 } 1927 1928 $variable_name = '_' . $name; 1929 1930 if (isset($this->$variable_name)) { 1931 return $this->$variable_name * SUPERSAMPLING_SCALE; 1932 } else { 1933 JpGraphError::RaiseL('25132', $name); 1934 } 1935 } 1936 1937 function __set($name, $value) { 1938 $this->{'_'.$name} = $value; 1939 } 1940 1252 function SetImgFormat($aFormat,$aQuality=75) { 1253 $this->quality = $aQuality; 1254 $aFormat = strtolower($aFormat); 1255 $tst = true; 1256 $supported = imagetypes(); 1257 if( $aFormat=="auto" ) { 1258 if( $supported & IMG_PNG ) 1259 $this->img_format="png"; 1260 elseif( $supported & IMG_JPG ) 1261 $this->img_format="jpeg"; 1262 elseif( $supported & IMG_GIF ) 1263 $this->img_format="gif"; 1264 elseif( $supported & IMG_WBMP ) 1265 $this->img_format="wbmp"; 1266 elseif( $supported & IMG_XPM ) 1267 $this->img_format="xpm"; 1268 else 1269 JpGraphError::RaiseL(25109);//("Your PHP (and GD-lib) installation does not appear to support any known graphic formats. You need to first make sure GD is compiled as a module to PHP. If you also want to use JPEG images you must get the JPEG library. Please see the PHP docs for details."); 1270 1271 return true; 1272 } 1273 else { 1274 if( $aFormat=="jpeg" || $aFormat=="png" || $aFormat=="gif" ) { 1275 if( $aFormat=="jpeg" && !($supported & IMG_JPG) ) 1276 $tst=false; 1277 elseif( $aFormat=="png" && !($supported & IMG_PNG) ) 1278 $tst=false; 1279 elseif( $aFormat=="gif" && !($supported & IMG_GIF) ) 1280 $tst=false; 1281 elseif( $aFormat=="wbmp" && !($supported & IMG_WBMP) ) 1282 $tst=false; 1283 elseif( $aFormat=="xpm" && !($supported & IMG_XPM) ) 1284 $tst=false; 1285 else { 1286 $this->img_format=$aFormat; 1287 return true; 1288 } 1289 } 1290 else 1291 $tst=false; 1292 if( !$tst ) 1293 JpGraphError::RaiseL(25110,$aFormat);//(" Your PHP installation does not support the chosen graphic format: $aFormat"); 1294 } 1295 } 1941 1296 } // CLASS 1942 1297 … … 1948 1303 class RotImage extends Image { 1949 1304 public $a=0; 1950 public $dx=0,$dy=0,$transx=0,$transy=0; 1305 public $dx=0,$dy=0,$transx=0,$transy=0; 1951 1306 private $m=array(); 1952 1953 function __construct($aWidth,$aHeight,$a=0,$aFormat=DEFAULT_GFORMAT,$aSetAutoMargin=true) {1954 parent::__construct($aWidth,$aHeight,$aFormat,$aSetAutoMargin);1955 $this->dx=$this->width/2;1956 $this->dy=$this->height/2;1957 $this->SetAngle($a); 1958 } 1959 1307 1308 function RotImage($aWidth,$aHeight,$a=0,$aFormat=DEFAULT_GFORMAT,$aSetAutoMargin=true) { 1309 $this->Image($aWidth,$aHeight,$aFormat,$aSetAutoMargin); 1310 $this->dx=$this->left_margin+$this->plotwidth/2; 1311 $this->dy=$this->top_margin+$this->plotheight/2; 1312 $this->SetAngle($a); 1313 } 1314 1960 1315 function SetCenter($dx,$dy) { 1961 1962 1963 1964 1965 1966 1967 } 1968 1316 $old_dx = $this->dx; 1317 $old_dy = $this->dy; 1318 $this->dx=$dx; 1319 $this->dy=$dy; 1320 $this->SetAngle($this->a); 1321 return array($old_dx,$old_dy); 1322 } 1323 1969 1324 function SetTranslation($dx,$dy) { 1970 1971 1972 1973 1325 $old = array($this->transx,$this->transy); 1326 $this->transx = $dx; 1327 $this->transy = $dy; 1328 return $old; 1974 1329 } 1975 1330 1976 1331 function UpdateRotMatrice() { 1977 1978 1979 $sa=sin($a); $ca=cos($a); 1980 1981 1982 1983 1984 1985 1986 1332 $a = $this->a; 1333 $a *= M_PI/180; 1334 $sa=sin($a); $ca=cos($a); 1335 // Create the rotation matrix 1336 $this->m[0][0] = $ca; 1337 $this->m[0][1] = -$sa; 1338 $this->m[0][2] = $this->dx*(1-$ca) + $sa*$this->dy ; 1339 $this->m[1][0] = $sa; 1340 $this->m[1][1] = $ca; 1341 $this->m[1][2] = $this->dy*(1-$ca) - $sa*$this->dx ; 1987 1342 } 1988 1343 1989 1344 function SetAngle($a) { 1990 1991 1992 1993 1345 $tmp = $this->a; 1346 $this->a = $a; 1347 $this->UpdateRotMatrice(); 1348 return $tmp; 1994 1349 } 1995 1350 1996 1351 function Circle($xc,$yc,$r) { 1997 1998 1352 list($xc,$yc) = $this->Rotate($xc,$yc); 1353 parent::Circle($xc,$yc,$r); 1999 1354 } 2000 1355 2001 1356 function FilledCircle($xc,$yc,$r) { 2002 2003 2004 } 2005 2006 1357 list($xc,$yc) = $this->Rotate($xc,$yc); 1358 parent::FilledCircle($xc,$yc,$r); 1359 } 1360 1361 2007 1362 function Arc($xc,$yc,$w,$h,$s,$e) { 2008 2009 2010 2011 1363 list($xc,$yc) = $this->Rotate($xc,$yc); 1364 $s += $this->a; 1365 $e += $this->a; 1366 parent::Arc($xc,$yc,$w,$h,$s,$e); 2012 1367 } 2013 1368 2014 1369 function FilledArc($xc,$yc,$w,$h,$s,$e,$style='') { 2015 2016 2017 2018 1370 list($xc,$yc) = $this->Rotate($xc,$yc); 1371 $s += $this->a; 1372 $e += $this->a; 1373 parent::FilledArc($xc,$yc,$w,$h,$s,$e); 2019 1374 } 2020 1375 2021 1376 function SetMargin($lm,$rm,$tm,$bm) { 2022 parent::SetMargin($lm,$rm,$tm,$bm); 2023 $this->UpdateRotMatrice(); 2024 } 2025 1377 parent::SetMargin($lm,$rm,$tm,$bm); 1378 $this->dx=$this->left_margin+$this->plotwidth/2; 1379 $this->dy=$this->top_margin+$this->plotheight/2; 1380 $this->UpdateRotMatrice(); 1381 } 1382 2026 1383 function Rotate($x,$y) { 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 } 2037 1384 // Optimization. Ignore rotation if Angle==0 || Angle==360 1385 if( $this->a == 0 || $this->a == 360 ) { 1386 return array($x + $this->transx, $y + $this->transy ); 1387 } 1388 else { 1389 $x1=round($this->m[0][0]*$x + $this->m[0][1]*$y,1) + $this->m[0][2] + $this->transx; 1390 $y1=round($this->m[1][0]*$x + $this->m[1][1]*$y,1) + $this->m[1][2] + $this->transy; 1391 return array($x1,$y1); 1392 } 1393 } 1394 2038 1395 function CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1,$aMix=100) { 2039 2040 1396 list($toX,$toY) = $this->Rotate($toX,$toY); 1397 parent::CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight,$aMix); 2041 1398 2042 1399 } 2043 1400 2044 1401 function ArrRotate($pnts) { 2045 2046 2047 2048 2049 2050 1402 $n = count($pnts)-1; 1403 for($i=0; $i < $n; $i+=2) { 1404 list ($x,$y) = $this->Rotate($pnts[$i],$pnts[$i+1]); 1405 $pnts[$i] = $x; $pnts[$i+1] = $y; 1406 } 1407 return $pnts; 2051 1408 } 2052 1409 2053 1410 function DashedLine($x1,$y1,$x2,$y2,$dash_length=1,$dash_space=4) { 2054 2055 2056 2057 } 2058 1411 list($x1,$y1) = $this->Rotate($x1,$y1); 1412 list($x2,$y2) = $this->Rotate($x2,$y2); 1413 parent::DashedLine($x1,$y1,$x2,$y2,$dash_length,$dash_space); 1414 } 1415 2059 1416 function Line($x1,$y1,$x2,$y2) { 2060 2061 2062 1417 list($x1,$y1) = $this->Rotate($x1,$y1); 1418 list($x2,$y2) = $this->Rotate($x2,$y2); 1419 parent::Line($x1,$y1,$x2,$y2); 2063 1420 } 2064 1421 2065 1422 function Rectangle($x1,$y1,$x2,$y2) { 2066 2067 2068 } 2069 1423 // Rectangle uses Line() so it will be rotated through that call 1424 parent::Rectangle($x1,$y1,$x2,$y2); 1425 } 1426 2070 1427 function FilledRectangle($x1,$y1,$x2,$y2) { 2071 2072 2073 else 2074 2075 } 2076 1428 if( $y1==$y2 || $x1==$x2 ) 1429 $this->Line($x1,$y1,$x2,$y2); 1430 else 1431 $this->FilledPolygon(array($x1,$y1,$x2,$y1,$x2,$y2,$x1,$y2)); 1432 } 1433 2077 1434 function Polygon($pnts,$closed=FALSE,$fast=FALSE) { 2078 // Polygon uses Line() so it will be rotated through that call unless 2079 // fast drawing routines are used in which case a rotate is needed 2080 if( $fast ) { 2081 parent::Polygon($this->ArrRotate($pnts)); 2082 } 2083 else { 2084 parent::Polygon($pnts,$closed,$fast); 2085 } 2086 } 2087 1435 // Polygon uses Line() so it will be rotated through that call unless 1436 // fast drawing routines are used in which case a rotate is needed 1437 if( $fast ) { 1438 parent::Polygon($this->ArrRotate($pnts)); 1439 } 1440 else 1441 parent::Polygon($pnts,$closed,$fast); 1442 } 1443 2088 1444 function FilledPolygon($pnts) { 2089 2090 } 2091 1445 parent::FilledPolygon($this->ArrRotate($pnts)); 1446 } 1447 2092 1448 function Point($x,$y) { 2093 2094 2095 } 2096 1449 list($xp,$yp) = $this->Rotate($x,$y); 1450 parent::Point($xp,$yp); 1451 } 1452 2097 1453 function StrokeText($x,$y,$txt,$dir=0,$paragraph_align="left",$debug=false) { 2098 2099 1454 list($xp,$yp) = $this->Rotate($x,$y); 1455 return parent::StrokeText($xp,$yp,$txt,$dir,$paragraph_align,$debug); 2100 1456 } 2101 1457 } 2102 1458 2103 //=================================================== ====================1459 //=================================================== 2104 1460 // CLASS ImgStreamCache 2105 // Description: Handle caching of graphs to files. All image output goes 2106 // through this class 2107 //======================================================================= 1461 // Description: Handle caching of graphs to files 1462 //=================================================== 2108 1463 class ImgStreamCache { 2109 private $cache_dir, $ timeout=0;// Infinite timeout1464 private $cache_dir, $img=null, $timeout=0; // Infinite timeout 2110 1465 //--------------- 2111 1466 // CONSTRUCTOR 2112 function __construct($aCacheDir=CACHE_DIR) { 2113 $this->cache_dir = $aCacheDir; 2114 } 2115 2116 //--------------- 2117 // PUBLIC METHODS 1467 function ImgStreamCache($aImg, $aCacheDir=CACHE_DIR) { 1468 $this->img = $aImg; 1469 $this->cache_dir = $aCacheDir; 1470 } 1471 1472 //--------------- 1473 // PUBLIC METHODS 2118 1474 2119 1475 // Specify a timeout (in minutes) for the file. If the file is older then the … … 2122 1478 // timeout is set to -1 this is the same as infinite small timeout 2123 1479 function SetTimeout($aTimeout) { 2124 $this->timeout=$aTimeout; 2125 } 2126 1480 $this->timeout=$aTimeout; 1481 } 1482 2127 1483 // Output image to browser and also write it to the cache 2128 1484 function PutAndStream($aImage,$aCacheFileName,$aInline,$aStrokeFileName) { 2129 2130 // Check if we should always stroke the image to a file 2131 if( _FORCE_IMGTOFILE ) { 2132 $aStrokeFileName = _FORCE_IMGDIR.GenImgName(); 2133 } 2134 2135 if( $aStrokeFileName != '' ) { 2136 2137 if( $aStrokeFileName == 'auto' ) { 2138 $aStrokeFileName = GenImgName(); 2139 } 2140 2141 if( file_exists($aStrokeFileName) ) { 2142 2143 // Wait for lock (to make sure no readers are trying to access the image) 2144 $fd = fopen($aStrokeFileName,'w'); 2145 $lock = flock($fd, LOCK_EX); 2146 2147 // Since the image write routines only accepts a filename which must not 2148 // exist we need to delete the old file first 2149 if( !@unlink($aStrokeFileName) ) { 2150 $lock = flock($fd, LOCK_UN); 2151 JpGraphError::RaiseL(25111,$aStrokeFileName); 2152 //(" Can't delete cached image $aStrokeFileName. Permission problem?"); 2153 } 2154 $aImage->Stream($aStrokeFileName); 2155 $lock = flock($fd, LOCK_UN); 2156 fclose($fd); 2157 2158 } 2159 else { 2160 $aImage->Stream($aStrokeFileName); 2161 } 2162 2163 return; 2164 } 2165 2166 if( $aCacheFileName != '' && USE_CACHE) { 2167 2168 $aCacheFileName = $this->cache_dir . $aCacheFileName; 2169 if( file_exists($aCacheFileName) ) { 2170 if( !$aInline ) { 2171 // If we are generating image off-line (just writing to the cache) 2172 // and the file exists and is still valid (no timeout) 2173 // then do nothing, just return. 2174 $diff=time()-filemtime($aCacheFileName); 2175 if( $diff < 0 ) { 2176 JpGraphError::RaiseL(25112,$aCacheFileName); 2177 //(" Cached imagefile ($aCacheFileName) has file date in the future!!"); 2178 } 2179 if( $this->timeout>0 && ($diff <= $this->timeout*60) ) return; 2180 } 2181 2182 // Wait for lock (to make sure no readers are trying to access the image) 2183 $fd = fopen($aCacheFileName,'w'); 2184 $lock = flock($fd, LOCK_EX); 2185 2186 if( !@unlink($aCacheFileName) ) { 2187 $lock = flock($fd, LOCK_UN); 2188 JpGraphError::RaiseL(25113,$aStrokeFileName); 2189 //(" Can't delete cached image $aStrokeFileName. Permission problem?"); 2190 } 2191 $aImage->Stream($aCacheFileName); 2192 $lock = flock($fd, LOCK_UN); 2193 fclose($fd); 2194 2195 } 2196 else { 2197 $this->MakeDirs(dirname($aCacheFileName)); 2198 if( !is_writeable(dirname($aCacheFileName)) ) { 2199 JpGraphError::RaiseL(25114,$aCacheFileName); 2200 //('PHP has not enough permissions to write to the cache file '.$aCacheFileName.'. Please make sure that the user running PHP has write permission for this file if you wan to use the cache system with JpGraph.'); 2201 } 2202 $aImage->Stream($aCacheFileName); 2203 } 2204 2205 $res=true; 2206 // Set group to specified 2207 if( CACHE_FILE_GROUP != '' ) { 2208 $res = @chgrp($aCacheFileName,CACHE_FILE_GROUP); 2209 } 2210 if( CACHE_FILE_MOD != '' ) { 2211 $res = @chmod($aCacheFileName,CACHE_FILE_MOD); 2212 } 2213 if( !$res ) { 2214 JpGraphError::RaiseL(25115,$aStrokeFileName); 2215 //(" Can't set permission for cached image $aStrokeFileName. Permission problem?"); 2216 } 2217 2218 $aImage->Destroy(); 2219 if( $aInline ) { 2220 if ($fh = @fopen($aCacheFileName, "rb") ) { 2221 $aImage->Headers(); 2222 fpassthru($fh); 2223 return; 2224 } 2225 else { 2226 JpGraphError::RaiseL(25116,$aFile);//(" Cant open file from cache [$aFile]"); 2227 } 2228 } 2229 } 2230 elseif( $aInline ) { 2231 $aImage->Headers(); 2232 $aImage->Stream(); 2233 return; 2234 } 2235 } 2236 2237 function IsValid($aCacheFileName) { 2238 $aCacheFileName = $this->cache_dir.$aCacheFileName; 2239 if ( USE_CACHE && file_exists($aCacheFileName) ) { 2240 $diff=time()-filemtime($aCacheFileName); 2241 if( $this->timeout>0 && ($diff > $this->timeout*60) ) { 2242 return false; 2243 } 2244 else { 2245 return true; 2246 } 2247 } 2248 else { 2249 return false; 2250 } 2251 } 2252 2253 function StreamImgFile($aImage,$aCacheFileName) { 2254 $aCacheFileName = $this->cache_dir.$aCacheFileName; 2255 if ( $fh = @fopen($aCacheFileName, 'rb') ) { 2256 $lock = flock($fh, LOCK_SH); 2257 $aImage->Headers(); 2258 fpassthru($fh); 2259 $lock = flock($fh, LOCK_UN); 2260 fclose($fh); 2261 return true; 2262 } 2263 else { 2264 JpGraphError::RaiseL(25117,$aCacheFileName);//(" Can't open cached image \"$aCacheFileName\" for reading."); 2265 } 2266 } 2267 1485 // Some debugging code to brand the image with numbe of colors 1486 // used 1487 GLOBAL $gJpgBrandTiming; 1488 1489 if( $gJpgBrandTiming ) { 1490 global $tim; 1491 $t=$tim->Pop()/1000.0; 1492 $c=$aImage->SetColor("black"); 1493 $t=sprintf(BRAND_TIME_FORMAT,round($t,3)); 1494 imagestring($this->img->img,2,5,$this->img->height-20,$t,$c); 1495 } 1496 1497 // Check if we should stroke the image to an arbitrary file 1498 if( _FORCE_IMGTOFILE ) { 1499 $aStrokeFileName = _FORCE_IMGDIR.GenImgName(); 1500 } 1501 1502 if( $aStrokeFileName!="" ) { 1503 if( $aStrokeFileName == "auto" ) 1504 $aStrokeFileName = GenImgName(); 1505 if( file_exists($aStrokeFileName) ) { 1506 // Delete the old file 1507 if( !@unlink($aStrokeFileName) ) 1508 JpGraphError::RaiseL(25111,$aStrokeFileName);//(" Can't delete cached image $aStrokeFileName. Permission problem?"); 1509 } 1510 $aImage->Stream($aStrokeFileName); 1511 return; 1512 } 1513 1514 if( $aCacheFileName != "" && USE_CACHE) { 1515 1516 $aCacheFileName = $this->cache_dir . $aCacheFileName; 1517 if( file_exists($aCacheFileName) ) { 1518 if( !$aInline ) { 1519 // If we are generating image off-line (just writing to the cache) 1520 // and the file exists and is still valid (no timeout) 1521 // then do nothing, just return. 1522 $diff=time()-filemtime($aCacheFileName); 1523 if( $diff < 0 ) 1524 JpGraphError::RaiseL(25112,$aCacheFileName);//(" Cached imagefile ($aCacheFileName) has file date in the future!!"); 1525 if( $this->timeout>0 && ($diff <= $this->timeout*60) ) 1526 return; 1527 } 1528 if( !@unlink($aCacheFileName) ) 1529 JpGraphError::RaiseL(25113,$aStrokeFileName);//(" Can't delete cached image $aStrokeFileName. Permission problem?"); 1530 $aImage->Stream($aCacheFileName); 1531 } 1532 else { 1533 $this->MakeDirs(dirname($aCacheFileName)); 1534 if( !is_writeable(dirname($aCacheFileName)) ) { 1535 JpGraphError::RaiseL(25114,$aCacheFileName);//('PHP has not enough permissions to write to the cache file '.$aCacheFileName.'. Please make sure that the user running PHP has write permission for this file if you wan to use the cache system with JpGraph.'); 1536 } 1537 $aImage->Stream($aCacheFileName); 1538 } 1539 1540 $res=true; 1541 // Set group to specified 1542 if( CACHE_FILE_GROUP != "" ) 1543 $res = @chgrp($aCacheFileName,CACHE_FILE_GROUP); 1544 if( CACHE_FILE_MOD != "" ) 1545 $res = @chmod($aCacheFileName,CACHE_FILE_MOD); 1546 if( !$res ) 1547 JpGraphError::RaiseL(25115,$aStrokeFileName);//(" Can't set permission for cached image $aStrokeFileName. Permission problem?"); 1548 1549 $aImage->Destroy(); 1550 if( $aInline ) { 1551 if ($fh = @fopen($aCacheFileName, "rb") ) { 1552 $this->img->Headers(); 1553 fpassthru($fh); 1554 return; 1555 } 1556 else 1557 JpGraphError::RaiseL(25116,$aFile);//(" Cant open file from cache [$aFile]"); 1558 } 1559 } 1560 elseif( $aInline ) { 1561 $this->img->Headers(); 1562 $aImage->Stream(); 1563 return; 1564 } 1565 } 1566 2268 1567 // Check if a given image is in cache and in that case 2269 1568 // pass it directly on to web browser. Return false if the 2270 1569 // image file doesn't exist or exists but is to old 2271 function GetAndStream($aImage,$aCacheFileName) { 2272 if( $this->Isvalid($aCacheFileName) ) { 2273 $this->StreamImgFile($aImage,$aCacheFileName); 2274 } 2275 else { 2276 return false; 2277 } 2278 } 2279 1570 function GetAndStream($aCacheFileName) { 1571 $aCacheFileName = $this->cache_dir.$aCacheFileName; 1572 if ( USE_CACHE && file_exists($aCacheFileName) && $this->timeout>=0 ) { 1573 $diff=time()-filemtime($aCacheFileName); 1574 if( $this->timeout>0 && ($diff > $this->timeout*60) ) { 1575 return false; 1576 } 1577 else { 1578 if ($fh = @fopen($aCacheFileName, "rb")) { 1579 $this->img->Headers(); 1580 fpassthru($fh); 1581 return true; 1582 } 1583 else 1584 JpGraphError::RaiseL(25117,$aCacheFileName);//(" Can't open cached image \"$aCacheFileName\" for reading."); 1585 } 1586 } 1587 return false; 1588 } 1589 2280 1590 //--------------- 2281 // PRIVATE METHODS 1591 // PRIVATE METHODS 2282 1592 // Create all necessary directories in a path 2283 1593 function MakeDirs($aFile) { 2284 $dirs = array(); 2285 // In order to better work when open_basedir is enabled 2286 // we do not create directories in the root path 2287 while ( $aFile != '/' && !(file_exists($aFile)) ) { 2288 $dirs[] = $aFile.'/'; 2289 $aFile = dirname($aFile); 2290 } 2291 for ($i = sizeof($dirs)-1; $i>=0; $i--) { 2292 if(! @mkdir($dirs[$i],0777) ) { 2293 JpGraphError::RaiseL(25118,$aFile);//(" Can't create directory $aFile. Make sure PHP has write permission to this directory."); 2294 } 2295 // We also specify mode here after we have changed group. 2296 // This is necessary if Apache user doesn't belong the 2297 // default group and hence can't specify group permission 2298 // in the previous mkdir() call 2299 if( CACHE_FILE_GROUP != "" ) { 2300 $res=true; 2301 $res =@chgrp($dirs[$i],CACHE_FILE_GROUP); 2302 $res = @chmod($dirs[$i],0777); 2303 if( !$res ) { 2304 JpGraphError::RaiseL(25119,$aFile);//(" Can't set permissions for $aFile. Permission problems?"); 2305 } 2306 } 2307 } 2308 return true; 2309 } 1594 $dirs = array(); 1595 while ( !(file_exists($aFile)) ) { 1596 $dirs[] = $aFile; 1597 $aFile = dirname($aFile); 1598 } 1599 for ($i = sizeof($dirs)-1; $i>=0; $i--) { 1600 if(! @mkdir($dirs[$i],0777) ) 1601 JpGraphError::RaiseL(25118,$aFile);//(" Can't create directory $aFile. Make sure PHP has write permission to this directory."); 1602 // We also specify mode here after we have changed group. 1603 // This is necessary if Apache user doesn't belong the 1604 // default group and hence can't specify group permission 1605 // in the previous mkdir() call 1606 if( CACHE_FILE_GROUP != "" ) { 1607 $res=true; 1608 $res =@chgrp($dirs[$i],CACHE_FILE_GROUP); 1609 $res = @chmod($dirs[$i],0777); 1610 if( !$res ) 1611 JpGraphError::RaiseL(25119,$aFile);//(" Can't set permissions for $aFile. Permission problems?"); 1612 } 1613 } 1614 return true; 1615 } 2310 1616 } // CLASS Cache 2311 1617 1618 2312 1619 ?>
Note:
See TracChangeset
for help on using the changeset viewer.