使用GD库转换WebP时如何保留原JPG图片的元数据?
如何在JPG转WebP并缩放时保留元数据?
服务器上存储着JPG格式图片,当浏览器请求时,如果对应的WebP图片不存在,我会对原JPG进行缩放并转换为WebP格式。目前转换流程正常,但生成的WebP图片丢失了原JPG中的作者、版权、注释等元数据。请问能不能在缩放或转换过程中把原图片的元数据添加到新的WebP图片里?
原代码如下:
$image = new Image(DIR_IMAGE . $old_image); $image->resize($width, $height); $image->save_webp(DIR_IMAGE . $new_image_webp, $quality); public function resize($width = 0, $height = 0, $default = '') { if (!$this->info['width'] || !$this->info['height']) { return; } $xpos = 0; $ypos = 0; $scale = 1; $scale_w = $width / $this->info['width']; $scale_h = $height / $this->info['height']; if ($default == 'w') { $scale = $scale_w; } elseif ($default == 'h') { $scale = $scale_h; } else { $scale = min($scale_w, $scale_h); } if ($scale == 1 && $scale_h == $scale_w && $this->info['mime'] != 'image/png') { return; } $new_width = (int)($this->info['width'] * $scale); $new_height = (int)($this->info['height'] * $scale); $xpos = (int)(($width - $new_width) / 2); $ypos = (int)(($height - $new_height) / 2); $image_old = $this->image; $this->image = imagecreatetruecolor($width, $height); if (isset($this->info['mime']) && $this->info['mime'] == 'image/png') { imagealphablending($this->image, false); imagesavealpha($this->image, true); $background = imagecolorallocatealpha($this->image, 255, 255, 255, 127); imagecolortransparent($this->image, $background); } else { $background = imagecolorallocate($this->image, 255, 255, 255); } imagefilledrectangle($this->image, 0, 0, $width, $height, $background); imagecopyresampled($this->image, $image_old, $xpos, $ypos, 0, 0, $new_width, $new_height, $this->info['width'], $this->info['height']); imagedestroy($image_old); $this->info['width'] = $width; $this->info['height'] = $height; } public function save_webp($file, $quality = 40) { if (is_resource($this->image)) { imagewebp($this->image, $file, $quality); imagedestroy($this->image); } }
问题原因
你当前使用的GD库在通过imagecreatetruecolor创建新图像资源、imagecopyresampled缩放图像的过程中,不会保留原JPG的元数据;而且GD的imagewebp函数也没有提供写入元数据的参数,所以最终生成的WebP会丢失这些信息。
可行解决方案
方案1:使用cwebp命令行工具(推荐,无需扩展)
cwebp是Google官方的WebP转换工具,支持通过参数保留元数据。步骤如下:
- 确保服务器已安装cwebp(大部分Linux发行版可通过包管理器安装,比如
apt install webp) - 修改转换逻辑,先缩放原图片到临时JPG,再用cwebp转换并保留元数据:
$oldImagePath = DIR_IMAGE . $old_image; $newWebpPath = DIR_IMAGE . $new_image_webp; $quality = 40; // 先缩放原图片到临时文件 $image = new Image($oldImagePath); $image->resize($width, $height); $tempJpg = tempnam(sys_get_temp_dir(), 'resized_jpg_') . '.jpg'; // 假设你的Image类有save方法用于保存JPG(如果没有,可补充类似save_webp的save_jpg方法) $image->save_jpg($tempJpg, 100); // 用cwebp转换,-metadata all表示保留所有元数据 exec("cwebp -metadata all -q $quality $tempJpg -o $newWebpPath"); // 删除临时文件 unlink($tempJpg);
方案2:使用Imagick扩展(更简洁)
如果服务器支持Imagick扩展,处理起来更直接,Imagick默认支持保留图像元数据:
$imagick = new Imagick(DIR_IMAGE . $old_image); // 缩放图片,使用LANCZOS滤镜保证画质 $imagick->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1); // 设置输出格式为WebP,指定压缩质量 $imagick->setImageFormat('webp'); $imagick->setImageCompressionQuality($quality); // 写入文件,元数据会自动保留 $imagick->writeImage(DIR_IMAGE . $new_image_webp); $imagick->destroy();
方案3:GD库手动处理(不推荐)
GD库本身没有写入WebP元数据的API,手动解析并写入WebP的元数据区块(比如EXIF、XMP)需要深入了解WebP文件格式,开发成本极高,不建议采用。
内容的提问来源于stack exchange,提问作者bobi
相关产品推荐
相关产品推荐

