views:

260

answers:

2

I found the following function can draw a vertical gradient in PHP. However, many web designers like their gradients to have an upper-left lightsource to make the gradient look more realistic. So, how do I change the angle slightly on the vertical gradient, making it into a slight gradient? I don't want to completely overdo it, but just a slight movement to the right as it proceeds down the vertical gradient.

<?php

function hex2rgb($sColor) {
    $sColor = str_replace('#','',$sColor);
    $nLen = strlen($sColor) / 3;
    $anRGB = array();
    $anRGB[]=hexdec(str_repeat(substr($sColor,0,$nLen),2/$nLen));
    $anRGB[]=hexdec(str_repeat(substr($sColor,$nLen,$nLen),2/$nLen));
    $anRGB[]=hexdec(str_repeat(substr($sColor,2*$nLen,$nLen),2/$nLen));
    return $anRGB;
}

$nWidth = 960;
$nHeight = 250;
$sStartColor = '#2b8ae1';
$sEndColor = '#0054a1';
$nStep = 1;

$hImage = imagecreatetruecolor($nWidth,$nHeight);
$nRows = imagesy($hImage);
$nCols = imagesx($hImage);
list($r1,$g1,$b1) = hex2rgb($sStartColor);
list($r2,$g2,$b2) = hex2rgb($sEndColor);
$nOld_r = 0; $nOld_g = 0; $nOld_b = 0;
for ( $i = 0; $i < $nRows; $i=$i+1+$nStep ) {
    $r = ( $r2 - $r1 != 0 ) ? intval( $r1 + ( $r2 - $r1 ) * ( $i / $nRows ) ): $r1;
    $g = ( $g2 - $g1 != 0 ) ? intval( $g1 + ( $g2 - $g1 ) * ( $i / $nRows ) ): $g1;
    $b = ( $b2 - $b1 != 0 ) ? intval( $b1 + ( $b2 - $b1 ) * ( $i / $nRows ) ): $b1;
    if ( "$nOld_r,$nOld_g,$nOld_b" != "$r,$g,$b") {
        $hFill = imagecolorallocate( $hImage, $r, $g, $b );
    }
    imagefilledrectangle($hImage, 0, $i, $nCols, $i+$nStep, $hFill);
    $nOld_r= $r;
    $nOld_g= $g;
    $nOld_b= $b;
}
header("Content-type: image/png");
imagepng($hImage);
+1  A: 

I'm not going to do the geometry - but create the vertical gradient as a larger image then rotate and crop it:

...
$degrees = -5;
$newImage = imagecreatetruecolor($nWidth, $nHeight);
$rotated = imagerotate($hImage, $degrees, 0);
imagecopy($newImage, $rotated, 0, 0, $x, $y, $width, $height)
thetaiko
imagerotate() is not there for me on PHP 5.2.4. It says on the php.net page for this function that it is one of the GD library functions that has a memory leak and is not included with Ubuntu (which is what I'm running). Got another option?
Volomike
http://www.php.net/manual/en/function.imagerotate.php#93151I've never used this function - but someone has posted an alternate imageRotate function to solve this problem that looks quite promising.
thetaiko
I tried many of those and found that imagerotateEquivalent() did the trick! Thanks, thetaiko.
Volomike
Just wanted to add to thetaiko's advice that if I make $nWidth and $nHeight double their size at first (at the top of my code), then set $x to 25 and $y to 171 in his code, then $width and $height in his code to half of $nWidth and $nHeight, it resolves this problem 100% using imagerotateEquivalent.
Volomike
This isn't thread-safe, but PHP can shell out and do this command on Linux if ImageMagick is installed: convert -size 1000x400 gradient:#bfb-#4b4 -rotate -5 +repage -crop '960x250+25+100' greenbar.png. However, PHP does have an ImageMagick extension to do this internally.
Volomike
A: 

The following snippet runs much faster than the GD libraries and without the complexity. You have to install the ImageMagick extension for PHP, though.

$oImage = new Imagick();
$oImage->newPseudoImage(1000, 400, 'gradient:#09F-#048' );
$oImage->rotateImage(new ImagickPixel(), -3);
$oImage->cropImage(960, 250, 25, 100);
$oImage->setImageFormat('png');
header( "Content-Type: image/png" );
echo $oImage;
Volomike