前段时间遇到产品一个需求,在移动端上合成生成二维码,并且合成背景图和二维码给用户保存;
当时我在想,链接拼接生成二维码这个没什么,图片合成在移动端来做,结果后端的小伙伴说他们有现成的方案,他们合成,最后也就让后端做了;
最后想想,前端其实做起来也很方便啊,搞起!
-
兼容性,浏览器支持canvas,似乎这是最核心最低的门槛,自己确认了一下兼容性
形式一片大好
-
问题分析
合成,也就是将一个背景图,一个二维码图放在一个容器内,那么canvas不是有一个drawImage可以把图片给画进去么?最后再照葫芦画瓢画二维码,最后toDataURL把base64编码的图片信息导出给img标签不就OK啦!
// bgSize,qrSize为对应图的尺寸
// bgUrl,qrUrl为对应图的地址
// qrX,qrY为偏移值,target为你展示的img标签的class或者id
const canvas = document.createElement("canvas");
if (canvas.getContext) {
canvas.width = bgSize;
canvas.height = bgSize;
let ctx = canvas.getContext('2d');
ctx.fillRect(0 ,0, bgSize, bgSize);
ctx.fillStyle='transparent';
ctx.fill();
let bgImg = new Image();
// bgImg.crossOrigin = "anonymous";
bgImg.src = bgUrl;
bgImg.addEventListener("load", ()=> {
ctx.drawImage(bgImg, 0, 0, bgSize, bgSize);
let qrImg = new Image();
// qrImg.crossOrigin = "anonymous";
qrImg.src = qrUrl;
qrImg.addEventListener("load", ()=> {
ctx.drawImage(qrImg, qrX, qrY, qrSize, qrSize);
document.querySelector(target).src = canvas.toDataURL("image/png");
});
});
};
结果这是为什么呢?去搜索了很多,很多人说什么canvas不能使用跨域图片,问题都集中在跨域上;
跨域说对了一半,并不是canvas不能使用跨域图片,而是在用没有跨域权限图片导出信息时会报错,Canvas确实是为了安全性考虑,当绘制了外部图片后它会变成只可写不可读的状态,getImageData、toDataURL之类的试图读取数据的方法全都无法使用;
img.crossOrigin = "anonymous";
之后呢,其实也就是让前端开启了图片的跨域使用,为图片服务添加CROS(跨域)支持,具体方法是在图片的返回的header中添加Access-Control-Allow-Origin:*,同时在请求图片时,为image元素设置crossOrigin="" 属性设置为空字符串或者 "anonymous",这样就可以跨域导出图片信息,也就是画图了;
这边MDN上就介绍了这个启用了 CORS 的图片;