旋转和裁剪

6
我正在使用PHP旋转和裁剪图像,但是我得到了显示黑色边框的结果。我知道可以更改背景颜色,但我想将图像旋转和裁剪到填满整个图像。基本上类似于CSS中的background-size: cover;(左侧)与background-size: contain;(右侧) 。

请参见下面的图像,右侧是我现在得到的结果,左侧是我想要实现的效果。旋转的度数是动态的,要生成的图像和源图像都是正方形(200x200)。

Illustration of problem

编辑: 这是我的快速粗糙代码:

$rotate = imagecreatefromjpeg($image);
// part of code created by www.thewebhelp.com, modified
$square_size = 200;
$original_width = imagesx($rotate); 
$original_height = imagesy($rotate);
if($original_width > $original_height){
    $new_height = $square_size;
    $new_width = $new_height*($original_width/$original_height);
}
if($original_height > $original_width){
    $new_width = $square_size;
    $new_height = $new_width*($original_height/$original_width);
}
if($original_height == $original_width){
    $new_width = $square_size;
    $new_height = $square_size;
}

$new_width = round($new_width);
$new_height = round($new_height);

$smaller_image = imagecreatetruecolor($new_width, $new_height);
$square_image = imagecreatetruecolor($square_size, $square_size);

imagecopyresampled($smaller_image, $rotate, 0, 0, 0, 0, $new_width, $new_height, $original_width, $original_height);

if($new_width>$new_height){
    $difference = $new_width-$new_height;
    $half_difference =  round($difference/2);
    imagecopyresampled($square_image, $smaller_image, 0-$half_difference+1, 0, 0, 0, $square_size+$difference, $square_size, $new_width, $new_height);
}
if($new_height>$new_width){
    $difference = $new_height-$new_width;
    $half_difference =  round($difference/2);
    imagecopyresampled($square_image, $smaller_image, 0, 0-$half_difference+1, 0, 0, $square_size, $square_size+$difference, $new_width, $new_height);
}
if($new_height == $new_width){
    imagecopyresampled($square_image, $smaller_image, 0, 0, 0, 0, $square_size, $square_size, $new_width, $new_height);
}

$degrees = rand(1,360);
$square_image = imagerotate($square_image, $degrees, 0);
imagejpeg($square_image,NULL,100);

我认为你的background-size比喻与你所需求的不符。 - Ejaz
https://dev59.com/V2025IYBdhLWcg3wzZT3#22511805 - Arfan Mirza
1个回答

6

请在代码末尾附近替换这些行:

$degrees = rand(1,360);
$square_image = imagerotate($square_image, $degrees, 0);
imagejpeg($square_image,NULL,100);

有了这个:

$degrees = rand(1,360);
$square_image = imagerotate($square_image, $degrees, 0);

$rotated_size = imagesx($square_image);
$enlargement_coeff = ($rotated_size - $square_size) * 1.807;
$enlarged_size = round($rotated_size + $enlargement_coeff);
$enlarged_image = imagecreatetruecolor($enlarged_size, $enlarged_size);
$final_image = imagecreatetruecolor($square_size, $square_size);

imagecopyresampled($enlarged_image, $square_image, 0, 0, 0, 0, $enlarged_size, $enlarged_size, $rotated_size, $rotated_size);
imagecopyresampled($final_image, $enlarged_image, 0, 0, round($enlarged_size / 2) - ($square_size / 2), round($enlarged_size / 2) - ($square_size / 2), $square_size, $square_size, $square_size, $square_size);

imagejpeg($final_image,NULL,100);

这是这样的逻辑:
1)执行imagerotate()后,我们的新图像已更改其尺寸,因为每次旋转通常会导致图像变大。由于源是正方形图像,因此我们取宽度或高度以确定旋转图像的尺寸。
2)当原始图像被旋转时,即使只有一点点,可用像素数据的最大正方形尺寸也始终小于原始未旋转的正方形图像。因此,为了生成一个与初始正方形图像大小相同但没有“黑边”伪影的新正方形图像,我们需要扩大旋转图像,以便原始图像中在旋转图像中的可用像素数据的最大正方形可以变得与初始正方形图像一样大。
关键值在于1.807。该值基本上显示了每个像素差异之间需要多少像素来放大旋转图像。可能有更好的数学公式来检索该值,但不幸的是我不擅长数学,因此以下是得出该值的艰难方法。
  • 45/135/225/315度的旋转将总是产生具有最小可用像素数据正方形的最大图像。
  • 知道了这一点,您比较原始图像和其45度旋转版本的尺寸。在我们的情况下,原始图像为200x200,45度旋转版本约为283x283
  • 在像Photoshop这样的程序中,您确定需要多少次放大图像的45度旋转版本才能从中提取一个200x200的正方形,而不带“黑边” - 在我们的情况下,需要将283x283图像放大到433x433图像,以便我们可以提取一个200x200的正方形
  • 433-283 = 150->这意味着我们需要将最大可能的旋转图像放大150个像素,以便我们能够从中提取一个200x200的正方形。
  • 283-200 = 83->最大可能的旋转图像与原始未旋转的图像之间的差异为83个像素。
  • 变换越小,我们可以使用的正方形区域就越大,因此需要应用的放大量就越小。由于45度旋转导致原始图像和需要150像素放大的变换图像之间的差异为83像素,因此我们可以进行以下操作:
  • 150/83 = 1.807->这意味着原始图像和旋转图像之间的1个像素差异需要将旋转图像放大1.807个像素,以便我们可以从中提取一个具有相同尺寸的正方形。

3) 知道每相差1个像素需要扩大1.807个像素,我们检查旋转图像尺寸与原始图像尺寸之间的差异,并将其乘以该值,以确定扩大后的图像应具有的尺寸:

$enlargement_coeff = ($rotated_size - $square_size) * 1.807;
$enlarged_size = round($rotated_size + $enlargement_coeff);

4) 我们继续生成放大旋转后的图像。

imagecopyresampled($enlarged_image, $square_image, 0, 0, 0, 0, $enlarged_size, $enlarged_size, $rotated_size, $rotated_size);

5) 最后,我们从我们的放大旋转图像中提取一个200x200的正方形,使用它的中心坐标作为参考。

imagecopyresampled($final_image, $enlarged_image, 0, 0, round($enlarged_size / 2) - ($square_size / 2), round($enlarged_size / 2) - ($square_size / 2), $square_size, $square_size, $square_size, $square_size);

将其分解,($square_size / 2) 返回放大旋转图像中心点的X和Y坐标。round($enlarged_size / 2) 返回所需像素量,沿X轴从中心向左,沿Y轴向上,在200x200正方形中心左侧。


我希望你们能理解逻辑,虽然我知道我的解释可能有些含糊不清,如果您还有什么问题,请随时问我!

哇!感谢您提供如此详细的解释。您的解决方案有效,但由于调整大小而导致了很多质量损失,您能修复一下吗? - aNewStart847

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接