PHPのお勉強!

PHP TOP

imagerotate

(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)

imagerotate指定された角度で画像を回転する

説明

imagerotate(GdImage $image, float $angle, int $background_color): GdImage|false

画像 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);
?>

上の例の出力は、 たとえば以下のようになります。

出力例 : 画像を 180 度回転する

注意

注意:

この関数は、imagesetinterpolation() で設定した補間方式の影響を受けます。

参考

add a note

User Contributed Notes 38 notes

up
33
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);
?>
up
4
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
up
10
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;
up
8
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
up
4
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.
up
1
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);
up
1
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;
}

?>
up
1
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;
}
}

?>
up
1
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');
?>
up
1
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 );
?>
up
1
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;
}
?>
up
2
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);
?>
up
2
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;

}

}

}
?>
up
2
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);
}
}
?>
up
1
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).
up
0
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
up