PNG 转 JPG 透明背景变白?图片格式互转的能力边界
上周有个设计师把透明背景的 logo 发到工作群,是一张 PNG。我让她顺手转成 JPG 再发一遍,省点流量。她转完发出来,logo 周围多了一圈白底,贴到深色背景的网页上像个白色膏药。她跑来问我:是不是工具坏了?
工具没坏,是 JPG 这个格式压根不支持透明。这种「转完发现不对劲」的事在图片互转里太常见,而绝大多数都不是 bug,是格式本身的能力边界。这篇文章就讲一件事:把图片从一种格式转成另一种时,到底会丢什么。
三种格式的能力差异
先看一张对比表,这是后面所有讨论的基础:
| 格式 | 压缩方式 | 透明(Alpha) | 动画 | 典型用途 |
|---|---|---|---|---|
| JPG | 有损 | 不支持 | 不支持 | 照片、色彩丰富的图 |
| PNG | 无损 | 支持 | 不支持 | 图标、Logo、需要透明或锐利边缘的图形 |
| WebP | 有损和无损都支持 | 支持 | 支持 | 网页通用,可替代前两者 |
关键看中间两列:透明和动画。JPG 两项都不支持,PNG 支持透明但不支持动画,WebP 全都要。压缩方式决定了第二类问题:JPG 是有损,每次重新编码都会丢一点细节;PNG 是无损,画质不丢但体积大。
转换在浏览器里是怎么发生的
不管是网页工具还是你手写的脚本,浏览器里图片互转几乎都走同一条路:Canvas。
伪代码大概长这样:
const img = new Image()
img.src = URL.createObjectURL(file)
img.onload = () => {
const canvas = document.createElement('canvas')
canvas.width = img.width
canvas.height = img.height
const ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0)
canvas.toBlob(blob => { /* 保存 */ }, 'image/jpeg', 0.85)
}
四步:把原图解码进内存、画到 canvas、用 toBlob 按新格式重新编码、输出。重点在第三步,新格式能保存什么、不能保存什么,全由它决定。canvas 只是个中转的像素缓冲,它手里是完整的 RGBA 像素数据,但目标编码器吃不下,就只能丢掉。
toBlob 的第三个参数是 quality,0 到 1 之间,只对 JPG 和 WebP 的有损模式生效。PNG 是无损,传了也没用。
透明变白,是格式限制不是 bug
回到开头那个场景。PNG 的透明靠 Alpha 通道,每个像素除了 RGB 还带一个 0 到 1 的不透明度。WebP 也支持。JPG 没有这个通道,编码器拿到带透明的像素时必须做一个决定:透明区填什么颜色。
大多数实现默认填白。所以透明 logo 转 JPG,本来透明的位置全变成纯白像素,贴到任何非白背景上都会露馅。这也是为什么很多转换工具会让你指定一个背景色,本质是提前告诉编码器:透明区按这个颜色填。
想保留透明,输出格式必须支持 Alpha,也就是 PNG 或 WebP。这是硬规则,没有别的曲线救国办法。
体积反而变大,也是个常见坑
直觉上「转换」会减小体积,其实未必。两种情况会让转完反而更大:
第一种,PNG 转 JPG,图是简单图形。 PNG 对色块少、边缘锐利的图形压缩效率很高。如果这是一张图标或截图,转成 JPG 后,JPG 的有损压缩在锐利边缘上产生振铃,噪点变多反而吃掉了更多字节。一张 50KB 的 PNG 图标转 JPG 可能变成 120KB。
第二种,对已经压缩过的图再压一遍。 JPG 是有损,每次重新编码都会在已有失真上叠加新的失真,画质掉一档,但体积未必变小。把一张已经是 0.7 质量的 JPG 再以 0.85 质量「提升」一下转出来,体积暴涨,画质还回不去。这种操作叫世代损失,是图片处理里的大忌。
判断要不要转,看原图类型:照片、色彩渐变多的图,JPG 或 WebP 通常更小;图标、文字截图、扁平图形,PNG 更合适,硬转反而吃亏。
几个不那么明显的丢失
除了透明和体积,还有两类信息容易被忽略:
元数据(EXIF)。 拍照方向、拍摄时间、GPS、相机型号这些都在 EXIF 里。Canvas 解码时一般会丢掉,toBlob 出来的图通常没有 EXIF。如果你依赖照片里的方向信息旋转图片,转完会发现方向不对。
画质细节。 JPG 转 PNG 体积会变大但画质不会变好,丢掉的细节已经丢了,PNG 只是把已经损失过的画面无损保存下来。指望靠转格式「画质提升」是误解。
实操:动手试一下
想直观看到这些差异,把同一张图丢进 UPTools 图片格式转换工具 里来回转一次最清楚。透明 PNG 转 JPG 时可以指定背景色,转 WebP 可以调 quality。处理全在浏览器本地,不上传。
三句话总结
JPG 不支持透明和动画,透明 PNG 转 JPG 时透明区会被填成背景色,默认白,这不是 bug。Canvas 转换只是中转,丢什么完全由目标格式决定,想保留透明就只能输出 PNG 或 WebP。同图转同格式或对已压缩图再压,体积反而可能变大,照片用 JPG/WebP、图形用 PNG,别盲目互转。
相关文章