完整代码
// 获得图片
handleImg() {
const files = ['图片1.jpg','图片2.jpg','图片3.jpg','图片4.jpg','图片5.jpg','图片6.jpg','图片7.jpg','图片8.jpg','图片9.jpg']
this.filesToInstances(files).then(instances => {
this.drawImages(instances).then(finalImageUrl => {
console.log(finalImageUrl)
})
})
},
// 根据图片文件拿到图片实例
filesToInstances(files) {
return new Promise ((resolve,reject) => {
const length = files.length;
let instances = [];
let finished = 0;
files.forEach((file, index) => {
const image = new Image();
image.setAttribute("crossOrigin",'Anonymous');
image.src = file;
image.onload = () => {
// 图片实例化成功后存起来
instances[index] = image;
finished ++;
if (finished === length) {
resolve(instances);
}
}
});
})
},
// 拼图
drawImages(images) {
return new Promise ((resolve,reject) => {
// 图片的宽高
const widthImg = 300
const heightImg = 300
// 拼出来的图片的质量,0-1之间,越大质量越好
const encoderOptions = 0.5
// 第几列换行
const column = this.calculate(images.length)
const canvas = document.createElement('canvas');
canvas.width = widthImg * column;
canvas.height = heightImg * Math.ceil((images.length / column))
const context = canvas.getContext('2d');
context.fillStyle = '#fff';
context.fillRect(0, 0, canvas.width, canvas.height); // 将背景填充为白色
let y = 0;
let x = 0;
for (let [index,item] of Object.entries(images)) {
if (((index-0+1)%column) === 0) {
context.drawImage(item, x, y, widthImg, heightImg);
y += heightImg;
x = 0
} else {
context.drawImage(item, x, y, widthImg, heightImg);
x += widthImg;
}
}
const url = canvas.toDataURL('image/jpeg', encoderOptions) // 背景png默认透明,jpeg默认黑色
resolve(url);
})
}
// 根据图片数量动态计算
calculate(length) {
if (length <= 4) {
return 2
} else if (length <= 9) {
return 3
} else if (length <= 16) {
return 4
} else {
return 5
}
}
上面的代码,因为拼接图片的宽高是固定的,如果图片数量多,最终拼接好的图片分辨率将会很大。
可以采用固定画布大小,图片等比例缩放的方式
// 拼图
drawImages(images) {
return new Promise ((resolve,reject) => {
// 图片的宽高
const width = 500
const height = 500
// 拼出来的图片的质量,0-1之间,越大质量越好
const encoderOptions = 0.5
// 第几列换行
const column = this.calculate(images.length)
let widthImg = width / column
let heightImg = height / Math.ceil((images.length / column))
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height
const context = canvas.getContext('2d');
context.fillStyle = '#fff';
context.fillRect(0, 0, canvas.width, canvas.height); // 将背景填充为白色
let y = 0;
let x = 0;
for (let [index,item] of Object.entries(images)) {
if (((index-0+1)%column) === 0) {
context.drawImage(item, x, y, widthImg, heightImg);
y += heightImg;
x = 0
} else {
context.drawImage(item, x, y, widthImg, heightImg);
x += widthImg;
}
}
const url = canvas.toDataURL('image/jpeg', encoderOptions) // 背景png默认透明,jpeg默认黑色
resolve(url);
})
}
但固定画布大小也会有问题,就是图片数量不够填满九宫图时,图片缩放会变形。
另外如果图片是文件流不是url链接,可以用下面这个方式处理
// 根据图片文件拿到图片实例
filesToInstances(files) {
return new Promise ((resolve,reject) => {
const length = files.length;
let instances = [];
let finished = 0;
files.forEach((file, index) => {
const reader = new FileReader()
// 把文件读为 dataUrl
reader.readAsDataURL(file)
reader.onload = e => {
const image = new Image()
image.setAttribute("crossOrigin",'Anonymous');
image.src = e.target.result
image.onload = () => {
// 图片实例化成功后存起来
instances[index] = image
finished ++
if (finished === length) {
resolve(instances)
}
}
}
});
})
}
总结
记录一次代码实现尝试,大家有更好的想法,欢迎来评论区。