使用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属性“溢出”设置为“隐藏”;那会照顾到这个问题。 –