uni.compressimage 压缩后图片发灰、色偏、尺寸失控,根本原因是各端行为不一致且参数理解错误:quality 在 ios/android/小程序表现不同,compressedwidth/height 是最大值而非目标值,width 传字符串在部分安卓失效;canvas 压缩需按 dpr 缩放物理像素并控制 css 尺寸;base64 直传 uploadfile 会导致体积翻倍;微信分享封面超 120kb 会触发服务端强制压缩,须用 webp 或高质量 jpeg 并验证真实体积。

uni.compressImage 压缩后图片发灰、色偏、尺寸失控?别信 quality 参数
直接传 quality: 80 给 uni.compressImage 是多数人踩坑的起点。这个 API 在不同端行为完全不一致:iOS 可能只对 JPEG 生效,Android 常忽略 quality 改用固定比例缩放,微信小程序甚至会把 PNG 强制转成 JPEG,透明通道直接丢掉。
-
compressedWidth/compressedHeight不是目标尺寸,而是“最大允许宽高”,实际输出可能更小,且不保证等比 - 传
width: '85%'这类字符串参数,在部分安卓机型上解析失败,退化为原始尺寸 - 压缩后文件体积没变小?大概率是平台没真正执行压缩,只是返回了原图路径
canvas 压缩必须手动适配 DPR,否则必糊
在 iPhone 14 Pro(DPR=3)上用 800×600 的 canvas 画图,结果模糊,不是 canvas 问题,是你没告诉它“该画多少物理像素”。浏览器按 CSS 像素渲染,但高 DPR 设备需要更多物理像素才能清晰。
- 先调
uni.getSystemInfoSync().pixelRatio拿到当前 DPR - 创建 canvas 时,
width和height设为「目标 CSS 尺寸 × DPR」,比如要输出 800×600 图,DPR=3 就设 canvas 为 2400×1800 - 再用
canvas.style.width = '800px'、canvas.style.height = '600px'控制显示尺寸 -
drawImage时传入的 targetWidth/targetHeight 必须是 CSS 尺寸(如 800/600),不是 canvas 物理尺寸 -
uni.canvasToTempFilePath的destWidth/destHeight也必须填 CSS 尺寸,否则会二次缩放
上传前传 base64 是体积翻倍的陷阱
很多插件(如 uni-image-compress)默认返回 base64 字符串,直接把它当 filePath 传给 uni.uploadFile,会导致额外 base64 编码 —— 实测体积比原图还大 30%,服务器收到的是 double-encoded 数据。
- 确认插件文档:它返回的是
base64还是tempFilePath(如uni-file://xxx.jpg) - 如果是 base64,必须先用
uni.base64ToArrayBuffer+uni.arrayBufferToTempFile转成临时文件路径 - 上传时只认
filePath字段,且必须是本地文件路径,不能是 data URI 或 base64 字符串
微信小程序分享封面模糊,核心是体积超 120KB 触发强制压缩
微信服务端对分享封面有隐性限制:超过约 120KB 就会触发无损压缩算法,画质断崖式下降。这不是前端能绕过的,必须从源头控体积。
- 目标尺寸严格按 5:4(如 750×600),避免裁剪留白引入冗余像素
- 优先用 WebP 格式,比 JPEG 同质量小 30%+;若需兼容旧版微信,降级用高质量 JPEG(
quality: 92) - 压缩后务必用
uni.getFileInfo检查真实体积,别只信插件返回的“压缩成功” - 若仍超限,改用 canvas 逐层绘制(背景 + 文字 + logo),避开原图压缩失真











