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

 

posted @ 2020-11-30 19:17  杰哥斯坦森  阅读(2295)  评论(0编辑  收藏  举报