type
status
date
slug
category
tags
icon
password
summary

前言

在我第一次参加服创的比赛的时候,碰到有这样的一个任务:将STM32F407获取到的摄像头的图像数据上传到服务器端。然后当时我采用的是OV2640摄像头的压缩采集模式,也就是摄像头会输出照片的JPEG格式的字符串,其编码是HEX编码,也就是16进制编码。
 
然后当时我们用了百度AI的图像识别接口,他们接口对图片格式的要求是base64编码,然后当时我就很纠结这个从HEX编码转到Base64编码这个事情是在我STM32这边做,还是交给我后端的同学去做。经过讨论,我后端的同学说这个他不是很会,然后我就说那就我这边转码再发给他吧(不过在现在看来肯定是他那边转更加方便),然后就有了我第一次比赛挺艰难的一个过程,然后就有了这篇笔记。
 

什么是Base64编码

ASSIC编码

Base64编码其实和ASSIC编码是一样的,就是将不同的某一个二进制序列映射成一个可见的,有意义的字符。ASSIC编码和Base64编码的区别我认为就是编码规则的不同罢了。
ASSIC码表65~77
ASSIC码表65~77
在ASSIC编码中,有一套对应的映射码表,即ASSIC码表,这里我截取ASSIC码表的一部分内容做解释。
现在我有一个二进制的码值 01000001,它的十进制表示为65,那么我就将这个码值映射到符号序列中,让它表示 A,其他的码值依次表示不同的符号。因为计算机当中记录的是二进制信息,所以就用这个二进制码值表示了一个符号。根据这样的规则就形成了一套码表,只要我知道这个二进制的码值,就可以通过查表来知道他表示的是什么符号,这套码表就是我们现在使用的ASSIC码表。
 
假如说我现在收到一个二进制码值为:01001000 。我想知道它表示的是什么字符,那么我就查ASSIC码表,可以查到这个码值表示的字符是 H 。
 
然后,这个ASSIC码是由美国人发明出来的,他们的文字是有26个基本的英文字母组成的,算上大小写和一些常用的基本数字可能也就是100多个基本字符。所以他们使用了8个二进制为来表示一个ASSIC码值,也就是一个字节,这一个字节的ASSIC码可以表示的符号数为个,它远远大于了常用的基本字符数,所以基本上是够用了。
 
到现在ASSIC码在我们的计算机系统上使用非常广泛,我们学习C语言的时候应该就接触到ASSIC码表了,所以我认为应该也不是那么难以理解。
 
通过上面的内容,我们可以得出表示一套编码规则的基本内容应该有以下这些:
  • 一套码表
  • 一个符号的编码长度(也就是多少位二进制表示一个符号)
这样,我们就能够根据二进制码值和码表表示出它对应的符号是什么。
 

Base64编码

👇
以下内容引用自Base64 编码/解码 | 菜鸟工具 (runoob.com)
 
Base64 是一种基于 64 个可打印字符来表示二进制数据的表示方法,由于 2^6=64,所以每 6 个比特为一个单元,对应某个可打印字符。
Base64 常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据,包括 MIME 的电子邮件及 XML 的一些复杂数据。
Base64 编码要求把 3 个 8 位符号(3*8=24)转化为 4 个 6 位的符号(4*6=24),之后在 6 位的前面补两个 0,形成 8 位一个字节的形式。 如果剩下的字符不足 3 个字节,则用 0 填充,输出字符使用 =,因此编码后输出的文本末尾可能会出现 1 或 2 个 =。
 
为了保证所输出的编码位可读字符,Base64 制定了一个编码表,以便进行统一转换。编码表的大小为 2^6=64,这也是 Base64 名称的由来。
 
在 Base64 中的可打印字符包括字母 A-Za-z、数字 0-9,这样共有 62 个字符,此外两个可打印符号在不同的系统中而不同。
 
编码规则我没有引用这篇文章里面的描述,我认为它描述的不是很清楚,结合维基百科的解释,我将Base64编码规则描述如下:
  • 将数据划分为 3 个字节一组(24位)。
  • 将每个字节转换为 8 位二进制形式。
  • 将 24 位数据按照 6 位一组进行划分,得到 4 个 6 位的组。
  • 将每个 6 位的组转换为对应的 Base64 字符。
  • 如果要编码的字节数不能被3整除,最后会多出1个或2个字节,那么可以使用下面的方法进行处理:先使用0字节值在末尾补足,使其能够被3整除,然后再进行Base64的编码。在编码后的Base64文本后加上一个或两个=号,代表补足的字节数。
  • 将所有转换后的 Base64 字符连接起来,形成最终的编码结果。
 
由上面的描述,我的理解是Base64编码其实是根据原来的8位编码再转换一次编码形成的,至于为什么这样子弄我也不明白,应该是有它的方便之处吧。

Base64编码举例说明

它的码表如下图所示
Base64码表
Base64码表
 
按照编码规则,有以下三种情况发生:
  • 不差字节,编码的字节数刚刚好够被3整除
  • 差1个字节
  • 差2个字节
下面分别举例子讲解编码的过程。
1. 编码的字节数刚刚好够被3整除的情况
假设需要编码的ASSIC字符为:Hel
其二进制编码序列为:
0100 1000 0110 0101 0110 1100
按照6位一组:
010010 000110 010101 101100
对应的十进制(方便后面查表转换成字符):
18 6 21 44
对应Base64码表,得到对应的Base64编码内容:
S G V s
也就是说,ASSIC编码的字符串(Hel)转换成Base64编码后的内容是:(SGVs)
2. 差一个字节可以被3整除的情况
现在假设我们的内容是:He
因为它差一个字节就能够被3整除,所以在他后面补一个0字节,也就是 0x00,变成了:He(0X00),这个字节不参与后面的字符映射,但是要在编码完成的Base64字符串后面添加一个填充字符=
将它变成二进制:
01001000 01100101 00000000
按照6位一组:
010010 000110 010100 000000
对应的十进制,因为填充了一个0字节,所以后面的一个字符要用填充符号代替,也就是后面一串0要用符号=代替:
18 6 20 填充的0
对应的Base64码: S G U =
也就是,ASSIC的字符串He转换为Base64编码得到的结果是:SGU=
💡
后面的=是因为差一个字节能够被3整除,使用一个=作为填充符号
3. 差两个字节可以被3整除的情况
假设现在要编码的内容为:Hell
按照3字节一组划分,后面的l还缺两个字节,所以后面填充两个0字节。
对应的二进制序列:
01001000 01100101 01101100 01101100 00000000 00000000
按6位一组划分:
010010 000110 010101 101100 011011 000000 000000 000000
因为填充了两个0,所以后面连串零无效,用=填充
对应的十进制:
18 6 21 44 27 0 填充的0 填充的0
对应的Base64码:
S G V s b A = =
也就是说,ASSIC码字符串(Hell)转换成Base64字符后变成:(SGVsbA==)

Base64编码代码实现

这里我本来想自己写一段代码的,然后我想了一下,下面这位博主的讲解也许更加好,所以就给出了博主的链接,直接看这位博主的就好了。
 

参考资料

 
SPI 协议初步理解关于KEIL的软件仿真这件事
ycloong
ycloong
要做一个苦行僧,探索自己的人生道路