Monday, 29 March 2010

Set Perspective of an Image Using PHP GD

To set the perspective of an image (i.e make one side appear further away from the other in a isosceles trapezoid)

You could use a library like ImageMagick but I personally think that installing too many libraries takes up too much memory and cpu so I wrote my own function.

To keep it looking smooth, it enlarges the image by 5 (see $mult) and copies each column to a new image at the required size. It then shrinks the image back down to the original size.

With bigger images you will need to set $mult to a smaller integer, as it could use a lot of memory but with smaller images it works fine



$i is the image to be manipulated
$gradient is the gradient as percentage - (0.01 - 0.99)
$rightdown if true the right hand side comes down otherwise the left side.
$background rgb background color 0xFFFFFF is white 0x000000 is black.

function perspective($i,$gradient=0.85,$rightdown=true,$background=0xFFFFFF) {
$mult=5;
$w=imagesx($i);
$h=imagesy($i);
$image=imagecreatetruecolor($w*$mult,$h*$mult);
imagecopyresized($image,$i,0,0,0,0,$w*$mult,$h*$mult,$w,$h);
imagedestroy($i);
$w*=$mult;
$h*=$mult;
$im=imagecreatetruecolor($w,$h);
$background=imagecolorallocate($im,($background>>16)&0xFF,($background>>8)&0xFF,$background&0xFF);
imagefill($im,0,0,$background);
imageantialias($im,true);
$nh=$h-($h*$gradient);
for ($x=0; $x<$w; $x++) {
 $ni=(($rightdown) ? $x : $w-$x);
 $p=intval($h-(($ni/$w)*$nh));
 if (($p%2)<>0)
  $p-=1;
 $nx=intval(($p-$h)/2);
 imagecopyresampled($im,$image,$x,0,$x,$nx,1,$p,1,$h-1);
 imageline($im,$x,0,$x,-$nx-1,$background);
 imageline($im,$x,$h-1,$x,$h+$nx,$background);
}
imagedestroy($image);
imagefilter($im,IMG_FILTER_SMOOTH,10);
$i=imagecreatetruecolor($w/$mult,$h/$mult);
imageantialias($i,true);
imagecopyresampled($i,$im,0,0,0,0,$w,$h,$w*$mult,$h*$mult);
imagedestroy($im);
return $i;
}