一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情。
前端处理
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();
}
}