Canvas的drawImage九参数形式可实现等比例裁剪缩放:先按目标宽高比居中计算裁剪区域(sx,sy,sw,sh),再缩放绘制到(dx,dy,dw,dh);需图片加载完成后再调用,并注意跨域和内存管理。

Canvas 的 drawImage 方法本身不提供“一键裁剪+等比缩放”功能,但用它的九参数形式就能精准实现——关键在于算对裁剪区域,再映射到目标尺寸。
必须等图片加载完成再绘制
未加载完的 Image 对象,naturalWidth 和 naturalHeight 为 0,此时调用 drawImage 不报错也不出图。正确做法是把所有绘制逻辑放在 img.onload 回调里:
- 如果是用户上传文件,用
URL.createObjectURL(file)赋值给img.src,绘制完成后记得URL.revokeObjectURL()防止内存泄漏 - 加载 CDN 或跨域图片时,务必设置
img.crossOrigin = 'anonymous',否则后续调用toDataURL或读像素会触发安全错误
九参数 drawImage 是裁剪缩放的核心
只有 drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh) 这种写法才能同时控制“从哪裁”和“画多大”。各参数含义明确:
-
sx/sy:裁剪起点,在原图左上角坐标系中取值 -
sw/sh:裁剪区域宽高,不是目标尺寸,而是源图上实际截取的像素范围 -
dx/dy:在 canvas 上绘制的起始位置(常为 0, 0) -
dw/dh:最终绘制区域的宽高,决定缩放比例
例如:原图 1200×800,目标显示区域 400×300(宽高比 4:3),因原图更宽(1200/800 = 1.5 > 4/3 ≈ 1.33),就以高度为基准裁剪:sh = 800,sw = 800 × (4/3) ≈ 1066.67,sx = (1200 − 1066.67)/2 ≈ 66.67,sy = 0。
再传入 drawImage(img, 66.67, 0, 1066.67, 800, 0, 0, 400, 300) 即可居中裁剪并等比缩放。
裁剪区域计算要匹配宽高比
等比例裁剪的本质,是让裁剪区域与目标区域保持相同宽高比,并尽量居中保留主体。计算逻辑分两种情况:
- 当
img.width / img.height ≥ targetW / targetH(原图更宽或相等):按高度满裁,宽度按目标比例反推 →sh = img.height,sw = img.height × (targetW / targetH) - 当
img.width / img.height < targetW / targetH(原图更高):按宽度满裁,高度反推 →sw = img.width,sh = img.width / (targetW / targetH)
算出 sw、sh 后,sx 和 sy 就是居中偏移量:sx = (img.width − sw) / 2,sy = (img.height − sh) / 2,结果自然居中无变形。
导出结果要用 toDataURL 或 getImageData
drawImage 只是把像素画到 canvas 上,不会自动生成新图片文件。如需保存或上传:
- 调用
canvas.toDataURL('image/png')得到 base64 字符串,可直接赋给<img src>或发给后端 - 若要 JPEG 并控制质量,用
toDataURL('image/jpeg', 0.8)(第二参数仅对 JPEG 有效) - 如需逐像素处理(比如加滤镜),用
ctx.getImageData(0, 0, canvas.width, canvas.height)获取 RGBA 数据数组









