Vue实现图片转Base64上传案例

  • 一、前端图片转Base64
  • 二、后台Base64转图片
  • 三、前端Base64转图片


一、前端图片转Base64

获取图片,将图片转为Base64字符串,AJAX提交到后台进行处理,前端使用了Vue基础。但是这种做法会比较复杂,后续会使用vant框架实现。

<!--上传图片-->
<div style="width: 90%;margin-left: 5%;margin-top: 30px">
        <div class="pics" v-for='(value, key) in imgs' style="text-align:center;float: left;width: 19%;">
            <div class="onepicdiv" style="float:left;width: 100%;">
                <div>
                    <img class="onepic" :id=key :src="getObjectURL(value)" style="width: 85%;" @click="showImgs(value)">
                </div>
                <div @click="delImg(key)" style="color: #999999;width: 100%;font-size: 13px;color: #999999;position: relative;top: -63px;left: 26px">
                    <van-icon name="close" color="rgb(0,0,0)"/>
                </div>
            </div>
        </div>
        <div v-if="imgLen>=5 ? false : true">
            <div class="addpicture">
                <input id="myfile" type="file" @change="addImg" ref="inputer" multiple accept="image/*"
                       style="opacity:0;width: 100%;"/>
            </div>
        </div>
        <div style="font-size: 10px;padding-top: 40px;color: #999999">  {{imgLen}}/5</div>
    </div>
    
<!--放大图片时被放大的图片和图片列表之间的遮罩层-->
<div id="showpicmask">
    <div v-show="show" @click="back()"
         style="position: fixed;z-index: 100;height: 100vh;width: 100%;background-color: rgba(0,0,0,0.95) ">
    </div>
</div>

<!--被放大的图片-->
<div id="showpic">
    <div v-show="show" @click="back()"
         style="position: fixed;z-index: 101;width:100%;height: 100vh;display: flex;float: left;align-items: center;justify-content: center;">
        <img :src="picpath" style="width: 100vw;">
    </div>
</div>

<script>
//上传图片
addImg(event) {
    let inputDOM = this.$refs.inputer;
    // 通过DOM取文件数据
    this.fil = inputDOM.files;

    let oldLen = this.imgLen;
    let len = this.fil.length + oldLen;
    if (len > 5) {
        alert('最多可上传5张,您还可以上传' + (5 - oldLen) + '张');
        return false;
    }
    for (let i = 0; i < this.fil.length; i++) {
        let size = Math.floor(this.fil[i].size / 1024);
        if (size > 3 * 1024) {
            layer.msg('请选择3M以内的图片');
            return false;
        }
        for(key in this.imgs){
            if(key == this.fil[i].name){
                layer.msg("请勿上传同一张图片")
                return
            }
        }
        this.imgLen++;
        this.$set(this.imgs, this.fil[i].name , event.target.files[i]);

        //转换为base64
        let self = this;
        let reader = new FileReader();
        reader.readAsDataURL(event.target.files[i]);
        if (size > 1024) {//图片大于1M,进行压缩
            if (typeof (FileReader) === 'undefined') {
                console.log("当前浏览器内核不支持base64图标压缩");
                //调用上传方式  不压缩
            } else {
                var file = event.target.files[i];
                if (!/image\/\w+/.test(file.type)) {
                    alert("请确保文件为图像类型");
                    return false;
                }
                //压缩图片
                reader.onload = function (event) {
                    if (reader.readyState === 2) {
                        let image = new Image()     //新建一个img标签(不嵌入DOM节点,仅做canvas操作)
                        image.src = event.target.result;    //让该标签加载base64格式的原图
                        image.onload = function () {
                            let canvas = document.createElement('canvas'), //创建一个canvas元素
                                context = canvas.getContext('2d'),    //context相当于画笔,里面有各种可以进行绘图的API
                                imageWidth = image.width / 2,    //压缩后图片的宽度,这里设置为缩小一半
                                imageHeight = image.height / 2,    //压缩后图片的高度,这里设置为缩小一半
                                data = ''    //存储压缩后的图片
                            canvas.width = imageWidth    //设置绘图的宽度
                            canvas.height = imageHeight    //设置绘图的高度
                            //使用drawImage重新设置img标签中的图片大小,实现压缩。drawImage方法的参数可以自行查阅W3C
                            context.drawImage(image, 0, 0, imageWidth, imageHeight)
                            //使用toDataURL将canvas上的图片转换为base64格式
                            data = canvas.toDataURL('image/jpeg')
                            var st = data.indexOf(',');
                            var stnew = parseInt(st) + 1;
                            data = data.substring(stnew);
                            self.$set(self.filelist, self.fil[i].name, data);
                        };
                    }
                }
            }
        } else {
            reader.onload = function (event) {
                self.headImg = event.target.result; //img base64
                var st = self.headImg.indexOf(',');
                var stnew = parseInt(st) + 1;
                self.headImg = self.headImg.substring(stnew);
                self.$set(self.filelist, self.fil[i].name, self.headImg);
            }
        }
    }

},
getObjectURL(file) {
    const that = this;
    var url = null;
    if (window.createObjectURL != undefined) { // basic
        url = window.createObjectURL(file);
    } else if (window.URL != undefined) { // mozilla(firefox)
        url = window.URL.createObjectURL(file);
    } else if (window.webkitURL != undefined) { // webkit or chrome
        url = window.webkitURL.createObjectURL(file);
    }
    return url;
},
//删除图片
delImg(key) {
    const that = this;
    this.$delete(that.filelist, key);
    this.$delete(this.imgs, key);
    this.imgLen--;
},
//放大图片
showImgs(value) {
    var url = this.getObjectURL(value);
    picmask.show = true
    showpic.show = true
    showpic.picpath = url
},
</script>

二、后台Base64转图片

后台获取前端Base64字符串,这里在后台转换为图片,存放到指定目录,并将新定义的图片名保存至数据库

//DataObject.java用于存储key-value类型数据的数据结构
//DataStore.java用于存储列表格式数据的数据结构。
//图片处理
DataObject objfile= DataObject.parseJSON(files);
DataStore fileds = DataStore.getInstance();
Set<String> keySet = objfile.keySet();// vdo里的键都是string
Iterator<String> it = keySet.iterator();// 开始遍历
String key;// vdo的键
Object value;// 值(数据类型待判断)
int n=0;
while (it.hasNext()) {
    key = it.next();
    value = objfile.get(key);
    if (value instanceof String) {
        //System.out.println("key=="+key +",value="+value);
        fileds.put(n, "imgname", key);
        fileds.put(n, "imgbase", value);
    } else {
        throw new BizException("files不是一个String类型的值");
    }
    n++;
}
if(fileds.rowCount()>0){
    DataObject returnobj = DataObject.getInstance();
    DataStore urlds = DataStore.getInstance();
    for (int j = 0; j < fileds.rowCount(); j++) {
        String imgStr = fileds.getString(j, "imgbase");
        String FILEPATH = picurl + suggestImgs;
        Calendar tempewmscsj = Calendar.getInstance();
        long sjid = tempewmscsj.getTimeInMillis();
        String idstr = String.valueOf(sjid);
        String nowstr = DateUtil.getCurrentTime();
        String fileName = "img_" + nowstr + "_" + idstr + ".jpg";
        fileNames = fileNames + ";" + fileName;
        //对字节数组字符串进行Base64解码并生成图片
        String imgUrl = "";
        //图像数据为空
        if (StringUtils.isBlank(imgStr)) {
            returnobj.put("retuendata", imgUrl);
        }
        BASE64Decoder decoder = new BASE64Decoder();
        byte[] b = decoder.decodeBuffer(imgStr);
        for (int i = 0; i < b.length; ++i) {
            //调整异常数据
            if (b[i] < 0) {
                b[i] += 256;
            }
        }
        //文件目录不存在则创建
        File outFile = new File(FILEPATH);
        if (!outFile.exists()) {
            outFile.mkdirs();
        }
        //文件最终的存储位置
        File dest = new File(FILEPATH + File.separator + fileName);
        //判断目标文件所在的目录是否存在
        if (!dest.getParentFile().exists()) {
            //创建目录
            if (!dest.getParentFile().mkdirs()) {
                returnobj.put("retuendata", imgUrl);
            }
        }
        //新生成的图片
        imgUrl = FILEPATH + File.separator + fileName;
        //这种写法不需要flush或者close 会自动关闭 FileOutputStream 实现了java中的java.lang.AutoCloseable接口。
        try (OutputStream out = new FileOutputStream(FILEPATH + File.separator + fileName);) {
            out.write(b);
        } catch (Exception e) {
            //logger.info("Base64Util GenerateImage e:" + e.getLocalizedMessage());
        } finally {
            returnobj.put("retuendata", imgUrl);
        }
        urlds.put(j, "imgurl", returnobj.getString("retuendata"));
    }
}
//数据库中存放新定义的图片名等信息
...

三、前端Base64转图片

如果选择第二步在后台直接存储Base64字符串到数据库,则可以在前端把Base64转为图片

let file = img.src; // 把整个base64给file
let name = filename + ".png"; // 定义文件名字(例如:cober.png)
var type = "image/png"; // 定义图片类型(canvas转的图片一般都是png,也可以指定其他类型)
let conversions = base64ToBlob(file, type); // 调用base64转图片方法
 
// conversions 就是转化之后的图片文件,
 
function base64ToBlob(urlData, type) {
    let arr = urlData.split(',');
    let mime = arr[0].match(/:(.*?);/)[1] || type;
    // 去掉url的头,并转化为byte
    let bytes = window.atob(arr[1]);
    // 处理异常,将ascii码小于0的转换为大于0
    let ab = new ArrayBuffer(bytes.length);
    // 生成视图(直接针对内存):8位无符号整数,长度1个字节
    let ia = new Uint8Array(ab);
    for (let i = 0; i < bytes.length; i++) {
        ia[i] = bytes.charCodeAt(i);
    }
    return new Blob([ab], {
        type: mime
    });
},