一 、python中
import bash64
1.1 bash64与cv互转
import cv2
import numpy as np
bash64-->cv2
# base64解码
img_data = base64.b64decode(img_base64_str)
# 转换为np数组
img_array = np.frombuffer(img_data, np.uint8) #推荐
或 img_array = np.fromstring(img_data, np.uint8)
# 转换成opencv可用格式
image = cv2.imdecode(img_array, cv2.IMREAD_COLOR) #推荐
或者image = cv2.imdecode(img_array, cv2.COLOR_RGB2BGR)[:, :, :3]
cv2-->bash64
retval, buffer = cv2.imencode('.jpg', img_array)
img_base64= base64.b64encode(buffer).decode()
或者str(base64.b64encode(image))[2:-1]
由于encode是 bytes格式 有 b'故需要取[2:]
1.2 bash64与PIL互转
from io import BytesIO
from PIL import Image
bash64-->PIL
def base64_pil(base64_str):
image = base64.b64decode(base64_str)
image = BytesIO(image)
image = Image.open(image)
return image
PIL-->bash64
def pil_base64(image):
img_buffer = BytesIO()
image.save(img_buffer, format='JPEG')
byte_data = img_buffer.getvalue()
base64_str = base64.b64encode(byte_data)
return base64_str
1.3 补充:PIP与二进制互转
PIL 转二进制
from PIL import Image
from io import BytesIO
def PIL2bytes(im):
# im: PIL 图片
bytesIO = BytesIO()
try:
im.save(bytesIO, format='JPEG')
except:
im.save(bytesIO, format='PNG')
return bytesIO.getvalue() # 转二进制
二进制转PIL
with open(图片) 并read()后的为二进制
def bytes2PIL(im):
#im:二进制图片数据
return Image.open(BytesIO(im))
二、C++中
2.1 bash64与二进制图片的互转
代码1:bash64.hpp
#include <iostream>
#include <vector>
#include <string>
using namespace std;
#define IMG_JPG "data:image/jpeg;base64," //jpg图片信息,其他类似.从CSS跟HTML中会有这些信息
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(const char c)
{
return (isalnum(c) || (c == '+') || (c == '/'));
}
//加密:二进制转bash64
//bytes_to_encode:二进制信息
//in_len: 二进制文本长度,int in_len = (int) encoded_string.size()获取
std::string base64_encode(const unsigned 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;
}
//解密 bash64转二进制
//encoded_string: bash64文本
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;
}
收到数据后我们首先要去除数据中的图片信息(数据中没有图片信息的此步骤可跳过)
image=image.replace(data.find(IMG_JPG),sizeof(IMG_JPG),"");
在对图片进行解密保存(bash64转二进制)
#include <fstream>
#include <sstream>
#include <algorithm>
string img_data=base64_decode(img);
std::ofstream fout("/home/mayun_bak.jpg", std::ios::binary);
fout.write(base.c_str(), base.size());
fout.close();
这样图片就保存好了,
从图片二进制读取—>base64加密—>base64解密—>写图片的测试代码如下(没有图片信息头):
int main()
{
std::ifstream fin("/home/mayun.jpg", std::ios::binary); //二进制打开图片
fin.seekg(0, ios::end);
int iSize = fin.tellg();
char* szBuf = new (std::nothrow) char[iSize];
fin.seekg(0, ios::beg);
fin.read(szBuf, sizeof(char) * iSize);
fin.close();
string img=base64_encode(szBuf,iSize);
string img_data=base64_decode(img);
std::ofstream fout("/home/mayun_bak.jpg", std::ios::binary);
fout.write(img_data.c_str(), img_data.size());
fout.close();
return 0;
}
代码2:bash_cv.hpp
#include <vector>
#include <string>
using namespace std;
static std::string base64_encode(const unsigned char* Data, int DataByte) {
//编码表
const char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//返回值
std::string strEncode;
unsigned char Tmp[4] = { 0 };
int LineLength = 0;
for (int i = 0; i < (int)(DataByte / 3); i++) {
Tmp[1] = *Data++;
Tmp[2] = *Data++;
Tmp[3] = *Data++;
strEncode += EncodeTable[Tmp[1] >> 2];
strEncode += EncodeTable[((Tmp[1] << 4) | (Tmp[2] >> 4)) & 0x3F];
strEncode += EncodeTable[((Tmp[2] << 2) | (Tmp[3] >> 6)) & 0x3F];
strEncode += EncodeTable[Tmp[3] & 0x3F];
if (LineLength += 4, LineLength == 76) { strEncode += "\r\n"; LineLength = 0; }
}
//对剩余数据进行编码
int Mod = DataByte % 3;
if (Mod == 1) {
Tmp[1] = *Data++;
strEncode += EncodeTable[(Tmp[1] & 0xFC) >> 2];
strEncode += EncodeTable[((Tmp[1] & 0x03) << 4)];
strEncode += "==";
}
else if (Mod == 2) {
Tmp[1] = *Data++;
Tmp[2] = *Data++;
strEncode += EncodeTable[(Tmp[1] & 0xFC) >> 2];
strEncode += EncodeTable[((Tmp[1] & 0x03) << 4) | ((Tmp[2] & 0xF0) >> 4)];
strEncode += EncodeTable[((Tmp[2] & 0x0F) << 2)];
strEncode += "=";
}
return strEncode;
}
static std::string base64_decode(const char* Data, int DataByte) {
//解码表
const char DecodeTable[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62, // '+'
0, 0, 0,
63, // '/'
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'
0, 0, 0, 0, 0, 0, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z'
0, 0, 0, 0, 0, 0,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'
};
std::string strDecode;
int nValue;
int i = 0;
while (i < DataByte) {
if (*Data != '\r' && *Data != '\n') {
nValue = DecodeTable[*Data++] << 18;
nValue += DecodeTable[*Data++] << 12;
strDecode += (nValue & 0x00FF0000) >> 16;
if (*Data != '=') {
nValue += DecodeTable[*Data++] << 6;
strDecode += (nValue & 0x0000FF00) >> 8;
if (*Data != '=') {
nValue += DecodeTable[*Data++];
strDecode += nValue & 0x000000FF;
}
}
i += 4;
}
else {
Data++;
i++;
}
}
return strDecode;
}
2.2 bash64与cv::Mat的互转
不能直接转,需要经过二进制中转.
所以在代码1或在代码2后面增加以下内容:
#include "opencv2/opencv.hpp"
#include "opencv2/imgcodecs/legacy/constants_c.h" //CV_IMWRITE_JPEG_QUALITY跟CV_LOAD_IMAGE_COLOR的头文件
using namespace cv;
//imgType 包括png bmp jpg jpeg等opencv能够进行编码解码的文件
static std::string Mat2Base64(const cv::Mat& img) {
//Mat转base64
std::string img_data;
std::vector<uchar> vecImg;
std::vector<int> vecCompression_params;
vecCompression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
vecCompression_params.push_back(90); //质量,默认值为95
cv::imencode("jpg", img, vecImg, vecCompression_params);
img_data = base64_encode(vecImg.data(), vecImg.size());
return img_data;
}
static cv::Mat Base2Mat(std::string& base64_data) {
cv::Mat img;
std::string s_mat;
s_mat = base64_decode(base64_data.data());
std::vector<char> base64_img(s_mat.begin(), s_mat.end());
img = cv::imdecode(base64_img, CV_LOAD_IMAGE_COLOR);
return img;
}
2.3 补充:opencv imdecode和imencode用法
string fname = "D:/image.jpg";
//! 以二进制流方式读取图片到内存
FILE* pFile = fopen(fname.c_str(), "rb");
fseek(pFile, 0, SEEK_END);
long lSize = ftell(pFile);
rewind(pFile);
char* pData = new char[lSize];
fread(pData, sizeof(char), lSize, pFile);
fclose(pFile);
//! 解码内存数据,变成cv::Mat数据
cv::Mat img_decode;
vector<uchar> data;
for (int i = 0; i < lSize; ++i){
data.push_back(pData[i]);
}
img_decode = cv::imdecode(data, CV_LOAD_IMAGE_COLOR);
cv::flip(img_decode, img_decode, -1);
img_decode.channels();
//! 将cv::Mat数据编码成数据流
vector<unsigned char> img_encode;
cv::imencode(".jpg", img_decode, img_encode);
unsigned char *encode_data = new unsigned char[lSize];
for (int i = 0; i<lSize; i++){
encode_data[i] = img_encode[i];
}
网友评论