核心是用处理画布执行精确裁剪并生成可用资源,需校正CSS像素与设备像素缩放比,用naturalWidth/naturalHeight获取真实分辨率,通过9参数drawImage裁剪,再用toDataURL或toBlob导出。

图像裁剪后导出图片数据,核心是**用处理画布(而非展示画布)执行精确裁剪并生成可用资源**,不能依赖截图式取图,否则会因缩放、跨域或坐标错位导致黑图、偏移或空白。
确保裁剪区域映射到原始像素坐标
用户看到的裁剪框位置是 CSS 像素,而 Canvas 绘图基于设备像素。必须做两层校正:
- 用 canvas.getBoundingClientRect() 获取显示尺寸,再通过 canvas.width / canvas.clientWidth 算出实际缩放比
- 将裁剪框的 left/top 除以该缩放比,得到对应 Canvas 像素坐标系中的位置
- 原始图片要用 img.naturalWidth / naturalHeight 获取真实分辨率,不能用 img.width/height(那是渲染尺寸)
- 最终源区域坐标按比例换算:sourceX = (cropLeft × img.naturalWidth) / canvas.width,并确保 sourceX + sourceWidth ≤ img.naturalWidth
用 drawImage 进行高效裁剪(推荐)
避免 getImageData + putImageData 的内存开销和兼容性风险,直接用 9 参数版 drawImage 将原始图中指定区域绘制到新 canvas:
- 创建一个临时 canvas,宽高设为裁剪目标尺寸(如 cropWidth × cropHeight)
- 调用 ctx.drawImage(img, sourceX, sourceY, sourceWidth, sourceHeight, 0, 0, targetWidth, targetHeight)
- 务必使用 9 参数签名——传错参数顺序(比如把目标位置当源位置)会导致静默失败,画面全黑或空白
导出为可用图片格式
裁剪完成后,从临时 canvas 导出数据。根据用途选择合适方式:
- 需要 Base64 字符串(如上传、嵌入 HTML):调用 canvas.toDataURL('image/jpeg', 0.85);JPEG 质量必须是 0.0–1.0 的小数,PNG 不支持质量参数
- 导出 JPEG 时透明背景会变黑:导出前先填白底 —— ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, canvas.width, canvas.height)
- 大图(如 >2000×2000)优先用 canvas.toBlob(callback, 'image/jpeg', 0.85),更省内存,再配合 URL.createObjectURL() 下载
- 跨域图片必须同时满足:img.crossOrigin = 'anonymous' + 服务端返回 Access-Control-Allow-Origin 头,本地开发禁用 file:// 协议











