zoukankan      html  css  js  c++  java
  • 前台图片Canvas压缩上传小结

    需求来源:之前有个提交审核表单的业务,表单中含有大量附件图片,大约有20多张吧,为了省事,采用的同步上传,一次需要上传很多照片,本来单张图片限制为200KB,这样子总图片大小约为5MB左右,想想也可以接收。业务上线后,得知用户大部分都是中老年人居多,手机拍照的图片很大,不会压缩。放开图片尺寸上传限制后,上传数据太大,体验很不好,就有了前台图片压缩的需求。

    业务实现要点:

    1、上传的图片使用canvas压缩图片,并导出base64字符串数据;

    2、每一类型附件可以传多张图片,这些图片的base64数据存放到hashmap集合中,key值为file的id;

    3、后台将接收到图片的base64字符串转存为图片格式。

    核心业务代码如下:

    -- 前台图片压缩保存

    /**
     * 存储图片数据
     * @param _this
     * @param picType
     */
    function picStrore(_this,picType) {
        var obj = $(_this);
        var id = obj.attr('id');// 元素id
        // $("#fw_pic_1")[0].files[0]  是否包含文件
        var file = $("#"+id)[0].files[0];
        if(file){ // 有图片
            imgeToBase64_save(file,id,picType); // 保存数据到hashmap
        }else{ // 无图片
            removeImgdata(id,picType); // 从hashmap中移除数据
        }
    }
    /**
     * 将图片转成base64字符串存储hashmap中
     * @param file  文件对象
     * @param fileId 元素id
     * @param picType 文件类型
     * @returns {boolean}
     */
    function imgeToBase64_save(file,fileId,picType) {
        if (!/image/w+/.test(file.type)) {
            return false;
        }
        var reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = function (e) {
            var img = new Image,
                width = 640,quality = 0.8,canvas = document.createElement("canvas"),drawer = canvas.getContext("2d");
            img.src = this.result;
            img.onload = function () {
                // 计算绘图尺寸(重构的图片尺寸宽度显示最大为640,图片质量设置为0.8) 
                if (img.height > img.width) {
                    if (img.width < width) {
                        canvas.width = img.width;
                        canvas.height = img.height;
                    } else {
                        canvas.width = width;
                        canvas.height = width * (img.height / img.width);
                    }
                } else {
                    if (img.height < width) {
                        canvas.width = img.width;
                        canvas.height = img.height;
                    } else {
                        canvas.height = width;
                        canvas.width = width * (img.width / img.height);
                    }
                }
                drawer.drawImage(img, 0, 0, canvas.width, canvas.height);
                var tmpsrc = canvas.toDataURL("image/jpeg", quality);
                var imgbase64 = tmpsrc.substr(23); // base64字符串
                // 保存base64数据到hashmap
                if('fw_pic'== picType){ // 房屋所有权证
                    fw_pic_map.put(fileId,imgbase64);
                }else if('td_pic'== picType){ // 国有土地使用权证
                    td_pic_map.put(fileId,imgbase64);
                }else if('bdc_pic'== picType){ // 不动产权证
                    bdc_pic_map.put(fileId,imgbase64);
                }else if('syf_pic'== picType){ // 住房买卖合同
                    syf_pic_map.put(fileId,imgbase64);
                }else if('fp_pic'== picType){ // 购房发票
                    fp_pic_map.put(fileId,imgbase64);
                }else if('sfz_pic'== picType){ // 身份证
                    sfz_pic_map.put(fileId,imgbase64);
                }else if('zl_pic'== picType){ // 户口簿资料页
                    zl_pic_map.put(fileId,imgbase64);
                }else if('gzs_pic'== picType){ // 委托书/公证书/通知书
                    gzs_pic_map.put(fileId,imgbase64);
                }else if('other_pic'== picType){ // 其他材料
                    other_pic_map.put(fileId,imgbase64);
                }
            }
        }
    }
    /**
     * 从hashmap中移除数据
     * @param fileId
     * @param picType
     */
    function removeImgdata(fileId,picType) {
        if('fw_pic'== picType){ // 房屋所有权证
            fw_pic_map.remove(fileId);
        }else if('td_pic'== picType){ // 国有土地使用权证
            td_pic_map.remove(fileId);
        }else if('bdc_pic'== picType){ // 不动产权证
            bdc_pic_map.remove(fileId);
        }else if('syf_pic'== picType){ // 住房买卖合同
            syf_pic_map.remove(fileId);
        }else if('fp_pic'== picType){ // 购房发票
            fp_pic_map.remove(fileId);
        }else if('sfz_pic'== picType){ // 身份证
            sfz_pic_map.remove(fileId);
        }else if('zl_pic'== picType){ // 户口簿资料页
            zl_pic_map.remove(fileId);
        }else if('gzs_pic'== picType){ // 委托书/公证书/通知书
            gzs_pic_map.remove(fileId);
        }else if('other_pic'== picType){ // 其他材料
            other_pic_map.remove(fileId);
        }
    }
    -- 后台图片保存
    	/**
    	 * 保存BASE64图片数据
    	 * @param imgStr 图片base64数据
    	 * @param savePath 图片保存路径
    	 */
    	public static void saveBase64Img(String imgStr,String savePath) {
    		if (imgStr == null) //图像数据为空
    			return;
    		BASE64Decoder decoder = new BASE64Decoder();
    		try {
    			//Base64解码
    			byte[] b = decoder.decodeBuffer(imgStr);
    			for(int i=0; i<b.length; ++i) {
    				if(b[i]<0) {
    					b[i]+=256; //调整异常数据
    				}
    			}
    			//生成jpeg图片
    			OutputStream out = new FileOutputStream(savePath);
    			out.write(b);
    			out.flush();
    			out.close();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    压缩效果:压缩后的图片附件总大小控制在1MB左右。
    注:canvas的大小有限制,如果canvas的大小大于大概五百万像素(即宽高乘积)的时候,不仅图片画不出来,其他什么东西也都是画不出来的。

    坑:前台上传使用ajax提交请求,但是必须保证enctype = "multipart/form-data",否则post的数据长度会超出限制,使用FormData对象提交请求,具体代码如下:

        var formData = new FormData();
        formData.append('buyerone',$("#buyerone").val());
        formData.append('buyerone_no',$("#buyerone_no").val());
        formData.append('buyerone_phone',$("#buyerone_phone").val());
    
        formData.append('buyertwo',$("#buyertwo").val());
        formData.append('buyertwo_no',$("#buyertwo_no").val());
        formData.append('buyertwo_phone',$("#buyertwo_phone").val());
    
        formData.append('buyerthree',$("#buyerthree").val());
        formData.append('buyerthree_no',$("#buyerthree_no").val());
        formData.append('buyerthree_phone',$("#buyerthree_phone").val());
    
        formData.append('handler',$("#handler").val());
        formData.append('handler_no',$("#handler_no").val());
        formData.append('handler_phone',$("#handler_phone").val());
    
        formData.append('remark',$("#remark").val());
    
        formData.append('house_site',$("#house_site").val());
        formData.append('house_area',$("#house_area").val());
        formData.append('loft_area',$("#loft_area").val());
        formData.append('sign_date',$("#sign_date").val());
        formData.append('ownership_no',$("#ownership_no").val());
        formData.append('landuse_no',$("#landuse_no").val());
        formData.append('immovable_no',$("#immovable_no").val());
    
        formData.append('apply_type',$("input[name='apply_type']:checked").val());
        formData.append('buy_total',$("#buy_total").val());
        formData.append('house_price_v',$("#house_price_v").val());
        formData.append('loft_price_v',$("#loft_price_v").val());
        formData.append('estimate_total_v',$("#estimate_total_v").val());
        formData.append('pay_price_v',$("#pay_price_v").val());
    
        formData.append('fw_pic',fw_pic);
        formData.append('td_pic',td_pic);
        formData.append('bdc_pic',bdc_pic);
        formData.append('syf_pic',syf_pic);
        formData.append('fp_pic',fp_pic);
        formData.append('sfz_pic',sfz_pic);
        formData.append('zl_pic',zl_pic);
        formData.append('gzs_pic',gzs_pic);
        formData.append('other_pic',other_pic);
    
        $.ajax({
            url: http_url+"/api/upfile/houseApplyUpload2",
            type: "POST",
            cache: false,
            data: formData,
            processData: false,
            contentType: false,
            dataType: "json",
            success: function(res){
                var resobj = res;
                if(resobj.code=="4901"){ // 上传文件超限
                    window.parent.layer.alert("上传文件大小超出限制", {icon: 0});
                }else if(resobj.code=="0000"){
                    var data = resobj.data;
                    var isSuccess = data.isSuccess;
                    var msg = data.msg;
                    if(isSuccess==0){ //成功
                        window.location.href="houseApplyOk.shtml";
                    }else if(isSuccess==1){// 失败
                        window.parent.layer.alert(msg, {icon: 0});
                    }else{ // 异常
                        window.parent.layer.alert("申请审核表提交失败", {icon: 0});
                    }
                }
                window.parent.layer.close(ha_index);// 清除加载
            },
            error:function(res) {
                window.parent.layer.close(ha_index);// 清除加载
            }
        });

  • 相关阅读:
    Java 中文数字转换为阿拉伯数字
    正则表达式转义符
    git .gitignore详解
    git 陷阱小记
    git log 附加命令归纳
    git 命令归纳版
    《Effective Java》 读书笔记(九)使用try-with-resources 语句替代try-finally
    架构设计 | 接口幂等性原则,防重复提交Token管理
    数据源管理 | OLAP查询引擎,ClickHouse集群化管理
    Java并发编程(04):线程间通信,等待/通知机制
  • 原文地址:https://www.cnblogs.com/archermeng/p/8587516.html
Copyright © 2011-2022 走看看