从中心裁剪图像 PHP

13

我想从中心裁剪尺寸为200 * 130的图像,被裁剪的图像可能大小不一,如果图像较小则不进行裁剪。我知道如何检查图像的高度和宽度,但在从图像中间裁剪方面有些困惑。

因为我无法确定如何将中心作为裁剪点,然后向外裁剪。

4个回答

36

从版本4.3.6开始,GD已经随所有PHP安装包一起提供了,因此很可能您已经拥有它。

这是您需要执行的步骤...

  1. 使用GDimagecreatefrom*()函数之一创建图像资源。您使用的函数取决于您处理的图像类型
  2. 使用imagesx()imagesy()确定图像尺寸
  3. 使用以下算法确定裁剪坐标并使用imagecopy()进行裁剪

查找裁剪坐标

$width  = imagesx($img);
$height = imagesy($img);
$centreX = round($width / 2);
$centreY = round($height / 2);

$cropWidth  = 200;
$cropHeight = 130;
$cropWidthHalf  = round($cropWidth / 2); // could hard-code this but I'm keeping it flexible
$cropHeightHalf = round($cropHeight / 2);

$x1 = max(0, $centreX - $cropWidthHalf);
$y1 = max(0, $centreY - $cropHeightHalf);

$x2 = min($width, $centreX + $cropWidthHalf);
$y2 = min($height, $centreY + $cropHeightHalf);

有人在这里实现了一个方便的类,将这个逻辑封装起来 ~ ImageManipulator.php


在第一个算法中,哪些变量对应于imagecopy()的正确参数? - Chris Harrison
@Phil 使用你的库。谢谢! - William Weckl
嗨@Phil,Gist链接已经失效了,8年过去了。你还有这个库吗? - Eugene van der Merwe
@EugenevanderMerwe 你很幸运,有人克隆了它~ https://github.com/hungtrieu/html5-image-upload/blob/master/ImageManipulator.php - Phil

20

可配置对齐方式的图像裁剪

这是一个本地实现的函数(称为cropAlign),可以将图像裁剪为给定的宽度和高度,并按照9个标准点(4个边缘、4个角落、1个中心)对齐。

Alignment points

只需将图像、所需剪裁的尺寸以及在两个轴上的对齐方式(您可以使用leftcenterright或者topmiddlebottom,无论轴线如何)传递给cropAlign函数。

规格说明

描述

cropAlign(resource $image, int $width, int $height, string $horizontalAlign = 'center', string $verticalAlign = 'middle')

参数

  • image: 图像资源,由图像创建函数之一返回,例如imagecreatetruecolor()
  • width: 最终裁剪图像的宽度。
  • height: 最终裁剪图像的高度。
  • horizontalAlign: 裁剪应该沿水平轴对齐的位置。可能的值为:left/topcenter/middleright/bottom
  • verticalAlign: 裁剪应该沿垂直轴对齐的位置。可能的值为:left/topcenter/middleright/bottom

返回值

成功时返回被裁剪后的图像资源,失败时返回FALSE。这来自于imagecrop()函数。

function cropAlign($image, $cropWidth, $cropHeight, $horizontalAlign = 'center', $verticalAlign = 'middle') {
    $width = imagesx($image);
    $height = imagesy($image);
    $horizontalAlignPixels = calculatePixelsForAlign($width, $cropWidth, $horizontalAlign);
    $verticalAlignPixels = calculatePixelsForAlign($height, $cropHeight, $verticalAlign);
    return imageCrop($image, [
        'x' => $horizontalAlignPixels[0],
        'y' => $verticalAlignPixels[0],
        'width' => $horizontalAlignPixels[1],
        'height' => $verticalAlignPixels[1]
    ]);
}

function calculatePixelsForAlign($imageSize, $cropSize, $align) {
    switch ($align) {
        case 'left':
        case 'top':
            return [0, min($cropSize, $imageSize)];
        case 'right':
        case 'bottom':
            return [max(0, $imageSize - $cropSize), min($cropSize, $imageSize)];
        case 'center':
        case 'middle':
            return [
                max(0, floor(($imageSize / 2) - ($cropSize / 2))),
                min($cropSize, $imageSize),
            ];
        default: return [0, $imageSize];
    }
}

使用示例

以下是一些使用此图像的裁剪示例,图像来自Utah茶壶

$im = imagecreatefrompng('https://istack.dev59.com/NJcML.webp');
imagePng(cropAlign($im, 200, 250, 'center', 'middle'));
imagePng(cropAlign($im, 300, 150, 'left', 'top'));
imagePng(cropAlign($im, 1000, 250, 'right', 'middle'));

输入

示例输入:犇亭茶壶

输出

cropAlign($im, 200, 250, 'center', 'middle')

Output #1

cropAlign($im, 300, 150, 'left', 'top')

Output #2

cropAlign($im, 1000, 250, 'right', 'middle')

Output #3


2
真的很棒,更加有用。 - carry0987

2

天啊,你为什么要选择这种困难的方式呢?只需将x和y位置设置为要裁剪的数量的一半即可。

   $imageSize = getimagesize('thumbnail.png');

$croppedImage = imagecrop(imagecreatefrompng('thumbnail.png'), ['x' => 0, 'y' => ($imageSize[1]-$imageSize[0]*(9/16))/2, 'width' => $imageSize[0], 'height' =>  $imageSize[0]*(9/16)]);

注意我如何使用了 $imageSize[0]*(9/16),这是我在 y 方向上裁剪的数量,然后我从原始图像高度中减去了这个值以找到裁剪量,然后除以 2。如果你想对宽度进行相同操作,只需按照相同步骤进行即可。


0

这可能会对你有所帮助。

function cropCentered($img, $w, $h)
{
  $cx = $img->getWidth() / 2;
  $cy = $img->getHeight() / 2;
  $x = $cx - $w / 2;
  $y = $cy - $h / 2;
  if ($x < 0) $x = 0;
  if ($y < 0) $y = 0;
  return $img->crop($x, $y, $w, $h);
}

我假设您正在使用GD库。$img是一个GD图像,$w和$h分别是您想要新图像具有的宽度和高度。在您的情况下,$w = 200,$h = 130。


我没有可用的GD库。 - June
2
@June GD通常包含在大多数PHP安装中,使用phpinfo()函数,您很可能会看到它。 - Lawrence Cherone
什么是“GD图像”?所有的GD创建函数都会返回一个资源标识符。据我所知,没有现成的面向对象的GD接口。 - Phil
你说得对,Phil。实际上,我习惯使用包装类来进行这种图像操作。当我回答问题时,我假设那个人对于图像操作有更多的了解。 - P. R. Ribeiro
我很困惑,GD库中没有裁剪功能...所以这个答案是原始答案的附带吗?如果是的话,你应该提到,否则这个答案就完全不正确,因为用户不知道你所说的上下文。 - djowinz
显示剩余2条评论

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