美文网首页
图片与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