如何使用ImageMagick实现和浏览器效果一致的高质量图片缩小?
正方形商品图服务端缩放质量优化求助
背景
为提升移动端网店的加载速度,需要将1080x1080这类正方形商品图缩小至375x375的移动端屏幕适配尺寸。最初使用PHP标准GD库进行缩放,输出的图片质量极差,且文件体积没有明显下降。
改用ImageMagick进行缩放后效果有提升,但仍达不到预期:图片要么过于模糊,要么锐度过高,尝试不同滤镜时还会出现振铃效应、锯齿、模糊、色彩失真等问题,质量损失十分明显。但现代浏览器缩放同尺寸大图时却能保持极佳的质量,因此在翻阅Chromium源码之前,先来向社区请教优化方案。
已尝试的方案
已分别或组合测试了以下方案:
- 使用所有现有滤镜进行缩放
- 缩放后执行非锐化蒙版处理
- 不直接缩放到目标尺寸,先将原图宽度缩小一半,剩余缩放工作交给浏览器完成
测试与代码
所有测试结果汇总在以下页面,可调整参数查看效果:
核心实现代码
$imageBlob = file_get_contents('pics/'.$url.'.jpg'); $imagick = new Imagick(); $imagick->readImageBlob($imageBlob); if (isset($_GET['krat'])) { $imageWidth = $imagick->getImageWidth()/2; } else { $imageWidth = $width; } $gaussRadius = floatval($_GET['gauss_radius'] ?? 0); $sigma = floatval($_GET['sigma'] ?? 0.5); $threshold = floatval($_GET['threshold'] ?? 0.05); $sharp = isset($_GET['sharpen']); $quality = intval($_GET['qual'] ?? 100); $blur = floatval($_GET['blur'] ?? 1.0); $filters = [ 'scale' => 'scale', 'LANCZOS' => Imagick::FILTER_LANCZOS, 'LANCZOSSHARP' => Imagick::FILTER_LANCZOSSHARP, 'ROBIDOUX' => Imagick::FILTER_ROBIDOUX, 'ROBIDOUXSHARP' => Imagick::FILTER_ROBIDOUXSHARP, 'LANCZOS2' => Imagick::FILTER_LANCZOS2, 'LANCZOS2SHARP' => Imagick::FILTER_LANCZOS2SHARP, 'BOX' => Imagick::FILTER_BOX, 'TRIANGLE' => Imagick::FILTER_TRIANGLE, 'HERMITE' => Imagick::FILTER_HERMITE, 'HANNING' => Imagick::FILTER_HANNING, 'HAMMING' => Imagick::FILTER_HAMMING, 'BLACKMAN' => Imagick::FILTER_BLACKMAN, 'GAUSSIAN' => Imagick::FILTER_GAUSSIAN, 'CATROM' => Imagick::FILTER_CATROM, 'MITCHELL' => Imagick::FILTER_MITCHELL, 'BESSEL' => Imagick::FILTER_BESSEL, 'KAISER' => Imagick::FILTER_KAISER, 'PARZEN' => Imagick::FILTER_PARZEN, 'WELSH' => Imagick::FILTER_WELSH, 'SINC' => Imagick::FILTER_SINC, ]; foreach ($filters as $name => $filter) { $im = clone $imagick; if (isset($_GET['srgb'])) { $im->setImageColorspace(\Imagick::COLORSPACE_SRGB); } $im->setImageCompressionQuality($quality); switch ($filter) { case 'scale': $im->scaleImage($imageWidth, 0); break; default: $im->resizeImage($imageWidth, 0, $filter, $blur); } if ($sharp) { $im->unsharpMaskImage($gaussRadius, $sigma, 1, $threshold); } echo '<img style="width:'.$width.'px; height:'.$width.'px" src="data:image/' . $imagick->getImageFormat() . ';base64,' . base64_encode($im->getImageBlob()) . '"/>'; $im->removeImage(); }
内容的提问来源于stack exchange,提问作者Alex Rsk
相关产品推荐
相关产品推荐

