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宽高
}