必须用canvas重绘导出Blob才能真正减小图片体积;需在img.onload中读取naturalWidth/naturalHeight确保准确缩放;toBlob质量参数仅对JPEG/WEBP生效,PNG应优先转JPEG并设0.7–0.85质量压缩。

直接用 width 和 height 属性硬设尺寸,或靠 CSS 强行缩放,都不能真正减小图片体积——浏览器仍会下载完整原始文件。真要解决“大图卡顿、上传失败、带宽浪费”,必须在前端做**像素级压缩**,也就是用 canvas 重绘并导出更小的 Blob。
canvas 压缩前必须用 naturalWidth/naturalHeight
很多人用 img.width 和 img.height 获取尺寸,结果缩放错乱甚至拉伸变形。这是因为这两个属性可能已被 CSS 或 HTML 属性覆盖,不代表原始分辨率。
正确做法是等 img.onload 触发后,读取 img.naturalWidth 和 img.naturalHeight——这才是图片真实的像素宽高。
常见错误现象:竖图变横图、人像被压扁、缩放后边缘模糊。
实操建议:
- 永远在
img.onload回调里读取naturalWidth/naturalHeight,别在外面提前取值 - 计算缩放比例时,先判断长边(
Math.max(naturalWidth, naturalHeight)),再按目标最大值(如 1200)等比缩放 - 若原图是 4000×3000,目标长边 1200,则新宽 = 4000 × (1200 / 4000) = 1200,新高 = 3000 × (1200 / 4000) = 900
toBlob 的质量参数只对 JPEG/WEBP 生效
canvas.toBlob(callback, 'image/jpeg', 0.7) 中的 0.7 是关键压缩开关,但它对 PNG 完全无效——PNG 不支持质量调节,只认像素和透明通道。
所以如果你传入一张 PNG,却用 JPEG 参数压缩,结果可能更大:canvas 会把透明背景填黑,再编码成 JPEG,反而增加冗余。
实操建议:
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
- 优先转 JPEG:只要不需要透明,一律用
'image/jpeg'+0.7–0.85区间,体积下降最明显 - 需要透明才用 PNG:此时删掉第三个参数,改用尺寸压缩(比如从 3000px → 800px)来降体积
- iOS Safari 对
toBlob支持不稳定,可 fallback:canvas.toDataURL('image/jpeg', 0.7)再用dataURLToBlob()转回 Blob
FileReader 必须在 onload 里处理结果
写 reader.readAsDataURL(file) 后立刻读 reader.result,十有八九是 undefined 或空字符串。这不是 bug,是异步读取没完成。
典型错误代码:reader.readAsDataURL(file); const data = reader.result; // ❌ 这里 data 总是空
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 所有基于
FileReader的逻辑,包括创建Image、设置src、触发drawImage,都必须塞进reader.onload回调内 - 大文件(>5MB)建议加
reader.onprogress显示进度条,避免用户以为卡死 - 读取失败时检查
reader.error,常见报错如DOMException: Failed to execute 'readAsDataURL',多因文件被释放或跨域限制
真正难的不是写几行 drawImage,而是处理各种隐性陷阱:EXIF 方向错乱(尤其 iOS 拍照)、透明通道误填、长边判断逻辑漏 case、iOS 上 toBlob 失效却不报错。这些点不手动测过真机+不同格式图片,很容易上线后才发现某类图死活压不下来。


















