canvas drawImage绘图实现contain和cover的效果
我们常用到css的background-size属性中的contain和cover属性,来实现背景图的适配,
本文将要介绍在用canvas绘制图片的时候,如何实现contain或cover效果呢?
contain概念
缩放背景图片以完全装入背景区,可能背景区部分空白。
contain
尽可能的缩放背景并保持图像的宽高比例(图像不会被压缩)。该背景图会填充所在的容器。当背景图和容器的大小
不同时,容器的空白区域(上/下或者左/右)会显示由 background-color 设置的背景颜色。
说白了就是保持图片宽高比并保证图片的长边能完整显示,用到canvas的 drawImage(img, dx, dy, dw, dh)方法
参数dx, dy分别表示图片左上角顶点的横 纵坐标
参数dw, dh分别表示定义图片的宽 高。
公式推导
需要分两种情况,
①当图片宽高比 <= 画布宽高比时,如图:
已知:
imgRatio = imgWidth / imgHeight canvasRatio = canvasWidth / canvasHeight 由图得出条件: imgHeight = canvasHeight 推导: imgWidth = imgRatio * imgHeight = imgRatio * canvasHeight
即:
dw = imgRatio * canvasHeight
dh = canvasHeight
dx = (canvasWidth - imgWidth) / 2 dy = 0
②当图片的宽高比 >= canvas画布宽高比时, 如图:
同理推导出:
imgWidth = canvasWidth
imgHeight = imgWidth / imgRatio = canvasWidth / imgRatio
即:
dw = canvasWidth
dh = dw / imgRatio
dx = 0
dy = (canvasHeight - dh) / 2
所以以contain方式适应画布的代码为:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = "images/pic1.jpg";
let dx, dy, dw, dh, imgRatio, canvasRatio;
canvasRatio = canvas.width / canvas.height;
// contain 方式
img.onload = function () {
imgRatio = img.width / img.height;
if(imgRatio <= canvasRatio){
dw = imgRatio * canvas.width
dh = canvas.height
dx = (canvas.width - dw) / 2
dy = 0
}else{
dw = canvas.width
dh = dw / imgRatio
dx = 0
dy = (canvas.height - dh) / 2
}
ctx.drawImage(img, dx, dy, dw, dh)
}
cover概念
缩放背景图片以完全覆盖背景区,可能背景图片部分看不见。和
contain
值相反,
cover
值尽可能大的缩放背景图像并保持图像的宽高比例(图像不会被压扁)。该背景图以它的全部宽或者高覆盖所在容器。当容器和背景图大小不同时,
背景图的 左/右 或者 上/下 部分会被裁剪。
说白了就是保持图片宽高比的同时保证图片的短边能完全显示出来,
因为可能会有裁剪,所以用到canvas的drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh)方法。
参数sx, sy分别表示源图片被截取部分左上角顶点的横 纵坐标
参数sw, sh 分别表示源图片被截取部分的宽 高
参数 dx, dy, dw, dh 分别表示切片后将要在画布上绘制的左上角顶点坐标及绘制的宽高。
公式推导
同样分两种情况,
① 图片宽高比 <= 画布宽高比时, 如图:
已知:
imgRatio = imgWidth / imgHeight
canvasRatio = canvasWidth / canvasHeight
由图知:
dw = canvasWidth
dh = canvasHeight
dx = 0
dy = 0
此时图片的宽要在画布完整展示,所以源图片要裁剪的区域为:
sw = imgWidth
sh = sw / canvasRatio
sx = 0
sy = (imgHeight - sh) / 2
②当图片宽高比 >= 画布宽高比时, 如图:
同理:
此时图片的高要在画布完整展示,源图片的裁剪区域为:
sh = imgHeight
sw = sh * canvasRatio
sx = (imgWidth - sw) / 2
sy = 0
所以以cover方式适应画布的代码为:
var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var img = new Image(); img.src = "images/pic1.jpg"; let sx, sy, sw, sh, imgRatio, canvasRatio; canvasRatio = canvas.width / canvas.height; // cover 方式 img.onload = function () { imgRatio = img.width / img.height; if(imgRatio <= canvasRatio){ sw = img.width sh = sw / canvasRatio sx = 0 sy = (img.height - sh) / 2
}else{
sh = img.height
sw = sh * canvasRatio
sx = (img.width - sw) / 2
sy = 0
}
ctx.drawImage(img, sx, sy, sw, sh, 0, 0, canvas.width, canvas.height) // 因为是cover覆盖, 所以dx,dy都是0,绘制宽高即为canvas宽高
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)