基于QRencode的 QT二维码显示 QImage像素操作和QPainter

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会显示不全
在这里插入图片描述


常见图片格式的文件标识符

下面是一些常见图片格式,开头固定文件头的标识符,可以用来区分是什么图片:

  • BMP0x42 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 0x490x4D 0x4D,分别对应于Intel和Motorola字节序的TIFF文件。这些字节是ASCII字符 “II” 或 “MM” 的16进制表示。
  • ICO: 0x00 0x00 0x01 0x00

总结

由于QRencode计算后返回的数据就是二维码的点阵图,所以只需要考虑循环方式,然后循环内部根据返回数据的对应位是0 or 1即可绘画出一张二维码图。故实现方法有很多,在这里仅作记录给大家提供一个思路参考。 如果有更好的方法或以上程序改进方式欢迎在评论区指正! 大家一起进步!

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值