PHP GD调整大小和裁剪图像背景时保持正确比例以提高性能

3
我使用 PHP GD 库开发了一个图像大小调整和裁剪类。在第一步中,我使用 skibulks image trim script 来剪裁图像背景,并在第二步中将图像按比例缩放到所需尺寸(保持原始比例)。 问题:在从 $this->_trimBackground() 函数获取新的裁剪图像尺寸后,是否真的需要在第一次使用 imagecopy 重新创建图像,并在之后再次调整大小?还是可以将此操作与以下的缩放部分 imagecopyresampled 合并?
还有其他可能的性能改进吗?欢迎提出每个性能建议! 函数 1:
/**
 * Resize image file
 * 
 * @param   string $filepath the image filepath
 * @param   integer $width the width to resize
 * @param   integer $height the height to resize
 * @return  (image blob|boolean status)
 * @throws  Asset_Model_Image_Exception
 */
private function _resizeImageByFilepathAndReturn($filepath, $width, $height) {

    list($imageWidth, $imageHeight, $imageType) = getimagesize($filepath);

   switch($imageType) {
    case IMAGETYPE_GIF:
            $gdImage = imagecreatefromgif($filepath);
            break;
      case IMAGETYPE_JPEG:
            $gdImage = imagecreatefromjpeg($filepath);
            break;
      case IMAGETYPE_PNG:
            $gdImage = imagecreatefrompng($filepath);
            break;
      default:
                return false;
   }

   if($box = $this->_trimBackground($gdImage)) {

    $gdTrimmed = imagecreatetruecolor($box['w'], $box['h']);
    imagecopy($gdTrimmed, $gdImage, 0, 0, $box['l'], $box['t'], $box['w'], $box['h']);

    $imageWidth = $box['w'];
    $imageHeight = $box['h'];
    $gdImage = $gdTrimmed;

    unset($gdTrimmed);

   }

   if($imageWidth <= $width && $imageHeight <= $height) {

    $fwidth = $imageWidth;
        $fheight = $imageHeight;

   } else {

        $wscale = $width / $imageWidth;
        $hscale = $height / $imageHeight;
        $scale = min($wscale, $hscale);
        $fwidth = $scale * $imageWidth;
        $fheight = $scale * $imageHeight;

   }

   $gdThumbnail = imagecreatetruecolor($width, $height);

   imagefill($gdThumbnail, 0, 0, 0x00FFFFFF);

   imagecopyresampled($gdThumbnail, $gdImage, ($width - $fwidth) / 2, ($height - $fheight) / 2, 0, 0, $fwidth, $fheight, $imageWidth, $imageHeight);

   ob_start();
   imagejpeg($gdThumbnail, null, 90);
   $image = ob_get_contents();
   ob_end_clean();

   imagedestroy($gdImage);
   imagedestroy($gdThumbnail);

   return $image;

}

函数 2:

/**
 * Trim image background
 * 
 * @param $gdImage image ressource
 */
private function _trimBackground($gdImage){

    $hex = imagecolorat($gdImage, 0,0);

    $width = imagesx($gdImage);
    $height = imagesy($gdImage);

    $bTop = 0;
    $bLft = 0;
    $bBtm = $height - 1;
    $bRt = $width - 1;

    for(; $bTop < $height; ++$bTop) {
        for($x = 0; $x < $width; ++$x) {
            if(imagecolorat($gdImage, $x, $bTop) != $hex) {
                break 2;
            }
        }
    }

    if($bTop == $height) {
        return false;
    }

    for(; $bBtm >= 0; --$bBtm) {
        for($x = 0; $x < $width; ++$x) {
            if(imagecolorat($gdImage, $x, $bBtm) != $hex) {
                break 2;
            }
        }
    }

    for(; $bLft < $width; ++$bLft) {
        for($y = $bTop; $y <= $bBtm; ++$y) {
            if(imagecolorat($gdImage, $bLft, $y) != $hex) {
                break 2;
            }
        }
    }

    for(; $bRt >= 0; --$bRt) {
        for($y = $bTop; $y <= $bBtm; ++$y) {
            if(imagecolorat($gdImage, $bRt, $y) != $hex) {
                break 2;
            }
        }
    }

    $bBtm++;
    $bRt++;

    return array('l' => $bLft, 't' => $bTop, 'r' => $bRt, 'b' => $bBtm, 'w' => $bRt - $bLft, 'h' => $bBtm - $bTop);

}

2
这个问题可能更适合在http://codereview.stackexchange.com上提问。 - thaJeztah
谢谢你的提示,jeztah!我也在这里创建了它:http://codereview.stackexchange.com/questions/21228/performance-improvements-php-gd-resize-and-trim-image-background-keeping-the-cor - user544452
你为什么要优化性能?有什么原因吗? - Lukasz Kujawa
2
什么?为什么我要优化性能?因为有大约1000万张图片,时间就是金钱? :-) - user544452
1
你是否必须使用GD?你是否有访问IMagick模块的权限?或者访问convert程序?(也可以使用ImageMagick)我敢打赌,使用其中任何一个都会给你带来非常好的性能提升。(我们处理大量这样的图像,由Gearman作业队列支持,并分布在几个应用服务器上) - hank
显示剩余3条评论
1个回答

5

imagecopy()函数将$gdImage的一部分复制到$gdTrimmed中,几行代码后又用$gdTrimmed覆盖了$gdImage。

第一个imagecopy()真的必要吗?

这是你应该问自己的问题。

使用imagedestroy()函数代替unset()可能会大大提高性能。以下是imagedestroy()的有用评论:

重用图像变量不会清除旧数据!您必须使用imagedestroy()来清除数据。(我不知道unset()是否同样有效)。

还要注意,内存中的图像数据是原始的,因此不要根据压缩图像(如jpeg或png)的原始文件大小来确定使用了多少内存。


非常感谢,使用imagedestroy()函数提高了40%的性能。 - deepika jain

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