【问题标题】:How to speed up image resizing in a CodeIgniter PHP application?如何加快 CodeIgniter PHP 应用程序中的图像大小调整?
【发布时间】:2026-02-06 22:25:01
【问题描述】:

我有一个允许用户上传图片的应用程序。我使用的测试用例是 1.6MB 的 jpeg,尺寸为 3872 x 2592px。后端的上传脚本会将上传的图片调整为额外的 6 种格式:

  • 正方形(小号 75 x 75)
  • 小拇指 (50 x 38)
  • 拇指 (100 x 76)
  • 小 (240 x 161)
  • 中等 (500 x 378)
  • 大 (1024 x 774)

我知道这很多,但相信我,我需要这个。我使用 Code Igniter 的 Image Manipulation 类来调整大小,该类使用 GD、GD2 或 ImageMagick 来调整大小。我首先将其配置为使用 GD2,并注意到整个调整大小过程需要 11 秒。

由于用户必须等待这个过程,这是不可接受的。经过大量阅读后,我了解到 ImageMagick 是一个更快、更高效的操作库,所以我改用它:

$sourceimage = $data['filedata']['file_path'] . $data['imagedata']['user_id'] . "/" . $imageid . $data['filedata']['file_ext'];
$resize_settings['image_library'] = 'imagemagick';
$resize_settings['library_path'] = '/usr/bin';
$resize_settings['source_image'] = $sourceimage;
$resize_settings['maintain_ratio'] = false;
$resize_settings['quality'] = "100%";
$this->load->library('image_lib', $resize_settings);

令我惊讶的是,调整大小的过程现在需要更长的时间:具体来说是 15 秒。

查看我的日志,我发现每次调整大小操作都需要 2 秒,无论它调整大小的文件格式如何。我想这是因为我总是从原始大小调整大小,这非常大。

我不愿意将调整大小的过程转移到预定的过程中,因为这会降低网站的可用性。这意味着用户必须等待几分钟才能开始查看/使用图像。

那么,有没有什么聪明的方法可以显着加快这个调整大小的过程,以便我可以实时保持它?请明确:不允许使用较小的分辨率,这是我正在建立的摄影网站。另外,我真的需要上面提到的六种格式。

【问题讨论】:

  • 您能否提供给我们 1.6MB 原始 JPEG 图片?

标签: php codeigniter imagemagick gd2


【解决方案1】:

好像你已经接受了一个答案,但我还是会发布我的。

首先,您真的不需要在质量上使用 100%90%85% 值就可以了很好,同时减少了处理时间和图像大小(如果您不相信我,只需运行一些测试)。

我还用this image 和自定义JPEG() 函数做了一些基准测试,第一个测试用例:

JPEG('./original.jpg', null, '1024*774', './output/large.jpg');
JPEG('./original.jpg', null, '500*378', './output/medium.jpg');
JPEG('./original.jpg', null, '240*161', './output/small.jpg');
JPEG('./original.jpg', null, '100*76', './output/thumb.jpg');
JPEG('./original.jpg', null, '50*38', './output/small_thumb.jpg');
JPEG('./original.jpg', null, '75*75', './output/square.jpg');

这在我的慢计算机上平均需要 60 秒。


第二个测试用例

JPEG('./original.jpg', null, '1024*774', './output/large.jpg');
JPEG('./output/large.jpg', null, '500*378', './output/medium.jpg');
JPEG('./output/medium.jpg', null, '240*161', './output/small.jpg');
JPEG('./output/medium.jpg', null, '100*76', './output/thumb.jpg');
JPEG('./output/medium.jpg', null, '50*38', './output/small_thumb.jpg');
JPEG('./output/medium.jpg', null, '75*75', './output/square.jpg');

这个“只”需要 16 秒(我的电脑真的很慢 ATM :P),快了将近 4 倍。


这里是 JPEG() 函数,以防您想进行自己的基准测试:

function JPEG($source, $crop = null, $scale = null, $destination = null)
{
    $source = ImageCreateFromJPEG($source);

    if (is_resource($source) === true)
    {
        $size = array(ImageSX($source), ImageSY($source));

        if (isset($crop) === true)
        {
            $crop = array_filter(explode('/', $crop), 'is_numeric');

            if (count($crop) == 2)
            {
                $crop = array($size[0] / $size[1], $crop[0] / $crop[1]);

                if ($crop[0] > $crop[1])
                {
                    $size[0] = $size[1] * $crop[1];
                }

                else if ($crop[0] < $crop[1])
                {
                    $size[1] = $size[0] / $crop[1];
                }

                $crop = array(ImageSX($source) - $size[0], ImageSY($source) - $size[1]);
            }

            else
            {
                $crop = array(0, 0);
            }
        }

        else
        {
            $crop = array(0, 0);
        }

        if (isset($scale) === true)
        {
            $scale = array_filter(explode('*', $scale), 'is_numeric');

            if (count($scale) >= 1)
            {
                if (empty($scale[0]) === true)
                {
                    $scale[0] = $scale[1] * $size[0] / $size[1];
                }

                else if (empty($scale[1]) === true)
                {
                    $scale[1] = $scale[0] * $size[1] / $size[0];
                }
            }

            else
            {
                $scale = array($size[0], $size[1]);
            }
        }

        else
        {
            $scale = array($size[0], $size[1]);
        }

        $result = ImageCreateTrueColor($scale[0], $scale[1]);

        if (is_resource($result) === true)
        {
            if (ImageCopyResampled($result, $source, 0, 0, $crop[0] / 2, $crop[1] / 2, $scale[0], $scale[1], $size[0], $size[1]) === true)
            {
                return ImageJPEG($result, $destination, 90);
            }
        }
    }

    return false;
}

【讨论】:

  • 谢谢,您的回答绝对丰富了话题。实际上,我确实尝试过改变质量,作为一个极端的测试用例,我使用了 10%。结果是整个调整大小的过程仍然和以前一样长。这使我相信解决方案是问题,而不是质量。我刚刚在我改进的调整大小逻辑中再次测试了相同的 10% 质量,并且再次与 100% 质量一样长。不知道为什么。
  • 再说一点,如果可能的话,我真的很想继续使用 CodeIgniter 图像类,因为它可以处理几乎所有图像文件类型,并且隐藏了处理较低级别图像调整大小例程的复杂性。只有当所有其他方法都失败并且有明显优势时,我才会切换。
  • @Ferdy:是的,在速度方面应该没多大关系,但你还是应该使用较低的质量,90% 将图像尺寸缩小一半并保持所有质量。
  • @Alix,非常感谢。我刚刚将质量更改为 90%,并注意到文件大小下降了 2 到 3 倍。该因素取决于图像的大小,越大,因素越大。我确实看不到质量差异。这很漂亮,因为我有一个将这些图像传输到 Amazon S3 的预定服务,所以你为我节省了很多钱!
  • 没问题 Ferdy,很高兴我能帮上忙。 =)
【解决方案2】:

作为一个想法,您可以从上传的尺寸调整为更合理的中间尺寸,然后以此作为进一步操作的基础。

或者,您可以执行到 ImageMagick 的命令行版本,并使用Asynchronous shell exec in PHP 中描述的过程在后台执行(至少大部分)图像转换。

最后,虽然有点跑题了,但您是否要允许纵向放置,或者这可能不是一个因素?

【讨论】:

  • 非常感谢。我现在使用涓滴效应调整大小,这意味着我从大开始调整到中等大小,接下来我使用中等图像(而不是大图像)调整到小等。现在只需不到 3 秒的时间就可以完成处理.我确实撕掉了一种格式(方形)并切换回 GD2,而不是 imagemagick。据我所知,使用这种涓滴调整大小没有明显的质量问题。再次感谢!