先说个事
上个月接了个小活,帮一个卖宠物用品的店主整理商品图。摄影师给的是 6000×4000 的 TIFF,一共 412 张,我一看这尺寸就头大,随手写了段 shell 准备一把梭。结果第一批图发过去,店主回了一句“怎么看着不如原来的清楚”。我当时还不太服气,自己放大对比了一下,发现猫毛的边缘确实是发虚的,那种说不清的糊,不是马赛克那种糊。
问题不在压缩率,在缩放链条
我一开始的直觉是压缩质量给低了,把 mozjpeg 的 q 从 82 提到 95,单张从 70KB 涨到 210KB,看着还是不对。后来盯着脚本看了半天才反应过来,我干了这么一件事:原图先缩到 1200×800 存了一份,再从 1200×800 缩到 800×800 当主图。等于同一张图被重采样了两次。重采样本质上是拿周围像素做加权平均,Lanczos 那个核函数在边缘附近会产生过冲,也就是你放大之后能看到的白边或者黑边。一次还能忍,叠两次,锐利的边缘就被磨圆了。这跟压缩质量一点关系都没有,你把 q 开到 100 也救不回来。
我后来把脚本改成每次都从原图出发,算好目标尺寸,一次 resize 直接输出,中间不落地成文件。就这一改,同样的 q82,同样的文件大小,肉眼观感完全两样。所以我现在判断一张图处理得好不好,不看它多大,先看它被缩了几次。
那些藏在参数里的坑
改成一次缩放之后又踩了几个。ImageMagick 的 -thumbnail 比 -resize 快,但它默认会把 EXIF 和 ICC profile 一起抹掉,我那批图有一部分是 AdobeRGB 的,缩完直接发灰,店主还以为是显示器的问题。要留色彩空间就得自己加 -profile 或者干脆用 -resize 手动控制。sharp 那边也有类似的,它的 kernel 默认是 lanczos3,处理那种带噪点的高感照片时,噪点周围会起振铃,改成 mitchell 会稳很多,代价是锐度稍微降一点点。
另一个很多人不看的东西是色度子采样。JPEG 默认走 4:2:0,意思是每四个亮度像素共用一组色度信息。风景照上完全没感觉,但你的图里有红色小字、细的彩色线条,边缘就会糊成一坨。带文字的产品图可以试试 4:4:4,文件大概大两到三成,清晰度是肉眼能看出来的差别。
我最后落地的参数
412 张跑完一共 4 分 20 秒,M1 Mac mini,ImageMagick 7.1.1 配 cjpeg 4.1.1。主图 800×800 走 mozjpeg q82、4:4:4、加 -tune-ms-ssim,平均 68KB;详情页 750 宽出 WebP -q 80 -m 6,平均 41KB;小程序要的 1200 宽用 AVIF,cq-level 28,平均 33KB。图标那类纯色图不走 JPEG,用 pngquant --quality=65-90 --speed 1,从 40KB 压到 9KB 左右。
这些数字不是标准答案,是我这批图跑出来相对舒服的位置,你换个素材可能就不一样。但有个顺序是通用的:先定尺寸,再定格式,最后才动质量参数。反过来做,基本就是白折腾。
前端那一层也别忘了
还有个事挺多店主不知道的,图糊不一定是图本身糊,是 <img> 没配 srcset。800px 的图在 iPhone 上按 375 逻辑宽度显示,CSS 里写死 width:100%,3x 屏就得拉一张 800 的图去填 1170 个物理像素,不糊才怪。正确写法是 srcset 给 800w/1200w/1600w,sizes 写对,浏览器自己挑。这事儿跟后端压缩是两码事,两边都得管。
我也不是什么专业人士,就是踩坑踩多了有点心得。如果你手上就十张图,PS 里手动处理完全没问题。但到了几百张这个量级,每一步能不能复现、能不能从原图重来一遍,比某个参数调得多精贵重要多了。