需求
有一个由图片地址组成的数组,要将这个数组中的所有图片拼接成一张图片,并返回图片地址或者展示出来
解决方案
思路:创建一个函数,将图片数组做为参数。函数内部循环图片数组,将图片依次使用 canvas 拼接到一起。
// list 为图片数组
function mergeImgs(list) {
// 创建一个 img 节点,用于显示拼接完成后的图片
const imgDom = document.createElement('img')
document.body.appendChild(imgDom)
// 创建 canvas 节点并初始化
const canvas = document.createElement('canvas')
canvas.width = 500
canvas.height = 500 * list.length
const context = canvas.getContext('2d')
// 循环图片数组
list.map((item, index) => {
const img = new Image()
img.src = item
// 跨域
img.crossOrigin = 'Anonymous'
// 图片加载完成后再拼接
img.onload = () => {
context.drawImage(img, 0, 500 * index, 500, 500)
const base64 = canvas.toDataURL('image/png')
imgDom.setAttribute('src', base64)
// console.log(baseList)
}
})
}
const urlList = ['./img/timg%20(1).jpg', './img/timg.jpg']
mergeImgs(urlList )
上面代码有些缺陷,图片加载慢时,会闪屏。如果后续逻辑需要使用拼接完成的图片,无法保证后续拿到的图片是否是最终版,因为 img.onload
是异步的。
下面使用 Promise
稍微优化一下,降低代码耦合性,改成公共方法。
/**
* 合并多张图片,返回新的图片
* @param {Array} list 图片url数组
* @param {Number} cwith 画布宽度 默认500
* @param {Number} cheight 画布高度 默认500
*/
function mergeImgs(list, cwith = 500, cheight = 500) {
return new Promise((resolve, reject) => {
const baseList = []
// 创建 canvas 节点并初始化
const canvas = document.createElement('canvas')
canvas.width = cwith
canvas.height = cheight * list.length
const context = canvas.getContext('2d')
list.map((item, index) => {
const img = new Image()
img.src = item
// 跨域
img.crossOrigin = 'Anonymous'
img.onload = () => {
context.drawImage(img, 0, cheight * index, cwith, cheight)
const base64 = canvas.toDataURL('image/png')
baseList.push(base64)
if (baseList[list.length - 1]) {
console.log(baseList)
// 返回新的图片
resolve(baseList[list.length - 1])
}
}
})
})
}
const urlList = ['./img/timg%20(1).jpg', './img/timg.jpg']
mergeImgs(urlList ).then(base64 => {
const imgDom = document.createElement('img')
imgDom.src = base64
document.body.appendChild(imgDom)
})
这样就可以保证在 then
中拿到的是正确图片了