使用PHP的GD庫,您可以使用imagerotate
函數旋轉圖像。這個函數的缺點是它不會剪裁邊緣,這正是我需要的。PHP使用修剪邊緣旋轉圖像
下面是一個例子形象,顯示了我的問題:
正如你所看到的,在Photoshop邊緣裁剪。在PHP中,由於旋轉,圖像的大小剛剛增加。我真的想得到和我在Photoshop中一樣的結果。任何想法如何在PHP中做到這一點?
(我只能訪問GD庫)。
使用PHP的GD庫,您可以使用imagerotate
函數旋轉圖像。這個函數的缺點是它不會剪裁邊緣,這正是我需要的。PHP使用修剪邊緣旋轉圖像
下面是一個例子形象,顯示了我的問題:
正如你所看到的,在Photoshop邊緣裁剪。在PHP中,由於旋轉,圖像的大小剛剛增加。我真的想得到和我在Photoshop中一樣的結果。任何想法如何在PHP中做到這一點?
(我只能訪問GD庫)。
如果你懶得計算旋轉圖像的新大小,只需使用支持這些計算開箱的GD基於圖像庫。
一個這樣的庫是Wideimage。
$image = WideImage::load('big.png');
$width = $image->getWidth();
$height = $image->getHeight();
$image->rotate(120)->crop("center", "middle", $width, $height);
center
,
middle
並與原始圖像的寬度和高度裁剪
目前的答案僅作爲一個辦法讓周圍的問題。它不討論計算新盒子大小所需的數學。
旋轉後需要用imagecrop
裁剪圖像。爲此,您可以使用以下公式來保持居中。
rotated_dimension * (1 - source_dimension/rotated_dimension) * 0.5
下面是一個工作示例。 placehold.it URL可以用本地文件路徑替換。
<?php
$filename = 'http://placehold.it/200x200';
$degrees = -45;
header('Content-type: image/png');
$source = imagecreatefrompng($filename);
$sw = imagesx($source);
$sh = imagesy($source);
$rotate = imagerotate($source, $degrees, 0);
$rw = imagesx($rotate);
$rh = imagesy($rotate);
$crop = imagecrop($rotate, array(
'x' => $rw * (1 - $sw/$rw) * 0.5,
'y' => $rh * (1 - $sh/$rh) * 0.5,
'width' => $sw,
'height'=> $sh
));
imagepng($crop);
如果angle
是旋轉角度,則寬度和旋轉的圖像的高度,width′
和height′
,is given by:
width′ = height * s + width * c height′ = height * c + width * s
其中width
是源圖像的寬度,height
是源圖像身高和:
s = abs(sin(angle)) c = abs(cos(angle))
請注意,由於trigono度量標識罪( - θ)= - SIN(θ)和cos( - θ)= COS(θ),它不會在上式中,如果測量angle
時無所謂,正方向是順時針或逆時針。
你知道的一件事是源圖像的中心點被映射到旋轉圖像的中心。因此,如果width′ ≥ width
和height′ ≥ height
,你有左上點的旋轉圖像中的座標是:
x = rotated_width/2 - width/2 y = rotated_height/2 - height/2
所以,如果width′ ≥ width
和height′ ≥ height
,下面的PHP代碼將根據需要裁剪圖像:
$cropped = imagecrop($rotated, array(
'x' => $rotated_width/2 - $width/2,
'y' => $rotated_height/2 - $height/2,
'width' => $width,
'height' => $height
));
但是,這隻適用於width′ ≥ width
和height′ ≥ height
。例如,如果源圖像的尺寸是正方形,則這適用,因爲:
length′ = length * (abs(sin(angle)) + abs(cos(angle)))
和abs(sin(angle)) + abs(cos(angle)) ≥ 1
。
參見"y = abs(sin(theta)) + abs(cos(theta)) minima" on WolframAlpha。
如果width′ ≥ width
和height′ ≥ height
不成立(例如250 × 40圖像旋轉了50 °順時針方向),然後將所得的圖像將是完全黑(作爲無效裁剪矩形傳遞給imagecrop())。
這些問題可以固定用下面的代碼:
$cropped = imagecrop($rotated, array(
'x' => max(0, $rotated_width/2 - $width/2),
'y' => max(0, $rotated_height/2 - $height/2),
'width' => min($width, $rotated_width),
'height'=> min($height, $rotated_height)
));
此代碼的結果是藍色着色的區域中的下圖中:
(對於參見http://fiddle.jshell.net/5jf3wqn4/show/一個SVG版本。)
在該圖中,半透明的紅色矩形代表原始圖像。紅色矩形表示圖像的旋轉。虛線矩形表示由imagerotate()創建的圖像的邊界。
把所有這些組合起來,這裏是PHP代碼,以旋轉和裁剪圖像:
$filename = 'http://placehold.it/250x40';
$degrees = -50;
$source = imagecreatefrompng($filename);
$width = imagesx($source);
$height = imagesy($source);
$rotated = imagerotate($source, $degrees, 0);
imagedestroy($source);
$rotated_width = imagesx($rotated);
$rotated_height = imagesy($rotated);
$cropped = imagecrop($rotated, array(
'x' => max(0, (int)(($rotated_width - $width)/2)),
'y' => max(0, (int)(($rotated_height - $height)/2)),
'width' => min($width, $rotated_width),
'height'=> min($height, $rotated_height)
));
imagedestroy($rotated);
imagepng($cropped);
編輯:那地方1px的黑線被添加到裁剪圖像的底部似乎a bug in imagecrop() 。有關解決方法,請參見imagecrop() alternative for PHP < 5.5。
編輯2:我發現imageaffine()可以導致比imagerotate()更好的質量。用戶「abc at ed48 dot com」has commented與仿射變換,您將使用逆時針旋轉給定的角度。
這裏是代碼,使用imageaffine()的imagerotate而不是():
// Crops the $source image, avoiding the black line bug in imagecrop()
// See:
// - https://bugs.php.net/bug.php?id=67447
// - https://stackoverflow.com/questions/26722811/imagecrop-alternative-for-php-5-5
function fixedcrop($source, array $rect)
{
$cropped = imagecreate($rect['width'], $rect['height']);
imagecopyresized(
$cropped,
$source,
0,
0,
$rect['x'],
$rect['y'],
$rect['width'],
$rect['height'],
$rect['width'],
$rect['height']
);
return $cropped;
}
$filename = 'http://placehold.it/250x40';
$degrees = -50;
$source = imagecreatefrompng($filename);
$width = imagesx($source);
$height = imagesy($source);
$radians = deg2rad($degrees);
$cos = cos($radians);
$sin = sin($radians);
$affine = [ $cos, -$sin, $sin, $cos, 0, 0 ];
$rotated = imageaffine($source, $affine);
imagedestroy($source);
$rotated_width = imagesx($rotated);
$rotated_height = imagesy($rotated);
$cropped = fixedcrop($rotated, array(
'x' => max(0, (int)(($rotated_width - $width)/2)),
'y' => max(0, (int)(($rotated_height - $height)/2)),
'width' => min($width, $rotated_width),
'height'=> min($height, $rotated_height)
));
imagedestroy($rotated);
imagepng($cropped);
這只是一個簡單的數學的事情:你需要切出一個矩形的原始圖像的大小。矩形的中心將是新圖像的中心 –
您是否考慮過使用瀏覽器的CSS旋轉? (是的,它可以在所有瀏覽器中完成,甚至是舊版本的IE) – Spudley
使用CSS進行旋轉;將圖像放在容器內;給容器一個固定的寬度,並將其CSS屬性「溢出」設置爲「隱藏」;那會照顧到這個問題。 –