最近做项目的时候,需要用MFC写一个二维码生成器,要求根据指定内容生成二维码,显示在屏幕上,并能够保存在电脑中。
一、 libqrencode库编译
libqrencode是一个日本人写的生成二维码的库,库在这里下载。
1、新建一个config.h文件
文件中的内容为:
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define if you have the iconv() function and it works. */
/* #undef HAVE_ICONV */
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if using pthread is enabled. */
//#define HAVE_LIBPTHREAD 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strdup' function. */
#define HAVE_STRDUP 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
/* Major version number */
#define MAJOR_VERSION 3
/* Micro version number */
#define MICRO_VERSION 4
/* Minor version number */
#define MINOR_VERSION 4
/* Name of package */
#define PACKAGE "qrencode"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME "QRencode"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "QRencode 3.4.4"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "qrencode"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "3.4.4"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "3.4.4"
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* #undef inline */
#endif
/* Define to 'static' if no test programs will be compiled. */
#define STATIC_IN_RELEASE static
/* #undef WITH_TESTS */
2、编译libqrencode
1)增删文件
解压libqrencode库之后,将config.h添加进去,将除了.c和.h的文件全部删除,还要删除qrenc.c,如果保留此文件,编译静态库时会发生错误。
处理完之后还剩下如下文件:
2)编译
在VS中创建一个win32项目,选择生成静态库,不使用预编译头。
将所有的.h和.c文件都添加进去。
然后选中项目,点击右键,属性->配置属性->C/C++ ->预处理器,在“预处理器”定义中添加HAVE_CONFIG_H.
点击生成->生成解决方案。出现以下错误
定位到错误位置,将该文件中标红位置的!去掉即可。再次点击生成解决方案,即可生成静态库。
二、生成二维码
1、生成二维码
1)新建MFC项目,绘制窗口
一个编辑框,两个按钮控件,一个图像控件。修改图像控件的ID,为图像控件添加变量。(如果不修改图像控件的ID则无法添加变量)。
2)使用静态库
将生成的lib文件和源码中的qrencode.h两个文件拷贝到项目中。
然后配置属性->C/C++->常规->附加包含目录,加入qrencode.h的所在路径。
配置属性->链接器属性->链接器->常规->附加库目录,加入Project1.lib所在路径。
配置属性->链接器属性->输入->附加依赖项,加入Project1.lib。
3)生成二维码并显示
由于个人能力有限,只能先将二维码保存到本地在加载图片,显示到屏幕上。
代码如下
CString str;
GetDlgItem(IDC_VALUE)->GetWindowText(str);
// CString 转换成char*
// 1、使用函数T2A或者W2A
//USES_CONVERSION;
//char* szSourceSring = W2A(str);
// 2、使用API函数WideCharToMutiByte进行转换
//int n = str.GetLength();
int len = WideCharToMultiByte(CP_ACP, 0, str, str.GetLength(), NULL, 0, NULL, NULL);
char* szSourceSring = new char[len + 1];
WideCharToMultiByte(CP_ACP, 0, str, str.GetLength(), szSourceSring, len, NULL, NULL);
szSourceSring[len] = '\0';
unsigned int unWidth, x, y, l, n, unWidthAdjusted, unDataBytes;
unsigned char* pRGBData, * pSourceData, * pDestData;
QRcode* pQRC;
FILE* f;
if (pQRC = QRcode_encodeString(szSourceSring, 0, QR_ECLEVEL_H, QR_MODE_8, 1))
{
unWidth = pQRC->width;
unWidthAdjusted = unWidth * 8 * 3;
if (unWidthAdjusted % 4)
unWidthAdjusted = (unWidthAdjusted / 4 + 1) * 4;
unDataBytes = unWidthAdjusted * unWidth * 8;
// Allocate pixels buffer
if (!(pRGBData = (unsigned char*)malloc(unDataBytes)))
{
exit(-1);
}
// Preset to white
memset(pRGBData, 0xff, unDataBytes);
// Prepare bmp headers
// 位图文件头
BITMAPFILEHEADER kFileHeader;
kFileHeader.bfType = 0x4d42; // 位图文件的类型,必须为"BM"
kFileHeader.bfSize = sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) + unDataBytes;// 位图文件的大小
kFileHeader.bfReserved1 = 0;// 位图文件保留字,必须为0
kFileHeader.bfReserved2 = 0;// 位图文件保留字,必须为0
kFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER);// 位图数据的起始位,位图文件头+位图信息头+调色板的大小
// 位图信息头
BITMAPINFOHEADER kInfoHeader;
kInfoHeader.biSize = sizeof(BITMAPINFOHEADER);// 本结构所占用字节数
kInfoHeader.biWidth = unWidth* 8; // 位图的宽度,以像素为单位
kInfoHeader.biHeight = ((int)unWidth*8);// 位图的高度,以像素为单位
kInfoHeader.biPlanes = 1;// 目标设备的级别,必须为1
kInfoHeader.biBitCount = 24; // 每个像素所需的位数,必须是1(双色)、
//4(16色)、8(256色)或24(真彩色)之一
kInfoHeader.biCompression = BI_RGB;// 位图压缩格式,必须是0,不压缩
kInfoHeader.biSizeImage = 0; // 位图的大小,以字节为单位
kInfoHeader.biXPelsPerMeter = 0; // 位图水平分辨率
kInfoHeader.biYPelsPerMeter = 0; // 位图垂直分辨率
kInfoHeader.biClrUsed = 0; // 位图实际使用的颜色表中的颜色数
kInfoHeader.biClrImportant = 0; // 位图显示过程中重要的颜色数,0表示所有的颜色都重要
// Convert QrCode bits to bmp pixels
pSourceData = pQRC->data;
for(int y=unWidth-1;y>=0;y--)
{
pDestData = pRGBData + unWidthAdjusted * y * 8;
// y
for (x = 0; x < unWidth; x++)
{
if (*pSourceData & 1)
{
for (int l = 0; l < 8; l++)
{
for (int n=0; n < 8; n++)
{
*(pDestData + n * 3 + unWidthAdjusted * l) = 0;
*(pDestData + 1 + n * 3 + unWidthAdjusted * l) = 0;
*(pDestData + 2 + n * 3 + unWidthAdjusted * l) = 0;
}
}
}
pDestData += 3 * 8;
pSourceData++;
}
}
// Output the bmp file
if (!(fopen_s(&f, "temp.bmp", "wb")))
{
fwrite(&kFileHeader, sizeof(BITMAPFILEHEADER), 1, f);
fwrite(&kInfoHeader, sizeof(BITMAPINFOHEADER), 1, f);
fwrite(pRGBData, sizeof(unsigned char), unDataBytes, f);
fclose(f);
}
else
{
printf("Unable to open file");
exit(-1);
}
// Free data
free(pRGBData);
QRcode_free(pQRC);
}
else
{
printf("NULL returned");
exit(-1);
}
//显示图片
CRect rect;
m_picStatic.GetWindowRect(&rect);
HBITMAP hBmp = (HBITMAP)::LoadImage(NULL, _T("temp.bmp"), IMAGE_BITMAP,
rect.Width(), rect.Height(), LR_LOADFROMFILE);
m_picStatic.ModifyStyle(0xf, SS_BITMAP);
m_picStatic.SetBitmap(hBmp);
4)保存图片
CImage image;
image.Load(_T("temp.bmp"));
CString fileName = _T("Image");
TCHAR szFilter[] = _T("JPG图片(*.jpg)|*.jpg|BMP图片(*.bmp)|*.bmp|PNG图片(*.png)|*.png|JPEG图片(*.jpeg)|*.jpeg|DIB图片(*.dib)|*.dib|PBM图片(*.pbm)|*.pbm||");
CFileDialog fileDlg(FALSE, _T("bmp"), fileName, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter, this);
fileDlg.m_ofn.lpstrTitle = _T("另存为");
CString strFilePath;
//显示保存文件对话框
if (IDOK == fileDlg.DoModal())
{
strFilePath = fileDlg.GetPathName();
}
HRESULT hresult = image.Save(strFilePath);
完成啦,如果有问题可以联系我哦。