Qt二维码
QRencode库
1,QRencode库的github源址 2,文档
QRencode简单介绍
- 该库提供了一种快速构建二维码的方案,由于使用C语言编写,所以移植性非常好,如果不想移植可以下载github源码后将所有源文件添加进工程目录即可。
- 能够快速将字符串转换为
uchar
型数据,其中每一个字节的最后一位都代表该处是黑点还是白点,可以根据返回的数据直接进行绘画二维码。 - 还可以将结构体数据转化为二维码,使用该库的
QRinput
类型即可。在其唯一的头文件qrencode.h
可以看到所有可操作的函数。
常用的API是QRcode_encodeString(),调用之后返回的QRcode->date
就是以qrcode->width
*qrcode->width
的一个正方形数据,其中每一个数据点的第0
位就代表这个点是黑还是白,如图1-1所示
( 图 1-1 QRcode->date
的数据格式)
Qt中使用QRencode库显示二维码
方法一(QImage直接修改操作像素点,但只有黑白灰色)
// 把输入的字符串换成 QRcode源数据
void MainWindow::encode_string_toQR(QByteArray src,int w)
{
unsigned char* line = NULL;
QRcode * qrcode = NULL;
unsigned char b;
// 源数据、最小输出、最高错误修正、utf-8编码、区分大小写(1)
qrcode = QRcode_encodeString(src.data(),2,QR_ECLEVEL_Q,QR_MODE_8,1);
if(qrcode)
{
qint32 qrcode_width = qrcode->width;
qint32 scale_x = w / (double)qrcode_width; // 获取缩放比例
qDebug() << " qrcode_width:" << qrcode->width << " w:" << w << " scale_x:" << scale_x;
QImage img(w,w,QImage::Format_Indexed8);
img.fill(0xff);
for(int y = 0; y < qrcode_width; y ++)
{
// 重复的列循环
for(auto x = 0;x <scale_x;x++)
{
//获取行像素进行修改
line = img.scanLine(y* scale_x + x);
// 修改一行的像素
for(int x = 0 ;x < qrcode_width ; x++ )
{
// 重复的行循环
b = qrcode->data[y * qrcode_width + x];
if(b & 0x1){
for(auto i = 0;i<scale_x;i++)
line[x*scale_x + i] = black ;
}
else{
for(auto i = 0;i<scale_x;i++)
line[x*scale_x + i] = white ;
}
}
}
}
//-------------------------显示QImage部分,不重要--------------------------------------
ui->label->setPixmap(QPixmap::fromImage( img ));
QRcode_free(qrcode);
}
else{
qDebug() << "is return NULL!" << strerror(errno);
}
}
这个方法显示二维码图片的优缺点如下:
优点
速度较快(当数据量超过130个英文utf-8字符,图片放大到QT设计的301*301时,耗时为1~2ms)- 因为放大倍数(生成二维码图片的大小与label大小之间的倍差),数据过大的时候就算铺不满整个label,也能保证是一张完整的二维码图片(如图1-3)
-
原因:放大倍数计算的时候会忽略四舍五入导致4.7、2.6等情况被算为4和2,导致铺不满,而四舍五入又会导致访问越界
缺点
- 绘制完成后的img对象,不能调用
scaled
调整函数,因为返回的QImage对象是全黑(如图1-2),具体原因还不知道,等日后有时间在研究底层逻辑。(可能是我学识较浅,欢迎各位评论区指正!) - 由于在新建
Qimage
用的是QImage::Format_Indexed8
,所以绘出的二维码图片只有黑白灰三色。
图片 1-2 绘画完成的二维码img不允许调用scaled
放大
方法二(QImage + QPainter , 可自定义颜色,可以自由变换)
// 把字符串转为二维码数据qrpic, w 和 h 分别是该二维码图像的宽和高 ----使用QPainter操作
void MainWindow::encode_string_toQR_painter(QByteArray src, int w)
{
QRcode * qrcode = NULL;
unsigned char b;
// 源数据、最小输出、最高错误修正、utf-8编码、区分大小写(1)
qrcode = QRcode_encodeString(src.data(),2,QR_ECLEVEL_Q,QR_MODE_8,1);
if(qrcode)
{
qint32 qrcode_width = qrcode->width;
qint32 scale_x = qRound(w / (double)qrcode_width); // 获取缩放比例 - 使用四舍五入
//qDebug() << " QPainter: qrcode_width:" << qrcode->width << " w:" << w << " scale_x:" << scale_x;
QImage img(w,w,QImage::Format_RGB32);
img.fill(0xffffffff); // 填充背景为白色 RGB
// 新建画笔并设置绘画的对象
QPainter painter(&img);
painter.setBrush(QColor(0,0,0)); // 要使二维码颜色不同,可以在这里修改
painter.setPen(Qt::NoPen);
for(int y = 0; y < qrcode_width; y ++)
{
for(int x = 0 ;x < qrcode_width ; x++ )
{
b = qrcode->data[y * qrcode_width + x];
if(b & 0x01)
{
// 把矩形当做二维码上的一个个黑点,放大填充进图片
QRectF rect(x*scale_x ,y*scale_x ,scale_x,scale_x);
painter.drawRect(rect);
}
}
}
//-------------------------显示QImage部分,不重要--------------------------------------
ui->label_2->setPixmap(QPixmap::fromImage( img ));
QRcode_free(qrcode);
}
else
{
qDebug() << "is return NULL!" << strerror(errno);
}
}
这个方法显示二维码的优缺点如下:
优点
- 能随意改变二维码的背景色、及点阵图色。如可改成白底绿码、灰底黄码。
- 跟上面的操作像素不同,绘画完成的二维码图可以随意
scaled
变换大小且不会失真
缺点
速度较慢(当数据量超过130个英文utf-8字符,图片放大到QT设计的301*301时,耗时为3~4ms)- 因为放大倍数(生成二维码图片的大小与label大小之间的倍差),数据过大的时候会超过整个label,不是一张完整的二维码图片(如图1-3)
-
原因:当放大倍数过大的时候,单次绘画的矩形
painter.drawRect(rect);
过大,导致最终图片显示不全(与像素操作相比,QPainter的方法使用了四舍五入。)
图1-3 放大倍数过大的时候,像素画图会铺不满,而QPainter会显示不全
常见图片格式的文件标识符
下面是一些常见图片格式,开头固定文件头的标识符,可以用来区分是什么图片:
- BMP:
0x42 0x4D
,即ASCII字符 “BM” 的16进制表示。 - PNG:
0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A
即ASCII字符 “PNG\r\n\x1a\n” 的16进制表示,用于标识PNG文件的开始。 - JPEG (JPG):
0xFF 0xD8
,文件结束标记是0xFF 0xD9
。 - GIF: 87a版本
0x47 0x49 0x46 0x38 0x37 0x61
或 89a版本0x47 0x49 0x46 0x38 0x39 0x61
,这取决于GIF版本(87a或89a)。这些字节是ASCII字符 “GIF87a” 或 “GIF89a” 的16进制表示。 - TIFF: 通常是
0x49 0x49
或0x4D 0x4D
,分别对应于Intel和Motorola字节序的TIFF文件。这些字节是ASCII字符 “II” 或 “MM” 的16进制表示。 - ICO:
0x00 0x00 0x01 0x00
总结
由于QRencode
计算后返回的数据就是二维码的点阵图,所以只需要考虑循环方式,然后循环内部根据返回数据的对应位是0 or 1即可绘画出一张二维码图。故实现方法有很多,在这里仅作记录给大家提供一个思路参考。 如果有更好的方法或以上程序改进方式欢迎在评论区指正! 大家一起进步!