前端图片压缩

346 阅读1分钟

背景描述:最近在做一个移动端h5上传图片的功能,本来这个功能并不复杂,只需要将图片文件通过axios传到服务端即可,但是考虑到现在手机设配的拍照功能十分强大,随便一张照片都能动辄五六兆,而服务端的要求是上传图片必须小于两兆,而且直接传这么大图片,带宽它也受不了,所以前端进行压缩图片就成了一个必要的环节。

思路:

第一步: 图片选择触发change事件,先判断当前图片是否大于后台要求,如果大于,则压缩图片,否则,直接上传。

// 选择图片 
handle (evt) {      
    const maxSize = 2 * 1024 * 1024      
    this.loading = true      
    const file = Array.prototype.slice.call(evt.target.files)[0]      
    let render = new FileReader()      
    render.readAsDataURL(file)      
    render.onload = (e) => {        
        if (file.size > maxSize) {          
            let img = new Image()          
            img.src = e.target.result          
            img.onload = () => {            
                const data = this.compress(img)            
                    if (data.length > maxSize) {              
                        this.$toast('上传图片过大')            
                    } else {              
                        this.upload(data, 'image/jpeg', file.name)            
                    }         
                }        
            } else {          
                this.upload(e.target.result, file.type, file.name)        
            }      
        }    
},

第二步:compress压缩方法

 compress (img) {      
    // 用于压缩图片的canvas      
    let canvas = document.createElement("canvas")      
    let ctx = canvas.getContext('2d')
    // 瓦片canvas      
    var tCanvas = document.createElement("canvas")      
    var tctx = tCanvas.getContext("2d")      
    let initSize = img.src.length      
    let width = img.width      
    let height = img.height      
    // 如果图片大于四百万像素,计算压缩比并将大小压至400万以下      
    var ratio      
    if ((ratio = width * height / 4000000) > 1) {       
        ratio = Math.sqrt(ratio)        
        width /= ratio        
        height /= ratio      
    } else {        
        ratio = 1      
    }      
    canvas.width = width      
    canvas.height = height      
    // 铺底色      
    ctx.fillStyle = "#fff"      
    ctx.fillRect(0, 0, canvas.width, canvas.height)      
    // 如果图片像素大于100万则使用瓦片绘制      
    var count      
    if ((count = width * height / 1000000) > 1) {        
        count = ~~(Math.sqrt(count) + 1) // 计算要分成多少块瓦片        
        // 计算每块瓦片的宽和高        
        var nw = ~~(width / count)        
        var nh = ~~(height / count)        
        tCanvas.width = nw        
        tCanvas.height = nh        
        for (var i = 0; i < count; i++) {          
            for (var j = 0; j < count; j++) {            
                tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio * 2, nh * ratio * 2, 0, 0, nw, nh)            
                ctx.drawImage(tCanvas, i * nw, j * nh, nw * 2, nh * 2)          
                }        
            }      
        } else {        
            ctx.drawImage(img, 0, 0, width * 2, height * 2)      
        }      
        // 进行最小压缩      
        let ndata = canvas.toDataURL('image/jpeg', 0.8)      
        console.log('压缩前:' + initSize)      
        console.log('压缩后:' + ndata.length)      
        console.log('压缩率:' + ~~(100 * (initSize - ndata.length) / initSize) + '%')      
        return ndata    
    },

第三步:上传图片

// 上传图片    
upload(basestr, type, name){      
    let text = window.atob(basestr.split(",")[1])      
    let buffer = new ArrayBuffer(text.length)      
    let ubuffer = new Uint8Array(buffer)      
    for (let i = 0; i < text.length; i++) {        
        ubuffer[i] = text.charCodeAt(i)      
    }      
    let Builder = window.WebKitBlobBuilder || window.MozBlobBuilder      
    let blob      
    if (Builder) {        
        let builder = new Builder()        
        builder.append(buffer)        
        blob = builder.getBlob(type)      
    } else {        
        blob = new window.Blob([buffer], {type: type})      
    }      
    let formdata = new FormData()      
    formdata.append('file', blob)      
    formdata.append('certType', this.certType)      
    formdata.append('desCountryAreaCode', this.orderInfo.order.receiverCountryCode)      
    formdata.append('ieFlag', this.ieFlag)      
    formdata.append('postFlag', this.postFlag)      
    formdata.append('srcCountryAreaCode', this.orderInfo.order.senderCountryCode)      
    this.$httpExt().post(this.apiUrl.upload.uploadImg, formdata).then((res) => {       
         if (res.data && res.code == 0) {          
            this.imgList.push({            
                imgSrc: basestr,            
                fileNo: res.data[0]          
            })          
        this.$emit('update:imgList', this.imgList)        
        }      
    }).finally(() => {        
        this.loading = false      
    })    
}