BASE64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本。完整的BASE64定义可见 RFC1421和 RFC2045。编码后的数据比原始数据略长,为原来的4/3。在电子邮件中,根据RFC822规定,每76个字符,还需要加上一个回车换行。

转换的时候,将三个byte的数据,先后放入一个24bit的缓冲区中,先来的byte占高位。数据不足3byte的话,于缓冲区中剩下的Bit用0补足。然后,每次取出6个bit,按照其值选择ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符作为编码后的输出。不断进行,直到全部输入数据转换完成。如果最后剩下两个输入数据,在编码结果后加1个“=”;如果最后剩下一个输入数据,编码结果后加2个“=”;如果没有剩下任何数据,就什么都不要加,这样才可以保证资料还原的正确性。

BASE64_API.h  文件内容

/* ----------------------------------------------------------
文件名称:BASE64_API.h 作者:秦建辉 MSN:splashcn@msn.com 当前版本:V1.1 历史版本:
V1.1 2010年05月11日
修正BASE64解码的Bug。 V1.0 2010年05月07日
完成正式版本。 功能描述:
BASE64编码和解码 接口函数:
Base64_Encode
Base64_Decode 说明:
1. 参考openssl-1.0.0。
2. 改进接口,以使其适应TCHAR字符串。
3. 修正EVP_DecodeBlock函数解码时未去掉填充字节的缺陷。
------------------------------------------------------------ */
#pragma once

#include "stdafx.h"

#include <windows.h>

#ifdef    __cplusplus
extern "C" {
#endif /*
功能:将二进制数据转换成BASE64编码字符串
参数说明:
inputBuffer:要编码的二进制数据
inputCount:数据长度
outputBuffer:存储转换后的BASE64编码字符串
返回值:
-1:参数错误
>=0:有效编码长度(字符数),不包括字符串结束符。
备注:
等效于openssl中EVP_EncodeBlock函数
*/
INT BASE64_Encode( const BYTE* inputBuffer, INT inputCount, TCHAR* outputBuffer ); /*
功能:将BASE64编码字符串转换为二进制数据
参数说明:
inputBuffer:BASE64编码字符串
inputCount:编码长度(字符数),应该为4的倍数。
outputBuffer:存储转换后的二进制数据
返回值:
-1:参数错误
-2:数据错误
>=0:转换后的字节数
备注:
等效于openssl中EVP_DecodeBlock函数
*/
INT BASE64_Decode( const TCHAR* inputBuffer, INT inputCount, BYTE* outputBuffer ); #ifdef __cplusplus
}
#endif

BASE64_API.cpp 文件内容

#pragma once

#include "stdafx.h"

#include "BASE64_API.h"

static const CHAR* DATA_BIN2ASCII = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

INT BASE64_Encode( const BYTE* inputBuffer, INT inputCount, TCHAR* outputBuffer )
{
INT i;
BYTE b0, b1, b2; if( (inputBuffer == NULL) || (inputCount < 0) )
{
return -1; // 参数错误
} if( outputBuffer != NULL )
{
for( i = inputCount; i > 0; i -= 3 )
{
if( i >= 3 )
{ // 将3字节数据转换成4个ASCII字符
b0 = *inputBuffer++;
b1 = *inputBuffer++;
b2 = *inputBuffer++; *outputBuffer++ = DATA_BIN2ASCII[b0 >> 2];
*outputBuffer++ = DATA_BIN2ASCII[((b0 << 4) | (b1 >> 4)) & 0x3F];
*outputBuffer++ = DATA_BIN2ASCII[((b1 << 2) | (b2 >> 6)) & 0x3F];
*outputBuffer++ = DATA_BIN2ASCII[b2 & 0x3F];
}
else
{
b0 = *inputBuffer++;
if( i == 2 )b1 = *inputBuffer++; else b1 = 0; *outputBuffer++ = DATA_BIN2ASCII[b0 >> 2];
*outputBuffer++ = DATA_BIN2ASCII[((b0 << 4) | (b1 >> 4)) & 0x3F];
*outputBuffer++ = (i == 1) ? TEXT('=') : DATA_BIN2ASCII[(b1 << 2) & 0x3F];
*outputBuffer++ = TEXT('=');
}
} // End for i *outputBuffer++ = TEXT('/0'); // 添加字符串结束标记
} return ((inputCount + 2) / 3) * 4; // 返回有效字符个数
} #define B64_EOLN 0xF0 // 换行/n
#define B64_CR 0xF1 // 回车/r
#define B64_EOF 0xF2 // 连字符-
#define B64_WS 0xE0 // 跳格或者空格(/t、space)
#define B64_ERROR 0xFF // 错误字符
#define B64_NOT_BASE64(a) (((a)|0x13) == 0xF3) static const BYTE DATA_ASCII2BIN[128] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0xF0,0xFF,0xFF,0xF1,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xE0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3E,0xFF,0xF2,0xFF,0x3F,
0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,
0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0xFF,0xFF,0xFF,0xFF,0xFF
}; INT BASE64_Decode( const TCHAR* inputBuffer, INT inputCount, BYTE* outputBuffer )
{
INT i, j;
BYTE b[4];
TCHAR ch; if( (inputBuffer == NULL) || (inputCount < 0) )
{
return -1; // 参数错误
} // 去除头部空白字符
while( inputCount > 0 )
{
ch = *inputBuffer;
if( (ch < 0) || (ch >= 0x80) )
{
return -2; // 数据错误,不在ASCII字符编码范围内
}
else
{
if( DATA_ASCII2BIN[ch] == B64_WS )
{
inputBuffer++;
inputCount--;
}
else
{
break;
}
}
} // 去除尾部的空白字符、回车换行字符、连字符
while( inputCount >= 4 )
{
ch = inputBuffer[inputCount - 1];
if( (ch < 0) || (ch >= 0x80) )
{
return -2; // 数据错误,不在ASCII字符编码范围内
}
else
{
if( B64_NOT_BASE64(DATA_ASCII2BIN[ch]) )
{
inputCount--;
}
else
{
break;
}
}
} // 字符串长度必须为4的倍数
if( (inputCount % 4) != 0 )
{
return -2; // 数据错误
} if( outputBuffer != NULL )
{
for( i = 0; i < inputCount; i += 4 )
{
for( j = 0; j < 4; j++ )
{
ch = *inputBuffer++;
if( (ch < 0) || (ch >= 0x80) )
{
return -2; // 数据错误,不在ASCII字符编码范围内
}
else
{
if( ch == '=' ) // 发现BASE64编码中的填充字符
{
break;
}
else
{
b[j] = DATA_ASCII2BIN[ch];
if( b[j] & 0x80 )
{
return -2; // 数据错误,无效的Base64编码字符
}
}
}
} // End for j if( j == 4 )
{
*outputBuffer++ = (b[0] << 2) | (b[1] >> 4);
*outputBuffer++ = (b[1] << 4) | (b[2] >> 2 );
*outputBuffer++ = (b[2] << 6) | b[3];
}
else if( j == 3 )
{ // 有1个填充字节
*outputBuffer++ = (b[0] << 2) | (b[1] >> 4);
*outputBuffer++ = (b[1] << 4) | (b[2] >> 2 ); return (i >> 2) * 3 + 2;
}
else if( j == 2 )
{ // 有2个填充字节
*outputBuffer++ = (b[0] << 2) | (b[1] >> 4); return (i >> 2) * 3 + 1;
}
else
{
return -2; // 数据错误,无效的Base64编码字符
}
} // End for i
} return (inputCount >> 2) * 3;
}

采用以上方法就可以将二进制数据转换成可见字符进行传递就可以了.

那么如何使用呢?举以下两个例子

第一个:将一个图片转换成 txt 文本 并保存起来

//选择一个图像文件,将它转为 文本保存至  _T("D:\\2.txt"
void CTextPicDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码 CFileDialog file(TRUE,".jpg","");
if (file.DoModal() == IDOK)
{
CFile data(file.GetPathName(), CFile::modeReadWrite);
int len = data.GetLength();
BYTE *dv;
dv = (BYTE *)malloc(len*sizeof(BYTE));
data.Read(dv, len);
data.Close(); int slen = (len / 3) * 4;
slen += 10;
TCHAR * tc;
tc = (TCHAR *)malloc(slen); slen = BASE64_Encode(dv, len, tc); CFile save(_T("D:\\2.txt"), CFile::modeCreate | CFile::modeWrite);
save.Write(tc, slen);
save.Close(); free(tc);
free(dv); } }

第二个例子,将一个文本文件还原为一个图像

void CTextPicDlg::OnBnClickedButton3()
{
// TODO: 在此添加控件通知处理程序代码 CFileDialog file(TRUE, ".txt", "");
if (file.DoModal() == IDOK)
{
CFile data(file.GetPathName(), CFile::modeReadWrite);
int len = data.GetLength();
TCHAR *dv;
dv = (TCHAR *)malloc(len*sizeof(TCHAR));
data.Read(dv, len);
data.Close(); int slen = (len / 4) * 3;
slen += 10;
BYTE * tc;
tc = (BYTE *)malloc(slen); BASE64_Decode(dv, len, tc);
 
        //直接在内存里面构建CIMAGE,需要使用IStream接口,如何使用
        //构建内存环境
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, slen);
void * pData = GlobalLock(hGlobal);
memcpy(pData, tc, slen); // 拷贝位图数据进去
GlobalUnlock(hGlobal); // 创建IStream
IStream * pStream = NULL;
if (CreateStreamOnHGlobal(hGlobal, TRUE, &pStream) != S_OK)
return ;
// 使用CImage加载位图内存
CImage img;
if (SUCCEEDED(img.Load(pStream)) )
{
CClientDC dc(this); //使用内在中构造的图像 直接在对话框上绘图
img.Draw(dc.m_hDC, 0, 0, 500, 300); }
//释放内存
pStream->Release();
GlobalFree(hGlobal); //如果要保存图像文件的话,那就使用下面的代码
//CFileDialog savefile(FALSE, ".jpg", "");
//if (savefile.DoModal()==IDOK)
//{
// CFile save(savefile.GetPathName(), CFile::modeCreate | CFile::modeWrite);
// save.Write(tc, slen);
// save.Close();
//} free(tc);
free(dv); } }

至此,利用Base64转码的方式,来显示保存显示图片的方法,就算是成功了!

BASE64编码和解码(VC源代码) 并 内存加载 CImage 图像的更多相关文章

  1. base64编码、解码的C语言实现

    转自:http://www.cnblogs.com/yejianfei/archive/2013/04/06/3002838.html base64是一种基于64个可打印字符来表示二进制数据的表示方法 ...

  2. Java 8中的Base64编码和解码

    转自:https://juejin.im/post/5c99b2976fb9a070e76376cc Java 8会因为将lambdas,流,新的日期/时间模型和Nashorn JavaScript引 ...

  3. android Java BASE64编码和解码二:图片的编码和解码

    1.准备工作 (1)在项目中集成 Base64 代码,集成方法见第一篇博文:android Java BASE64编码和解码一:基础 (2)添加 ImgHelper 工具类 package com.a ...

  4. Python中进行Base64编码和解码

    Base64编码 广泛应用于MIME协议,作为电子邮件的传输编码,生成的编码可逆,后一两位可能有“=”,生成的编码都是ascii字符.优点:速度快,ascii字符,肉眼不可理解缺点:编码比较长,非常容 ...

  5. Javascript Base64编码与解码

    原文:[转]Javascript Base64编码与解码 <html> <head> <META HTTP-EQUIV="MSThemeCompatible&q ...

  6. C# base64编码、解码

    public class TransferCode { #region base-64编码.解码 /// <summary> /// BASE64编码 /// </summary&g ...

  7. Url的Base64编码以及解码

    Base64可以将二进制转码成可见字符方便进行http传输,但是base64转码时会生成“+”,“/”,“=”这些被URL进行转码的特殊字符,导致两方面数据不一致.我们可以在发送前将“+”,“/”,“ ...

  8. NET MVC全局异常处理(一) 【转载】网站遭遇DDoS攻击怎么办 使用 HttpRequester 更方便的发起 HTTP 请求 C#文件流。 Url的Base64编码以及解码 C#计算字符串长度,汉字算两个字符 2019周笔记(2.18-2.23) Mysql语句中当前时间不能直接使用C#中的Date.Now传输 Mysql中Count函数的正确使用

    NET MVC全局异常处理(一)   目录 .NET MVC全局异常处理 IIS配置 静态错误页配置 .NET错误页配置 程序设置 全局异常配置 .NET MVC全局异常处理 一直知道有.NET有相关 ...

  9. js的Base64编码与解码

    js的Base64编码与解码 pc和手机app项目中,经常需要将手机自带的表情图片转换特定的编码格式与后台进行交互. Base64其实是一种简单的置换加密方式,但是BASE64的用处往往并不是为了防止 ...

随机推荐

  1. 通过Daffodil for VS使VS2010的IDE可以用VC6 VC7.1 VC9等编译器进行项目编译

    本文内容中的部分资料和知识来源于网络,具体引用出处不明. VS的IDE从VC6到VS2010的变化可谓是天翻地覆,最新的VS2010有一个特性就是支持多显示器开发,这无疑为我们的开发带来很大的便利. ...

  2. [转]Django与遗留系统和数据库集成

    From:http://www.czug.org/python/django/17.html 尽管Django最适合从零开始开发项目--所谓的"绿色领域"开发--将框架与遗留系统和 ...

  3. php生成curl命令行

    e.g. curl “http://localhost/other/serverInfo.php?dd=ddd” -H “Host:localhost” -H “Connection:keep-ali ...

  4. Android Studio 小技巧/快捷键 合集

    参考: http://jaeger.itscoder.com/android/2016/02/14/android-studio-tips.html 1. 书签(Bookmarks) 描述:这是一个很 ...

  5. HBase工程师线上工作经验总结----HBase常见问题及分析

    阅读本文可以带着下面问题:1.HBase遇到问题,可以从几方面解决问题?2.HBase个别请求为什么很慢?你认为是什么原因?3.客户端读写请求为什么大量出错?该从哪方面来分析?4.大量服务端excep ...

  6. AX 2012 两种lookup 的显示方式

    第一种:只能单选的lookup: 代码: public void BusinessUnitLookup(FormStringControl _formstrcontroll) { //OMOperat ...

  7. C++注意

    断言assert是仅在Debug版本起作用的宏,它用于检查“不应该”发生的情况. 在函数的入口处,使用断言检查参数的有效性(合法性). 如果程序在assert处终止了,并不是说含有该assert的函数 ...

  8. AndroidManifest.xml的android:name是否带.的区别

    android项目里面的AndroidManifest.xml,会有这样的定义        <activity android:name=".Main"           ...

  9. messagePaneHost

    Microsoft.Dynamics.Framework.UI.WinForms.Controls.MessageBarType messageBarType; super(); imageList ...

  10. Bootstrap3-技巧之解决Bootstrap模态框切换时页面抖动 or页面滚动条

    Bootstrap为了让所有的页面(这里指内容溢出和不溢出)显示效果一样,采取的方法如下: 当Modal显示时,设置body -- overflow:hidden;margin-right:15px; ...