项目中需要在每台4G设备上粘贴标签用于登记设备中SIM卡的uid,考虑使用二维码的形式方便后续管理,标签上显示相关的版本信息及uid,最终结果如下:
由于用途很单一而且代码简单,准备采用开源的Qrencode库来生成二维码,Qrencode库直接提供了C代码,使用时包含一个头文件即可,也可以将其编译成静态或动态库,但是考虑代码量,没这个必要。最终代码以控制台程序形式运行,所以决定用DevC++实现,开发速度快,效率高。
下载Qrencode库地址为:https://fukuchi.org/works/qrencode/
使用非常简单,下载后解压得到源文件文件夹,在DevC++中建立控制台项目,将其拷贝到项目文件夹下,然后在项目中包含头文件,相关头文件及用途:
#include //使用输入输出流
#include "qrencode.h" //Qrencode库头文件
#include //动态分配内存用
#include //使用位图文件头结构体和位图信息头结构体
#include //访问文件用
#include //获取当前运行路径用
然后在项目中将Qrencode库中的.c文件加入到项目中。
生产二维码其实就一句代码:pQRC= QRcode_encodeString(instr, 0, QR_ECLEVEL_H, QR_MODE_8, 1);这个函数直接设置要编码的字符串内容,以及对二维码的设置,如版本(即大小等级1~40)、容错等级、模式等,返回的是一个结构体指针,QRcode,
typedef struct {
int version; ///< version of the symbol
int width; ///< width of the symbol
unsigned char *data; ///< symbol data
} QRcode;
它的数据data就是二维码的内容,生成的是BIT数据,也就是说1对应深色块,0对应浅色块,每字节对应8个像素数据。
为了生产最终图片,使用PS制作了一个BMP图片模板,当然原因是BMP格式是BitMap原始数据格式,使用简单,模板如下,右侧空着预留植入二维码区域:
程序实现:
程序首先读取模板图片,模板放在当前执行文件夹,使用getcwd();获取当前路径,读取图片分四步,读取文件头,读取位图信息头,读取调色板(由于使用灰度图像),读取图像数据:
FILE *f,*df;//输入文件指针和输出文件指针
getcwd(path,128); //获取当前运行路径
strcat(path,"\\template.bmp");
f=fopen(path, "rb");
if (f!=NULL)
{
fread(&kFileHeader,sizeof(BITMAPFILEHEADER),1,f);
fread(&kInfoHeader,sizeof(BITMAPINFOHEADER),1,f);
fread(pPalette,1024,1,f);
}
cout<<"BitMap Height="<8)//不是灰度图像,退出
exit(-1);
pBitmap2D=new unsigned char*[kInfoHeader.biHeight]; //分配二维数组
if (!(pBitmapData = (unsigned char*)malloc(kInfoHeader.biWidth*kInfoHeader.biHeight)))//分配读BMP位图数据
if(pBitmapData==NULL)
{
cout<<"fail-1"<
这里使用一个pBitmap2D指针将图像序列数据转换成二维数组,便于后续植入二维码数据。
由于生成的二维码为基础像素,因此需要放大一定的倍率适应模板图片:
pQRC= QRcode_encodeString(instr, 0, QR_ECLEVEL_H, QR_MODE_8, 1);//生成二维码数据
//计算二维码放大倍率,根据模板放大到430*430左右,如果不能整除,放大倍数加1,否则后续数组越界
scale=430/pQRC->width==430/pQRC->width*pQRC->width?430/pQRC->width:430/pQRC->width+1;
unWidth = pQRC->width*scale;//放大到430*430左右
unDataBytes=unWidth*unWidth;
// Allocate pixels buffer
if (!(pGayData = (unsigned char*)malloc(unDataBytes)))//分配二维码放大后图像数据区
{
cout<<"fail-2"<
然后转换BIT数据到灰度字节数据:
for ( y = 0; y < pQRC->width; y++)
{
pDestData = pGayData + unWidth * y * scale;
for ( x = 0; x < pQRC->width; x++)
{
if (*pSourceData & 1)
{
for (l = 0; l < scale; l++)
{
for (n = 0; n < scale; n++)
{
//以下三行是设置三基色,三基色都设置为0x00,则生成的二维码图片就是黑色的了,要什么颜色自己调整
*(pDestData + n + unWidth * l) = 0x00;
}
}
}
pDestData += scale;
pSourceData++;
}
}
由于数据已经准备好,而且有了二维数组,这个步骤简单:
//合成二维码数据到图像数据中,从第25行第600列开始
for ( y = 0; y < unWidth; y++)
{
for ( x = 0; x < unWidth; x++)
{
pBitmap2D[y+25][x+600]=*(pGayData++);
}
}
四、写最终数据到uid命名的文件
strcpy(filename,".\\");
strcat(filename,instr);
strcat(filename,".bmp");
df=fopen(filename, "wb");
if (df!=NULL)
{
fwrite(&kFileHeader,sizeof(BITMAPFILEHEADER),1,df);
fwrite(&kInfoHeader,sizeof(BITMAPINFOHEADER),1,df);
fwrite(pPalette,1024,1,df);
for(y=kInfoHeader.biHeight;y>0;y--)
{
fwrite(pBitmap2D[y-1],kInfoHeader.biWidth,1,df);
}
}
else
cout<<"fail"<
最终搞一个循环,就可以连续生成图像了。
全部代码及图像模板下载地址:https://download.csdn.net/download/weixin_48341920/87062873?spm=1001.2014.3001.5503