最近使用人脸识别restfulAPI遇到了要求图片base64编码后传输问题。
1 什么是base64编码
所谓Base64,就是说选出64个字符—-小写字母a-z、大写字母A-Z、数字0-9、符号”+”、”/”(再加上作为垫字的”=”,实际上是65个字符)—-作为一个基本字符集。然后,其他所有符号都转换成这个字符集中的字符。
2 解决的问题
网络传送渠道(纯文本协议)并不支持所有的字节,例如传统的邮件只支持可见字符的传送,像ASCII码的控制字符就不能通过邮件传送。
http针对二进制数据做了特殊规定是可以支持传输二进制数据的,但如果在json内部传输二进制数据就会遇到这种问题,我们可以先进行base64编码转成字符串进行处理。
3 主要用途
证书 电子邮件数据,经常要用到Base64编码。
4 如何编码
第一步,将每三个字节作为一组,一共是24个二进制位。
第二步,将这24个二进制位分为四组,每个组有6个二进制位。
第三步,在每组前面加两个00,扩展成32个二进制位,即四个字节。
第四部, 每个字节的对应符号即为base64编码后的值。
Base64编码后的文本,会比原文本大出三分之一左右。
C++实现:
以下代码来自百度云SDK中base64编码部分。简单好用。
Bash64.h:
#ifndef __BASE64_H__ #define __BASE64_H__ #include <iostream> #include <string> static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; static inline bool is_base64(const char c) { return (isalnum(c) || (c == '+') || (c == '/')); } std::string base64_encode(const char * bytes_to_encode, unsigned int in_len) { std::string ret; int i = 0; int j = 0; unsigned char char_array_3[3]; unsigned char char_array_4[4]; while (in_len--) { char_array_3[i++] = *(bytes_to_encode++); if(i == 3) { char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for(i = 0; (i <4) ; i++) { ret += base64_chars[char_array_4[i]]; } i = 0; } } if(i) { for(j = i; j < 3; j++) { char_array_3[j] = '\0'; } char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for(j = 0; (j < i + 1); j++) { ret += base64_chars[char_array_4[j]]; } while((i++ < 3)) { ret += '='; } } return ret; } std::string base64_decode(std::string const & encoded_string) { int in_len = (int) encoded_string.size(); int i = 0; int j = 0; int in_ = 0; unsigned char char_array_4[4], char_array_3[3]; std::string ret; while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { char_array_4[i++] = encoded_string[in_]; in_++; if (i ==4) { for (i = 0; i <4; i++) char_array_4[i] = base64_chars.find(char_array_4[i]); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; for (i = 0; (i < 3); i++) ret += char_array_3[i]; i = 0; } } if (i) { for (j = i; j <4; j++) char_array_4[j] = 0; for (j = 0; j <4; j++) char_array_4[j] = base64_chars.find(char_array_4[j]); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; } return ret; } #endif
测试部分:
#include <string> #include <iostream> #include "base64.h" #include <fstream> using namespace std; int main(int argc, char** argv){ fstream f; f.open("test.jpg", ios::in|ios::binary); f.seekg(0, std::ios_base::end); std::streampos sp = f.tellg(); int size = sp; char* buffer = (char*)malloc(sizeof(char)*size); f.read(buffer,size); cout << "file size:" << size << endl; string imgBase64 = base64_encode(buffer, size); cout << "img base64 encode size:" << imgBase64.size() << endl; string imgdecode64 = base64_decode(imgBase64); cout << "img decode size:" << imgdecode64.size() << endl; return 0; }