需求:
1、前端自己生成带有logo的二维码并保存二维码
2、logo是图片
思路:
1、引用生成二维码的库(此处使用的是node-qrcode
l,该库是目前我找到仍然在维护,且GitHub上星比较多的,但是生成的二维码不带logo,需要自己把logo加进去),插件链接
2、使用node-qrcode
生成不带logo的二维码
3、将 logo 图片转换成 canvas(使用了 canvas 的 drawImage 方法:ctx.drawImage(logoImg, 4, 4, 32, 32);
)
4、将第3步生成的 logo canvas 与第2步生成的 二维码合并
5、保存二维码图片(使用了toDataURL
)
<div class="qrcode" v-show="_showCode">
<img v-show="false" src="/media/img/logo.png" alt="" ref="logoImg">
<div class="qrcodeCanvas">
<canvas ref="qrcodeCanvas">canvas>
div>
<a href="javascript:;" class="button button-primary" @click="downloadCode">保存二维码a>
div>
import QRCode from 'qrcode'; //引入生成二维码的库
说明:
1、logoImg
是二维码中间的logo,这里预先加载进来,防止后面转换的时候获取不到图片。
2、logo 不能太大,不然二维码扫描不到内容,此处整个canvas画布是200200,logo是4040
imgToggleCanvas() {
const canvas = document.createElement('canvas');
const { logoImg } = this.$refs;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(0, 0, 40, 40); //先画一个40*40的正方形,颜色#ffffff,此处因为logo图片四周没有留白
ctx.drawImage(logoImg, 4, 4, 32, 32); //将 32*32 的 logoImg 画到 canvas 上
return canvas;
},
mergeCanvas(generateCanvas) { //生成的二维码 canvas
const { qrcodeCanvas } = this.$refs;
const logoCavans = this.imgToggleCanvas(); //第2步里面的转换后的canvas
const canvas = document.createElement('canvas');
canvas.width = generateCanvas.width;
canvas.height = generateCanvas.height;
canvas.getContext('2d').drawImage(generateCanvas, 0, 0); //将 generateCanvas 画到 canvas 上,坐标 0,0
canvas.getContext('2d').drawImage(logoCavans, 80, 80); //将 logoCavans 画到 canvas 上,坐标 80,80
qrcodeCanvas.width = canvas.width;
qrcodeCanvas.height = canvas.height;
qrcodeCanvas.getContext('2d').drawImage(canvas, 0, 0);
},
// 生成二维码
generateQrcode() {
const options = {
width: 200,
height: 200,
};
QRCode.toCanvas(this.link, options)
.then((el) => {
this.showCode = true; //showCode 决定是否显示二维码
this.mergeCanvas(el); //生成二维码后,合并二维码
})
.catch((err) => {
this.showCode = false;
});
},
downloadCode(event) {
const { qrcodeCanvas } = this.$refs;
const url = qrcodeCanvas.toDataURL('image/png');
//h5 的download属性在IE上,只从IE13开始兼容,所以需要 `window.navigator.msSaveOrOpenBlob` 里兼容IE10、11,IE9仍然无法兼容
if (window.navigator.msSaveOrOpenBlob) { //IE
const bstr = atob(url.split(',')[1])
let n = bstr.length
var u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
const blob = new Blob([u8arr])
window.navigator.msSaveOrOpenBlob(blob, '{% trans "Link QR code.png" %}')
} else { //非IE
$(event.target).attr('href', url);
$(event.target).attr('download', '{% trans "Link QR code.png" %}');
}
}
说明:因为后来考虑到 IE9及其他不兼容
download
属性的浏览器下载问题,将qrcodeCanvas.toDataURL('image/png');
生成的base64传给了后端,后端实现下载功能,前端及后端python代码如下:
var event= event||window.event;
var qrcodeCanvas=$('#qrcode_canvas')[0];
var url = qrcodeCanvas.toDataURL('image/png');
var downloadQRcode=$('#downloadQRcode'); //此处是一个表单,使用表单的 post 来提交 base64 数据
$('input.base64',downloadQRcode).val(url.split(',')[1]); //提交的base64数据,此处仅提交 base 64 内容
$('input[type="submit"]',downloadQRcode).click(); //表单提交,另外在提交的时候,最好禁止表单提交的默认事件,即打开新的页面
def download_base64_img(request):
base64_str =request.POST.get('base64data', '')
from django.http import StreamingHttpResponse
import base64
imagedata = base64.b64decode(base64_str)
response = StreamingHttpResponse(imagedata)
response['content-type'] = "application/octet-stream"
response['Content-Disposition'] = 'attachment;filename=QR_code.png'
return response