昨天,整个朋友圈都被支付宝的年度账单刷屏了。突然发现,原来自己的朋友圈里隐藏着众多土豪。当然啦,也有一些朋友ps一些好玩的截图。
实在无聊,晚上下班之后,就想着写个页面,让那些贪玩的朋友生成自己的年度关键词。先来看一下效果图。
基本功能点
- 用户输入文案
- 选取图片并裁剪
- 图片合成
实现思路
天下武功,唯快不破。这是移动端的单页小应用,便于快速实现,于是选择了vue。
找了一下图片裁剪相关的库,vue-cropper 可以满足需求,于是就不需要自己造轮子了。具体的使用请看文档,这里不再赘述。
前端图片合成,可以使用canvas。
关键代码
思路有了,接下来就是搬砖的时候了。
一、图片上传读取
html:
<input type="file" accept="image/png, image/jpeg, image/gif, image/jpg" @change="uploadImg">
js:
uploadImg (e, num) {
var file = e.target.files[0];
if (!/\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/.test(e.target.value)) {
alert('图片类型必须是.gif,jpeg,jpg,png,bmp中的一种');
return false;
}
var reader = new FileReader(file);
reader.onload = (e) => {
var data;
if (typeof e.target.result === 'object') {
data = window.URL.createObjectURL(new Blob([e.target.result]));
} else {
data = e.target.result;
}
this.option.img = data;
}
reader.readAsArrayBuffer(file);
}
二、图片合成
vue-cropper提供了一个getCropData的方法,用来获取裁剪框中的数据。将裁剪后的图像与背景图绘制在canvas上,再加上用户输入的文案,即可合成最终的效果图。
最后通过canvas的toDataURL方法,把画布里的图案转变成base64编码格式的图片数据,放在img标签中即可显示出来,用户长按图片,即可弹出保存选项。
function drawText(ctx, t, x, y, w) {//多行文字的绘制
var chr = t.split('');
var temp = '';
var row = [];
ctx.font = '45px Arial';
ctx.fillStyle = '#7B7B7B';
ctx.textBaseline = 'middle';
for (var a = 0; a < chr.length; a++) {
if (ctx.measureText(temp).width < w) {
} else {
row.push(temp);
temp = '';
}
temp += chr[a];
}
row.push(temp);
for (var b = 0; b < row.length; b++) {
ctx.fillText(row[b], x, y + (b + 1) * 60);
}
}
this.$refs.cropper.getCropData(data => {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var width = 1080;
var height = 1920;
canvas.width = width;
canvas.height = height;
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';
var bgImg = document.createElement('img');
bgImg.src = bg;
var avatarImg = document.createElement('img');
avatarImg.src = data;
var vm = this;
bgImg.onload = function() {
ctx.clearRect(0, 0, width, height);
ctx.drawImage(bgImg, 0, 0, width, height);
ctx.drawImage(avatarImg, 88, 476, 906, 664);
ctx.font = '120px SimSun';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = '#636363';
ctx.fillText(vm.title, 540, 1240);
drawText(ctx, vm.desc, 540, 1310, 700);
var dataURL = canvas.toDataURL('image/png');
vm.resultUrl = dataURL;
};
});
实现效果
TODO
效果上看,最突出的问题在于字体。
如何在canvas中描绘文字的时候使用自定义的字体呢?
后记
朋友圈中常见的生成个性化图片的小应用,基本上是通过这种方式实现的。比如某某学校校庆,然后生成个性化头像。套路就是这样。
不说了,我去做头发了。