上周三晚上十一点,朋友把她婚礼的 300 多张照片从 iPhone 导出来发我,微信上连发了三条一样的消息:为什么在电脑上看颜色是灰的,手机上好好的。这事我太熟了。2019 年做详情页的时候,我因为同一个问题被甲方退过两次稿,当时还以为是显示器色差,咬牙换了台艺卓,没用。后来才发现问题根本不在显示器上。
先说结论:顺序比参数重要
大多数人以为图片处理就是「调大小 + 压质量」,中间少了两步,而且顺序经常是反的。我这几年试下来,唯一不会翻车的流程是:
色域转换 → 裁剪缩放 → 锐化补偿 → 有损压缩
这四步里任何一步调换位置,你都得从头再来一遍。比如先压缩再锐化,压缩产生的块效应会被锐化放大成一片噪点;先锐化再缩放,锐化出来的边缘会被重采样抹掉,等于白做。下面一条条说。
坑一:色彩空间丢了,图就发灰
iPhone 从 7 那代开始默认拍 Display P3,文件里嵌一个 ICC profile 描述它的色域。传到电脑上,如果软件不认这个 profile——大部分 Windows 看图工具、一堆网页都这样——就会直接按 sRGB 来解释 P3 的像素数值。P3 能表示的绿和红比 sRGB 更饱和,同一组数字放到 sRGB 里就变淡了,看着就是发灰、发闷、皮肤发青。
先确认问题。装个 exiftool,跑:
exiftool -ProfileDescription -ColorSpace -icc_profile:all photo.jpg
输出里出现 Display P3 或者 P3 字样,那就是它了。转的话:
magick in.heic -profile "/System/Library/ColorSync/Profiles/sRGB Profile.icc" -resize 1600x -quality 82 out.jpg
Linux 上 sRGB profile 一般在 /usr/share/color/icc/ 下面,找不到就从 ImageMagick 自带的 icc 目录里翻。这里有个坑我要单独说:别拿 -colorspace sRGB 去代替 -profile。我 2020 年图省事这么干过,-colorspace 只是改色彩模型,不带色域映射,P3 的图这么转完颜色会歪得很难看,红色会往橙色跑。这个命令网上教程里到处都是,别信。
坑二:缩小图片用错了重采样滤波器
把 4032×3024 缩到 1600 宽,软件在算新像素值的时候有一堆算法可选,ImageMagick 默认是 Mitchell,Photoshop 默认是「两次立方(自动)」。这两个对照片来说都不算最优。缩图这个动作本质上是低通滤波,滤得不够狠就会出摩尔纹,滤得太狠就是糊。
我的经验值:照片用 Lanczos,文字和 UI 截图用点采样或者直接最近邻(缩放倍数是整数倍时才好看)。
magick in.jpg -filter Lanczos -resize 1600x -quality 82 out.jpg
顺带辟个谣。网上流传很广的「缩小要分多次、每次缩一半,直缩会糊」——我拿同一张 4032px 的图对比过,一次 Lanczos 和分四次缩的,100% 放大看几乎没差别,分多次反而多几次重采样,边缘更容易出振铃。真正决定糊不糊的是滤波器,不是次数。
另外算一下你到底需要多大。一张 27 寸 4K 屏(3840×2160),全屏看图最多也就用满 3840 宽;网页里展示的图,如果 CSS 宽度是 800px,给手机 2x 屏看就存 1600px 宽足够。存 4032 是纯浪费,一张多出几百 KB,20 张图就是几 MB 的流量。
坑三:锐化,缩完必做但别做过头
重采样之后图像的高频信息少了,视觉上就是「肉」。这里要补一次 USM 锐化,但参数要保守。我常用的一组:半径 0.5–0.8 像素,数量 60%–80%,阈值 3–4。阈值别设 0,设 0 会把天空、皮肤这些平滑区域里的噪点一起锐出来,放大看一脸麻子。
ImageMagick 对应的是:
-unsharp 0x0.75+0.7+0.004
格式是 半径x标准差+数量+阈值。这个 0.004 对应的是 1/255,差不多就是阈值 1 的量级,具体自己拿几张图看着调。还有个细节:锐化要在压缩之前做,而且因为 JPEG 压缩会吃掉一部分锐度,如果你最终输出是 JPEG 质量 80,锐化的量可以比输出 PNG 时再多给 10%–15%。
坑四:格式和质量参数,照片和截图的结论是反的
我拿手上十几张照片(室内、户外、人像混着)跑了一遍,都缩到 1600px 宽,平均下来大概是这么个量级:
- JPEG(mozjpeg,-quality 82):约 260 KB
- WebP(cwebp -q 75 -m 6):约 180 KB
- AVIF(cq-level 24):约 140 KB
- PNG(oxipng -o4):约 2.1 MB
注意最后一行。照片类的图压成 PNG 是灾难,比 JPEG 大八倍不止。但反过来,UI 截图、表格、线条图、二维码这些,PNG 或者 WebP 无损反而比 JPEG 小,而且干净——JPEG 对高频边缘处理很差,截图里的文字周围会出蚊噪,红字黑底尤其明显。
两个具体参数值得记:
一是 JPEG 的色度抽样。默认 4:2:0 会丢掉一半色度分辨率,结果是细黑字边上泛彩边。如果图里有文字,用 4:4:4(mozjpeg 加 -sample 1x1),文件会大 10%–20%,但干净。
二是质量值。那个 85 是个心理锚点,不是技术门槛。我实测照片在 mozjpeg 的 78–82 之间基本看不出差别,再往下到 70 才会在渐变天空里看到色带。真要抠体积,先把尺寸砍到实际需要的宽度,比降质量划算得多。
想一步到位的话,整条流水线是这样:
magick in.heic -profile sRGB.icc -filter Lanczos -resize 1600x \
-unsharp 0x0.75+0.7+0.004 -quality 82 out.jpg
cwebp -q 75 -m 6 -sharp_yuv -metadata none in.png -o out.webp
批量跑就套个 for 循环,几十行的事,别一个个拖进软件里点。
最后:什么时候别折腾
说了这么多,其实有个前提我没提——如果你的图只在手机相册里存着、只在朋友圈发,上面这些你一个都不用管。iOS 和微信自己处理得挺好,你手动转一遍反而可能变差。
真正值得折腾的场景就三个:要做网页/小程序,体积直接影响加载速度;要交付印刷或者给客户,色彩一致性会挨骂;要归档一批照片,希望十年后还能打开。其他的,别给自己找活干。我自己现在也只在导出给网站用的时候才走这套流程,平时拍完直接扔相册,不折腾。