2 /*=======================================================================
3 // File: JPGRAPH_GRADIENT.PHP
4 // Description: Create a color gradient
6 // Author: Johan Persson (johanp@aditus.nu)
7 // Ver: $Id: jpgraph_gradient.php,v 1.1 2006/07/07 13:37:14 powles Exp $
9 // Copyright (c) Aditus Consulting. All rights reserved.
10 //========================================================================
13 // Styles for gradient color fill
15 DEFINE("GRAD_VERT",1);
17 DEFINE("GRAD_MIDHOR",3);
18 DEFINE("GRAD_MIDVER",4);
19 DEFINE("GRAD_CENTER",5);
20 DEFINE("GRAD_WIDE_MIDVER",6);
21 DEFINE("GRAD_WIDE_MIDHOR",7);
22 DEFINE("GRAD_LEFT_REFLECTION",8);
23 DEFINE("GRAD_RIGHT_REFLECTION",9);
24 DEFINE("GRAD_RAISED_PANEL",10);
27 //===================================================
29 // Description: Handles gradient fills. This is to be
30 // considered a "friend" class of Class Image.
31 //===================================================
37 function __construct(&$img) {
42 function SetNumColors($aNum) {
43 $this->numcolors
=$aNum;
47 // Produce a gradient filled rectangle with a smooth transition between
49 // ($xl,$yt) Top left corner
50 // ($xr,$yb) Bottom right
51 // $from_color Starting color in gradient
52 // $to_color End color in the gradient
53 // $style Which way is the gradient oriented?
54 function FilledRectangle($xl,$yt,$xr,$yb,$from_color,$to_color,$style=1) {
57 $steps = round(abs($xr-$xl));
58 $delta = $xr>=$xl ?
1 : -1;
59 $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors
);
60 for( $i=0, $x=$xl; $i < $steps; ++
$i ) {
61 $this->img
->current_color
= $colors[$i];
62 $this->img
->Line($x,$yt,$x,$yb);
68 $steps = round(abs($yb-$yt));
69 $delta = $yb>=$yt ?
1 : -1;
70 $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors
);
71 for($i=0,$y=$yt; $i < $steps; ++
$i) {
72 $this->img
->current_color
= $colors[$i];
73 $this->img
->Line($xl,$y,$xr,$y);
79 $steps = round(abs($yb-$yt)/2);
80 $delta = $yb >= $yt ?
1 : -1;
81 $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors
);
82 for($y=$yt, $i=0; $i < $steps; ++
$i) {
83 $this->img
->current_color
= $colors[$i];
84 $this->img
->Line($xl,$y,$xr,$y);
88 if( abs($yb-$yt) %
2 == 1 ) --$steps;
89 for($j=0; $j < $steps; ++
$j, --$i) {
90 $this->img
->current_color
= $colors[$i];
91 $this->img
->Line($xl,$y,$xr,$y);
94 $this->img
->Line($xl,$y,$xr,$y);
98 $steps = round(abs($xr-$xl)/2);
99 $delta = $xr>=$xl ?
1 : -1;
100 $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors
);
101 for($x=$xl, $i=0; $i < $steps; ++
$i) {
102 $this->img
->current_color
= $colors[$i];
103 $this->img
->Line($x,$yb,$x,$yt);
107 if( abs($xr-$xl) %
2 == 1 ) --$steps;
108 for($j=0; $j < $steps; ++
$j, --$i) {
109 $this->img
->current_color
= $colors[$i];
110 $this->img
->Line($x,$yb,$x,$yt);
113 $this->img
->Line($x,$yb,$x,$yt);
116 case GRAD_WIDE_MIDVER
:
117 $diff = round(abs($xr-$xl));
118 $steps = floor(abs($diff)/3);
119 $firststep = $diff - 2*$steps ;
120 $delta = $xr >= $xl ?
1 : -1;
121 $this->GetColArray($from_color,$to_color,$firststep,$colors,$this->numcolors
);
122 for($x=$xl, $i=0; $i < $firststep; ++
$i) {
123 $this->img
->current_color
= $colors[$i];
124 $this->img
->Line($x,$yb,$x,$yt);
128 $this->img
->current_color
= $colors[$i];
129 for($j=0; $j< $steps; ++
$j) {
130 $this->img
->Line($x,$yb,$x,$yt);
134 for($j=0; $j < $steps; ++
$j, --$i) {
135 $this->img
->current_color
= $colors[$i];
136 $this->img
->Line($x,$yb,$x,$yt);
141 case GRAD_WIDE_MIDHOR
:
142 $diff = round(abs($yb-$yt));
143 $steps = floor(abs($diff)/3);
144 $firststep = $diff - 2*$steps ;
145 $delta = $yb >= $yt?
1 : -1;
146 $this->GetColArray($from_color,$to_color,$firststep,$colors,$this->numcolors
);
147 for($y=$yt, $i=0; $i < $firststep; ++
$i) {
148 $this->img
->current_color
= $colors[$i];
149 $this->img
->Line($xl,$y,$xr,$y);
153 $this->img
->current_color
= $colors[$i];
154 for($j=0; $j < $steps; ++
$j) {
155 $this->img
->Line($xl,$y,$xr,$y);
158 for($j=0; $j < $steps; ++
$j, --$i) {
159 $this->img
->current_color
= $colors[$i];
160 $this->img
->Line($xl,$y,$xr,$y);
165 case GRAD_LEFT_REFLECTION
:
166 $steps1 = round(0.3*abs($xr-$xl));
167 $delta = $xr>=$xl ?
1 : -1;
169 $from_color = $this->img
->rgb
->Color($from_color);
171 $m = ($adj-1.0)*(255-min(255,min($from_color[0],min($from_color[1],$from_color[2]))));
172 $from_color2 = array(min(255,$from_color[0]+
$m),
173 min(255,$from_color[1]+
$m), min(255,$from_color[2]+
$m));
175 $this->GetColArray($from_color2,$to_color,$steps1,$colors,$this->numcolors
);
177 for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++
$i) {
178 $this->img
->current_color
= $colors[$i];
179 $this->img
->Line($x,$yb,$x,$yt);
182 $steps2 = max(1,round(0.08*abs($xr-$xl)));
183 $this->img
->SetColor($to_color);
184 for($j=0; $j< $steps2; ++
$j) {
185 $this->img
->Line($x,$yb,$x,$yt);
188 $steps = abs($xr-$xl)-$steps1-$steps2;
189 $this->GetColArray($to_color,$from_color,$steps,$colors,$this->numcolors
);
191 for($i=0; $i < $steps && $i < $n; ++
$i) {
192 $this->img
->current_color
= $colors[$i];
193 $this->img
->Line($x,$yb,$x,$yt);
198 case GRAD_RIGHT_REFLECTION
:
199 $steps1 = round(0.7*abs($xr-$xl));
200 $delta = $xr>=$xl ?
1 : -1;
202 $this->GetColArray($from_color,$to_color,$steps1,$colors,$this->numcolors
);
204 for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++
$i) {
205 $this->img
->current_color
= $colors[$i];
206 $this->img
->Line($x,$yb,$x,$yt);
209 $steps2 = max(1,round(0.08*abs($xr-$xl)));
210 $this->img
->SetColor($to_color);
211 for($j=0; $j< $steps2; ++
$j) {
212 $this->img
->Line($x,$yb,$x,$yt);
216 $from_color = $this->img
->rgb
->Color($from_color);
218 $m = ($adj-1.0)*(255-min(255,min($from_color[0],min($from_color[1],$from_color[2]))));
219 $from_color = array(min(255,$from_color[0]+
$m),
220 min(255,$from_color[1]+
$m), min(255,$from_color[2]+
$m));
222 $steps = abs($xr-$xl)-$steps1-$steps2;
223 $this->GetColArray($to_color,$from_color,$steps,$colors,$this->numcolors
);
225 for($i=0; $i < $steps && $i < $n; ++
$i) {
226 $this->img
->current_color
= $colors[$i];
227 $this->img
->Line($x,$yb,$x,$yt);
233 $steps = ceil(min(($yb-$yt)+
1,($xr-$xl)+
1)/2);
234 $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors
);
237 $x=$xl;$y=$yt;$x2=$xr;$y2=$yb;
239 for($x=$xl, $i=0; $x < $xl+
$dx && $y < $yt+
$dy && $i < $n; ++
$x, ++
$y, --$x2, --$y2, ++
$i) {
240 $this->img
->current_color
= $colors[$i];
241 $this->img
->Rectangle($x,$y,$x2,$y2);
243 $this->img
->Line($x,$y,$x2,$y2);
246 case GRAD_RAISED_PANEL
:
249 $delta = $xr>=$xl ?
1 : -1;
250 $this->GetColArray($to_color,$from_color,$steps1,$colors,$this->numcolors
);
252 for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++
$i) {
253 $this->img
->current_color
= $colors[$i];
254 $this->img
->Line($x,$yb,$x,$yt);
264 $delta = $xr>=$xl ?
1 : -1;
265 for($x=$xl, $j=$steps2; $j >= 0; --$j) {
266 $this->img
->current_color
= $colors[$j];
267 $this->img
->Line($x,$yb,$x,$yt);
273 JpGraphError
::RaiseL(7001,$style);
274 //("Unknown gradient style (=$style).");
279 // Fill a special case of a polygon with a flat bottom
280 // with a gradient. Can be used for filled line plots.
281 // Please note that this is NOT a generic gradient polygon fill
282 // routine. It assumes that the bottom is flat (like a drawing
284 function FilledFlatPolygon($pts,$from_color,$to_color) {
285 if( count($pts) == 0 ) return;
290 for( $i=0, $idx=0; $i < $n; $i +
= 2) {
291 $x = round($pts[$i]);
292 $y = round($pts[$i+
1]);
293 $miny = min($miny,$y);
294 $maxy = max($maxy,$y);
298 $this->GetColArray($from_color,$to_color,abs($maxy-$miny)+
1,$colors,$this->numcolors
);
299 for($i=$miny, $idx=0; $i <= $maxy; ++
$i ) {
300 $colmap[$i] = $colors[$idx++
];
305 while( $idx < $n-1 ) {
306 $p1 = array(round($pts[$idx*2]),round($pts[$idx*2+
1]));
307 $p2 = array(round($pts[++
$idx*2]),round($pts[$idx*2+
1]));
309 // Find the largest rectangle we can fill
310 $y = max($p1[1],$p2[1]) ;
311 for($yy=$maxy; $yy > $y; --$yy) {
312 $this->img
->current_color
= $colmap[$yy];
313 $this->img
->Line($p1[0],$yy,$p2[0]-1,$yy);
316 if( $p1[1] == $p2[1] ) continue;
318 // Fill the rest using lines (slow...)
319 $slope = ($p2[0]-$p1[0])/($p1[1]-$p2[1]);
323 if( $p1[1] > $p2[1] ) {
324 while( $y >= $p2[1] ) {
325 $x1=$slope*($start-$y)+
$p1[0];
326 $this->img
->current_color
= $colmap[$y];
327 $this->img
->Line($x1,$y,$x2,$y);
332 while( $y >= $p1[1] ) {
333 $x2=$p2[0]+
$slope*($start-$y);
334 $this->img
->current_color
= $colmap[$y];
335 $this->img
->Line($x1,$y,$x2,$y);
344 // Add to the image color map the necessary colors to do the transition
345 // between the two colors using $numcolors intermediate colors
346 function GetColArray($from_color,$to_color,$arr_size,&$colors,$numcols=100) {
347 if( $arr_size==0 ) return;
348 // If color is given as text get it's corresponding r,g,b values
349 $from_color = $this->img
->rgb
->Color($from_color);
350 $to_color = $this->img
->rgb
->Color($to_color);
352 $rdelta=($to_color[0]-$from_color[0])/$numcols;
353 $gdelta=($to_color[1]-$from_color[1])/$numcols;
354 $bdelta=($to_color[2]-$from_color[2])/$numcols;
355 $colorsperstep = $numcols/$arr_size;
357 $from_alpha = $from_color[3];
358 $to_alpha = $to_color[3];
359 $adelta = ( $to_alpha - $from_alpha ) / $numcols ;
360 for ($i=0; $i < $arr_size; ++
$i) {
361 $colnum = floor($colorsperstep*$i);
362 if ( $colnum == $prevcolnum )
363 $colors[$i] = $colidx;
365 $r = floor($from_color[0] +
$colnum*$rdelta);
366 $g = floor($from_color[1] +
$colnum*$gdelta);
367 $b = floor($from_color[2] +
$colnum*$bdelta);
368 $alpha = $from_alpha +
$colnum*$adelta;
369 $colidx = $this->img
->rgb
->Allocate(sprintf("#%02x%02x%02x",$r,$g,$b),$alpha);
370 $colors[$i] = $colidx;
372 $prevcolnum = $colnum;