前言
base64是一种用64个可打印字符编码任意二进制的方法。所谓Base64,就是说选出64个字符----小写字母a-z、大写字母A-Z、数字0-9、符号"+"、"/"(再加上作为垫字的"=",实际上是65个字符)----作为一个基本字符集。然后,其他所有符号都转换成这个字符集中的字符。
具体来说,转换方式可以分为四步。
- 第一步,将每三个字节作为一组,一共是
24个二进制位。 - 第二步,将这
24个二进制位分为四组,每个组有6个二进制位。 - 第三步,在每组前面加两个
00,扩展成32个二进制位,即四个字节。 - 根据上表,得到扩展后的每个字节的对应符号,这就是
Base64的编码值。
因为,Base64将三个字节转化成四个字节,因此Base64编码后的文本,会比原文本大出三分之一左右。
Base64的码表只有64个字符, 如果要表达64个字符的话,使用6的bit即可完全表示(2的6次方为64)。因为Base64的编码只有6个bit即可表示,而正常的字符是使用8个bit表示, 8和6的最小公倍数是24,所以4个Base64字符可以表示3个标准的ascll字符。
将字符串转换为base64时,会先把字符串转换为对应的ascll码,然后从左往右6位截取(6位对应一位base64码),若最后不足6位(一个base64码)补0,不足3个字符串则补=(解码时会自动去掉)
由于=字符也可能出现在Base64编码中,但=用在URL、Cookie里面会造成歧义,所以,很多Base64编码后会把=去掉。因为base64码的位数永远是4的倍数,所以解码时若位数不足可以在末尾补=。
将图片转换成Base64的编码方式是因为可以将图片直接嵌入到网页中,而不是从外部载入,这样就减少了HTTP请求。
例子:汉字"严"如何转化成Base64编码
这里需要注意,汉字本身可以有多种编码,比如gb2312、utf-8、gbk等等,每一种编码的Base64对应值都不一样。下面的例子以utf-8为例。
首先,"严"的utf-8编码为E4B8A5,写成二进制就是三字节的"11100100 10111000 10100101"。将这个24位的二进制字符串,转换成四组一共32位的二进制值"00111001 00001011 00100010 00100101",相应的十进制数为57、11、34、37,它们对应的Base64值就为5、L、i、l。
所以,汉字"严"(utf-8编码)的Base64值就是5Lil。
原生atob和btoa方法
从IE10+浏览器开始,所有浏览器就原生提供了Base64编码解码方法,不仅可以用于浏览器环境,Service Worker环境也可以使用。
方法名就是atob和btoa,具体语法如下:
1. Base64解码
// 浏览器中
var decodedData = window.atob(encodedData);
// 浏览器或js Worker线程中
var decodedData = self.atob(encodedData);
例如
window.atob('RnJ1aXQgQnJv');
// 返回:'Fruit Bro
atob这个方法名称乍一看,很奇怪,不知道这个单词什么意思。我们可以理解为 A to B,也就是从A到B。也就是把base64转为字符串。
2. Base64编码
// 浏览器中
var encodedData = window.btoa(stringToEncode);
// 浏览器或js Worker线程中
var encodedData = self.btoa(stringToEncode);
3. 任意文件Base64编码
借助FileReader对象和readAsDataURL方法,我们可以把任意文件转为Base64 Data-URI。假设我们的文件对象是file,则转换的JavaScript代码如下:
var reader = new FileReader();
reader.onload = function(e) {
// e.target.result就是该文件的完整Base64 Data-URI
};
reader.readAsDataURL(file);
Uint8Array
developer.mozilla.org/zh-CN/docs/…
Uint8Array 数组类型表示一个8位无符号整型数组,创建时内容被初始化为0。创建完后,可以以对象的方式或使用数组下标索引的方式引用数组中的元素。
new Uint8Array(); // ES2017 最新语法
new Uint8Array(length); // 创建初始化为0的,包含length个元素的无符号整型数组
new Uint8Array(typedArray);
new Uint8Array(object);
new Uint8Array(buffer [, byteOffset [, length]]);
charCodeAt
developer.mozilla.org/zh-CN/docs/…
charCodeAt() 方法返回 0 到 65535 之间的整数,表示给定索引处的 UTF-16 代码单元。
UTF-16编码单元匹配能用一个UTF-16编码单元表示的 Unicode 码点。如果 Unicode 码点不能用一个 UTF-16 编码单元表示(因为它的值大于0xFFFF),则所返回的编码单元会是这个码点代理对的第一个编码单元) 。如果你想要整个码点的值,使用 codePointAt()。
最终实现
function dataURLtoFile(dataurl: string, filename: string) {
// 获取到base64编码
const arr = dataurl.split(',')
// 将base64编码转为字符串
const bstr = window.atob(arr[1])
let n = bstr.length
const u8arr = new Uint8Array(n) // 创建初始化为0的,包含length个元素的无符号整型数组
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], filename, {
type: 'image/jpeg',
})
}
const photoName = `${new Date().getTime()}`
const picContent = dataURLtoFile(
'data:image/gif;base64,' + pic,
`${photoName}.jpg`
)
参考文档:
stackoverflow.com/questions/3…
stackoverflow.com/questions/1…