美文网首页
图片与bash64互转

图片与bash64互转

作者: 一个摸鱼AI喵 | 来源:发表于2021-10-21 09:29 被阅读0次

一 、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];
    }

参考1(https://www.freesion.com/article/83441075024/)

参考2OpenCV-Mat与Base64之间的相互转换

相关文章

网友评论

      本文标题:图片与bash64互转

      本文链接:https://www.haomeiwen.com/subject/dddonltx.html