Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

base64 原理及转换会变大的原因 #37

Open
Yuanfang-fe opened this issue Jun 30, 2021 · 0 comments
Open

base64 原理及转换会变大的原因 #37

Yuanfang-fe opened this issue Jun 30, 2021 · 0 comments

Comments

@Yuanfang-fe
Copy link
Owner

Yuanfang-fe commented Jun 30, 2021

以前用到base64有这么几个场景:

  1. 使用html2canvas 将html 转成图片的时候,html 里面的跨域图片无法生成图片,所以将图片先转成base64再生成
  2. jpg之类的图片有损压缩,使用canvas.toDataUrl()
  3. webpack 打包时,为了减少 https(http) 的请求数量(主要是为了减少三次握手,如果是http1.1开启了长连接或者http2.0/3.0之类的有多路复用,其实我觉得可以不用转base64),将小于10k(好像是10k,记不清了)的图片转成base64打在代码里。

但是,图片转成base64,体积会变大33%,所以大点的图片也不建议转换。

那么,转成 base64 为什么会变大呢?

还有为啥叫 base64, 不叫base16或者base24、base32呢?

针对上面的疑问,我们一步步来解释,别急,老弟!

base64 生成步骤

假设我们有个单词要转成base64: Hello

1. 找到每个字母对应的ASCII值

ASCII值 控制字符 ASCII值 控制字符 ASCII值 控制字符 ASCII值 控制字符
0 NUT 32 (space) 64 @ 96
1 SOH 33 ! 65 A 97 a
2 STX 34 " 66 B 98 b
3 ETX 35 # 67 C 99 c
4 EOT 36 $ 68 D 100 d
5 ENQ 37 % 69 E 101 e
6 ACK 38 & 70 F 102 f
7 BEL 39 , 71 G 103 g
8 BS 40 ( 72 H 104 h
9 HT 41 ) 73 I 105 i
10 LF 42 * 74 J 106 j
11 VT 43 + 75 K 107 k
12 FF 44 , 76 L 108 l
13 CR 45 - 77 M 109 m
14 SO 46 . 78 N 110 n
15 SI 47 / 79 O 111 o
16 DLE 48 0 80 P 112 p
17 DCI 49 1 81 Q 113 q
18 DC2 50 2 82 R 114 r
19 DC3 51 3 83 S 115 s
20 DC4 52 4 84 T 116 t
21 NAK 53 5 85 U 117 u
22 SYN 54 6 86 V 118 v
23 TB 55 7 87 W 119 w
24 CAN 56 8 88 X 120 x
25 EM 57 9 89 Y 121 y
26 SUB 58 : 90 Z 122 z
27 ESC 59 ; 91 [ 123 {
28 FS 60 < 92 / 124 |
29 GS 61 = 93 ] 125 }
30 RS 62 > 94 ^ 126 `
31 US 63 ? 95 _ 127 DEL
通过上表可以得知分别为:

image

2. 将 ASCII 值转换为二进制

image

算数不好的同学(我)试试这个方法:
image

通过上面可以知道,其实 ASCII 码只有128个,也就是 7位就够了,但是存储确是用的 8 位,每个都是在前面补0,其实已经浪费了一些空间。假如说以后字符补充到256个,就可以充分利用空间了。

3. 将 ASCII 的二级制值每6个一组,重新组装(如果不足六位,在前面补0),并计算对应的10进制的值

那疑问来了,为什么是6个一组?

首先常用字符有a-z、A-Z、0-9

这些字符总共 26 + 26 + 10 = 62个,另外有找了2个凑数的字符 + /

其实我觉得其他字符拿来凑数也是可以的,例如 -、#、[、]等。

2的6次方等于64,也就是6位就足以覆盖全部的base64字符了,所以是6位。

但是存储还是按8位一组来的,所以要在前面补2个零。

6 和 8 的最小公倍数是24,也就是3个字节,每 6 位一组,也就是4组,每组前面补2个0,凑够8位。所以这个时候就变成了4个字节,也就是增加了33.33%

重新分组后新的值为:

image

同样计算过程为:

image

4. 接下来就是根据新的值在base64表查找对应的字符了

索引对应字符索引对应字符索引对应字符索引对应字符
0A17R34i51z
1B18S35j520
2C19T36k531
3D20U37l542
4E21V38m553
5F22W39n564
6G23X40o575
7H24Y41p586
8I25Z42q597
9J26a43r608
10K27b44s619
11L28c45t62+
12M29d46u63/
13N30e47v
14O31f48w
15P32g49x
16Q33h50y

最后的结果为:

image

这时候转换的结果是SGVsbGP

因为规定不足4字节的要在后面补 =

所以结果为SGVsbGP=

本以为这样就ok了,但是我去在线base64 加解密 算了下结果为 SGVsbG8=

什么?最后一位是8? 看了下base64 表里对用的值为60,也就是 parseInt(111100,2),仔细想了下,每三个字符一组,如果只有两个,那最后一个字符就是00000000,分组的时候 就变成了111100。
所以纠正后的结果为:

image

表格地址获取:https://docs.qq.com/doc/DU0tod0JXQ0J3UFRp

为什么是Base64,可以是Base16或者Base512吗?

前面已经说到ASCII码有128个,即 2 的 7 次方,一个字节等于8个无符号位,这种情况下,已经浪费了 1 个符号位,Base64 是 6位,假如说我们用4位的,也就是2的4次方16,可以命名为Base16,这个时候转换会有什么后果呢? 相当于一个字节拆成2个字节,4和8最小公倍数为32,也就是4个字节一组,但是重新组装后,长度变为原来的2倍,所以体积变为原来的2倍。这时候应该清楚为什么是Base64了吧,就是为了减少空间的浪费。那可以发明Base256、或者Base512 这种东西来节省体积吗?如果是Base256,也就是2的8次方,跟现在的位数一样,但是用不同的符号代替,则可以保证在不增加体积的情况下完成转换。如果是Base512,则是9位了,一个字节才8位,那就不行了。这么说来Base64 还有优化空间,上限就是Base512,哪天我高兴了,我也给编个Base512的表,发明Base512编码,哈哈哈!!!

然而实际情况是我并没有512个字符可以用

@Yuanfang-fe Yuanfang-fe changed the title base64 原理及图片转换会变大的原因 base64 原理及转换会变大的原因 Jul 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant