Dynamically drawing gradients with PHP

by Richard Bradshaw

Just a little script to create a PNG image of a simple linear gradient using PHP. You could adapt this to make it better in many ways! Insipired (by which I mean 99% ripped of!) by http://www.cutcodedown.com/

No demo to avoid load on the server, but it just makes a simple gradient.

I use it as a fallback for CSS3 gradients.

<?php
/* Put on a server, make the gradients folder, then call like so:
 
gradient.php?sc=ff0000&ec=0000ff&h=100&w=200
 
sc = start colour, ec = end colour, h = height, w = width.
 
The file should be cached, though I normally use mod_rewrite to tidy it up a little.
*/
 
/* Change this to suit, you'll need to make the folder first */
$destfolder = $_SERVER[ 'DOCUMENT_ROOT' ]."/gradients/";
 
function caching_headers ($file, $timestamp) {
	$gmt_mtime = gmdate('r', $timestamp);
	header('ETag: "'.md5($timestamp.$file).'"');
 
	if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
		if ($_SERVER['HTTP_IF_MODIFIED_SINCE'] == $gmt_mtime || str_replace('"', '', stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])) == md5($timestamp.$file)) {
			header('HTTP/1.1 304 Not Modified');
			exit();
		}
	}
 
	header('Last-Modified: '.$gmt_mtime);
	header('Cache-Control: public');
}
 
function gradient($width,$height,$startColor,$endColor) {
	$final=imagecreatetruecolor($width,$height);
 
	$r=($startColor >> 16) & 0xFF;
	$g=($startColor >> 8) & 0xFF;
	$b=($startColor) & 0xFF;
 
	if ($height==0) {
		imagefill($final,0,0,imagecolorallocate($final,$r,$g,$b));
	} else {
 
		$endR=($endColor >> 16) & 0xFF;
		$endG=($endColor >> 8) & 0xFF;
		$endB=($endColor) & 0xFF;
 
		$incR=($endR-$r);
		$incG=($endG-$g);
		$incB=($endB-$b);
 
		$absDisR=abs($incR);
		$absDisG=abs($incG);
		$absDisB=abs($incB);
 
		if ($absDisR>$absDisG) {
			if ($absDisR>$absDisB) {
				$distance=$absDisR;
			} else {
				$distance=$absDisB;
			}
		} else if ($absDisG>$absDisB) {
			$distance=$absDisG;
		} else {
			$distance=$absDisB;
		}
 
		if ($distance==0) {
			imagefill($final,0,0,imagecolorallocate($final,$r,$g,$b));
		} else {
			if ($distance>$height) $distance=$height;
 
			$sliver=imagecreatetruecolor(1,$distance);
			$sliverMax=$distance-1;
 
			$incR/=$sliverMax;
			$incG/=$sliverMax;
			$incB/=$sliverMax;
 
			$style=array();
 
			for ($t=0; $t<$distance; $t++) {
				$style[$t]=imagecolorallocate($sliver,$r,$g,$b);
				$r+=$incR;
				$g+=$incG;
				$b+=$incB;
			}
 
			imagesetstyle($sliver,$style);
			imageline($sliver,0,0,0,$sliverMax,IMG_COLOR_STYLED);
			imagecopyresized(
				$final,$sliver,
				0,0,0,0,
				$width,$height,1,$distance
			);
			imagedestroy($sliver);
		}
	}
	return $final;
}
 
/* This bit isn't really very good, but you get the idea. */
$width=is_numeric(str_replace("px","",$_GET['w'])) ? $_GET['w'] : 96;
$height=is_numeric(str_replace("px","",$_GET['h'])) ? $_GET['h'] : 96;
$startColor=empty($_GET['sc']) ? 0 : hexdec($_GET['sc']);
$endColor=empty($_GET['ec']) ? 0xFFFFFF : hexdec($_GET['ec']);
 
$filename = $width."_".$height."_".$_GET['sc']."_".$_GET['ec'].".png";
 
if (!file_exists($destfolder.$filename)) {
	$image=gradient($width,$height,$startColor,$endColor);
	imagepng($image,$destfolder.$filename);
	imagedestroy($image);
}
 
caching_headers ($filename, filemtime($destfolder.$filename));
 
header('Parameters : '.$_GET['w']."x".$_GET['h']." ".$_GET['sc']." to ".$_GET['ec']);
header('Content-Type: image/png');
 
$image = imagecreatefrompng($destfolder.$filename);	
imagepng($image);
imagedestroy($image);
 
?>

Related Posts