summaryrefslogtreecommitdiff
path: root/html/jpgraph/gd_image.inc.php
diff options
context:
space:
mode:
Diffstat (limited to 'html/jpgraph/gd_image.inc.php')
-rw-r--r--html/jpgraph/gd_image.inc.php2304
1 files changed, 2304 insertions, 0 deletions
diff --git a/html/jpgraph/gd_image.inc.php b/html/jpgraph/gd_image.inc.php
new file mode 100644
index 0000000..fecc401
--- /dev/null
+++ b/html/jpgraph/gd_image.inc.php
@@ -0,0 +1,2304 @@
+<?php
+//=======================================================================
+// File: GD_IMAGE.INC.PHP
+// Description: PHP Graph Plotting library. Low level image drawing routines
+// Created: 2001-01-08, refactored 2008-03-29
+// Ver: $Id: gd_image.inc.php 1922 2010-01-11 11:42:50Z ljp $
+//
+// Copyright (c) Asial Corporation. All rights reserved.
+//========================================================================
+
+require_once 'jpgraph_rgb.inc.php';
+require_once 'jpgraph_ttf.inc.php';
+require_once 'imageSmoothArc.php';
+
+// Line styles
+define('LINESTYLE_SOLID',1);
+define('LINESTYLE_DOTTED',2);
+define('LINESTYLE_DASHED',3);
+define('LINESTYLE_LONGDASH',4);
+
+// The DEFAULT_GFORMAT sets the default graphic encoding format, i.e.
+// PNG, JPG or GIF depending on what is installed on the target system
+// in that order.
+if( !DEFINED("DEFAULT_GFORMAT") ) {
+ define("DEFAULT_GFORMAT","auto");
+}
+
+//========================================================================
+// CLASS Image
+// Description: The very coor image drawing class that encapsulates all
+// calls to the GD library
+// Note: The class used by the library is the decendant
+// class RotImage which extends the Image class with transparent
+// rotation.
+//=========================================================================
+class Image {
+ public $img=null;
+ public $rgb=null;
+ public $img_format;
+ public $ttf=null;
+ public $line_style=LINESTYLE_SOLID;
+ public $current_color,$current_color_name;
+ public $original_width=0, $original_height=0;
+ public $plotwidth=0,$plotheight=0;
+
+ // for __get, __set
+ private $_left_margin=30,$_right_margin=30,$_top_margin=20,$_bottom_margin=30;
+ //private $_plotwidth=0,$_plotheight=0;
+ private $_width=0, $_height=0;
+ private $_line_weight=1;
+
+ protected $expired=true;
+ protected $lastx=0, $lasty=0;
+ protected $obs_list=array();
+ protected $font_size=12,$font_family=FF_DEFAULT, $font_style=FS_NORMAL;
+ protected $font_file='';
+ protected $text_halign="left",$text_valign="bottom";
+ protected $use_anti_aliasing=false;
+ protected $quality=null;
+ protected $colorstack=array(),$colorstackidx=0;
+ protected $canvascolor = 'white' ;
+ protected $langconv = null ;
+ protected $iInterlace=false;
+ protected $bbox_cache = array(); // STore the last found tetx bounding box
+ protected $ff_font0;
+ protected $ff_font0_bold;
+ protected $ff_font1;
+ protected $ff_font1_bold;
+ protected $ff_font2;
+ protected $ff_font2_bold;
+
+
+ //---------------
+ // CONSTRUCTOR
+ function __construct($aWidth=0,$aHeight=0,$aFormat=DEFAULT_GFORMAT,$aSetAutoMargin=true) {
+
+ $this->original_width = $aWidth;
+ $this->original_height = $aHeight;
+ $this->CreateImgCanvas($aWidth, $aHeight);
+
+ if( $aSetAutoMargin ) {
+ $this->SetAutoMargin();
+ }
+
+ if( !$this->SetImgFormat($aFormat) ) {
+ JpGraphError::RaiseL(25081,$aFormat);//("JpGraph: Selected graphic format is either not supported or unknown [$aFormat]");
+ }
+ $this->ttf = new TTF();
+ $this->langconv = new LanguageConv();
+
+ $this->ff_font0 = imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT0.gdf");
+ $this->ff_font1 = imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT1.gdf");
+ $this->ff_font2 = imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT2.gdf");
+ $this->ff_font1_bold = imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT1-Bold.gdf");
+ $this->ff_font2_bold = imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT2-Bold.gdf");
+ }
+
+ // Enable interlacing in images
+ function SetInterlace($aFlg=true) {
+ $this->iInterlace=$aFlg;
+ }
+
+ // Should we use anti-aliasing. Note: This really slows down graphics!
+ function SetAntiAliasing($aFlg=true) {
+ $this->use_anti_aliasing = $aFlg;
+ if( function_exists('imageantialias') ) {
+ imageantialias($this->img,$aFlg);
+ }
+ else {
+ 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.')
+ }
+ }
+
+ function GetAntiAliasing() {
+ return $this->use_anti_aliasing ;
+ }
+
+ function CreateRawCanvas($aWidth=0,$aHeight=0) {
+
+ $aWidth *= SUPERSAMPLING_SCALE;
+ $aHeight *= SUPERSAMPLING_SCALE;
+
+ if( $aWidth <= 1 || $aHeight <= 1 ) {
+ JpGraphError::RaiseL(25082,$aWidth,$aHeight);//("Illegal sizes specified for width or height when creating an image, (width=$aWidth, height=$aHeight)");
+ }
+
+ $this->img = @imagecreatetruecolor($aWidth, $aHeight);
+ if( $this->img < 1 ) {
+ JpGraphError::RaiseL(25126);
+ //die("Can't create truecolor image. Check that you really have GD2 library installed.");
+ }
+ $this->SetAlphaBlending();
+
+ if( $this->iInterlace ) {
+ imageinterlace($this->img,1);
+ }
+ if( $this->rgb != null ) {
+ $this->rgb->img = $this->img ;
+ }
+ else {
+ $this->rgb = new RGB($this->img);
+ }
+ }
+
+ function CloneCanvasH() {
+ $oldimage = $this->img;
+ $this->CreateRawCanvas($this->width,$this->height);
+ imagecopy($this->img,$oldimage,0,0,0,0,$this->width,$this->height);
+ return $oldimage;
+ }
+
+ function CreateImgCanvas($aWidth=0,$aHeight=0) {
+
+ $old = array($this->img,$this->width,$this->height);
+
+ $aWidth = round($aWidth);
+ $aHeight = round($aHeight);
+
+ $this->width=$aWidth;
+ $this->height=$aHeight;
+
+
+ if( $aWidth==0 || $aHeight==0 ) {
+ // We will set the final size later.
+ // Note: The size must be specified before any other
+ // img routines that stroke anything are called.
+ $this->img = null;
+ $this->rgb = null;
+ return $old;
+ }
+
+ $this->CreateRawCanvas($aWidth,$aHeight);
+ // Set canvas color (will also be the background color for a
+ // a pallett image
+ $this->SetColor($this->canvascolor);
+ $this->FilledRectangle(0,0,$this->width-1,$this->height-1);
+
+ return $old ;
+ }
+
+ function CopyCanvasH($aToHdl,$aFromHdl,$aToX,$aToY,$aFromX,$aFromY,$aWidth,$aHeight,$aw=-1,$ah=-1) {
+ if( $aw === -1 ) {
+ $aw = $aWidth;
+ $ah = $aHeight;
+ $f = 'imagecopyresized';
+ }
+ else {
+ $f = 'imagecopyresampled';
+ }
+ $f($aToHdl,$aFromHdl,$aToX,$aToY,$aFromX,$aFromY, $aWidth,$aHeight,$aw,$ah);
+ }
+
+ function Copy($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1) {
+ $this->CopyCanvasH($this->img,$fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight);
+ }
+
+ function CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1,$aMix=100) {
+ if( $aMix == 100 ) {
+ $this->CopyCanvasH($this->img,$fromImg,
+ $toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight);
+ }
+ else {
+ if( ($fromWidth != -1 && ($fromWidth != $toWidth)) || ($fromHeight != -1 && ($fromHeight != $fromHeight)) ) {
+ // Create a new canvas that will hold the re-scaled original from image
+ if( $toWidth <= 1 || $toHeight <= 1 ) {
+ JpGraphError::RaiseL(25083);//('Illegal image size when copying image. Size for copied to image is 1 pixel or less.');
+ }
+
+ $tmpimg = @imagecreatetruecolor($toWidth, $toHeight);
+
+ if( $tmpimg < 1 ) {
+ JpGraphError::RaiseL(25084);//('Failed to create temporary GD canvas. Out of memory ?');
+ }
+ $this->CopyCanvasH($tmpimg,$fromImg,0,0,0,0,
+ $toWidth,$toHeight,$fromWidth,$fromHeight);
+ $fromImg = $tmpimg;
+ }
+ imagecopymerge($this->img,$fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$aMix);
+ }
+ }
+
+ static function GetWidth($aImg=null) {
+ if( $aImg === null ) {
+ $aImg = $this->img;
+ }
+ return imagesx($aImg);
+ }
+
+ static function GetHeight($aImg=null) {
+ if( $aImg === null ) {
+ $aImg = $this->img;
+ }
+ return imagesy($aImg);
+ }
+
+ static function CreateFromString($aStr) {
+ $img = imagecreatefromstring($aStr);
+ if( $img === false ) {
+ 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.');
+ }
+ return $img;
+ }
+
+ function SetCanvasH($aHdl) {
+ $this->img = $aHdl;
+ $this->rgb->img = $aHdl;
+ }
+
+ function SetCanvasColor($aColor) {
+ $this->canvascolor = $aColor ;
+ }
+
+ function SetAlphaBlending($aFlg=true) {
+ ImageAlphaBlending($this->img,$aFlg);
+ }
+
+ function SetAutoMargin() {
+ $min_bm=5;
+ $lm = min(40,$this->width/7);
+ $rm = min(20,$this->width/10);
+ $tm = max(5,$this->height/7);
+ $bm = max($min_bm,$this->height/6);
+ $this->SetMargin($lm,$rm,$tm,$bm);
+ }
+
+ //---------------
+ // PUBLIC METHODS
+
+ function SetFont($family,$style=FS_NORMAL,$size=10) {
+ $this->font_family=$family;
+ $this->font_style=$style;
+ $this->font_size=$size*SUPERSAMPLING_SCALE;
+ $this->font_file='';
+ if( ($this->font_family==FF_FONT1 || $this->font_family==FF_FONT2) && $this->font_style==FS_BOLD ){
+ ++$this->font_family;
+ }
+ if( $this->font_family > FF_FONT2+1 ) { // A TTF font so get the font file
+
+ // Check that this PHP has support for TTF fonts
+ if( !function_exists('imagettfbbox') ) {
+ // use internal font when php is configured without '--with-ttf'
+ $this->font_family = FF_FONT1;
+// JpGraphError::RaiseL(25087);//('This PHP build has not been configured with TTF support. You need to recompile your PHP installation with FreeType support.');
+ } else {
+ $this->font_file = $this->ttf->File($this->font_family,$this->font_style);
+ }
+ }
+ }
+
+ // Get the specific height for a text string
+ function GetTextHeight($txt="",$angle=0) {
+ $tmp = preg_split('/\n/',$txt);
+ $n = count($tmp);
+ $m=0;
+ for($i=0; $i< $n; ++$i) {
+ $m = max($m,strlen($tmp[$i]));
+ }
+
+ if( $this->font_family <= FF_FONT2+1 ) {
+ if( $angle==0 ) {
+ $h = imagefontheight($this->font_family);
+ if( $h === false ) {
+ JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.');
+ }
+
+ return $n*$h;
+ }
+ else {
+ $w = @imagefontwidth($this->font_family);
+ if( $w === false ) {
+ JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.');
+ }
+
+ return $m*$w;
+ }
+ }
+ else {
+ $bbox = $this->GetTTFBBox($txt,$angle);
+ return $bbox[1]-$bbox[5]+1;
+ }
+ }
+
+ // Estimate font height
+ function GetFontHeight($angle=0) {
+ $txt = "XOMg";
+ return $this->GetTextHeight($txt,$angle);
+ }
+
+ // Approximate font width with width of letter "O"
+ function GetFontWidth($angle=0) {
+ $txt = 'O';
+ return $this->GetTextWidth($txt,$angle);
+ }
+
+ // Get actual width of text in absolute pixels. Note that the width is the
+ // texts projected with onto the x-axis. Call with angle=0 to get the true
+ // etxt width.
+ function GetTextWidth($txt,$angle=0) {
+
+ $tmp = preg_split('/\n/',$txt);
+ $n = count($tmp);
+ if( $this->font_family <= FF_FONT2+1 ) {
+
+ $m=0;
+ for($i=0; $i < $n; ++$i) {
+ $l=strlen($tmp[$i]);
+ if( $l > $m ) {
+ $m = $l;
+ }
+ }
+
+ if( $angle==0 ) {
+ $w = @imagefontwidth($this->font_family);
+ if( $w === false ) {
+ JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.');
+ }
+ return $m*$w;
+ }
+ else {
+ // 90 degrees internal so height becomes width
+ $h = @imagefontheight($this->font_family);
+ if( $h === false ) {
+ JpGraphError::RaiseL(25089);//('You have a misconfigured GD font support. The call to imagefontheight() fails.');
+ }
+ return $n*$h;
+ }
+ }
+ else {
+ // For TTF fonts we must walk through a lines and find the
+ // widest one which we use as the width of the multi-line
+ // paragraph
+ $m=0;
+ for( $i=0; $i < $n; ++$i ) {
+ $bbox = $this->GetTTFBBox($tmp[$i],$angle);
+ $mm = $bbox[2] - $bbox[0];
+ if( $mm > $m )
+ $m = $mm;
+ }
+ return $m;
+ }
+ }
+
+
+ // Draw text with a box around it
+ function StrokeBoxedText($x,$y,$txt,$dir=0,$fcolor="white",$bcolor="black",
+ $shadowcolor=false,$paragraph_align="left",
+ $xmarg=6,$ymarg=4,$cornerradius=0,$dropwidth=3) {
+
+ $oldx = $this->lastx;
+ $oldy = $this->lasty;
+
+ if( !is_numeric($dir) ) {
+ if( $dir=="h" ) $dir=0;
+ elseif( $dir=="v" ) $dir=90;
+ else JpGraphError::RaiseL(25090,$dir);//(" Unknown direction specified in call to StrokeBoxedText() [$dir]");
+ }
+
+ if( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) {
+ $width=$this->GetTextWidth($txt,$dir) ;
+ $height=$this->GetTextHeight($txt,$dir) ;
+ }
+ else {
+ $width=$this->GetBBoxWidth($txt,$dir) ;
+ $height=$this->GetBBoxHeight($txt,$dir) ;
+ }
+
+ $height += 2*$ymarg;
+ $width += 2*$xmarg;
+
+ if( $this->text_halign=="right" ) $x -= $width;
+ elseif( $this->text_halign=="center" ) $x -= $width/2;
+
+ if( $this->text_valign=="bottom" ) $y -= $height;
+ elseif( $this->text_valign=="center" ) $y -= $height/2;
+
+ $olda = $this->SetAngle(0);
+
+ if( $shadowcolor ) {
+ $this->PushColor($shadowcolor);
+ $this->FilledRoundedRectangle($x-$xmarg+$dropwidth,$y-$ymarg+$dropwidth,
+ $x+$width+$dropwidth,$y+$height-$ymarg+$dropwidth,
+ $cornerradius);
+ $this->PopColor();
+ $this->PushColor($fcolor);
+ $this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg,
+ $x+$width,$y+$height-$ymarg,
+ $cornerradius);
+ $this->PopColor();
+ $this->PushColor($bcolor);
+ $this->RoundedRectangle($x-$xmarg,$y-$ymarg,
+ $x+$width,$y+$height-$ymarg,$cornerradius);
+ $this->PopColor();
+ }
+ else {
+ if( $fcolor ) {
+ $oc=$this->current_color;
+ $this->SetColor($fcolor);
+ $this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius);
+ $this->current_color=$oc;
+ }
+ if( $bcolor ) {
+ $oc=$this->current_color;
+ $this->SetColor($bcolor);
+ $this->RoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius);
+ $this->current_color=$oc;
+ }
+ }
+
+ $h=$this->text_halign;
+ $v=$this->text_valign;
+ $this->SetTextAlign("left","top");
+
+ $debug=false;
+ $this->StrokeText($x, $y, $txt, $dir, $paragraph_align,$debug);
+
+ $bb = array($x-$xmarg,$y+$height-$ymarg,$x+$width,$y+$height-$ymarg,
+ $x+$width,$y-$ymarg,$x-$xmarg,$y-$ymarg);
+ $this->SetTextAlign($h,$v);
+
+ $this->SetAngle($olda);
+ $this->lastx = $oldx;
+ $this->lasty = $oldy;
+
+ return $bb;
+ }
+
+ // Draw text with a box around it. This time the box will be rotated
+ // with the text. The previous method will just make a larger enough non-rotated
+ // box to hold the text inside.
+ function StrokeBoxedText2($x,$y,$txt,$dir=0,$fcolor="white",$bcolor="black",
+ $shadowcolor=false,$paragraph_align="left",
+ $xmarg=6,$ymarg=4,$cornerradius=0,$dropwidth=3) {
+
+ // This version of boxed text will stroke a rotated box round the text
+ // thta will follow the angle of the text.
+ // This has two implications:
+ // 1) This methos will only support TTF fonts
+ // 2) The only two alignment that makes sense are centered or baselined
+
+ if( $this->font_family <= FF_FONT2+1 ) {
+ JpGraphError::RaiseL(25131);//StrokeBoxedText2() Only support TTF fonts and not built in bitmap fonts
+ }
+
+ $oldx = $this->lastx;
+ $oldy = $this->lasty;
+ $dir = $this->NormAngle($dir);
+
+ if( !is_numeric($dir) ) {
+ if( $dir=="h" ) $dir=0;
+ elseif( $dir=="v" ) $dir=90;
+ else JpGraphError::RaiseL(25090,$dir);//(" Unknown direction specified in call to StrokeBoxedText() [$dir]");
+ }
+
+ $width=$this->GetTextWidth($txt,0) + 2*$xmarg;
+ $height=$this->GetTextHeight($txt,0) + 2*$ymarg ;
+ $rect_width=$this->GetBBoxWidth($txt,$dir) ;
+ $rect_height=$this->GetBBoxHeight($txt,$dir) ;
+
+ $baseline_offset = $this->bbox_cache[1]-1;
+
+ if( $this->text_halign=="center" ) {
+ if( $dir >= 0 && $dir <= 90 ) {
+
+ $x -= $rect_width/2;
+ $x += sin($dir*M_PI/180)*$height;
+ $y += $rect_height/2;
+
+ } elseif( $dir >= 270 && $dir <= 360 ) {
+
+ $x -= $rect_width/2;
+ $y -= $rect_height/2;
+ $y += cos($dir*M_PI/180)*$height;
+
+ } elseif( $dir >= 90 && $dir <= 180 ) {
+
+ $x += $rect_width/2;
+ $y += $rect_height/2;
+ $y += cos($dir*M_PI/180)*$height;
+
+ }
+ else {
+ // $dir > 180 && $dir < 270
+ $x += $rect_width/2;
+ $x += sin($dir*M_PI/180)*$height;
+ $y -= $rect_height/2;
+ }
+ }
+
+ // Rotate the box around this point
+ $this->SetCenter($x,$y);
+ $olda = $this->SetAngle(-$dir);
+
+ // We need to use adjusted coordinats for the box to be able
+ // to draw the box below the baseline. This cannot be done before since
+ // the rotating point must be the original x,y since that is arounbf the
+ // point where the text will rotate and we cannot change this since
+ // that is where the GD/GreeType will rotate the text
+
+
+ // For smaller <14pt font we need to do some additional
+ // adjustments to make it look good
+ if( $this->font_size < 14 ) {
+ $x -= 2;
+ $y += 2;
+ }
+ else {
+ // $y += $baseline_offset;
+ }
+
+ if( $shadowcolor ) {
+ $this->PushColor($shadowcolor);
+ $this->FilledRectangle($x-$xmarg+$dropwidth,$y+$ymarg+$dropwidth-$height,
+ $x+$width+$dropwidth,$y+$ymarg+$dropwidth);
+ //$cornerradius);
+ $this->PopColor();
+ $this->PushColor($fcolor);
+ $this->FilledRectangle($x-$xmarg, $y+$ymarg-$height,
+ $x+$width, $y+$ymarg);
+ //$cornerradius);
+ $this->PopColor();
+ $this->PushColor($bcolor);
+ $this->Rectangle($x-$xmarg,$y+$ymarg-$height,
+ $x+$width,$y+$ymarg);
+ //$cornerradius);
+ $this->PopColor();
+ }
+ else {
+ if( $fcolor ) {
+ $oc=$this->current_color;
+ $this->SetColor($fcolor);
+ $this->FilledRectangle($x-$xmarg,$y+$ymarg-$height,$x+$width,$y+$ymarg);//,$cornerradius);
+ $this->current_color=$oc;
+ }
+ if( $bcolor ) {
+ $oc=$this->current_color;
+ $this->SetColor($bcolor);
+ $this->Rectangle($x-$xmarg,$y+$ymarg-$height,$x+$width,$y+$ymarg);//,$cornerradius);
+ $this->current_color=$oc;
+ }
+ }
+
+ if( $this->font_size < 14 ) {
+ $x += 2;
+ $y -= 2;
+ }
+ else {
+
+ // Restore the original y before we stroke the text
+ // $y -= $baseline_offset;
+
+ }
+
+ $this->SetCenter(0,0);
+ $this->SetAngle($olda);
+
+ $h=$this->text_halign;
+ $v=$this->text_valign;
+ if( $this->text_halign == 'center') {
+ $this->SetTextAlign('center','basepoint');
+ }
+ else {
+ $this->SetTextAlign('basepoint','basepoint');
+ }
+
+ $debug=false;
+ $this->StrokeText($x, $y, $txt, $dir, $paragraph_align,$debug);
+
+ $bb = array($x-$xmarg, $y+$height-$ymarg,
+ $x+$width, $y+$height-$ymarg,
+ $x+$width, $y-$ymarg,
+ $x-$xmarg, $y-$ymarg);
+
+ $this->SetTextAlign($h,$v);
+ $this->SetAngle($olda);
+
+ $this->lastx = $oldx;
+ $this->lasty = $oldy;
+
+ return $bb;
+ }
+
+ // Set text alignment
+ function SetTextAlign($halign,$valign="bottom") {
+ $this->text_halign=$halign;
+ $this->text_valign=$valign;
+ }
+
+ function _StrokeBuiltinFont($x,$y,$txt,$dir,$paragraph_align,&$aBoundingBox,$aDebug=false) {
+
+ if( is_numeric($dir) && $dir!=90 && $dir!=0)
+ JpGraphError::RaiseL(25091);//(" Internal font does not support drawing text at arbitrary angle. Use TTF fonts instead.");
+
+ $h=$this->GetTextHeight($txt);
+ $fh=$this->GetFontHeight();
+ $w=$this->GetTextWidth($txt);
+
+ if( $this->text_halign=="right") {
+ $x -= $dir==0 ? $w : $h;
+ }
+ elseif( $this->text_halign=="center" ) {
+ // For center we subtract 1 pixel since this makes the middle
+ // be prefectly in the middle
+ $x -= $dir==0 ? $w/2-1 : $h/2;
+ }
+ if( $this->text_valign=="top" ) {
+ $y += $dir==0 ? $h : $w;
+ }
+ elseif( $this->text_valign=="center" ) {
+ $y += $dir==0 ? $h/2 : $w/2;
+ }
+
+ $use_font = $this->font_family;
+
+ if( $dir==90 ) {
+ imagestringup($this->img,$use_font,$x,$y,$txt,$this->current_color);
+ $aBoundingBox = array(round($x),round($y),round($x),round($y-$w),round($x+$h),round($y-$w),round($x+$h),round($y));
+ if( $aDebug ) {
+ // Draw bounding box
+ $this->PushColor('green');
+ $this->Polygon($aBoundingBox,true);
+ $this->PopColor();
+ }
+ }
+ else {
+ if( preg_match('/\n/',$txt) ) {
+ $tmp = preg_split('/\n/',$txt);
+ for($i=0; $i < count($tmp); ++$i) {
+ $w1 = $this->GetTextWidth($tmp[$i]);
+ if( $paragraph_align=="left" ) {
+ imagestring($this->img,$use_font,$x,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color);
+ }
+ elseif( $paragraph_align=="right" ) {
+ imagestring($this->img,$use_font,$x+($w-$w1),$y-$h+1+$i*$fh,$tmp[$i],$this->current_color);
+ }
+ else {
+ imagestring($this->img,$use_font,$x+$w/2-$w1/2,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color);
+ }
+ }
+ }
+ else {
+ //Put the text
+ imagestring($this->img,$use_font,$x,$y-$h+1,$txt,$this->current_color);
+ }
+ if( $aDebug ) {
+ // Draw the bounding rectangle and the bounding box
+ $p1 = array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y));
+
+ // Draw bounding box
+ $this->PushColor('green');
+ $this->Polygon($p1,true);
+ $this->PopColor();
+
+ }
+ $aBoundingBox=array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y));
+ }
+ }
+
+ function AddTxtCR($aTxt) {
+ // If the user has just specified a '\n'
+ // instead of '\n\t' we have to add '\r' since
+ // the width will be too muchy otherwise since when
+ // we print we stroke the individually lines by hand.
+ $e = explode("\n",$aTxt);
+ $n = count($e);
+ for($i=0; $i<$n; ++$i) {
+ $e[$i]=str_replace("\r","",$e[$i]);
+ }
+ return implode("\n\r",$e);
+ }
+
+ function NormAngle($a) {
+ // Normalize angle in degrees
+ // Normalize angle to be between 0-360
+ while( $a > 360 )
+ $a -= 360;
+ while( $a < -360 )
+ $a += 360;
+ if( $a < 0 )
+ $a = 360 + $a;
+ return $a;
+ }
+
+ function imagettfbbox_fixed($size, $angle, $fontfile, $text) {
+
+
+ if( ! USE_LIBRARY_IMAGETTFBBOX ) {
+
+ $bbox = @imagettfbbox($size, $angle, $fontfile, $text);
+ if( $bbox === false ) {
+ JpGraphError::RaiseL(25092,$this->font_file);
+ //("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.");
+ }
+ $this->bbox_cache = $bbox;
+ return $bbox;
+ }
+
+ // The built in imagettfbbox is buggy for angles != 0 so
+ // we calculate this manually by getting the bounding box at
+ // angle = 0 and then rotate the bounding box manually
+ $bbox = @imagettfbbox($size, 0, $fontfile, $text);
+ if( $bbox === false ) {
+ JpGraphError::RaiseL(25092,$this->font_file);
+ //("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.");
+ }
+
+ $angle = $this->NormAngle($angle);
+
+ $a = $angle*M_PI/180;
+ $ca = cos($a);
+ $sa = sin($a);
+ $ret = array();
+
+ // We always add 1 pixel to the left since the left edge of the bounding
+ // box is sometimes coinciding with the first pixel of the text
+ //$bbox[0] -= 1;
+ //$bbox[6] -= 1;
+
+ // For roatated text we need to add extra width for rotated
+ // text since the kerning and stroking of the TTF is not the same as for
+ // text at a 0 degree angle
+
+ if( $angle > 0.001 && abs($angle-360) > 0.001 ) {
+ $h = abs($bbox[7]-$bbox[1]);
+ $w = abs($bbox[2]-$bbox[0]);
+
+ $bbox[0] -= 2;
+ $bbox[6] -= 2;
+ // The width is underestimated so compensate for that
+ $bbox[2] += round($w*0.06);
+ $bbox[4] += round($w*0.06);
+
+ // and we also need to compensate with increased height
+ $bbox[5] -= round($h*0.1);
+ $bbox[7] -= round($h*0.1);
+
+ if( $angle > 90 ) {
+ // For angles > 90 we also need to extend the height further down
+ // by the baseline since that is also one more problem
+ $bbox[1] += round($h*0.15);
+ $bbox[3] += round($h*0.15);
+
+ // and also make it slighty less height
+ $bbox[7] += round($h*0.05);
+ $bbox[5] += round($h*0.05);
+
+ // And we need to move the box slightly top the rright (from a tetx perspective)
+ $bbox[0] += round($w*0.02);
+ $bbox[6] += round($w*0.02);
+
+ if( $angle > 180 ) {
+ // And we need to move the box slightly to the left (from a text perspective)
+ $bbox[0] -= round($w*0.02);
+ $bbox[6] -= round($w*0.02);
+ $bbox[2] -= round($w*0.02);
+ $bbox[4] -= round($w*0.02);
+
+ }
+
+ }
+ for($i = 0; $i < 7; $i += 2) {
+ $ret[$i] = round($bbox[$i] * $ca + $bbox[$i+1] * $sa);
+ $ret[$i+1] = round($bbox[$i+1] * $ca - $bbox[$i] * $sa);
+ }
+ $this->bbox_cache = $ret;
+ return $ret;
+ }
+ else {
+ $this->bbox_cache = $bbox;
+ return $bbox;
+ }
+ }
+
+ // Deprecated
+ function GetTTFBBox($aTxt,$aAngle=0) {
+ $bbox = $this->imagettfbbox_fixed($this->font_size,$aAngle,$this->font_file,$aTxt);
+ return $bbox;
+ }
+
+ function GetBBoxTTF($aTxt,$aAngle=0) {
+ // Normalize the bounding box to become a minimum
+ // enscribing rectangle
+
+ $aTxt = $this->AddTxtCR($aTxt);
+
+ if( !is_readable($this->font_file) ) {
+ JpGraphError::RaiseL(25093,$this->font_file);
+ //('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.');
+ }
+ $bbox = $this->imagettfbbox_fixed($this->font_size,$aAngle,$this->font_file,$aTxt);
+
+ if( $aAngle==0 ) return $bbox;
+
+ if( $aAngle >= 0 ) {
+ if( $aAngle <= 90 ) { //<=0
+ $bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1],
+ $bbox[2],$bbox[5],$bbox[6],$bbox[5]);
+ }
+ elseif( $aAngle <= 180 ) { //<= 2
+ $bbox = array($bbox[4],$bbox[7],$bbox[0],$bbox[7],
+ $bbox[0],$bbox[3],$bbox[4],$bbox[3]);
+ }
+ elseif( $aAngle <= 270 ) { //<= 3
+ $bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5],
+ $bbox[6],$bbox[1],$bbox[2],$bbox[1]);
+ }
+ else {
+ $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3],
+ $bbox[4],$bbox[7],$bbox[0],$bbox[7]);
+ }
+ }
+ elseif( $aAngle < 0 ) {
+ if( $aAngle <= -270 ) { // <= -3
+ $bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1],
+ $bbox[2],$bbox[5],$bbox[6],$bbox[5]);
+ }
+ elseif( $aAngle <= -180 ) { // <= -2
+ $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3],
+ $bbox[4],$bbox[7],$bbox[0],$bbox[7]);
+ }
+ elseif( $aAngle <= -90 ) { // <= -1
+ $bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5],
+ $bbox[6],$bbox[1],$bbox[2],$bbox[1]);
+ }
+ else {
+ $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3],
+ $bbox[4],$bbox[7],$bbox[0],$bbox[7]);
+ }
+ }
+ return $bbox;
+ }
+
+ function GetBBoxHeight($aTxt,$aAngle=0) {
+ $box = $this->GetBBoxTTF($aTxt,$aAngle);
+ return abs($box[7]-$box[1]);
+ }
+
+ function GetBBoxWidth($aTxt,$aAngle=0) {
+ $box = $this->GetBBoxTTF($aTxt,$aAngle);
+ return $box[2]-$box[0]+1;
+ }
+
+
+ function _StrokeTTF($x,$y,$txt,$dir,$paragraph_align,&$aBoundingBox,$debug=false) {
+
+ // Setup default inter line margin for paragraphs to be
+ // 3% of the font height.
+ $ConstLineSpacing = 0.03 ;
+
+ // Remember the anchor point before adjustment
+ if( $debug ) {
+ $ox=$x;
+ $oy=$y;
+ }
+
+ if( !preg_match('/\n/',$txt) || ($dir>0 && preg_match('/\n/',$txt)) ) {
+ // Format a single line
+
+ $txt = $this->AddTxtCR($txt);
+ $bbox=$this->GetBBoxTTF($txt,$dir);
+ $width = $this->GetBBoxWidth($txt,$dir);
+ $height = $this->GetBBoxHeight($txt,$dir);
+
+ // The special alignment "basepoint" is mostly used internally
+ // in the library. This will put the anchor position at the left
+ // basepoint of the tetx. This is the default anchor point for
+ // TTF text.
+
+ if( $this->text_valign != 'basepoint' ) {
+ // Align x,y ot lower left corner of bbox
+
+
+ if( $this->text_halign=='right' ) {
+ $x -= $width;
+ $x -= $bbox[0];
+ }
+ elseif( $this->text_halign=='center' ) {
+ $x -= $width/2;
+ $x -= $bbox[0];
+ }
+ elseif( $this->text_halign=='baseline' ) {
+ // This is only support for text at 90 degree !!
+ // Do nothing the text is drawn at baseline by default
+ }
+
+ if( $this->text_valign=='top' ) {
+ $y -= $bbox[1]; // Adjust to bottom of text
+ $y += $height;
+ }
+ elseif( $this->text_valign=='center' ) {
+ $y -= $bbox[1]; // Adjust to bottom of text
+ $y += $height/2;
+ }
+ elseif( $this->text_valign=='baseline' ) {
+ // This is only support for text at 0 degree !!
+ // Do nothing the text is drawn at baseline by default
+ }
+ }
+ ImageTTFText ($this->img, $this->font_size, $dir, $x, $y,
+ $this->current_color,$this->font_file,$txt);
+
+ // Calculate and return the co-ordinates for the bounding box
+ $box = $this->imagettfbbox_fixed($this->font_size,$dir,$this->font_file,$txt);
+ $p1 = array();
+
+ for($i=0; $i < 4; ++$i) {
+ $p1[] = round($box[$i*2]+$x);
+ $p1[] = round($box[$i*2+1]+$y);
+ }
+ $aBoundingBox = $p1;
+
+ // Debugging code to highlight the bonding box and bounding rectangle
+ // For text at 0 degrees the bounding box and bounding rectangle are the
+ // same
+ if( $debug ) {
+ // Draw the bounding rectangle and the bounding box
+
+ $p = array();
+ $p1 = array();
+
+ for($i=0; $i < 4; ++$i) {
+ $p[] = $bbox[$i*2]+$x ;
+ $p[] = $bbox[$i*2+1]+$y;
+ $p1[] = $box[$i*2]+$x ;
+ $p1[] = $box[$i*2+1]+$y ;
+ }
+
+ // Draw bounding box
+ $this->PushColor('green');
+ $this->Polygon($p1,true);
+ $this->PopColor();
+
+ // Draw bounding rectangle
+ $this->PushColor('darkgreen');
+ $this->Polygon($p,true);
+ $this->PopColor();
+
+ // Draw a cross at the anchor point
+ $this->PushColor('red'