js生成二维码、合成图片及js压缩图片

近期接到几个功能类似的需求,都是js处理图片相关的,在开发过程中踩了一些坑,现在把过程记录下来。

第一个需求是后端返回包含底图和二维码的数据列表,要将二维码绘制到底图对应的区域,图片使用canvas来进行绘制
首先创建画布

    var width = $('#img_list li').width()
    var height = $('#img_list li').height()
    var canvas= document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
    var context = canvas.getContext("2d");
    context.rect(0, 0, canvas.width, canvas.height);
    context.fill();

这里就踩了一个坑,因为 $('#img_list li') 是从后端获取数据之后循环的,所以在一开始是无法获取到宽高的,当时绘制完成列表上怎么都不出来图片,后面才发现这个问题,所以在创建画布的时候一定要保证宽高是有值的。
下面是将图片绘制到画布上,这里不能直接使用图片,要先new图片对象,在对象的onload事件里进行绘制,

      var myImage = new Image();
      myImage.setAttribute('crossOrigin', 'anonymous')
      myImage.src = image;
      myImage.onload = function () {
        context.drawImage(myImage, 0, 0, width, height);
        var myImage2 = new Image();
        myImage2.setAttribute('crossOrigin', 'anonymous')
        myImage2.src = qrcode;
        myImage2.onload = function () {
          var x = width * 0.205
          var y = height * 3.39
          var w_ = height / 8
          var h_ = height / 8
          context.drawImage(myImage2, x, y, w_, h_);
        }
      }

context.drawImage(myImage, 0, 0, width, height)是将图片在canvas上进行绘制,方法的五个参数分别是(绘制的文件,绘制起点在画布的X轴坐标,Y轴坐标,绘制图片的宽,高)。
这里又有一个坑,如果图片是非本地图片,将会出现图片跨域的情况不能直接使用,首先要后端先配置好允许图片跨域,我这边是后端给nginx加跨域处理,然后前端需要加

myImage.setAttribute('crossOrigin', 'anonymous')

现在已经绘制完成了,但是现在是canvas,用户不能下载,需求是要用户能下载合成之后的图片,那就将canvas转成base64,再赋值给图片的URL。

var base64 = canvas.toDataURL("image/png");
var img = document.getElementById('avatar');
img.setAttribute('src', base64);

现在就可以进行下载了。

第二个需求是前端生成带logo的二维码,这次的底图是固定的所以就存在前端,不会存在图片跨域的问题,绘制方法跟前面一样,所以只考虑生成二维码的问题,二维码的生成工具很多,但大都不能带二维码,本次生成使用了 jquery.qrcode.js

$("#qrcode").qrcode({ 
    render: "canvas",
    text: val, // 二维码携带的参数
    width : "180", // 二维码的宽度 
    height : "180", // 二维码的高度 
    background : "#ffffff", // 二维码的后景色 
    foreground : "#000000", // 二维码的前景色 
    quiet: 1, // 边距
    mode: 4,
    mSize: 11 * 0.01,
    mPosX: 50 * 0.01,
    mPosY: 50 * 0.01,
    image: $('#logo')[0] // 二维码中间的图片 
}); 

二维码生成完成,然后就是图片合成以及canvas转图片下载,文章前面已经有记录就不在重复。

第三个需求是OCR车牌识别功能,客户在C端进行拍照上传识别车牌号码,现在市面上的手机像素都很高,一张照片小则4、5M,大则10+M,在上传的时候比较慢而且浪费流量,OCR接口也要求图片必须小于3M,所以压缩图片就是非常必要的操作了,压缩还是使用canvas。



let formData = new FormData()
let files = this.$refs.uploadFile.files
let size = files[0].size / 1024 / 1024

根据size来判断大小,小于3M直接走上传流程,大于3M就进行压缩。

let divisor =  Math.ceil(size / 3)  // 文件大于3M,向上取整,倍数压缩
var oFile = files[0];
var reader = new FileReader();
reader.onload=function(){
    var oImg = new Image();
    oImg.src = this.result;
    oImg.style.display = "none"
    document.body.appendChild(oImg);
    oImg.onload = function(){
        var imgWidth = this.width
        var imgHeight = this.height
        var w = imgWidth / divisor;
        var h = imgHeight / divisor;
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        var anw = document.createAttribute("width");
        anw.nodeValue = w;
        var anh = document.createAttribute("height");
        anh.nodeValue = h;
        canvas.setAttributeNode(anw);
        canvas.setAttributeNode(anh);
        ctx.fillRect(0, 0, w, h);
        ctx.drawImage(oImg, 0, 0, w, h);
        const base64 = canvas.toDataURL('image/jpeg', 0.75); // 压缩后质量
        that.uploadFile(that.dataURLtoFile(base64))  // base64转文件 - 然后上传
    };
};
reader.readAsDataURL(oFile);

dataURLtoFile (dataurl) { // base64转文件
    let arr = dataurl.split(',')
    let mime = arr[0].match(/:(.*?);/)[1]
    let suffix = mime.split('/')[1]
    let bstr = atob(arr[1])
    let n = bstr.length
    let u8arr = new Uint8Array(n)
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
    }
    return new File([u8arr], `file.${suffix}`, {
        type: mime
    })
 }

最后将base64转回文件方便上传。

你可能感兴趣的:(js生成二维码、合成图片及js压缩图片)