PHP Imagick JPEG 优化

12

我正在使用 PHP Imagick 在运行时调整图像大小。网站具有图像上传功能,我们不能信任用户使用适用于Web的JPEGs,因为在批量导入期间有许多35MB的图像,甚至有一些大达13MB。每个图像都会变成缩略图(200x200),当从列表视图进入详细视图时,只显示一个图像,因此性能不是很重要,尽管我们不能完全忽略它。目前我们正在做以下操作:

$iMagick = new Imagick($file);
$iMagick->setImageResolution(72,72);
$iMagick->resampleImage(72,72,imagick::FILTER_UNDEFINED,1);
$geometry = $iMagick->getImageGeometry();
if ($geometry['height'] > 1920 || $geometry['width'] > 1080) {
    $iMagick->scaleImage(1920, 0);
    if($geometry['height'] > $resizeHeight) {
        $iMagick->scaleImage(0, 1080);
    }
}
$iMagick->setImageCompression(Imagick::COMPRESSION_JPEG);
$iMagick->setImageCompressionQuality($compression);
$iMagick->writeImage($file);
$Imagick->clear();

补充说明:我刚意识到我的条件逻辑在高度/宽度方面存在缺陷,请暂时忽略这一点。我很快会编辑问题,以反映正确的条件比较。对于那些没有注意到的人,它会将所有图像缩放到1920宽度,即使它应该缩放高度,然后在缩放后将其调整为1080高度

我用来测试的图像开始时是一张3MB 2398×2400的图片。将其缩放为1079x1080将产生一个1.5MB的图像,然后在质量为70的情况下添加JPEG压缩,将其降至750KB。使用kraken.io,该图像能够被压缩到不到60KB。由于需要在运行时优化图像,是否有其他额外的事情可以对这个脚本做呢?

我已经阅读了使用libjpeg的建议,它已安装,但我找不到任何关于它启用的功能或是否有一种方法强制Imagick专门使用它的文档。我甚至不确定Imagick是否已经在使用它。

编辑:解决方案

function itm_optimizeImage($file, $compression = 70, $maxDimensions = ['width' => null, 'height' => null]) {
    $save = false;
    $fi = new finfo(FILEINFO_MIME);
    $mime = explode(';', $fi->file($file));
    switch ($mime[0]) {
        // possible to optimize other image types in the future
        case 'image/jpeg':
            try {
                $iMagick = new Imagick($file);
                if ($iMagick->getImageCompressionQuality() > $compression) {
                    $file = !itm_compressJPEG($file, $compression, $maxDimensions, $iMagick);
                }
            }
            catch (Exception $e) {
                error_log(__FUNCTION__ . " $path/$file failed: " . $e->getMessage());
                return false;
            }
            if ($file) {
                $pathParts = pathinfo($file);
                rename($file, $pathParts['dirname'] . '/' . $pathParts['filename'] . '.large.' . $pathParts['extension']);
                $iMagick->writeImage($file);
            }
            $iMagick->clear();
            break;
    }

    return $file;
}

function itm_compressJPEG($file, $compression = 70, $maxDimensions = ['width' => null, 'height' => null], &$iMagick = null) {
    try {
        $iMagickCreated = true;
        if ($iMagick) $iMagickCreated = false;
        else $iMagick = new Imagick($file);

        $iMagick->setImageResolution(72,72);
        $iMagick->resampleImage(72,72,imagick::FILTER_UNDEFINED,1);
        $geometry = $iMagick->getImageGeometry();
        if (($geometry['width'] / $maxDimensions['width']) > ($geometry['height'] / $maxDimensions['height'])) {
            // scale by width
            $iMagick->scaleImage($maxDimensions['width'], 0);
        } else {
            // scale by height
            $iMagick->scaleImage(0, $maxDimensions['height']);
        }
        $iMagick->setImageCompression(Imagick::COMPRESSION_JPEG);
        $iMagick->setImageCompressionQuality($compression);
        $iMagick->setImageFormat('jpg');
        $iMagick->stripImage();

        if ($iMagickCreated) {
            $pathParts = pathinfo($file);
            rename($file, $pathParts['dirname'] . '/' . $pathParts['filename'] . '.large.' . $pathParts['extension']);
            $iMagick->writeImage($file);
            $Imagick->clear();
        }
        return $file;
    }
    catch (Exception $e) {
        error_log(__FUNCTION__ . " $path/$file failed: " . $e->getMessage());
        return false;
    }
}

一个1079x1080的图像大小为60KB似乎相当不错。我认为如果不降低像素尺寸或严重降低质量,你无法将其缩小得更小。 - GolezTrol
问题在于我的脚本远远达不到这个目标。它现在大约是750KB,而60KB只是一个比较(kraken.io工具在同一图像上的能力)。我并不把60KB看作是一个确切的目标,但200KB以下会很好。 - MaKR
1个回答

14

将setImageCompressionQuality设置为70,并在其后添加以下两行代码。

$image->setImageFormat("jpg");
$image->stripImage();

这将大幅减小图片的尺寸。


1
我之前使用过stripImage(),但没有效果。添加setImageFormat('jpg')而不使用stripImage()可以再减小约20KB的大小(我们试图保存exif/meta数据,但性能次之)。同时使用两者,这张测试图片的最终结果是178KB,这是质量和压缩的完美结合。谢谢! - MaKR
1
有人能解释一下@MaKR描述的奇怪行为吗?如果文件名以.jpg结尾,为什么还需要setImageFormat('jpg')呢?为什么首先需要setImageCompression()呢?这些Imagick的荒谬之处是否有解释? - matteo
出色的解决方案...我只将5MB大小的图像压缩到了788KB,使用这些额外方法后,文件大小缩小到了两位数KB。 - John the Ripper
这仍然非常有效。一切都大大减少了。一个样本jpg从45747kb降至12818kb。不过必须小心。原始文件错误地上传为PNG,导致文件大小膨胀到121778kb!所以,我猜要远离pngs... - LizardKG

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