imagerotate
(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)
imagerotate — 指定された角度で画像を回転する
説明
画像 image
を、
angle
で指定された角度だけ回転します。
回転の中心は画像の中心です。 回転後の画像の大きさは、もとの大きさと異なる可能性があります。
パラメータ
image
imagecreatetruecolor()のような画像作成関数が返す GdImage オブジェクト。
angle
-
回転角度。これは、画像を反時計回りに回転させるときの度数を表します。
background_color
-
回転後、カバーされない部分の色。
戻り値
回転させた画像オブジェクトを返します。失敗した場合に false
を返します。
変更履歴
バージョン | 説明 |
---|---|
8.3.0 |
使われていなかった ignore_transparent が、完全に削除されました。
|
8.0.0 | 成功時には、 この関数は GDImage クラスのインスタンスを返すようになりました。 これより前のバージョンでは、 resource を返していました。 |
8.0.0 |
image は、
GdImage
クラスのインスタンスを期待するようになりました。
これより前のバージョンでは、有効な gd resource が期待されていました。
|
8.0.0 |
使われていなかった
ignore_transparent は、
bool を期待するようになりました。
これより前のバージョンでは、数値型を期待していました。
|
例
例1 画像を 180 度回転する
この例は、画像を 180 度 - 上下逆さまに回転します
<?php
// ファイルと回転角
$filename = 'test.jpg';
$degrees = 180;
// コンテントタイプ
header('Content-type: image/jpeg');
// 読み込み
$source = imagecreatefromjpeg($filename);
// 回転
$rotate = imagerotate($source, $degrees, 0);
// 出力
imagejpeg($rotate);
// メモリの解放
imagedestroy($source);
imagedestroy($rotate);
?>
上の例の出力は、 たとえば以下のようになります。
注意
注意:
この関数は、imagesetinterpolation() で設定した補間方式の影響を受けます。
参考
- imagesetinterpolation() - 補間方法を設定する
+add a note
User Contributed Notes 38 notes
meisterix at gmx dot com ¶
12 years ago
After some INet searches and personal try-and-failures I succeed to rotate PNG images with preserving alpha channel transparency (semi transparency).
<?php
$filename = 'YourFile.png';
$rotang = 20; // Rotation angle
$source = imagecreatefrompng($filename) or die('Error opening file '.$filename);
imagealphablending($source, false);
imagesavealpha($source, true);
$rotation = imagerotate($source, $rotang, imageColorAllocateAlpha($source, 0, 0, 0, 127));
imagealphablending($rotation, false);
imagesavealpha($rotation, true);
header('Content-type: image/png');
imagepng($rotation);
imagedestroy($source);
imagedestroy($rotation);
?>
Mike Knoop ¶
15 years ago
Don't be tricked into thinking this function will rotate the image resource handle in-place. While the documentation currently doesn't specify and return values, I've found the following return values to be true:
"Returns an image resource identifier on success, FALSE on errors. "
Simply make sure you're doing something like...
<?php
$rotated_img = imagerotate($src_img, 45, $color)
?>
-Mike
henzeberkheij at gmail dot com ¶
12 years ago
Keep in mind this function rotates counterclockwise. if you want to go 90 degrees clockwise, you have to tell imagerotate to go 270 degrees counter-clockwise.
$angle = 360-$angle;
xavtak at gmail dot com ¶
14 years ago
I've benchmarked three methods described here for rotating an image.
I used a 1600 x 1200 jpeg picture that was duplicated ten times on the disk. I looped through them to apply a CW rotation using either method.
First algorithm (the "imagesetpixel" algorithm):
<?php
function CWRotation($image)
{
$w = imagesx($image);
$h = imagesy($image);
$result = @imagecreatetruecolor($h, $w);
if($result)
{
for ($i = 0; $i < $w; $i++)
for ($j = 0; $j < $h; $j++)
{
$ref = imagecolorat($image, $i, $j);
imagesetpixel($result, ($h - 1) - $j, $i, $ref);
}
}
return $result;
}
?>
Second algorithm (the "imagecopy" algorithm):
<?php
function CWRotation($image)
{
$w = imagesx($image);
$h = imagesy($image);
$result = @imagecreatetruecolor($h, $w);
if($result)
{
for ($i = 0; $i < $w; $i++)
for ($j = 0; $j < $h; $j++)
imagecopy($result, $image, ($h - 1) - $j, $i, $i, $j, 1, 1);
}
return $result;
}
?>
Third algorithm (the "imagerotate" algorithm):
<?php
function CWRotation($image)
{
return imagerotate($image, 270, 0);
}
?>
In each step of the loop, the image is loaded, rotated then a copy is written on the disk.
Here are the results:
imagesetpixel algorithm: the 10 pictures were processed in 29 seconds
imagecopy algorithm: the 10 pictures were processed in 26 seconds
imagerotate algorithm: the 10 pictures were processed in 2 seconds (no typo here)
Writing the pictures on the disk allowed me to control the results. Every resulting picture was the same (tested with winmerge).
Conclusion: imagerotate is way faster than other "home-made" algorithms.
I ran the tests several times to see if the difference between imagesetpixel and imagecopy was introduced by my computer's independent activity, but I always got that 10% difference.
Note: the picture I used was taken from a camera, so no transparency was involved.
I ran the tests on Windows XP using PHP Version 5.3.0
xarris_ at hotmail dot com ¶
9 years ago
An issue with imagerotate() is it might need more memory than what is available. It was failing in my script so I tried to increase it with ini_set('memory_limit', '256M')
and everything works fine now.
joseluis at pellicer dot org ¶
16 years ago
About that rotating function by david at horizon-nigh not working, I found the bug.
I noticed that the x1 and y1 where not used, so, in the loop through every pixel and transform it, change
$x2 = $x * cos($theta) - $y * sin($theta);
$y2 = $x * sin($theta) + $y * cos($theta);
to:
$x2 = $x1 * cos($theta) - $y1 * sin($theta);
$y2 = $x1 * sin($theta) + $y1 * cos($theta);
kmrohe at letsco dot de ¶
14 years ago
As an alternative to the GD rotateImage() function, this is an easy way to rotate images by 90 degrees ccw *without* loosing transparency:
<?php
function rotateImage($image) {
$width = imagesx($image);
$height = imagesy($image);
$newImage= imagecreatetruecolor($height, $width);
imagealphablending($newImage, false);
imagesavealpha($newImage, true);
for($w=0; $w<$width; $w++)
for($h=0; $h<$height; $h++) {
$ref = imagecolorat($image, $w, $h);
imagesetpixel($newImage, $h, ($width-1)-$w, $ref);
}
return $newImage;
}
?>
krteczek01 at gmail dot com ¶
15 years ago
Hi, I've rewrote function to class with static methods. Advantage of this solution is ability to be called several times during script execution.
<?php
/*
Unfinished imagerotate replacement. ignore_transparent is, well, ignored. :)
Also, should have some standard functions for 90, 180 and 270 degrees, since they are quite
easy to implement faster.
*/
if(!function_exists("imagerotate")) {
function imagerotate(&$srcImg, $angle, $bgcolor, $ignore_transparent = 0) {
return imagerotateEquivalent::rotate(&$srcImg, $angle, $bgcolor, $ignore_transparent);
}
}
class imagerotateEquivalent {
static private function rotateX($x, $y, $theta){
return $x * cos($theta) - $y * sin($theta);
}
static private function rotateY($x, $y, $theta){
return $x * sin($theta) + $y * cos($theta);
}
public static function rotate(&$srcImg, $angle, $bgcolor, $ignore_transparent = 0) {
$srcw = imagesx($srcImg);
$srch = imagesy($srcImg);
if($angle == 0) return $srcImg;
// Convert the angle to radians
$theta = deg2rad ($angle);
// Calculate the width of the destination image.
$temp = array ( self::rotateX(0, 0, 0-$theta),
self::rotateX($srcw, 0, 0-$theta),
self::rotateX(0, $srch, 0-$theta),
self::rotateX($srcw, $srch, 0-$theta)
);
$minX = floor(min($temp));
$maxX = ceil(max($temp));
$width = $maxX - $minX;
// Calculate the height of the destination image.
$temp = array ( self::rotateY(0, 0, 0-$theta),
self::rotateY($srcw, 0, 0-$theta),
self::rotateY(0, $srch, 0-$theta),
self::rotateY($srcw, $srch, 0-$theta)
);
$minY = floor(min($temp));
$maxY = ceil(max($temp));
$height = $maxY - $minY;
$destimg = imagecreatetruecolor($width, $height);
imagefill($destimg, 0, 0, imagecolorallocate($destimg, 0,255, 0));
// sets all pixels in the new image
for($x=$minX;$x<$maxX;$x++) {
for($y=$minY;$y<$maxY;$y++)
{
// fetch corresponding pixel from the source image
$srcX = round(self::rotateX($x, $y, $theta));
$srcY = round(self::rotateY($x, $y, $theta));
if($srcX >= 0 && $srcX < $srcw && $srcY >= 0 && $srcY < $srch)
{
$color = imagecolorat($srcImg, $srcX, $srcY );
}
else
{
$color = $bgcolor;
}
imagesetpixel($destimg, $x-$minX, $y-$minY, $color);
}
}
return $destimg;
}
}
?>
AJenbo ¶
16 years ago
I modified cbl25's function to allow it to rotate an image either clock wise or counter clock wise.
<?php
function rotateImage($image, $direction) {
$direction = strtolower($direction);
$degrees = $direction == 'cw' ? 270 : ($direction == 'ccw' ? 90 : NULL);
if(!$degrees)
return $image;
$width = imagesx($image);
$height = imagesy($image);
$side = $width > $height ? $width : $height;
$imageSquare = imagecreatetruecolor($side, $side);
imagecopy($imageSquare, $image, 0, 0, 0, 0, $width, $height);
imagedestroy($image);
$imageSquare = imagerotate($imageSquare, $degrees, 0, -1);
$image = imagecreatetruecolor($height, $width);
$x = $degrees == 90 ? 0 : ($height > $width ? 0 : ($side - $height));
$y = $degrees == 270 ? 0 : ($height < $width ? 0 : ($side - $width));
imagecopy($image, $imageSquare, 0, 0, $x, $y, $height, $width);
imagedestroy($imageSquare);
return $image;
}
//Usage
$image = rotateImage($image, 'cw');
$image = rotateImage($image, 'ccw');
?>
shaun at slickdesign dot com dot au ¶
7 years ago
The angle in imagerotate() is the number of degrees to rotate the image anti-clockwise, but while it may seem natural to use '-90' to turn an image 90 degrees clockwise, the end result may appear on a slight angle, and may cause the rotated image to appear slightly blurred with a background or border. Excessively large angles may also present sampling issues.
The easiest way to prevent these, is to ensure all angles are between 0 and 360.
<?php
while ( $angle < 0 ) { $angle += 360; }
while ( $angle >= 360 ) { $angle -= 360; }
$rotated = imagerotate( $image, $angle, $color );
?>
anon at here dot com ¶
15 years ago
I was quite surprised to see that no one had done any working rotate function. And since I needed one for my web hotel, I whipped this one up. Someone might want to expand it so that it matches imagerotate.
Also, does imagerotate really rotate things counter clockwise? Otherwise this should also be changed.
<?php
if(!function_exists("imagerotate")) {
function imagerotate(&$srcImg, $angle, $bgcolor, $ignore_transparent = 0) {
return imagerotateEquivalent(&$srcImg, $angle, $bgcolor, $ignore_transparent);
}
}
/*
Unfinished imagerotate replacement. ignore_transparent is, well, ignored. :)
Also, should have some standard functions for 90, 180 and 270 degrees, since they are quite
easy to implement faster.
*/
function imagerotateEquivalent(&$srcImg, $angle, $bgcolor, $ignore_transparent = 0)
{
function rotateX($x, $y, $theta){
return $x * cos($theta) - $y * sin($theta);
}
function rotateY($x, $y, $theta){
return $x * sin($theta) + $y * cos($theta);
}
$srcw = imagesx($srcImg);
$srch = imagesy($srcImg);
if($angle == 0) return $srcImg;
// Convert the angle to radians
$theta = deg2rad ($angle);
// Calculate the width of the destination image.
$temp = array ( rotateX(0, 0, 0-$theta),
rotateX($srcw, 0, 0-$theta),
rotateX(0, $srch, 0-$theta),
rotateX($srcw, $srch, 0-$theta)
);
$minX = floor(min($temp));
$maxX = ceil(max($temp));
$width = $maxX - $minX;
// Calculate the height of the destination image.
$temp = array ( rotateY(0, 0, 0-$theta),
rotateY($srcw, 0, 0-$theta),
rotateY(0, $srch, 0-$theta),
rotateY($srcw, $srch, 0-$theta)
);
$minY = floor(min($temp));
$maxY = ceil(max($temp));
$height = $maxY - $minY;
$destimg = imagecreatetruecolor($width, $height);
imagefill($destimg, 0, 0, imagecolorallocate($destimg, 0,255, 0));
// sets all pixels in the new image
for($x=$minX;$x<$maxX;$x++) {
for($y=$minY;$y<$maxY;$y++)
{
// fetch corresponding pixel from the source image
$srcX = round(rotateX($x, $y, $theta));
$srcY = round(rotateY($x, $y, $theta));
if($srcX >= 0 && $srcX < $srcw && $srcY >= 0 && $srcY < $srch)
{
$color = imagecolorat($srcImg, $srcX, $srcY );
}
else
{
$color = $bgcolor;
}
imagesetpixel($destimg, $x-$minX, $y-$minY, $color);
}
}
return $destimg;
}
?>
sjef at bosman dot fr ¶
15 years ago
I wanted to draw a transparent GIF-image and show it on a page, at an angle specified in the URL:
<img src="image.php?angle=90" type="image/gif">
I used the native imagerotate() but at angles of 90, 180, etc. the old background colour would become non-transparent. Apparently, there's a bug somewhere in GD, and has been for ages.
My solution below:
<?php
$height = 100;
$width = 100;
$lsize= $width/2;
$angle= $_GET["angle"];
// avoid the bug:
if(($angle%90)==0)
$angle+= 0.001;
$image_p = imagecreatetruecolor($width, $height);
$trans = imagecolorallocate($image_p, 254, 0, 0);
imagefill($image_p, 0, 0, $trans);
imagecolortransparent($image_p, $trans);
$black = imagecolorallocate($image_p, 1, 1, 1);
$red = imagecolorallocate($image_p, 255, 0, 0);
$white = imagecolorallocate($image_p, 255, 255, 255);
// draw something here
imageline($image_p, 3, $lsize, $lsize/2, $lsize, $black);
$image_r= imagerotate($image_p, -$angle, $trans, 0);
$w= imagesx($image_r);
$h= imagesy($image_r);
$image_s = imagecreatetruecolor($width, $height);
imagecopyresized($image_s, $image_r, 0, 0, ($w-$width)/2, ($h-$height)/2, $width, $height, $width, $height);
$trans = imagecolorallocate($image_s, 254, 0, 0);
imagecolortransparent($image_s, $trans);
imagegif($image_s);
?>
david at horizon-nigh dot org ¶
16 years ago
I couldn't get the replacements from 'the dot thawk' or 'pilot' to work for some reason, so here's my own replacement. It uses ImageMagick; binary must be installed, and you may need to modify the search path. (I didn't use PHP's ImageMagick support for my own reasons.)
<?php
/**
* imagerotate()
* Debian php5-gd packages do not include imagerotate() due to some convoluted reason.
*
* @param int $angle - same as PHP builtin function
* @param $bgd_color - not implemented, apparently always #FFFFFF
*
* @return same as PHP builtin function
*/
if ( !function_exists( 'imagerotate' ) ) {
function imagerotate( $source_image, $angle, $bgd_color ) {
$angle = 360-$angle; // GD rotates CCW, imagick rotates CW
foreach ( array( '/usr/bin', '/usr/local/bin', '/opt/local/bin', '/sw/bin' ) as $path ) {
if ( file_exists( $path . '/convert' ) ) {
$imagick = $path . '/convert';
if ( $path == '/opt/local/bin' ) {
$imagick = 'DYLD_LIBRARY_PATH="" ' . $imagick; // some kind of conflict with MacPorts and MAMP
}
break;
}
}
if ( !isset( $imagick ) ) {
//trigger_error( 'imagerotate(): could not find imagemagick binary, original image returned', E_USER_WARNING );
return $source_image;
}
$file1 = '/tmp/imagick_' . rand( 10000,99999 ) . '.png';
$file2 = '/tmp/imagick_' . rand( 10000,99999 ) . '.png';
if ( @imagepng( $source_image, $file1 ) ) {
exec( $imagick . ' -rotate ' . $angle . ' ' . $file1 . ' ' . $file2 );
if ( file_exists( $file2 ) ) {
$new_image = imagecreatefrompng( $file2 );
unlink( $file1 );
unlink( $file2 );
return $new_image;
} else {
//trigger_error( 'imagerotate(): imagemagick conversion failed, original image returned', E_USER_WARNING );
return $source_image;
}
} else {
//trigger_error( 'imagerotate(): could not write to ' . $file1 . ', original image returned', E_USER_WARNING );
return $source_image;
}
}
}
?>
the dot thawk+phpnet at gmail dot com ¶
16 years ago
In response to pilot at myupb dot com on 31-May-2008 02:23
---
I am not sure why you would be defining your own PI, instead of using the built-in constant, and why you do the degrees to radian conversion manually. There might be a speed issue, however here is the exact same code with that small difference.
<?php
if(!function_exists("imagerotate")) {
function imagerotate(&$srcImg, $angle, $transparentColor = null) {
$srcw = imagesx($srcImg);
$srch = imagesy($srcImg);
if($angle == 0) return $srcImg;
// Convert the angle to radians
$theta = deg2rad ($angle);
// Get the origin (center) of the image
$originx = $srcw / 2;
$originy = $srch / 2;
// The pixels array for the new image
$pixels = array();
$minx = 0;
$maxx = 0;
$miny = 0;
$maxy = 0;
$dstw = 0;
$dsth = 0;
// Loop through every pixel and transform it
for($x=0;$x<$srcw;$x++) {
for($y=0;$y<$srch;$y++) {
list($x1, $y1) = translateCoordinate($originx, $originy, $x, $y, false);
$x2 = $x * cos($theta) - $y * sin($theta);
$y2 = $x * sin($theta) + $y * cos($theta);
// Store the pixel color
$pixels[] = array($x2, $y2, imagecolorat($srcImg, $x, $y));
// Check our boundaries
if($x2 > $maxx) $maxx = $x2;
if($x2 < $minx) $minx = $x2;
if($y2 > $maxy) $maxy = $y2;
if($y2 < $miny) $miny = $y2;
}
}
// Determine the new image size
$dstw = $maxx - $minx + 1;
$dsth = $maxy - $miny + 1;
// Create our new image
$dstImg = imagecreatetruecolor($dstw, $dsth);
// Fill the background with our transparent color
if($transparentColor == null) $transparentColor = imagecolorallocate($dstImg, 1, 2, 3);
imagecolortransparent($dstImg, $transparentColor);
imagefilledrectangle($dstImg, 0, 0, $dstw + 1, $dsth + 1, $transparentColor);
// Get the new origin
$neworiginx = -$minx;
$neworiginy = -$miny;
// Fill in the pixels
foreach($pixels as $data) {
list($x, $y, $color) = $data;
list($newx, $newy) = translateCoordinate($neworiginx, $neworiginy, $x, $y);
imagesetpixel($dstImg, $newx, $newy, $color);
}
return $dstImg;
}
/**
* Translates from mathematical coordinate system to computer coordinate system using
* origin coordinates from the computer system or visa versa
*
* @param int $originx
* @param int $originy
* @param int $x
* @param int $y
* @param bool $toComp
* @return array(int $x, int $y)
*/
function translateCoordinate($originx, $originy, $x, $y, $toComp=true) {
if($toComp) {
$newx = $originx + $x;
$newy = $originy - $y;
} else {
$newx = $x - $originx;
$newy = $originy - $y;
}
return array($newx, $newy);
}
}
?>
foi02 at cartefoi dot net ¶
16 years ago
For those who are looking for the GD library for Ubuntu, I let a copy on my server: http://www.cartefoi.net/compl_compl_2.php
It was pretty hard to find, somebody gaveme his. Thanks a lot to him (message up).
Anonymous ¶
15 years ago
Sorry, the previous class contains an error, the original image after the rotation 1px move on and get the unwanted "border".
After a careful reading of the local debate, I am using the tip from Dave Richards wrote a new function. With its images can be rotated only 90 ° (default), 180 ° and 270 °, but one rarely needs more ...
The function returns False, or rotated image
<?php
if(!function_exists("imagerotate")) {
function imagerotate($srcImg, $angle, $bgcolor, $ignore_transparent = 0) {
return rotateImage($srcImg, $angle);
}
}
function rotateImage($img1, $rec) {
$wid = imagesx($img1);
$hei = imagesy($img1);
switch($rec) {
case 270:
$img2 = @imagecreatetruecolor($hei, $wid);
break;
case 180:
$img2 = @imagecreatetruecolor($wid, $hei);
break;
default :
$img2 = @imagecreatetruecolor($hei, $wid);
}
if($img2) {
for($i = 0;$i < $wid; $i++) {
for($j = 0;$j < $hei; $j++) {
$ref = imagecolorat($img1,$i,$j);
switch($rec) {
case 270:
if(!@imagesetpixel($img2, ($hei - 1) - $j, $i, $ref)){
return false;
}
break;
case 180:
if(!@imagesetpixel($img2, $i, ($hei - 1) - $j, $ref)) {
return false;
}
break;
default:
if(!@imagesetpixel($img2, $j, ($wid - 1) - $i, $ref)) {
return false;
}
}
}
}
return $img2;
}
return false;
}
?>
Petr