我们常用到 CSS 的 background-size
属性中的 contain
和 cover
属性,来实现背景图的适配。本文将要介绍在用 canvas 绘制图片的时候,如何实现 contain
或 cover
效果呢?
缩放背景图片以完全装入背景区,可能背景区部分空白。
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);
};
缩放背景图片以完全覆盖背景区,可能背景图片部分看不见。和
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宽高
};