6

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

看下图,右边是我现在得到的,左边是我想要实现的。旋转的度数是动态的,要生成的图像和源图像都是正方形 (200x200)。

问题说明

编辑:这是我快速而肮脏的代码:

$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);
4

1 回答 1

5

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

$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 度旋转导致原始图像和转换后的图像之间存在 83 像素的差异,需要放大 150 像素,我们可以这样做:
  • 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 的正方形。


我希望你理解逻辑,虽然我理解我的解释可能听起来有点模棱两可,所以请随时提出更多问题!

于 2013-04-27T20:59:01.070 回答