QT 实现条形码或二维码生成,并使用条码打印机打印

968 阅读5分钟

前言

最近用 Qt 实现一个小项目,通过串口连接板子读取部分信息然后在界面上生成二维码或者条形码,然后调用连接的打印机打印出来。

效果

image.png

image.png

打印预览实现效果

image.png

实现

条码的生成依赖了两个开源软件 QZXingZint,目前 QZxing 目前只实现了QR码也就是二维码生成,以及一些条形码识别功能,Zint用来实现生成条形码

QZxing

QZxing 是 Zxing的 Qt实现,Zxing 是一个开源的一维/二维条码图像处理库,使用 Java 语言开发。 附Zxing 链接:github.com/zxing/zxin 如果想了解自行学习

QZXing 的主要作用是:

  • 扫描二维码并解码其内容
  • 创建二维码并将其保存为图像文件

编译和使用

QZxing 的下载链接:github.com/ftylitak/qz…

这里官方给了两种方法在项目中使用

  • 直接集成到项目
  • 编译成库

这里使用直接集成到项目中最方便,编译成库只要编译器配置正确也很方便编译出来,这里不做过多介绍

配置

将整个项目添加到你的当前项目中

image.png

在 pro 文件中添加以下内容

include(QZXing/src/QZXing.pri)

调用

使用前需要引用头文件 #include "QZXing.h"

测试代码

// 根据传入的参数返回图片,这里的encodeData还有很多参数设置,这里是最简单的直接生成二维码,具体看官方描述使用
QString msg  = "1111202419980823";
QImage image = QZXing::encodeData(msg);
QPixmap pixmap = QPixmap::fromImage(image);
// 设置二维码展示
 ui->lb_qr->setPixmap(pixmap);

Zint

Zint是用纯C写的,如果你能直接找到别人编译好的库也行,关于zint有很多方法调用,dll、exe调用,这里我选择了偷懒的方法,直接使用官方的zint.exe 工具,通过没命令行调用传入参数生成图片,读取到qt控件上展示

官网链接:zint.org.uk/

zint链接:github.com/zint/zint

zint.exe 下载链接:sourceforge.net/projects/zi… (注:可能需要科学上网)

关于编译zint的编译再提一嘴,网上有其他人很多编译成功的文章,如果想要了解可以去参考,官方给的readme中也有写好的cmkae,根据命令直接编译也能编译出来,笔者在这里也成功编译出来,但是调用时出了些问题,如果使用msvc的可以很轻松的编译出来,

image.png

image.png

Zint.exe 调用

这里参数有很多,只介绍我使用到的,想要具体的可以参考命令行提示,或者官网文档

直接默认生成(code128 编码)

默认输出名 output.png 在当前目录下,加 -o 可以指定定向生成 -o "c:/other.png"

zint.exe -d "KFC v me 50"

image.png

调整线条高度

这里是将条形码的高度调整,这一点很有作用,以为在条码打印机中,条码尺寸大小是随需求变化的,所以需要能够动态调整尺寸高度,方便打印在条码纸上,不管高低,只要显示内容完整都可以扫码识别出来

zint.exe -d "KFC v me 50" -height=20

image.png

对于zint 的可设置参数还有很多,可以根据需求自行查找注(他其实也可以生成二维码)

源码

最后贴个封装的函数,以及在Qt中调用的实现

生成

// 生成二维码
QImage MainWindow::generateQRCode(const QString &data)
{
    return QZXing::encodeData(data);
}

// 生成条形码,--height参数存放在配置文件,方便实时调整高度
QImage MainWindow::generateBarCode(const QString &data)
{
    QDir currentDir(QCoreApplication::applicationDirPath());
    QString exePath = currentDir.absoluteFilePath("zint.exe");

    QSettings settings("config.ini", QSettings::IniFormat);
    QString height = settings.value("Size/height", "--height=25").toString();
    qDebug() << height;
    QStringList argList;
    argList.append(height);
    argList.append("-d");
    argList.append(data);

    m_process.start(exePath, argList);
    if (!m_process.waitForStarted()) {
        qDebug() << "Failed to start.exe";
        QMessageBox::warning(this, "Tips", "Zint 程序异常,请联系软件开发人员");
        return QImage();;
    }

    QImage image;
    QString filePath = QCoreApplication::applicationDirPath() +("/out.png");
    qDebug() << filePath;
    if (!image.load(filePath)){
        qDebug() << "Failed to load image.";
        QMessageBox::warning(this, "Tips", "条码异常,请重试(File is no exist)");
        return QImage();
    }

    return image;
}

调用

// 待生成数据
QString msg = "12345678abcc";
// 生成二维码
QImage barcodeImage = generateQRCode(msg);
// 在控件上展示
ui->lb_qr->setPixmap(QPixmap::fromImage(barcodeImage));

// 生成条形码
QImage image = generateBarCode(msg);
ui->lb_qr->setPixmap(QPixmap::fromImage(image));

打印机的调用部分

打印机我这里实现其实并不是很友好,而且使用的是QT6和5有很多不一样的函数地方,将条码数据,传入到Qt封装好的打印机预览窗口中,然后调用系统打印机打印,对于调整条码位置的地方,还需要再研究,不过这里的功能已经满足现场使用了,有需求再深入研究。

void MainWindow::on_btn_print_code_clicked()
{
    QImage image;
    QString filePath = QCoreApplication::applicationDirPath() +("/out.png");
    qDebug() << filePath;
    if (!image.load(filePath)){
        qDebug() << "Failed to load image.";
        QMessageBox::warning(this, "Tips", "条码异常,请尝试重新生成");
        return;
    }
    // 缩放到标签纸尺寸
    // QImage scaledImage = image.scaled(250, 100, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
    QPixmap pixmap = QPixmap::fromImage(image);
    ui->lb_qr->setPixmap(pixmap);
    
    // 创建打印机对象并设置页面尺寸
    QPrinter printer(QPrinter::HighResolution);
    // 非标准尺寸,需要手动指定大小
    QPageSize customPageSize(QSizeF(100, 20), QPageSize::Unit::Millimeter);     //这个尺寸值也影响打印图片出来的位置和效果(100x20)稳定

    printer.setPageSize(customPageSize);

    // 创建打印预览对话框并设置打印机
    QPrintPreviewDialog preview(&printer, this);
    // 当要生成预览页面时,发射paintRequested()信号
    connect(&preview, &QPrintPreviewDialog::paintRequested, [&](QPrinter *printer) {
        QPainter painter(printer);
        // 设置缩放比例
        // painter.scale(1,1);
        // 绘制图片
        painter.drawPixmap(x, y, pixmap);                  //间距值也影响打印出来位置和显示效果
        // 绘制第二个图片,控制间距
        painter.drawPixmap(spacing + pixmap.width() , y, pixmap);
    });
    preview.exec();
}