阻止 WordPress 把你的图片压缩到 82%
WordPress 会把它生成的每一张 JPEG 都以 0–100 标度中的 82 质量重新编码。这个默认值来自 WP_Image_Editor::get_default_quality(),并作用于每一张衍生图。
发布于
WordPress 会把它生成的每一张 JPEG 都以 0–100 标度中的 82 质量重新编码。这个默认值位于 WP_Image_Editor::get_default_quality(),并作用于 WordPress 从你上传的图片切出的每一个衍生尺寸——thumbnail、medium、medium_large、large,以及你主题注册的每一个额外尺寸。对于照片来说,82 是文件体积与画质损伤之间一个合理的折中。但对于截图、界面截取、图表、Logo,以及任何带有锐利文字或纯色块的图片,82 的破坏是肉眼可见的:每个字母周围都会爬满蚊式噪声,平滑渐变上则会出现色带。
要修改它,加一个过滤器并重新生成缩略图即可。而要专门解决截图的问题,更好的答案通常是——从一开始就别把 JPEG 交给 WordPress。
82 这个数字究竟从何而来
WordPress 早在 4.5 版本(2016 年)就把 JPEG 默认值从 90 降到了 82,作为一项减小页面体积的优化。这个值由 wp-includes/class-wp-image-editor.php 中的 get_default_quality() 返回,每当当前生效的图像编辑器——如果你的主机装了 Imagick 就是 WP_Image_Editor_Imagick,否则是 WP_Image_Editor_GD——写入一个缩放后的文件时都会读取它。
关键细节在于:82 是按每个衍生尺寸各自应用一次的,而不是只应用一次。你上传一张图,WordPress 会让它多次经过编码器,每一遍都以 82 质量重新量化。原始上传的文件本身是不会被动的,前提是它没有超过大图阈值(长边 2560px)。一旦超过这个阈值,WordPress 就会生成一张以 82 质量重新编码的 -scaled.jpg,并把它当作「full」尺寸对外提供。所以「我的全分辨率原图看着没问题,但页面上那一版糊成一团」几乎总是因为 srcset 挑中了某个 82 质量的子尺寸,或者那个 -scaled 文件。
如何修改质量
只需挂载一个过滤器。wp_editor_set_quality 是现代的、规范的那个——它对 JPEG 和 WebP 都会触发,并会接收 MIME 类型,方便你按类型分支处理:
add_filter( 'wp_editor_set_quality', function ( $quality, $mime_type ) {
if ( 'image/jpeg' === $mime_type ) {
return 92; // up from 82
}
return $quality;
}, 10, 2 );
把它放进一个小型的 mu-plugin(wp-content/mu-plugins/)或一个站点专用插件里。放 functions.php 也行,但你一换主题这个设置就没了。
你还会看到有人推荐更老的 jpeg_quality 过滤器。它至今仍会触发(WordPress 会在 wp_editor_set_quality 之后紧接着应用它,且仅对 JPEG),但没有理由把两个都挂上——wp_editor_set_quality 覆盖了旧过滤器能做的一切,而且更多。
有一件事人人都会忘:**这个过滤器只对它生效之后编码的图片起作用。**已经躺在 wp-content/uploads 里的每一张缩略图当初都是以 82 写入的,也会一直保持 82。重新生成它们:
wp media regenerate --yes
如果你没用 WP-CLI,Regenerate Thumbnails 插件能在后台里做同样的事。
在你定下一个数字之前,值得先看看某个质量到底对你自己的图片做了什么,而不是靠猜。我们的 WordPress JPEG 质量工具会在浏览器里以每一档质量重新编码一张样图,让你亲眼看着画质损伤逐渐浮现——它能让 82、90 和 100 在一张截图上的差别一目了然,这是配置文件里一个冷冰冰的数字永远做不到的。
针对截图和纯色图形的更优解
调高 JPEG 数字只是治标。截图真正的问题在于,JPEG 对它们来说就是错误的编码格式。JPEG 的 DCT 压缩是为照片式渐变调校的;它在文字和界面元素那种黑白分明的硬边缘上会彻底崩溃,这正是为什么 82 质量在截图上比在照片上难看得多。
改上传 PNG。WordPress 会把 PNG 的子尺寸继续保存为 PNG,而 PNG 是无损的——质量过滤器碰都不碰它,所以不管什么尺寸都不会有画质损伤,只有干净的重采样。对一张截图来说,一张优化良好的 PNG 往往比同一图像的高质量 JPEG 还要小,因为纯色块在 PNG 里压缩得很好,在 JPEG 里则压缩得很糟。
如果你既想要有损格式那种更小的文件,又不想要 JPEG 的边缘损伤,WebP 就是中间地带——但你依然是通过上面展示的同一个 wp_editor_set_quality 过滤器来控制它的质量,按 image/webp 分支即可。
不要这样做
**不要把质量全局设成 100。**这是半数论坛帖里得票最高的答案,而它是错的。100 质量的 JPEG 并不是无损的——它照样会量化——但它会让你站点上的每一张照片都膨胀一大截,换不来任何肉眼可见的收益,还会拖垮 LCP 和核心网页指标。该给谁调就给需要的那个格式调,或者干脆给图形换格式;别把全站压缩一锅端掉。
**不要去改 class-wp-image-editor.php。**改核心里 get_default_quality() 的返回值确实能用,直到下一次 wp core update 悄无声息地把它覆盖掉。用过滤器。
**不要为了「避开压缩」而禁用图片尺寸。**关掉缩略图生成并不能阻止重新编码——它只会破坏响应式 srcset,导致浏览器在手机上下载你的全尺寸原图。换了个问题,结果更糟。
**不要以为重新上传就能修好现有图片。**如果你设了过滤器却跳过了重新生成这一步,每一张旧衍生图仍然是 82 质量。过滤器只对将来生效。
如果你的图片都在 2560px 以下,就别怪到 -scaled 文件头上——那条路径对它们根本不会执行。如果你确实触发了它,并且想让未经处理的原图对外提供,那是另一个设置;参见禁用 scaled 图片。
还是搞不定?
如果重新生成之后某个特定尺寸看着还是不对,确认一下页面实际提供的到底是哪个文件——在新标签页里打开这张图,看看文件名是以尺寸后缀(-1024x768.jpg)还是以 -scaled.jpg 结尾。图片尺寸检查工具会列出 WordPress 从一次上传生成的每一张衍生图,这样你就能清楚看到你的 srcset 到底把哪个尺寸递给了浏览器,从而不再去调错文件。