跨端图片压缩应统一用canvas+toDataURL,因uni.compressImage在H5不存在、小程序为空函数、App端quality参数指最大边长而非质量值;需先调uni.getImageInfo获取真实宽高,等比缩放,强制转JPEG压缩,H5优先用toDataURL得base64并设Content-Type头。

别直接调 uni.compressImage —— 它在 H5 不存在、小程序是空函数、App 端 quality 参数根本不是质量值,白忙一场。
跨端统一用 canvas + toDataURL 压缩最稳
这是目前唯一能同时跑通 H5、微信小程序、App 的方案,但必须绕开几个硬坑:
- 先调
uni.getImageInfo拿真实宽高,别信tempFilePath后缀或文件名(比如 .webp 实际可能是 JPEG) - 缩放必须等比:目标宽度设为 1200px,就用
scale = Math.min(1200 / originalWidth, 1),再算新高度,否则拉伸变形 -
toDataURL("image/jpeg", 0.75)中的0.75仅对 JPEG 生效;PNG 忽略第二参数,若想压体积,必须强制转 JPEG(会丢透明通道) - H5 下
canvas.toBlob在 iOS Safari 兼容性差,优先用toDataURL得到 base64,再传给uni.uploadFile,记得加 header:{"Content-Type": "image/jpeg"}
App 端非要硬上 uni.compressImage 怎么填参
只在 uni.getSystemInfoSync().platform === "app" 时才调,且参数语义和你想的完全相反:
-
quality: 800不是“质量 80%”,而是“长边最大 800px”,系统自动选 JPEG + 默认质量(≈0.8) - iOS 有静默限制:原图任一边 > 4096px,
compressImage直接跳过压缩,返回原图路径 - 别传
quality: 30—— 这会让输出图分辨率过高,文件反而更大 - 真要控体积(比如 ≤200KB),App 端也得 fallback 到 canvas 方案,
compressImage只适合控尺寸
上传前必须校验压缩结果
压缩不是终点,上传失败往往发生在压缩后:
- canvas 压缩后仍可能超 5MB(微信限制),得在
toDataURL后用atob算 base64 长度,粗略估算字节数:Math.ceil(base64.length * 3 / 4) - (base64.indexOf('==') > 0 ? 2 : base64.indexOf('=') > 0 ? 1 : 0) - 部分安卓机
getImageInfo返回type: "webp",但服务端不认,需统一转成image/jpeg - 别把 base64 当
filePath直接塞进uni.uploadFile—— 它只认本地路径或临时文件路径,base64 得走formData或后端 base64 解码逻辑
真正麻烦的不是写几行 canvas,而是每台 iPhone 的 DPR 不同、每个安卓厂商的 JPEG 编码器行为不同、每个小程序平台对 tempFilePath 的处理逻辑不同——压缩逻辑里漏掉一个 devicePixelRatio 或少做一次 MIME 校验,上线后就会有人拍糊图、传灰图、上传卡死。


















