Ignore:
Timestamp:
Apr 14, 2019, 2:31:40 PM (5 years ago)
Author:
roby
Message:
 
File:
1 edited

Legend:

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

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