阅读 115
Base64抛砖引玉,够不?

Base64抛砖引玉,够不?

这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战

前端处理

Data URI scheme是在RFC2397中定义的,目的是将一些小的数据,直接嵌入到网页中,从而不用再从外部文件载入。

base64简单地说,它把一些 8-bit 数据翻译成标准 ASCII 字符,图像文件的内容直接写在了HTML 文件中,这样做的好处是,节省了一个HTTP 请求。坏处呢,就是浏览器不会缓存这种图像。

Data URI scheme支持的类型有:

  • data:,文本数据
  • data:text/plain,文本数据
  • data:text/html,HTML代码
  • data:text/html;base64,base64编码的HTML代码
  • data:text/css,CSS代码
  • data:text/css;base64,base64编码的CSS代码
  • data:text/javascript,Javascript代码
  • data:text/javascript;base64,base64编码的Javascript代码
  • data:image/gif;base64,base64编码的gif图片数据
  • data:image/png;base64,base64编码的png图片数据
  • data:image/jpeg;base64,base64编码的jpeg图片数据
  • data:image/x-icon;base64,base64编码的icon图片数据

其实,还可以处理PDF等文件。

1.HTML标签显示

  • 以img标签为例进行举例说明
<img src="./images/test.jpg"/> <!-- 个人常用方式 -->
复制代码
  • 使用base64显示的形式:
<img src="data:image/png;base64,iVBORw0KGgoAAA Base64的代码"/>
复制代码

2.JavaScript图片转换为Base64

  • 我用的工具类分享一下,图片转换Base64
function image2Base64(img) {    //图片转为base64编码
    var canvas = document.createElement("canvas");
    canvas.width = img.width;
    canvas.height = img.height;
    var ctx = canvas.getContext("2d");
    ctx.drawImage(img, 0, 0, img.width, img.height);
    var dataURL = canvas.toDataURL("image/png");
    return dataURL;
}

function getImgBase64(){        //获取base64编码
    var base64="";
    var img = new Image();
    img.src="img/test.jpg";
    img.onload=function(){
        base64 = image2Base64(img);
        alert(base64);
    }
}
getImgBase64();    //使用函数
复制代码

通过上述的代码,其实我们应该能感觉到需要对图片进行Base64的编码和转码,上面主要是使用toDataURL进行处理的,其实还有其他的方式。

3.用JS进行Base64编码、解码

从IE10+浏览器开始,所有浏览器就原生提供了Base64编码、解码方法,不仅可以用于浏览器环境,Service Worker环境也可以使用。方法名就是 atob 和 btoa ,具体语法如下:

window.btoa('china is so nb') // 编码
"Y2hpbmEgaXMgc28gbmI="
window.atob("Y2hpbmEgaXMgc28gbmI=") // 解码
"china is so nb"
复制代码

E8/IE9的polyfill,当下,仍有不少PC项目还需要兼容IE9,所以,我们可以专门针对这些浏览器再引入一段ployfill脚本或者一个JS文件即可。

<!--[if IE]>
<script src="https://www.zhangxinxu.com/wordpress/2018/08/js-base64-atob-btoa-encode-decode/base64-polyfill.js"></script>
<![endif]-->
复制代码
  • **编码 btoa **
// base64转字符串
function getEncode64(str){
    // 对字符串进行编码
    var encode = encodeURI(str);
    // 对编码的字符串转化base64
    var base64 = btoa(encode);
    return base64
}
复制代码
  • **编码 atob **

// base64转字符串
function getDecode(str){
    // 对base64转编码
    var decode = atob(base64);
    // 编码转字符串
    var str = decodeURI(decode);
    return str;
}
复制代码
  • 示例代码
let url = 'http://百度一下.com'
//转base64编码
let base64Url = this.getEncode64(url);
 
//解码  后台返回JSON格式所以加了JSON.parse进行json解码,正常对象格式就不用加
let data =JSON.parse(this.getDecode(resp.data));
console.log(data);
复制代码

开源的base64.js ,使用很简单,浏览器引入该JS文件。

  • 编码就调用encode方法如下:
Base64.encode('china is so nb'); // 编码
"Y2hpbmEgaXMgc28gbmI="
复制代码
  • 解码就调用 decode方法,如下:
Base64.decode("Y2hpbmEgaXMgc28gbmI="); // 解码
'china is so nb'
复制代码

4.中文问题

Base64编码和解码,我前端操作编译和解码中文都是没有问题的,但是由于需要后台,编码后传输到后台,后台返回编码格式再解码的时候就会出现中文乱码。

原因: 一番查找下来,可能是由于常规的encode方法虽然界面上转的是utf-8,但是实际上传输存储的时候格式还是utf-16,后台返回的是utf-8格式,用decode界面实际上转的是utf-16转utf-8会出现中文乱码。也就是说上述的编码和解码,适用于页面本身编码解码,不适合传输用。

解决中文乱码问题:

//字符串转base64
function getEncode64(str){   
    return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,function toSolidBytes(match, p1) {
        return String.fromCharCode('0x' + p1);
    }));
}

function getDecode(str){
    return decodeURIComponent(atob(str).split('').map(function (c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
    }).join(''));
}
复制代码

5.图片下载保存

我想通过点击“保存按钮”,将这张base64图片保存到本地。


// 保存按钮点击事件方法
function saveImg(){
    var sampleImage = $("img")[0]; // 找到图片所在的img标签
    var canvas = convertImageToCanvas(sampleImage); //创建画板
    url = canvas.toDataURL("image/png"); //生成下载的url
    // 把url放到我们的a标签中,并得到a标签对象
    var triggerDownload = $("#saveImg").attr("href", url).attr("download", "ewm.png"); 
    triggerDownload[0].click(); //模拟点击一下a标签,即可下载啦!
}
 
/**
 * 根据图片生成画布
*/
function convertImageToCanvas(image) {
    var canvas = document.createElement("canvas");
    canvas.width = image.width;
    canvas.height = image.height;
    canvas.getContext("2d").drawImage(image, 0, 0);
    return canvas;
}


复制代码

另一种的参考代码

// 这里是获取到的图片base64编码,这里只是个例子哈,要自行编码图片替换这里才能测试看到效果
 const imgUrl = 'data:image/png;base64,...'
 // 如果浏览器支持msSaveOrOpenBlob方法(也就是使用IE浏览器的时候),那么调用该方法去下载图片
 if (window.navigator.msSaveOrOpenBlob) {
  var bstr = atob(imgUrl.split(',')[1])
  var n = bstr.length
  var u8arr = new Uint8Array(n)
  while (n--) {
   u8arr[n] = bstr.charCodeAt(n)
  }
  var blob = new Blob([u8arr])
  window.navigator.msSaveOrOpenBlob(blob, 'chart-download' + '.' + 'png')
 } else {
  // 这里就按照chrome等新版浏览器来处理
  const a = document.createElement('a')
  a.href = imgUrl
  a.setAttribute('download', 'chart-download')
  a.click()
 }
复制代码

服务端处理

关于后台的处理,我就粘贴一下我的代码,不想写了,可以使用就好

  • Base6转换工具类,Java8的处理性能好一些import java.util.Base64;
package com.hanpang.common;

import java.io.UnsupportedEncodingException;
import java.util.Base64;

public class Base64Util {
    private static final String UTF8="UTF-8";
    private static Base64.Encoder encoder;
    //即为安全的编码方式,替换“+” “/” “-”为“_”
    private static Base64.Encoder urlEncoder;
    private static Base64.Decoder decoder;
    private static Base64.Decoder urlDecoder;
    static {
        encoder = Base64.getEncoder();
        urlEncoder = Base64.getUrlEncoder();
        decoder = Base64.getDecoder();
        urlDecoder = Base64.getUrlDecoder();
    }
    // 编码 encode
    public static byte[] encode(byte[] bytes) {
        return encoder.encode(bytes);
    }
    public static String encode(String string) {
        byte[] encode = encode(string.getBytes());
        try {
            return new String(encode, UTF8);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static String encode2String(byte[] bytes) {
        return encoder.encodeToString(bytes);
    }
    public static byte[] encode2Byte(String string) {
        return encode(string.getBytes());
    }
    public static byte[] urlEncode(byte[] bytes) {
        return urlEncoder.encode(bytes);
    }
    public static String urlEncode(String string) {
        byte[] encode = urlEncode(string.getBytes());
        try {
            return new String(encode, UTF8);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static String urlEncode2String(byte[] bytes) {
        return urlEncoder.encodeToString(bytes);
    }
    public static byte[] urlEncode2Byte(String string) {
        return urlEncode(string.getBytes());
    }
    // 编码 encode
    public static byte[] decode(byte[] bytes) {
        return decoder.decode(bytes);
    }
    public static byte[] decode2Byte(String string) {
        return decoder.decode(string.getBytes());
    }
    public static String decode2String(byte[] bytes) {
        try {
            return new String(decoder.decode(bytes),UTF8);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static String decode(String string) {
        byte[] decode = decode(string.getBytes());
        try {
            return new String(decode, UTF8);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }
    //urlDecode
    public static byte[] urlDecode(byte[] bytes) {
        return urlDecoder.decode(bytes);
    }
    public static byte[] urlDecode2Byte(String string) {
        return urlDecode(string.getBytes());
    }
    public static String urlDecode2String(byte[] bytes) {
        try {
            return new String(urlDecode(bytes),UTF8);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static String urlDecode(String string) {
        byte[] decode = urlDecode(string.getBytes());
        try {
            return new String(decode, UTF8);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }
}
复制代码
  • 互转工具类
package com.hanpang.common;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

import java.io.*;
import java.util.Arrays;

public final class Base64Convert {
    /**
     * 图片转换为Base64字符串
     * @param imagePath
     * @return
     */
    public static String imageToStr(String imagePath){
        File imageFile = new File(imagePath);
        if(!imageFile.exists()){
            throw new RuntimeException("图片不存在,请查询之后在处理");
        }
        try {
            byte[] bytes = FileUtils.readFileToByteArray(imageFile);
            return Base64Util.encode2String(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * base64字符串转化成图片
     * @param imageData 图片编码
     * @param imageFilePath 存放到本地路径
     * @return
     */
    public static void strToImage(String imageData,String imageFilePath){
        if(imageData==null||imageData.trim().length()==0){
            throw new RuntimeException("字符串数据有问题,请重启之后再进行转换");
        }
        byte[] bytes = Base64Util.decode2Byte(imageData);
        try {
            IOUtils.copy(new ByteArrayInputStream(bytes),new FileOutputStream(imageFilePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 大文件转换为Base64字符串,应该一般用不到
     * @param filePath
     * @return
     */
    public static String fileBigToStr(String filePath){
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            InputStream in = new BufferedInputStream(new FileInputStream(filePath));
            byte[] b = new byte[3 * 1024 * 1024];//由于3个常规字符可以转换为4个base64编码字符,所以使用3的公倍数作为缓冲区大小
            byte[] base64Buffer;
            int len;
            while((len=in.read(b))!=-1){
                if(len!=b.length){//如果有效字节数不为3 * 1024 * 1024,则说明文件已经读到尾了,不够填充满b了
                    byte[] copy = Arrays.copyOf(b, len);//从b中截取包含有效字节数的字节段
                    base64Buffer = Base64Util.encode(copy);//对有效字节段进行编码
                }else{
                    base64Buffer = Base64Util.encode(b);
                }
                out.write(base64Buffer,0,base64Buffer.length);
                //FileUtils.writeByteArrayToFile(file, base64ByteBuf, true); // 将转换后的数据写入文件中,该方法会自动创建文件
                out.flush();
            }
            in.close();;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException("文件不存在,请查询之后在处理");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("读取文件过程有问题");
        }
        return out.toString();
    }




}

复制代码
文章分类
前端
文章标签