Ignore:
Timestamp:
Apr 13, 2019, 8:05:15 PM (5 years ago)
Author:
roby
Message:
 
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/client/modules/Elezioni/grafici/gd_image.inc.php

    r17 r265  
    11<?php
    22//=======================================================================
    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$
     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: gd_image.inc.php 1922 2010-01-11 11:42:50Z ljp $
    77//
    8 // Copyright (c) Aditus Consulting. All rights reserved.
     8// Copyright (c) Asial Corporation. All rights reserved.
    99//========================================================================
    1010
    11        
    12 //===================================================
     11require_once 'jpgraph_rgb.inc.php';
     12require_once 'jpgraph_ttf.inc.php';
     13require_once 'imageSmoothArc.php';
     14require_once 'jpgraph_errhandler.inc.php';
     15
     16// Line styles
     17define('LINESTYLE_SOLID',1);
     18define('LINESTYLE_DOTTED',2);
     19define('LINESTYLE_DASHED',3);
     20define('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.
     25if( !DEFINED("DEFAULT_GFORMAT") ) {
     26    define("DEFAULT_GFORMAT","auto");
     27}
     28
     29//========================================================================
    1330// CLASS Image
    14 // Description: Wrapper class with some goodies to form the
    15 // Interface to low level image drawing routines.
    16 //===================================================
     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//=========================================================================
    1737class Image {
    18     public $left_margin=30,$right_margin=30,$top_margin=20,$bottom_margin=30;
    1938    public $img=null;
    20     public $plotwidth=0,$plotheight=0;
    21     public $width=0, $height=0;
    2239    public $rgb=null;
    23     public $current_color,$current_color_name;
    24     public $line_weight=1, $line_style=LINESTYLE_SOLID;
    2540    public $img_format;
    2641    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, __set
     48    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
    2753    protected $expired=true;
    2854    protected $lastx=0, $lasty=0;
    2955    protected $obs_list=array();
    30     protected $font_size=12,$font_family=FF_FONT1, $font_style=FS_NORMAL;
     56    protected $font_size=12,$font_family=FF_DEFAULT, $font_style=FS_NORMAL;
    3157    protected $font_file='';
    3258    protected $text_halign="left",$text_valign="bottom";
     
    3763    protected $langconv = null ;
    3864    protected $iInterlace=false;
     65    protected $bbox_cache = array(); // STore the last found tetx bounding box
     66    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
    3974    //---------------
    4075    // CONSTRUCTOR
    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();
     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");
    5197    }
    5298
    5399    // Enable interlacing in images
    54100    function SetInterlace($aFlg=true) {
    55         $this->iInterlace=$aFlg;
     101        $this->iInterlace=$aFlg;
    56102    }
    57103
    58104    // Should we use anti-aliasing. Note: This really slows down graphics!
    59105    function SetAntiAliasing($aFlg=true) {
    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         }
     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 ;
    67117    }
    68118
    69119    function CreateRawCanvas($aWidth=0,$aHeight=0) {
    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);                           
     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        }
    96144    }
    97145
    98146    function CloneCanvasH() {
    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    
     147        $oldimage = $this->img;
     148        $this->CreateRawCanvas($this->width,$this->height);
     149        imagecopy($this->img,$oldimage,0,0,0,0,$this->width,$this->height);
     150        return $oldimage;
     151    }
     152
    105153    function CreateImgCanvas($aWidth=0,$aHeight=0) {
    106154
    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 ;
     155        $old = array($this->img,$this->width,$this->height);
     156
     157        $aWidth = round($aWidth);
     158        $aHeight = round($aHeight);
     159
     160        $this->width=$aWidth;
     161        $this->height=$aHeight;
     162
     163
     164        if( $aWidth==0 || $aHeight==0 ) {
     165            // We will set the final size later.
     166            // Note: The size must be specified before any other
     167            // img routines that stroke anything are called.
     168            $this->img = null;
     169            $this->rgb = null;
     170            return $old;
     171        }
     172
     173        $this->CreateRawCanvas($aWidth,$aHeight);
     174        // Set canvas color (will also be the background color for a
     175        // a pallett image
     176        $this->SetColor($this->canvascolor);
     177        $this->FilledRectangle(0,0,$this->width-1,$this->height-1);
     178
     179        return $old ;
    132180    }
    133181
    134182    function CopyCanvasH($aToHdl,$aFromHdl,$aToX,$aToY,$aFromX,$aFromY,$aWidth,$aHeight,$aw=-1,$ah=-1) {
    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);
     183        if( $aw === -1 ) {
     184            $aw = $aWidth;
     185            $ah = $aHeight;
     186            $f = 'imagecopyresized';
     187        }
     188        else {
     189            $f = 'imagecopyresampled';
     190        }
     191        $f($aToHdl,$aFromHdl,$aToX,$aToY,$aFromX,$aFromY, $aWidth,$aHeight,$aw,$ah);
    144192    }
    145193
    146194    function Copy($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1) {
    147         $this->CopyCanvasH($this->img,$fromImg,$toX,$toY,$fromX,$fromY,
    148                            $toWidth,$toHeight,$fromWidth,$fromHeight);
     195        $this->CopyCanvasH($this->img,$fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight);
    149196    }
    150197
    151198    function CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1,$aMix=100) {
    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         }
     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        }
    177221    }
    178222
    179223    static function GetWidth($aImg=null) {
    180         if( $aImg === null )
    181             $aImg = $this->img;
    182         return imagesx($aImg);
     224        if( $aImg === null ) {
     225            $aImg = $this->img;
     226        }
     227        return imagesx($aImg);
    183228    }
    184229
    185230    static function GetHeight($aImg=null) {
    186         if( $aImg === null )
    187             $aImg = $this->img;
    188         return imagesy($aImg);
    189     }
    190    
     231        if( $aImg === null ) {
     232            $aImg = $this->img;
     233        }
     234        return imagesy($aImg);
     235    }
     236
    191237    static function CreateFromString($aStr) {
    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;
     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;
    197244    }
    198245
    199246    function SetCanvasH($aHdl) {
    200         $this->img = $aHdl;
    201         $this->rgb->img = $aHdl;
     247        $this->img = $aHdl;
     248        $this->rgb->img = $aHdl;
    202249    }
    203250
    204251    function SetCanvasColor($aColor) {
    205         $this->canvascolor = $aColor ;
     252        $this->canvascolor = $aColor ;
    206253    }
    207254
    208255    function SetAlphaBlending($aFlg=true) {
    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                                
     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
    228268    //---------------
    229     // PUBLIC METHODS   
    230        
     269    // PUBLIC METHODS
     270
    231271    function SetFont($family,$style=FS_NORMAL,$size=10) {
    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         }
     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        }
    247290    }
    248291
    249292    // Get the specific height for a text string
    250293    function GetTextHeight($txt="",$angle=0) {
    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        
     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
    281325    // Estimate font height
    282326    function GetFontHeight($angle=0) {
    283         $txt = "XOMg";
    284         return $this->GetTextHeight($txt,$angle);
    285     }
    286        
     327        $txt = "XOMg";
     328        return $this->GetTextHeight($txt,$angle);
     329    }
     330
    287331    // Approximate font width with width of letter "O"
    288332    function GetFontWidth($angle=0) {
    289         $txt = 'O';
    290         return $this->GetTextWidth($txt,$angle);
    291     }
    292        
    293     // Get actual width of text in absolute pixels
     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.
    294340    function GetTextWidth($txt,$angle=0) {
    295341
    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        
     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
    339386    // Draw text with a box around it
    340387    function StrokeBoxedText($x,$y,$txt,$dir=0,$fcolor="white",$bcolor="black",
    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       
     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;
     442            }
     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;
     448            }
     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
    414625    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));
     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));
    444659            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             }
     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            }
    473686            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 
    482             }
    483             $aBoundingBox=array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y));
    484         }
     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        }
    485698    }
    486699
    487700    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 
     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
    500816    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;
     817        $bbox = $this->imagettfbbox_fixed($this->font_size,$aAngle,$this->font_file,$aTxt);
     818         return $bbox;
    507819    }
    508820
    509821    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;
     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;
    560872    }
    561873
    562874    function GetBBoxHeight($aTxt,$aAngle=0) {
    563         $box = $this->GetBBoxTTF($aTxt,$aAngle);
    564         return $box[1]-$box[7]+1;
     875        $box = $this->GetBBoxTTF($aTxt,$aAngle);
     876        return abs($box[7]-$box[1]);
    565877    }
    566878
    567879    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
     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
    621956            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();
    648             }
    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        
     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
    7441086    function StrokeText($x,$y,$txt,$dir=0,$paragraph_align="left",$debug=false) {
    7451087
    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        
     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
    7661110    function SetMargin($lm,$rm,$tm,$bm) {
    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         }
     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        }
    7771126    }
    7781127
    7791128    function SetTransparent($color) {
    780         imagecolortransparent ($this->img,$this->rgb->allocate($color));
    781     }
    782        
     1129        imagecolortransparent ($this->img,$this->rgb->allocate($color));
     1130    }
     1131
    7831132    function SetColor($color,$aAlpha=0) {
    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        
     1133        $this->current_color_name = $color;
     1134        $this->current_color=$this->rgb->allocate($color,$aAlpha);
     1135        if( $this->current_color == -1 ) {
     1136            $tc=imagecolorstotal($this->img);
     1137            JpGraphError::RaiseL(25096);
     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        return $this->current_color;
     1141    }
     1142
    7941143    function PushColor($color) {
    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        
     1144        if( $color != "" ) {
     1145            $this->colorstack[$this->colorstackidx]=$this->current_color_name;
     1146            $this->colorstack[$this->colorstackidx+1]=$this->current_color;
     1147            $this->colorstackidx+=2;
     1148            $this->SetColor($color);
     1149        }
     1150        else {
     1151            JpGraphError::RaiseL(25097);//("Color specified as empty string in PushColor().");
     1152        }
     1153    }
     1154
    8061155    function PopColor() {
    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        
     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
    8141164    function SetLineWeight($weight) {
    815         imagesetthickness($this->img,$weight);
    816         $this->line_weight = $weight;
    817     }
    818        
     1165        $old = $this->line_weight;
     1166        imagesetthickness($this->img,$weight);
     1167        $this->line_weight = $weight;
     1168        return $old;
     1169    }
     1170
    8191171    function SetStartPoint($x,$y) {
    820         $this->lastx=round($x);
    821         $this->lasty=round($y);
    822     }
    823        
     1172        $this->lastx=round($x);
     1173        $this->lasty=round($y);
     1174    }
     1175
    8241176    function Arc($cx,$cy,$w,$h,$s,$e) {
    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    
     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
    8331183    function FilledArc($xc,$yc,$w,$h,$s,$e,$style='') {
    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         }
     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        }
    8421194    }
    8431195
    8441196    function FilledCakeSlice($cx,$cy,$w,$h,$s,$e) {
    845         $this->CakeSlice($cx,$cy,$w,$h,$s,$e,$this->current_color_name);
     1197        $this->CakeSlice($cx,$cy,$w,$h,$s,$e,$this->current_color_name);
    8461198    }
    8471199
    8481200    function CakeSlice($xc,$yc,$w,$h,$s,$e,$fillcolor="",$arccolor="") {
    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         }
     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        }
    8741232    }
    8751233
    8761234    function Ellipse($xc,$yc,$w,$h) {
    877         $this->Arc($xc,$yc,$w,$h,0,360);
    878     }
    879                        
     1235        $this->Arc($xc,$yc,$w,$h,0,360);
     1236    }
     1237
    8801238    function Circle($xc,$yc,$r) {
    881         imageellipse($this->img,round($xc),round($yc),$r*2,$r*2,$this->current_color);
    882     }
    883        
     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
    8841244    function FilledCircle($xc,$yc,$r) {
    885         imagefilledellipse($this->img,round($xc),round($yc),2*$r,2*$r,$this->current_color);
    886     }
    887        
     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
    8881249    // Linear Color InterPolation
    8891250    function lip($f,$t,$p) {
    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);
     1251        $p = round($p,1);
     1252        $r = $f[0] + ($t[0]-$f[0])*$p;
     1253        $g = $f[1] + ($t[1]-$f[1])*$p;
     1254        $b = $f[2] + ($t[2]-$f[2])*$p;
     1255        return array($r,$g,$b);
    8951256    }
    8961257
    8971258    // Set line style dashed, dotted etc
    8981259    function SetLineStyle($s) {
    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        
     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
    9181282    // Same as Line but take the line_style into account
    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        
     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
    9491331    function DashedLine($x1,$y1,$x2,$y2,$dash_length=1,$dash_space=4) {
    9501332
    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     }
     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    }
    9731391
    9741392    function Line($x1,$y1,$x2,$y2) {
    9751393
    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;             
     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;
    9861405    }
    9871406
    9881407    function Polygon($p,$closed=FALSE,$fast=FALSE) {
    9891408
    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        
     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
    10171436    function FilledPolygon($pts) {
    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        
     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
    10271451    function Rectangle($xl,$yu,$xr,$yl) {
    1028         $this->Polygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl,$xl,$yu));
    1029     }
    1030        
     1452        $this->Polygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl,$xl,$yu));
     1453    }
     1454
    10311455    function FilledRectangle($xl,$yu,$xr,$yl) {
    1032         $this->FilledPolygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl));
     1456        $this->FilledPolygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl));
    10331457    }
    10341458
    10351459    function FilledRectangle2($xl,$yu,$xr,$yl,$color1,$color2,$style=1) {
    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
     1460        // Fill a rectangle with lines of two colors
     1461        if( $style===1 ) {
     1462            // Horizontal stripe
     1463            if( $yl < $yu ) {
     1464                $t = $yl; $yl=$yu; $yu=$t;
     1465            }
     1466            for( $y=$yu; $y <= $yl; ++$y) {
     1467                $this->SetColor($color1);
     1468                $this->Line($xl,$y,$xr,$y);
     1469                ++$y;
     1470                $this->SetColor($color2);
     1471                $this->Line($xl,$y,$xr,$y);
     1472            }
     1473        }
     1474        else {
     1475            if( $xl < $xl ) {
     1476                $t = $xl; $xl=$xr; $xr=$t;
     1477            }
     1478            for( $x=$xl; $x <= $xr; ++$x) {
     1479                $this->SetColor($color1);
     1480                $this->Line($x,$yu,$x,$yl);
     1481                ++$x;
     1482                $this->SetColor($color2);
     1483                $this->Line($x,$yu,$x,$yl);
     1484            }
     1485        }
     1486    }
     1487
     1488    function ShadowRectangle($xl,$yu,$xr,$yl,$fcolor=false,$shadow_width=4,$shadow_color='darkgray',$useAlpha=true) {
     1489        // This is complicated by the fact that we must also handle the case where
    10661490        // the reactangle has no fill color
    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         }
     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        }
    10801520    }
    10811521
    10821522    function FilledRoundedRectangle($xt,$yt,$xr,$yl,$r=5) {
    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);
     1523        if( $r==0 ) {
     1524            $this->FilledRectangle($xt,$yt,$xr,$yl);
     1525            return;
     1526        }
     1527
     1528        // To avoid overlapping fillings (which will look strange
     1529        // when alphablending is enabled) we have no choice but
     1530        // to fill the five distinct areas one by one.
     1531
     1532        // Center square
     1533        $this->FilledRectangle($xt+$r,$yt+$r,$xr-$r,$yl-$r);
     1534        // Top band
     1535        $this->FilledRectangle($xt+$r,$yt,$xr-$r,$yt+$r);
     1536        // Bottom band
     1537        $this->FilledRectangle($xt+$r,$yl-$r,$xr-$r,$yl);
     1538        // Left band
     1539        $this->FilledRectangle($xt,$yt+$r,$xt+$r,$yl-$r);
     1540        // Right band
     1541        $this->FilledRectangle($xr-$r,$yt+$r,$xr,$yl-$r);
     1542
     1543        // Topleft & Topright arc
     1544        $this->FilledArc($xt+$r,$yt+$r,$r*2,$r*2,180,270);
     1545        $this->FilledArc($xr-$r,$yt+$r,$r*2,$r*2,270,360);
     1546
     1547        // Bottomleft & Bottom right arc
     1548        $this->FilledArc($xt+$r,$yl-$r,$r*2,$r*2,90,180);
     1549        $this->FilledArc($xr-$r,$yl-$r,$r*2,$r*2,0,90);
     1550
     1551    }
     1552
     1553    function RoundedRectangle($xt,$yt,$xr,$yl,$r=5) {
     1554
     1555        if( $r==0 ) {
     1556            $this->Rectangle($xt,$yt,$xr,$yl);
     1557            return;
     1558        }
     1559
     1560        // Top & Bottom line
     1561        $this->Line($xt+$r,$yt,$xr-$r,$yt);
     1562        $this->Line($xt+$r,$yl,$xr-$r,$yl);
     1563
     1564        // Left & Right line
     1565        $this->Line($xt,$yt+$r,$xt,$yl-$r);
     1566        $this->Line($xr,$yt+$r,$xr,$yl-$r);
     1567
     1568        // Topleft & Topright arc
     1569        $this->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270);
     1570        $this->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360);
     1571
     1572        // Bottomleft & Bottomright arc
     1573        $this->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180);
     1574        $this->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90);
    11351575    }
    11361576
    11371577    function FilledBevel($x1,$y1,$x2,$y2,$depth=2,$color1='white@0.4',$color2='darkgray@0.4') {
    1138         $this->FilledRectangle($x1,$y1,$x2,$y2);
    1139         $this->Bevel($x1,$y1,$x2,$y2,$depth,$color1,$color2);
     1578        $this->FilledRectangle($x1,$y1,$x2,$y2);
     1579        $this->Bevel($x1,$y1,$x2,$y2,$depth,$color1,$color2);
    11401580    }
    11411581
    11421582    function Bevel($x1,$y1,$x2,$y2,$depth=2,$color1='white@0.4',$color2='black@0.5') {
    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();
     1583        $this->PushColor($color1);
     1584        for( $i=0; $i < $depth; ++$i ) {
     1585            $this->Line($x1+$i,$y1+$i,$x1+$i,$y2-$i);
     1586            $this->Line($x1+$i,$y1+$i,$x2-$i,$y1+$i);
     1587        }
     1588        $this->PopColor();
     1589
     1590        $this->PushColor($color2);
     1591        for( $i=0; $i < $depth; ++$i ) {
     1592            $this->Line($x1+$i,$y2-$i,$x2-$i,$y2-$i);
     1593            $this->Line($x2-$i,$y1+$i,$x2-$i,$y2-$i-1);
     1594        }
     1595        $this->PopColor();
    11561596    }
    11571597
    11581598    function StyleLineTo($x,$y) {
    1159         $this->StyleLine($this->lastx,$this->lasty,$x,$y);
    1160         $this->lastx=$x;
    1161         $this->lasty=$y;
    1162     }
    1163        
     1599        $this->StyleLine($this->lastx,$this->lasty,$x,$y);
     1600        $this->lastx=$x;
     1601        $this->lasty=$y;
     1602    }
     1603
    11641604    function LineTo($x,$y) {
    1165         $this->Line($this->lastx,$this->lasty,$x,$y);
    1166         $this->lastx=$x;
    1167         $this->lasty=$y;
    1168     }
    1169        
     1605        $this->Line($this->lastx,$this->lasty,$x,$y);
     1606        $this->lastx=$x;
     1607        $this->lasty=$y;
     1608    }
     1609
    11701610    function Point($x,$y) {
    1171         imagesetpixel($this->img,round($x),round($y),$this->current_color);
    1172     }
    1173        
     1611        imagesetpixel($this->img,round($x),round($y),$this->current_color);
     1612    }
     1613
    11741614    function Fill($x,$y) {
    1175         imagefill($this->img,round($x),round($y),$this->current_color);
     1615        imagefill($this->img,round($x),round($y),$this->current_color);
    11761616    }
    11771617
    11781618    function FillToBorder($x,$y,$aBordColor) {
    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);
     1619        $bc = $this->rgb->allocate($aBordColor);
     1620        if( $bc == -1 ) {
     1621            JpGraphError::RaiseL(25106);//('Image::FillToBorder : Can not allocate more colors');
     1622        }
     1623        imagefilltoborder($this->img,round($x),round($y),$bc,$this->current_color);
    11841624    }
    11851625
    11861626    function SetExpired($aFlg=true) {
    1187         $this->expired = $aFlg;
    1188     }
    1189        
     1627        $this->expired = $aFlg;
     1628    }
     1629
    11901630    // Generate image header
    11911631    function Headers() {
    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");
     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");
    12171656    }
    12181657
    12191658    // Adjust image quality for formats that allow this
    12201659    function SetQuality($q) {
    1221         $this->quality = $q;
    1222     }
    1223        
     1660        $this->quality = $q;
     1661    }
     1662
    12241663    // Stream image to browser or to file
    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.");
     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                                }
    12401677               
    1241             }
    1242         }
    1243     }
    1244                
    1245     // Clear resource tide up by image
     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
    12461711    function Destroy() {
    1247         imagedestroy($this->img);
    1248     }
    1249        
     1712        imagedestroy($this->img);
     1713    }
     1714
    12501715    // Specify image format. Note depending on your installation
    12511716    // of PHP not all formats may be supported.
    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     }   
     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
    12961941} // CLASS
    12971942
     
    13031948class RotImage extends Image {
    13041949    public $a=0;
    1305     public $dx=0,$dy=0,$transx=0,$transy=0; 
     1950    public $dx=0,$dy=0,$transx=0,$transy=0;
    13061951    private $m=array();
    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        
     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
    13151960    function SetCenter($dx,$dy) {
    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        
     1961        $old_dx = $this->dx;
     1962        $old_dy = $this->dy;
     1963        $this->dx=$dx;
     1964        $this->dy=$dy;
     1965        $this->SetAngle($this->a);
     1966        return array($old_dx,$old_dy);
     1967    }
     1968
    13241969    function SetTranslation($dx,$dy) {
    1325         $old = array($this->transx,$this->transy);
    1326         $this->transx = $dx;
    1327         $this->transy = $dy;
    1328         return $old;
     1970        $old = array($this->transx,$this->transy);
     1971        $this->transx = $dx;
     1972        $this->transy = $dy;
     1973        return $old;
    13291974    }
    13301975
    13311976    function UpdateRotMatrice()  {
    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 ;
     1977        $a = $this->a;
     1978        $a *= M_PI/180;
     1979        $sa=sin($a); $ca=cos($a);
     1980        // Create the rotation matrix
     1981        $this->m[0][0] = $ca;
     1982        $this->m[0][1] = -$sa;
     1983        $this->m[0][2] = $this->dx*(1-$ca) + $sa*$this->dy ;
     1984        $this->m[1][0] = $sa;
     1985        $this->m[1][1] = $ca;
     1986        $this->m[1][2] = $this->dy*(1-$ca) - $sa*$this->dx ;
    13421987    }
    13431988
    13441989    function SetAngle($a) {
    1345         $tmp = $this->a;
    1346         $this->a = $a;
    1347         $this->UpdateRotMatrice();
    1348         return $tmp;
     1990        $tmp = $this->a;
     1991        $this->a = $a;
     1992        $this->UpdateRotMatrice();
     1993        return $tmp;
    13491994    }
    13501995
    13511996    function Circle($xc,$yc,$r) {
    1352         list($xc,$yc) = $this->Rotate($xc,$yc);
    1353         parent::Circle($xc,$yc,$r);
     1997        list($xc,$yc) = $this->Rotate($xc,$yc);
     1998        parent::Circle($xc,$yc,$r);
    13541999    }
    13552000
    13562001    function FilledCircle($xc,$yc,$r) {
    1357         list($xc,$yc) = $this->Rotate($xc,$yc);
    1358         parent::FilledCircle($xc,$yc,$r);
    1359     }
    1360 
    1361        
     2002        list($xc,$yc) = $this->Rotate($xc,$yc);
     2003        parent::FilledCircle($xc,$yc,$r);
     2004    }
     2005
     2006
    13622007    function Arc($xc,$yc,$w,$h,$s,$e) {
    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);
     2008        list($xc,$yc) = $this->Rotate($xc,$yc);
     2009        $s += $this->a;
     2010        $e += $this->a;
     2011        parent::Arc($xc,$yc,$w,$h,$s,$e);
    13672012    }
    13682013
    13692014    function FilledArc($xc,$yc,$w,$h,$s,$e,$style='') {
    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);
     2015        list($xc,$yc) = $this->Rotate($xc,$yc);
     2016        $s += $this->a;
     2017        $e += $this->a;
     2018        parent::FilledArc($xc,$yc,$w,$h,$s,$e);
    13742019    }
    13752020
    13762021    function SetMargin($lm,$rm,$tm,$bm) {
    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        
     2022        parent::SetMargin($lm,$rm,$tm,$bm);
     2023        $this->UpdateRotMatrice();
     2024    }
     2025
    13832026    function Rotate($x,$y) {
    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        
     2027        // Optimization. Ignore rotation if Angle==0 || Angle==360
     2028        if( $this->a == 0 || $this->a == 360 ) {
     2029            return array($x + $this->transx, $y + $this->transy );
     2030        }
     2031        else {
     2032            $x1=round($this->m[0][0]*$x + $this->m[0][1]*$y,1) + $this->m[0][2] + $this->transx;
     2033            $y1=round($this->m[1][0]*$x + $this->m[1][1]*$y,1) + $this->m[1][2] + $this->transy;
     2034            return array($x1,$y1);
     2035        }
     2036    }
     2037
    13952038    function CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1,$aMix=100) {
    1396         list($toX,$toY) = $this->Rotate($toX,$toY);
    1397         parent::CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight,$aMix);
     2039        list($toX,$toY) = $this->Rotate($toX,$toY);
     2040        parent::CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight,$aMix);
    13982041
    13992042    }
    14002043
    14012044    function ArrRotate($pnts) {
    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;
     2045        $n = count($pnts)-1;
     2046        for($i=0; $i < $n; $i+=2) {
     2047            list ($x,$y) = $this->Rotate($pnts[$i],$pnts[$i+1]);
     2048            $pnts[$i] = $x; $pnts[$i+1] = $y;
     2049        }
     2050        return $pnts;
    14082051    }
    14092052
    14102053    function DashedLine($x1,$y1,$x2,$y2,$dash_length=1,$dash_space=4) {
    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        
     2054        list($x1,$y1) = $this->Rotate($x1,$y1);
     2055        list($x2,$y2) = $this->Rotate($x2,$y2);
     2056        parent::DashedLine($x1,$y1,$x2,$y2,$dash_length,$dash_space);
     2057    }
     2058
    14162059    function Line($x1,$y1,$x2,$y2) {
    1417         list($x1,$y1) = $this->Rotate($x1,$y1);
    1418         list($x2,$y2) = $this->Rotate($x2,$y2);
    1419         parent::Line($x1,$y1,$x2,$y2);
     2060        list($x1,$y1) = $this->Rotate($x1,$y1);
     2061        list($x2,$y2) = $this->Rotate($x2,$y2);
     2062        parent::Line($x1,$y1,$x2,$y2);
    14202063    }
    14212064
    14222065    function Rectangle($x1,$y1,$x2,$y2) {
    1423         // Rectangle uses Line() so it will be rotated through that call
    1424         parent::Rectangle($x1,$y1,$x2,$y2);
    1425     }
    1426        
     2066        // Rectangle uses Line() so it will be rotated through that call
     2067        parent::Rectangle($x1,$y1,$x2,$y2);
     2068    }
     2069
    14272070    function FilledRectangle($x1,$y1,$x2,$y2) {
    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        
     2071        if( $y1==$y2 || $x1==$x2 )
     2072        $this->Line($x1,$y1,$x2,$y2);
     2073        else
     2074        $this->FilledPolygon(array($x1,$y1,$x2,$y1,$x2,$y2,$x1,$y2));
     2075    }
     2076
    14342077    function Polygon($pnts,$closed=FALSE,$fast=FALSE) {
    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        
     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
    14442088    function FilledPolygon($pnts) {
    1445         parent::FilledPolygon($this->ArrRotate($pnts));
    1446     }
    1447        
     2089        parent::FilledPolygon($this->ArrRotate($pnts));
     2090    }
     2091
    14482092    function Point($x,$y) {
    1449         list($xp,$yp) = $this->Rotate($x,$y);
    1450         parent::Point($xp,$yp);
    1451     }
    1452        
     2093        list($xp,$yp) = $this->Rotate($x,$y);
     2094        parent::Point($xp,$yp);
     2095    }
     2096
    14532097    function StrokeText($x,$y,$txt,$dir=0,$paragraph_align="left",$debug=false) {
    1454         list($xp,$yp) = $this->Rotate($x,$y);
    1455         return parent::StrokeText($xp,$yp,$txt,$dir,$paragraph_align,$debug);
     2098        list($xp,$yp) = $this->Rotate($x,$y);
     2099        return parent::StrokeText($xp,$yp,$txt,$dir,$paragraph_align,$debug);
    14562100    }
    14572101}
    14582102
    1459 //===================================================
     2103//=======================================================================
    14602104// CLASS ImgStreamCache
    1461 // Description: Handle caching of graphs to files
    1462 //===================================================
     2105// Description: Handle caching of graphs to files. All image output goes
     2106//              through this class
     2107//=======================================================================
    14632108class ImgStreamCache {
    1464     private $cache_dir, $img=null, $timeout=0;  // Infinite timeout
     2109    private $cache_dir, $timeout=0;  // Infinite timeout
    14652110    //---------------
    14662111    // CONSTRUCTOR
    1467     function ImgStreamCache($aImg, $aCacheDir=CACHE_DIR) {
    1468         $this->img = $aImg;
    1469         $this->cache_dir = $aCacheDir;
    1470     }
    1471 
    1472 //---------------
    1473 // PUBLIC METHODS       
     2112    function __construct($aCacheDir=CACHE_DIR) {
     2113        $this->cache_dir = $aCacheDir;
     2114    }
     2115
     2116    //---------------
     2117    // PUBLIC METHODS
    14742118
    14752119    // Specify a timeout (in minutes) for the file. If the file is older then the
     
    14782122    // timeout is set to -1 this is the same as infinite small timeout
    14792123    function SetTimeout($aTimeout) {
    1480         $this->timeout=$aTimeout;       
    1481     }
    1482        
     2124        $this->timeout=$aTimeout;
     2125    }
     2126
    14832127    // Output image to browser and also write it to the cache
    14842128    function PutAndStream($aImage,$aCacheFileName,$aInline,$aStrokeFileName) {
    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        
     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
    15672268    // Check if a given image is in cache and in that case
    15682269    // pass it directly on to web browser. Return false if the
    15692270    // image file doesn't exist or exists but is to old
    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        
     2271    function GetAndStream($aImage,$aCacheFileName) {
     2272        if( $this->Isvalid($aCacheFileName) ) {
     2273            $this->StreamImgFile($aImage,$aCacheFileName);
     2274        }
     2275        else {
     2276            return false;
     2277        }
     2278    }
     2279
    15902280    //---------------
    1591     // PRIVATE METHODS 
     2281    // PRIVATE METHODS
    15922282    // Create all necessary directories in a path
    15932283    function MakeDirs($aFile) {
    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     }   
     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    }
    16162310} // CLASS Cache
    16172311
    1618 
    16192312?>
Note: See TracChangeset for help on using the changeset viewer.