<?php
$im = open_image("test.png");
/*
// this failed miserably...
$trans = imagecolorallocatealpha($im,200,200,200,127);
$rotated = imagerotate($im, 30, $trans);
*/
// this is a triumph!
imagerotatealpha($im, 30);
header('Content-type: image/png');
imagepng($im);
// imagerotatealpha($im,$angle) takes the image specified by $im and rotates it $angle degrees counter-clockwise, with unfilled areas alpha transparent
// returns a two-element array with the width and height of the resulting image
function imagerotatealpha(&$im, $angle, $upscale=3) {
$simple = ($angle % 90 == 0)?true:false; // don't want to upscale for simple rotations
$angle = deg2rad($angle);
$w = imagesx($im);
$h = imagesy($im);
if ($upscale > 1 and !$simple) {
// create upscale for sampling
$im_upscaled = imagecreatetruecolor($w*$upscale,$h*$upscale);
imagealphablending($im_upscaled, false);
imagesavealpha($im_upscaled, true);
$trans = imagecolorallocatealpha($im_upscaled,255,255,255,127); // white, fully transparent
imagefill($im_upscaled, 0, 0, $trans);
imagecopyresampled($im_upscaled, $im, 0, 0, 0, 0, $upscale*$w, $upscale*$h, $w, $h);
imagedestroy($im); $im = $im_upscaled;
$w *= $upscale; $h *= $upscale;
}
$rw = round( $w*abs(cos($angle))+abs($h*sin($angle)) );
$rh = round( $w*abs(sin($angle))+abs($h*cos($angle)) );
$cx = ($w-1)/2;
$cy = ($h-1)/2;
$rcx = ($rw-1)/2;
$rcy = ($rh-1)/2;
// new image to hold rotated version
$rotated = imagecreatetruecolor($rw,$rh);
imagealphablending($rotated,false);
imagesavealpha($rotated,true);
$trans = imagecolorallocatealpha($rotated,255,255,255,127); // white, fully transparent
imagefill($rotated, 0, 0, $trans);
// sample the original at the point where the new image would be if rotated the other direction (avoids gaps)
for($y=0; $y < $rh; $y++) {
for($x=0; $x < $rw; $x++) {
$rx = $cx+($x-$rcx)*cos($angle)-($y-$rcy)*sin($angle);
$ry = $cy+($x-$rcx)*sin($angle)+($y-$rcy)*cos($angle);
// if inside bounds of original image, then copy
if($rx<$w and $rx>=0 and $ry<$h and $ry>=0)
imagecopy($rotated,$im,$x,$y,$rx,$ry,1,1); // imagecopy floors the values
}
}
// discard old image
imagedestroy($im);
$im = $rotated;
if ($upscale > 1 and !$simple) {
// now let's downscale our rotated image back to normal
$final_w = round($rw/$upscale);
$final_h = round($rh/$upscale);
$im_final = imagecreatetruecolor($final_w, $final_h);
imagealphablending($im_final, false);
imagesavealpha($im_final, true);
$trans = imagecolorallocatealpha($im_final,255,255,255,127); // white, fully transparent
imagefill($im_final, 0, 0, $trans);
imagecopyresampled($im_final, $im, 0, 0, 0, 0, $final_w, $final_h, $rw, $rh);
// discard rotated upscale
imagedestroy($im);
$im = $im_final;
$rw = $final_w; $rh = $final_h;
}
return array($rw, $rh);
}
/*
//this is a copy of above without the upscale, so it's easier to understand:
// imagerotatealpha($im,$angle) takes the image specified by $im and rotates it $angle degrees counter-clockwise, with unfilled areas alpha transparent
function imagerotatealpha(&$im, $angle) {
$angle = deg2rad($angle);
$w = imagesx($im);
$h = imagesy($im);
$rw = round( $w*abs(cos($angle))+abs($h*sin($angle)) );
$rh = round( $w*abs(sin($angle))+abs($h*cos($angle)) );
$cx = ($w-1)/2;
$cy = ($h-1)/2;
$rcx = ($rw-1)/2;
$rcy = ($rh-1)/2;
$rotated = imagecreatetruecolor($rw,$rh);
imagealphablending($rotated,false);
imagesavealpha($rotated,true);
$trans = imagecolorallocatealpha($rotated,255,255,255,127); // white, fully transparent
imagefill($rotated, 0, 0, $trans);
// sample the original at the point where the new image would be if rotated the other direction (avoids gaps)
for($y=0; $y < $rh; $y++) {
for($x=0; $x < $rw; $x++) {
$rx = $cx+($x-$rcx)*cos($angle)-($y-$rcy)*sin($angle);
$ry = $cy+($x-$rcx)*sin($angle)+($y-$rcy)*cos($angle);
// if not outside bounds of original image, then copy
if($rx<$w and $rx>=0 and $ry<$h and $ry>=0)
imagecopy($rotated,$im,$x,$y,$rx,$ry,1,1); // imagecopy floors the values
}
}
imagedestroy($im);
$im = $rotated;
return array($rw,$rh);
}
*/
// overlay_image($overlaypath,$x,$y) opens the image at $imagepath and overlays it onto $sigimage at position ($x, $y)
// most image types should work, but 24-bit/true color PNG is recommended if you need transparency
function overlay_image($overlaypath,$x=0,$y=0) {
global $sigimage;
$overlay = open_image($overlaypath); // open any image
imagecopy($sigimage, $overlay, $x, $y, 0, 0, imagesx($overlay), imagesy($overlay)); // overlay onto our base image
@imagedestroy($overlay); // clean up memory, since we don't need the overlay image anymore
}
// open_image($path) will load an image into memory so we can work with it, and return an error if we fail
function open_image($path) {
if (!is_string($path)) return $path; // XXX assume binary data is a gd image already
$image = @imagecreatefromstring(file_get_contents($path));
if (!$image) die("could not open image ($path) make sure it exists");
imagealphablending($image,true); imagesavealpha($image,true); // preserve transparency
return $image;
}
?>