You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

PHP图片上传缩放后无法保持100%质量问题求助

解决PHP GD缩放图片质量不如Photoshop的问题

我之前也碰到过一模一样的情况——明明把JPEG质量拉到100,缩放后的图还是比PS导出的模糊发灰。这是因为GD库默认的配置比较基础,没有做PS那种自动的色彩校正、锐化和透明度处理,咱们一步步改你的代码就能解决:

1. 给JPEG加上优化参数(PHP 7.2+支持)

你的代码里已经设置了quality=100,但imagejpeg还有第四个参数可以开启优化模式,能让JPEG在100质量下更接近原图的色彩和细节:

// 替换你save_img里的JPEG保存代码
if($this->resize) {
    // 开启优化模式,让100质量的JPEG更接近无损表现
    imageJPEG($this->img_output, __DIR__ . "/../uploads/" . $path, $this->quality, IMG_JPEG_OPTIMIZE);
} else {
    copy($this->img_src, __DIR__ . "/../uploads/" . $path);
}

2. 修复PNG的透明度与边缘模糊问题

如果是PNG图,ImageCreateTrueColor默认不会保留透明通道,会导致边缘发灰。而且PNG的压缩等级不影响质量(因为是无损),所以可以保留9,但要添加透明支持:

// 在创建PNG的输出图后添加这两行(save_img方法里的Resize分支)
$this->img_output = ImageCreateTrueColor($this->x_output, $this->y_output);
// 开启alpha通道支持,避免透明边缘发灰
imagealphablending($this->img_output, false);
imagesavealpha($this->img_output, true);
ImageCopyResampled($this->img_output, $this->img_input, 0, 0, 0, 0, $this->x_output, $this->y_output, $this->x_input, $this->y_input);

3. 添加缩放后锐化(关键!PS自动做了这步)

GD库缩放后会丢失细节,而PS会自动添加轻微锐化。咱们可以用卷积核给缩放后的图做一次锐化,文字和边缘会清晰很多:

// 在你的imaging类里新增一个锐化方法
private function sharpen_image($image) {
    $sharpen_matrix = array(
        array(-1, -1, -1),
        array(-1, 16, -1),
        array(-1, -1, -1)
    );
    $divisor = 8;
    $offset = 0;
    imageconvolution($image, $sharpen_matrix, $divisor, $offset);
    return $image;
}

// 然后在save_img的Resize分支里,缩放后调用这个方法
$this->img_output = ImageCreateTrueColor($this->x_output, $this->y_output);
// 先处理透明(如果是PNG),然后缩放
ImageCopyResampled($this->img_output, $this->img_input, 0, 0, 0, 0, $this->x_output, $this->y_output, $this->x_input, $this->y_input);
// 调用锐化
$this->img_output = $this->sharpen_image($this->img_output);

4. 保留原图的ICC色彩配置文件(解决色彩暗淡)

原图可能带有ICC色彩配置文件,GD默认会忽略,导致色彩偏差。咱们可以读取原图的ICC信息,写入到新图里:

// 在set_img方法里,添加读取ICC的代码(获取完x_input和y_input之后)
$icc_data = iheader($this->img_src, 'ICC_PROFILE');
if($icc_data) {
    $this->icc_profile = $icc_data;
}

// 然后在save_img方法里,保存图片前添加:
if(isset($this->icc_profile)) {
    imageiccprofile($this->img_output, $this->icc_profile);
}

5. 启用更精确的插值算法(PHP 8.0+支持)

如果你的PHP版本是8.0以上,可以设置更精确的插值模式,比默认的双线性插值效果更好:

// 在创建输出图后添加
imageinterpolation($this->img_output, IMG_BICUBIC_PRECISE);

把这些修改加进去之后,你缩放后的图片质量会和PS导出的非常接近——文字清晰、色彩还原准确。本质上就是把PS自动做的那些细节处理,手动用GD的API实现出来。

内容的提问来源于stack exchange,提问作者pavel

火山引擎 最新活动