展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > 基于Qt的实用二维码生成解决方案

基于Qt的实用二维码生成解决方案

纯C++且无任何依赖的nayukiqrcode库最适合Qt项目集成二维码功能,通过QRCodeWidget类可方便实现生成、保存、添加Logo及自定义样式设置。该库轻量高效,无需额外配置。相比之下,QZXing和libqrencode因体积较大或需编译而推荐度较低。

本文目录

    在Qt项目中集成二维码生成功能,通常有几种主流选择。下面把各方案的优劣势摆出来,再结合集成难度和实际使用场景,给出一份靠谱的推荐。

    一、解决方案架构

    1.1 技术选型比较

    方案优点缺点推荐度
    qrcode (nayuki)纯C++, 轻量, 无依赖功能基础★★★★★
    QZXing功能强大, 支持多种格式体积大, 依赖多★★★★
    libqrencode性能好, 广泛使用需要额外编译★★★★
    ZXing-C++Google出品, 功能全编译复杂★★★

    推荐方案:qrcode (nayuki) - 最适合Qt集成

    基于Qt的实用二维码生成解决方案

    二、核心实现方案

    2.1 方案一:使用 qrcode (nayuki) - 推荐

    要说最轻量、最容易集成的方案,非它莫属。纯C++实现,没有任何外部依赖,直接扔进项目就能用。

    下载qrcode库

    # 下载qrcode库
    git clone https://github.com/nayuki/QR-Code-generator.git

    Qt项目集成

    文件结构:

    QRCodeDemo/

    ├── main.cpp

    ├── QRCodeWidget.h

    ├── QRCodeWidget.cpp

    ├── qrcode/

    │ ├── BitBuffer.hpp

    │ ├── QrCode.hpp

    │ ├── QrSegment.hpp

    │ └── README.md

    └── QRCodeDemo.pro

    QRCodeWidget.h:

    #ifndef QRCODEWIDGET_H
    #define QRCODEWIDGET_H
    #include 
    #include 
    #include 
    #include 
    #include 
    class QRCodeWidget : public QWidget
    {
        Q_OBJECT
    public:
        explicit QRCodeWidget(QWidget *parent = nullptr);
        // 生成二维码
        bool generateQRCode(const QString& text, 
                           int version = 5,  // 二维码版本(1-40)
                           int eccLevel = 1, // 纠错等级(0-3)
                           int border = 4);  // 边距
        // 获取二维码图片
        QImage getQRCodeImage() const { return m_qrCodeImage; }
        // 保存二维码图片
        bool sa veToFile(const QString& filename, 
                       int scale = 4,  // 缩放倍数
                       const QString& format = "PNG");
        // 设置样式
        void setForegroundColor(const QColor& color) { m_foregroundColor = color; }
        void setBackgroundColor(const QColor& color) { m_backgroundColor = color; }
        void setDrawStyle(bool rounded = false, bool useGradient = false);
        // 添加Logo
        bool addLogo(const QImage& logo, int logoSizePercentage = 20);
        // 二维码信息
        int getVersion() const { return m_version; }
        int getEccLevel() const { return m_eccLevel; }
        QString getEccLevelName() const;
        int getSize() const { return m_qrSize; }
    protected:
        void paintEvent(QPaintEvent *event) override;
    signals:
        void qrCodeGenerated(bool success, const QString& error = QString());
    private:
        // 绘制二维码
        void drawQRCode(QPainter& painter, int x, int y, int size);
        // 绘制Logo
        void drawLogo(QPainter& painter, int x, int y, int size);
        // 计算版本容量
        static int getMaxCapacity(int version, int eccLevel);
    private:
        QImage m_qrCodeImage;
        QImage m_logoImage;
        QColor m_foregroundColor = Qt::black;
        QColor m_backgroundColor = Qt::white;
        int m_version = 5;
        int m_eccLevel = 1;  // 1 = LOW, 0 = MEDIUM, 2 = QUARTILE, 3 = HIGH
        int m_border = 4;
        int m_qrSize = 0;
        bool m_roundedModules = false;
        bool m_useGradient = false;
        std::vector m_qrData;
    };
    #endif // QRCODEWIDGET_H

    QRCodeWidget.cpp:

    #include "QRCodeWidget.h"
    #include "qrcode/QrCode.hpp"
    #include 
    #include 
    #include 
    #include 
    #include 
    
    using qrcodegen::QrCode;
    using qrcodegen::QrSegment;
    
    QRCodeWidget::QRCodeWidget(QWidget *parent) 
        : QWidget(parent) {
        setMinimumSize(200, 200);
    }
    
    bool QRCodeWidget::generateQRCode(const QString& text, int version, int eccLevel, int border) {
        if (text.isEmpty()) {
            emit qrCodeGenerated(false, "文本不能为空");
            return false;
        }
        
        if (version < 1 || version > 40) {
            emit qrCodeGenerated(false, "版本必须在1-40之间");
            return false;
        }
        
        if (eccLevel < 0 || eccLevel > 3) {
            emit qrCodeGenerated(false, "纠错等级必须在0-3之间");
            return false;
        }
        
        m_version = version;
        m_eccLevel = eccLevel;
        m_border = border;
        
        try {
            // 将QString转换为UTF-8字节
            QByteArray utf8Data = text.toUtf8();
            std::vector data(utf8Data.begin(), utf8Data.end());
            
            // 创建QR码
            QrCode::Ecc ecc = static_cast(eccLevel);
            QrCode qr = QrCode::encodeBytes(data, ecc, version, version);
            
            m_qrSize = qr.getSize();
            m_qrData.clear();
            
            // 复制二维码数据
            for (int y = 0; y < m_qrSize; y++) {
                for (int x = 0; x < m_qrSize; x++) {
                    m_qrData.push_back(qr.getModule(x, y) ? 1 : 0);
                }
            }
            
            // 创建图片
            int imgSize = m_qrSize + 2 * m_border;
            m_qrCodeImage = QImage(imgSize, imgSize, QImage::Format_ARGB32);
            m_qrCodeImage.fill(m_backgroundColor);
            
            QPainter painter(&m_qrCodeImage);
            painter.setRenderHint(QPainter::Antialiasing);
            drawQRCode(painter, m_border, m_border, m_qrSize);
            
            // 如果有Logo,绘制Logo
            if (!m_logoImage.isNull()) {
                drawLogo(painter, m_border, m_border, m_qrSize);
            }
            
            painter.end();
            
            update();  // 触发重绘
            emit qrCodeGenerated(true);
            return true;
            
        } catch (const std::exception& e) {
            qWarning() << "生成二维码失败:" << e.what();
            emit qrCodeGenerated(false, QString("生成失败: %1").arg(e.what()));
            return false;
        }
    }
    
    void QRCodeWidget::drawQRCode(QPainter& painter, int x, int y, int size) {
        int moduleSize = size / m_qrSize;
        
        painter.setPen(Qt::NoPen);
        
        if (m_useGradient) {
            QLinearGradient gradient(x, y, x + size, y + size);
            gradient.setColorAt(0, m_foregroundColor);
            gradient.setColorAt(1, m_foregroundColor.darker(150));
            painter.setBrush(gradient);
        } else {
            painter.setBrush(m_foregroundColor);
        }
        
        for (int row = 0; row < m_qrSize; row++) {
            for (int col = 0; col < m_qrSize; col++) {
                if (m_qrData[row * m_qrSize + col]) {
                    int px = x + col * moduleSize;
                    int py = y + row * moduleSize;
                    
                    if (m_roundedModules) {
                        painter.drawRoundedRect(px, py, moduleSize, moduleSize, 
                                               moduleSize / 3, moduleSize / 3);
                    } else {
                        painter.drawRect(px, py, moduleSize, moduleSize);
                    }
                }
            }
        }
    }
    
    void QRCodeWidget::drawLogo(QPainter& painter, int x, int y, int size) {
        if (m_logoImage.isNull()) return;
        
        int logoSize = size * 0.2;  // Logo大小为二维码的20%
        int centerX = x + (size - logoSize) / 2;
        int centerY = y + (size - logoSize) / 2;
        
        QPixmap logoPixmap = QPixmap::fromImage(m_logoImage)
            .scaled(logoSize, logoSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
        
        // 绘制白色背景
        painter.setBrush(Qt::white);
        painter.setPen(Qt::NoPen);
        painter.drawRoundedRect(centerX - 2, centerY - 2, 
                               logoSize + 4, logoSize + 4, 8, 8);
        
        // 绘制Logo
        painter.drawPixmap(centerX, centerY, logoPixmap);
    }
    
    bool QRCodeWidget::sa veToFile(const QString& filename, int scale, const QString& format) {
        if (m_qrCodeImage.isNull()) {
            return false;
        }
        
        QImage scaledImage = m_qrCodeImage.scaled(
            m_qrCodeImage.width() * scale,
            m_qrCodeImage.height() * scale,
            Qt::KeepAspectRatio,
            Qt::SmoothTransformation
        );
        
        return scaledImage.sa ve(filename, format.toUpper().toUtf8());
    }
    
    void QRCodeWidget::setDrawStyle(bool rounded, bool useGradient) {
        m_roundedModules = rounded;
        m_useGradient = useGradient;
        update();
    }
    
    bool QRCodeWidget::addLogo(const QImage& logo, int logoSizePercentage) {
        if (logo.isNull()) {
            m_logoImage = QImage();
            return false;
        }
        
        m_logoImage = logo;
        update();
        return true;
    }
    
    QString QRCodeWidget::getEccLevelName() const {
        switch (m_eccLevel) {
        case 0: return "LOW (7%)";
        case 1: return "MEDIUM (15%)";
        case 2: return "QUARTILE (25%)";
        case 3: return "HIGH (30%)";
        default: return "UNKNOWN";
        }
    }
    
    int QRCodeWidget::getMaxCapacity(int version, int eccLevel) {
        // 简化的容量表(数字模式)
        static const int capacityTable[4][4] = {
            {17, 32, 53, 78},     // 版本1
            {32, 61, 100, 127},   // 版本2
            {53, 101, 165, 198},  // 版本3
            {78, 127, 198, 242}   // 版本4
        };
        
        if (version >= 1 && version <= 4 && eccLevel >= 0 && eccLevel <= 3) {
            return capacityTable[version-1][eccLevel];
        }
        return 0;
    }
    
    void QRCodeWidget::paintEvent(QPaintEvent *event) {
        Q_UNUSED(event);
        
        QPainter painter(this);
        painter.setRenderHint(QPainter::Antialiasing);
        
        if (!m_qrCodeImage.isNull()) {
            // 居中显示
            int x = (width() - m_qrCodeImage.width()) / 2;
            int y = (height() - m_qrCodeImage.height()) / 2;
            painter.drawImage(x, y, m_qrCodeImage);
        } else {
            // 显示提示
            painter.setPen(Qt::gray);
            painter.drawText(rect(), Qt::AlignCenter, "没有二维码数据");
        }
    }
    

    main.cpp:

    #include "MainWindow.h"
    #include 
    
    int main(int argc, char *argv[]) {
        QApplication app(argc, argv);
        
        // 设置应用程序信息
        app.setApplicationName("QR Code Generator");
        app.setOrganizationName("MyCompany");
        app.setApplicationVersion("1.0.0");
        
        MainWindow window;
        window.show();
        
        return app.exec();
    }
    

    2.2 方案二:使用QZXing库

    QZXing是Qt生态里功能比较全面的二维码处理库,不光能生成,还能解码,支持多种格式。

    安装QZXing

    # 方法1:通过vcpkg
    vcpkg install qzxing
    
    # 方法2:手动编译
    git clone https://github.com/ftylitak/qzxing.git
    cd qzxing
    mkdir build && cd build
    cmake ..
    make
    make install
    

    使用QZXing生成二维码

    // QZXingGenerator.h
    #ifndef QZXINGGENERATOR_H
    #define QZXINGGENERATOR_H
    
    #include 
    #include 
    #include 
    #include 
    
    class QZXingGenerator : public QObject
    {
        Q_OBJECT
        
    public:
        explicit QZXingGenerator(QObject *parent = nullptr);
        
        // 生成二维码
        QImage generateQRCode(const QString& data, 
                             const QSize& size = QSize(200, 200),
                             const QColor& foreground = Qt::black,
                             const QColor& background = Qt::white,
                             QZXing::EncoderCorrectionLevel correction = QZXing::EncodeErrorCorrectionLevel_M);
        
        // 生成带Logo的二维码
        QImage generateQRCodeWithLogo(const QString& data, 
                                     const QImage& logo,
                                     const QSize& size = QSize(200, 200));
        
        // 批量生成
        QList batchGenerate(const QStringList& dataList, 
                                   const QSize& size = QSize(200, 200));
        
        // 保存到文件
        bool sa veQRCode(const QString& data, 
                       const QString& filename,
                       const QSize& size = QSize(200, 200));
        
    signals:
        void generationComplete(const QImage& qrCode);
        void generationError(const QString& error);
        
    private:
        QZXing m_qzxing;
    };
    #endif // QZXINGGENERATOR_H
    
    // QZXingGenerator.cpp
    #include "QZXingGenerator.h"
    #include 
    #include 
    #include 
    
    QZXingGenerator::QZXingGenerator(QObject *parent) 
        : QObject(parent) {
        // 初始化QZXing
        m_qzxing.setDecoder(QZXing::DecoderFormat_QR_CODE);
    }
    
    QImage QZXingGenerator::generateQRCode(const QString& data, 
                                          const QSize& size,
                                          const QColor& foreground,
                                          const QColor& background,
                                          QZXing::EncoderCorrectionLevel correction) {
        if (data.isEmpty()) {
            emit generationError("数据不能为空");
            return QImage();
        }
        
        try {
            // 设置编码参数
            QZXing::EncodeErrorCorrectionLevel eccLevel = correction;
            
            // 生成二维码
            QImage qrCode = m_qzxing.encodeData(data, size, foreground, background, eccLevel);
            
            if (qrCode.isNull()) {
                emit generationError("生成二维码失败");
                return QImage();
            }
            
            emit generationComplete(qrCode);
            return qrCode;
            
        } catch (const std::exception& e) {
            emit generationError(QString("生成错误: %1").arg(e.what()));
            return QImage();
        }
    }
    
    QImage QZXingGenerator::generateQRCodeWithLogo(const QString& data, 
                                                  const QImage& logo,
                                                  const QSize& size) {
        // 先生成基本二维码
        QImage qrCode = generateQRCode(data, size);
        if (qrCode.isNull() || logo.isNull()) {
            return qrCode;
        }
        
        // 在二维码中心添加Logo
        QImage result = qrCode.copy();
        QPainter painter(&result);
        painter.setRenderHint(QPainter::Antialiasing);
        painter.setRenderHint(QPainter::SmoothPixmapTransform);
        
        // 计算Logo位置和大小
        int logoSize = qMin(size.width(), size.height()) * 0.2;  // Logo大小为20%
        int x = (size.width() - logoSize) / 2;
        int y = (size.height() - logoSize) / 2;
        
        // 绘制白色背景
        painter.setBrush(Qt::white);
        painter.setPen(Qt::NoPen);
        painter.drawRoundedRect(x-2, y-2, logoSize+4, logoSize+4, 5, 5);
        
        // 绘制Logo
        QPixmap scaledLogo = QPixmap::fromImage(logo)
            .scaled(logoSize, logoSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
        painter.drawPixmap(x, y, scaledLogo);
        
        return result;
    }
    
    QList QZXingGenerator::batchGenerate(const QStringList& dataList, 
                                                const QSize& size) {
        QList result;
        
        for (const QString& data : dataList) {
            QImage qrCode = generateQRCode(data, size);
            if (!qrCode.isNull()) {
                result.append(qrCode);
            }
        }
        
        return result;
    }
    
    bool QZXingGenerator::sa veQRCode(const QString& data, 
                                    const QString& filename,
                                    const QSize& size) {
        QImage qrCode = generateQRCode(data, size);
        if (qrCode.isNull()) {
            return false;
        }
        
        return qrCode.sa ve(filename);
    }
    

    2.3 方案三:使用libqrencode

    这是一款C语言写的二维码生成库,性能相当不错,在很多开源项目里都有它的身影。

    安装libqrencode

    # Ubuntu/Debian
    sudo apt-get install libqrencode-dev
    # macOS
    brew install qrencode
    # Windows (vcpkg)
    vcpkg install qrencode

    libqrencode封装

    // LibQRencodeWrapper.h
    #ifndef LIBQRENCODEWRAPPER_H
    #define LIBQRENCODEWRAPPER_H
    
    #include 
    #include 
    #include 
    
    class LibQRencodeWrapper
    {
    public:
        enum QRCorrectionLevel {
            QR_ECLEVEL_L = 0,  // 7% 纠错
            QR_ECLEVEL_M = 1,  // 15% 纠错
            QR_ECLEVEL_Q = 2,  // 25% 纠错
            QR_ECLEVEL_H = 3   // 30% 纠错
        };
        
        struct QRCodeOptions {
            int version = 0;           // 0 = 自动选择
            QRCorrectionLevel level = QR_ECLEVEL_M;
            int margin = 4;            // 边距
            int scale = 4;             // 缩放倍数
            bool caseSensitive = true; // 大小写敏感
        };
        
        static QImage generateQRCode(const QString& text, 
                                    const QRCodeOptions& options = QRCodeOptions());
        
        static QString getLibraryVersion();
        
        static int getMaxVersion() { return 40; }
        static int getMinVersion() { return 1; }
        
    private:
        static QRcode* encodeString(const QString& text, 
                                   const QRCodeOptions& options);
    };
    #endif // LIBQRENCODEWRAPPER_H
    
    // LibQRencodeWrapper.cpp
    #include "LibQRencodeWrapper.h"
    #include 
    #include 
    
    QImage LibQRencodeWrapper::generateQRCode(const QString& text, 
                                             const QRCodeOptions& options) {
        if (text.isEmpty()) {
            return QImage();
        }
        
        QRcode* qr = encodeString(text, options);
        if (!qr) {
            qWarning() << "Failed to generate QR code";
            return QImage();
        }
        
        // 计算图片大小
        int qrSize = qr->width;
        int imageSize = (qrSize + 2 * options.margin) * options.scale;
        
        QImage image(imageSize, imageSize, QImage::Format_ARGB32);
        image.fill(Qt::white);
        
        QPainter painter(&image);
        painter.setRenderHint(QPainter::Antialiasing);
        painter.setBrush(Qt::black);
        painter.setPen(Qt::NoPen);
        
        // 绘制二维码
        for (int y = 0; y < qrSize; y++) {
            for (int x = 0; x < qrSize; x++) {
                if (qr->data[y * qrSize + x] & 1) {
                    int px = (options.margin + x) * options.scale;
                    int py = (options.margin + y) * options.scale;
                    painter.drawRect(px, py, options.scale, options.scale);
                }
            }
        }
        
        painter.end();
        QRcode_free(qr);
        
        return image;
    }
    
    QRcode* LibQRencodeWrapper::encodeString(const QString& text, 
                                            const QRCodeOptions& options) {
        QRecLevel level = static_cast(options.level);
        QRecLevel* hint = options.caseSensitive ? QR_MODE_8 : QR_MODE_KANJI;
        
        QRcode* qr = nullptr;
        
        if (options.version > 0) {
            // 指定版本
            qr = QRcode_encodeString(text.toUtf8().constData(),
                                     options.version,
                                     level,
                                     hint,
                                     1);
        } else {
            // 自动选择版本
            qr = QRcode_encodeString(text.toUtf8().constData(),
                                     0,
                                     level,
                                     hint,
                                     1);
        }
        
        return qr;
    }
    
    QString LibQRencodeWrapper::getLibraryVersion() {
        return QString("libqrencode %1").arg(qrencode_version());
    }
    

    三、功能丰富的二维码生成器

    3.1 主窗口设计

    // MainWindow.h
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include 
    #include 
    #include "QRCodeWidget.h"
    
    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
        
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
        
    private slots:
        void onGenerateClicked();
        void onSa veClicked();
        void onClearClicked();
        void onAddLogoClicked();
        void onRemoveLogoClicked();
        void onTextChanged();
        void onStyleChanged();
        void onQRCodeGenerated(bool success, const QString& error = QString());
        void onUpdatePreview();
        
    private:
        void setupUI();
        void setupConnections();
        void updateCapacityInfo();
        void loadSettings();
        void sa veSettings();
        
    private:
        Ui::MainWindow *ui;
        QRCodeWidget *m_qrCodeWidget;
        QImage m_logoImage;
        QTimer *m_previewTimer;
    };
    #endif // MAINWINDOW_H
    
    // MainWindow.cpp
    #include "MainWindow.h"
    #include "ui_MainWindow.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
        , m_qrCodeWidget(new QRCodeWidget(this))
        , m_previewTimer(new QTimer(this)) {
        
        ui->setupUI(this);
        setupUI();
        setupConnections();
        loadSettings();
        
        m_previewTimer->setSingleShot(true);
        m_previewTimer->setInterval(500);  // 500ms延迟预览
    }
    
    MainWindow::~MainWindow() {
        sa veSettings();
        delete ui;
    }
    
    void MainWindow::setupUI() {
        // 设置中心窗口
        setCentralWidget(m_qrCodeWidget);
        
        // 创建工具栏
        QToolBar *toolBar = addToolBar("Main");
        toolBar->setMovable(false);
        
        toolBar->addAction("生成", this, &MainWindow::onGenerateClicked);
        toolBar->addAction("保存", this, &MainWindow::onSa veClicked);
        toolBar->addAction("清除", this, &MainWindow::onClearClicked);
        toolBar->addSeparator();
        toolBar->addAction("添加Logo", this, &MainWindow::onAddLogoClicked);
        toolBar->addAction("移除Logo", this, &MainWindow::onRemoveLogoClicked);
        
        // 创建状态栏
        statusBar()->showMessage("就绪");
        
        // 初始化控件
        for (int i = 1; i <= 10; i++) {
            ui->comboVersion->addItem(QString("V%1").arg(i), i);
        }
        ui->comboVersion->setCurrentIndex(4);  // 默认V5
        
        ui->comboECC->addItem("LOW (7%)", 0);
        ui->comboECC->addItem("MEDIUM (15%)", 1);
        ui->comboECC->addItem("QUARTILE (25%)", 2);
        ui->comboECC->addItem("HIGH (30%)", 3);
        ui->comboECC->setCurrentIndex(1);  // 默认MEDIUM
        
        ui->spinBorder->setValue(4);
        ui->spinScale->setValue(4);
        
        updateCapacityInfo();
    }
    
    void MainWindow::setupConnections() {
        connect(ui->btnGenerate, &QPushButton::clicked, 
                this, &MainWindow::onGenerateClicked);
        connect(ui->btnSa ve, &QPushButton::clicked, 
                this, &MainWindow::onSa veClicked);
        connect(ui->btnClear, &QPushButton::clicked, 
                this, &MainWindow::onClearClicked);
        connect(ui->btnAddLogo, &QPushButton::clicked, 
                this, &MainWindow::onAddLogoClicked);
        connect(ui->btnRemoveLogo, &QPushButton::clicked, 
                this, &MainWindow::onRemoveLogoClicked);
        connect(ui->textContent, &QTextEdit::textChanged, 
                this, &MainWindow::onTextChanged);
        connect(ui->checkRounded, &QCheckBox::toggled, 
                this, &MainWindow::onStyleChanged);
        connect(ui->checkGradient, &QCheckBox::toggled, 
                this, &MainWindow::onStyleChanged);
        connect(ui->btnCopy, &QPushButton::clicked,  {
            QApplication::clipboard()->setPixmap(
                QPixmap::fromImage(m_qrCodeWidget->getQRCodeImage())
            );
            statusBar()->showMessage("二维码已复制到剪贴板", 2000);
        });
        
        connect(m_qrCodeWidget, &QRCodeWidget::qrCodeGenerated,
                this, &MainWindow::onQRCodeGenerated);
        connect(m_previewTimer, &QTimer::timeout,
                this, &MainWindow::onUpdatePreview);
    }
    
    void MainWindow::onGenerateClicked() {
        QString text = ui->textContent->toPlainText().trimmed();
        if (text.isEmpty()) {
            QMessageBox::warning(this, "警告", "请输入要编码的内容");
            return;
        }
        
        int version = ui->comboVersion->currentData().toInt();
        int eccLevel = ui->comboECC->currentData().toInt();
        int border = ui->spinBorder->value();
        
        // 检查内容长度是否超过容量限制
        int maxCapacity = m_qrCodeWidget->getMaxCapacity(version, eccLevel);
        if (text.length() > maxCapacity) {
            QMessageBox::warning(this, "警告", 
                QString("内容过长!最大容量为%1字符,当前%2字符")
                .arg(maxCapacity).arg(text.length()));
            return;
        }
        
        statusBar()->showMessage("正在生成二维码...");
        m_qrCodeWidget->generateQRCode(text, version, eccLevel, border);
    }
    
    void MainWindow::onSa veClicked() {
        if (m_qrCodeWidget->getQRCodeImage().isNull()) {
            QMessageBox::warning(this, "警告", "没有可保存的二维码");
            return;
        }
        
        QString filter = "PNG 图片 (*.png);;JPEG 图片 (*.jpg *.jpeg);;BMP 图片 (*.bmp)";
        QString filename = QFileDialog::getSa veFileName(this, "保存二维码", 
                                                       "qrcode.png", filter);
        
        if (!filename.isEmpty()) {
            int scale = ui->spinScale->value();
            QString format = QFileInfo(filename).suffix().toUpper();
            
            if (m_qrCodeWidget->sa veToFile(filename, scale, format)) {
                statusBar()->showMessage(QString("保存成功: %1").arg(filename), 3000);
            } else {
                QMessageBox::critical(this, "错误", "保存失败");
            }
        }
    }
    
    void MainWindow::onClearClicked() {
        ui->textContent->clear();
        m_qrCodeWidget->addLogo(QImage());  // 移除Logo
        statusBar()->showMessage("已清除", 2000);
    }
    
    void MainWindow::onAddLogoClicked() {
        QString filename = QFileDialog::getOpenFileName(this, "选择Logo图片", 
                                                       "", 
                                                       "图片文件 (*.png *.jpg *.jpeg *.bmp)");
        if (!filename.isEmpty()) {
            m_logoImage.load(filename);
            if (m_logoImage.isNull()) {
                QMessageBox::warning(this, "警告", "无法加载图片");
                return;
            }
            
            m_qrCodeWidget->addLogo(m_logoImage, ui->spinLogoSize->value());
            statusBar()->showMessage("Logo已添加", 2000);
        }
    }
    
    void MainWindow::onRemoveLogoClicked() {
        m_logoImage = QImage();
        m_qrCodeWidget->addLogo(QImage());  // 移除Logo
        statusBar()->showMessage("Logo已移除", 2000);
    }
    
    void MainWindow::onTextChanged() {
        // 延迟预览
        m_previewTimer->start();
        updateCapacityInfo();
    }
    
    void MainWindow::onStyleChanged() {
        bool rounded = ui->checkRounded->isChecked();
        bool gradient = ui->checkGradient->isChecked();
        m_qrCodeWidget->setDrawStyle(rounded, gradient);
    }
    
    void MainWindow::onQRCodeGenerated(bool success, const QString& error) {
        if (success) {
            QString info = QString("版本: V%1, 纠错: %2, 尺寸: %3×%3")
                .arg(m_qrCodeWidget->getVersion())
                .arg(m_qrCodeWidget->getEccLevelName())
                .arg(m_qrCodeWidget->getSize());
            statusBar()->showMessage(info);
        } else {
            QMessageBox::critical(this, "错误", error);
            statusBar()->showMessage("生成失败");
        }
    }
    
    void MainWindow::onUpdatePreview() {
        if (ui->checkAutoPreview->isChecked()) {
            onGenerateClicked();
        }
    }
    
    void MainWindow::updateCapacityInfo() {
        int version = ui->comboVersion->currentData().toInt();
        int eccLevel = ui->comboECC->currentData().toInt();
        int currentLength = ui->textContent->toPlainText().length();
        int maxCapacity = m_qrCodeWidget->getMaxCapacity(version, eccLevel);
        
        QString info = QString("长度: %1 / %2").arg(currentLength).arg(maxCapacity);
        ui->labelCapacity->setText(info);
        
        // 进度条显示
        int percent = qMin(100, (currentLength * 100) / maxCapacity);
        ui->progressCapacity->setValue(percent);
        
        // 颜色指示
        if (percent > 90) {
            ui->progressCapacity->setStyleSheet("QProgressBar::chunk { background-color: red; }");
        } else if (percent > 70) {
            ui->progressCapacity->setStyleSheet("QProgressBar::chunk { background-color: orange; }");
        } else {
            ui->progressCapacity->setStyleSheet("");
        }
    }
    
    void MainWindow::loadSettings() {
        QSettings settings;
        
        // 加载窗口位置和大小
        if (settings.contains("geometry")) {
            restoreGeometry(settings.value("geometry").toByteArray());
        }
        
        // 加载上次的内容
        QString lastContent = settings.value("lastContent").toString();
        if (!lastContent.isEmpty()) {
            ui->textContent->setPlainText(lastContent);
        }
    }
    
    void MainWindow::sa veSettings() {
        QSettings settings;
        
        // 保存窗口位置和大小
        settings.setValue("geometry", sa veGeometry());
        
        // 保存当前内容
        settings.setValue("lastContent", ui->textContent->toPlainText());
    }
    

    3.2 UI界面设计 (ui_MainWindow.h)

    // UI设计文件 (通过Qt Designer创建)
    #ifndef UI_MAINWINDOW_H
    #define UI_MAINWINDOW_H
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    class Ui_MainWindow {
    public:
        QWidget *centralWidget;
        QVBoxLayout *verticalLayout;
        QHBoxLayout *horizontalLayout;
        QVBoxLayout *leftLayout;
        QTextEdit *textContent;
        QHBoxLayout *buttonLayout;
        QPushButton *btnGenerate;
        QPushButton *btnSa ve;
        QPushButton *btnClear;
        QPushButton *btnCopy;
        QVBoxLayout *rightLayout;
        QGroupBox *groupSettings;
        QVBoxLayout *settingsLayout;
        QHBoxLayout *layoutVersion;
        QLabel *labelVersion;
        QComboBox *comboVersion;
        QHBoxLayout *layoutECC;
        QLabel *labelECC;
        QComboBox *comboECC;
        QHBoxLayout *layoutBorder;
        QLabel *labelBorder;
        QSpinBox *spinBorder;
        QHBoxLayout *layoutScale;
        QLabel *labelScale;
        QSpinBox *spinScale;
        QHBoxLayout *layoutLogo;
        QLabel *labelLogo;
        QSpinBox *spinLogoSize;
        QPushButton *btnAddLogo;
        QPushButton *btnRemoveLogo;
        QGroupBox *groupStyle;
        QVBoxLayout *styleLayout;
        QCheckBox *checkRounded;
        QCheckBox *checkGradient;
        QCheckBox *checkAutoPreview;
        QGroupBox *groupInfo;
        QVBoxLayout *infoLayout;
        QLabel *labelCapacity;
        QProgressBar *progressCapacity;
        
        void setupUI(QMainWindow *MainWindow) {
            if (MainWindow->objectName().isEmpty())
                MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
            MainWindow->resize(800, 600);
            
            centralWidget = new QWidget(MainWindow);
            centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
            
            verticalLayout = new QVBoxLayout(centralWidget);
            verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
            
            horizontalLayout = new QHBoxLayout();
            horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
            
            // 左侧:输入区域
            leftLayout = new QVBoxLayout();
            leftLayout->setObjectName(QString::fromUtf8("leftLayout"));
            
            textContent = new QTextEdit(centralWidget);
            textContent->setObjectName(QString::fromUtf8("textContent"));
            textContent->setPlaceholderText("请输入要编码的内容...");
            leftLayout->addWidget(textContent);
            
            buttonLayout = new QHBoxLayout();
            buttonLayout->setObjectName(QString::fromUtf8("buttonLayout"));
            
            btnGenerate = new QPushButton(centralWidget);
            btnGenerate->setObjectName(QString::fromUtf8("btnGenerate"));
            btnGenerate->setText("生成二维码");
            buttonLayout->addWidget(btnGenerate);
            
            btnSa ve = new QPushButton(centralWidget);
            btnSa ve->setObjectName(QString::fromUtf8("btnSa ve"));
            btnSa ve->setText("保存");
            buttonLayout->addWidget(btnSa ve);
            
            btnClear = new QPushButton(centralWidget);
            btnClear->setObjectName(QString::fromUtf8("btnClear"));
            btnClear->setText("清除");
            buttonLayout->addWidget(btnClear);
            
            btnCopy = new QPushButton(centralWidget);
            btnCopy->setObjectName(QString::fromUtf8("btnCopy"));
            btnCopy->setText("复制");
            buttonLayout->addWidget(btnCopy);
            
            leftLayout->addLayout(buttonLayout);
            horizontalLayout->addLayout(leftLayout, 2);
            
            // 右侧:设置区域
            rightLayout = new QVBoxLayout();
            rightLayout->setObjectName(QString::fromUtf8("rightLayout"));
            
            // 设置组
            groupSettings = new QGroupBox(centralWidget);
            groupSettings->setObjectName(QString::fromUtf8("groupSettings"));
            groupSettings->setTitle("设置");
            settingsLayout = new QVBoxLayout(groupSettings);
            
            // 版本
            layoutVersion = new QHBoxLayout();
            labelVersion = new QLabel(groupSettings);
            labelVersion->setText("版本:");
            layoutVersion->addWidget(labelVersion);
            
            comboVersion = new QComboBox(groupSettings);
            layoutVersion->addWidget(comboVersion);
            settingsLayout->addLayout(layoutVersion);
            
            // 纠错等级
            layoutECC = new QHBoxLayout();
            labelECC = new QLabel(groupSettings);
            labelECC->setText("纠错等级:");
            layoutECC->addWidget(labelECC);
            
            comboECC = new QComboBox(groupSettings);
            layoutECC->addWidget(comboECC);
            settingsLayout->addLayout(layoutECC);
            
            // 边距
            layoutBorder = new QHBoxLayout();
            labelBorder = new QLabel(groupSettings);
            labelBorder->setText("边距:");
            layoutBorder->addWidget(labelBorder);
            
            spinBorder = new QSpinBox(groupSettings);
            spinBorder->setRange(0, 20);
            spinBorder->setValue(4);
            layoutBorder->addWidget(spinBorder);
            settingsLayout->addLayout(layoutBorder);
            
            // 缩放
            layoutScale = new QHBoxLayout();
            labelScale = new QLabel(groupSettings);
            labelScale->setText("保存缩放:");
            layoutScale->addWidget(labelScale);
            
            spinScale = new QSpinBox(groupSettings);
            spinScale->setRange(1, 10);
            spinScale->setValue(4);
            layoutScale->addWidget(spinScale);
            settingsLayout->addLayout(layoutScale);
            
            // Logo设置
            layoutLogo = new QHBoxLayout();
            labelLogo = new QLabel(groupSettings);
            labelLogo->setText("Logo大小:");
            layoutLogo->addWidget(labelLogo);
            
            spinLogoSize = new QSpinBox(groupSettings);
            spinLogoSize->setRange(5, 50);
            spinLogoSize->setValue(20);
            spinLogoSize->setSuffix("%");
            layoutLogo->addWidget(spinLogoSize);
            
            btnAddLogo = new QPushButton(groupSettings);
            btnAddLogo->setText("添加");
            layoutLogo->addWidget(btnAddLogo);
            
            btnRemoveLogo = new QPushButton(groupSettings);
            btnRemoveLogo->setText("移除");
            layoutLogo->addWidget(btnRemoveLogo);
            settingsLayout->addLayout(layoutLogo);
            
            rightLayout->addWidget(groupSettings);
            
            // 样式组
            groupStyle = new QGroupBox(centralWidget);
            groupStyle->setObjectName(QString::fromUtf8("groupStyle"));
            groupStyle->setTitle("样式");
            styleLayout = new QVBoxLayout(groupStyle);
            
            checkRounded = new QCheckBox(groupStyle);
            checkRounded->setText("圆角模块");
            styleLayout->addWidget(checkRounded);
            
            checkGradient = new QCheckBox(groupStyle);
            checkGradient->setText("渐变颜色");
            styleLayout->addWidget(checkGradient);
            
            checkAutoPreview = new QCheckBox(groupStyle);
            checkAutoPreview->setText("实时预览");
            styleLayout->addWidget(checkAutoPreview);
            
            rightLayout->addWidget(groupStyle);
            
            // 信息组
            groupInfo = new QGroupBox(centralWidget);
            groupInfo->setObjectName(QString::fromUtf8("groupInfo"));
            groupInfo->setTitle("信息");
            infoLayout = new QVBoxLayout(groupInfo);
            
            labelCapacity = new QLabel(groupInfo);
            labelCapacity->setText("长度: 0/0");
            infoLayout->addWidget(labelCapacity);
            
            progressCapacity = new QProgressBar(groupInfo);
            progressCapacity->setRange(0, 100);
            infoLayout->addWidget(progressCapacity);
            
            rightLayout->addWidget(groupInfo);
            rightLayout->addStretch();
            
            horizontalLayout->addLayout(rightLayout, 1);
            verticalLayout->addLayout(horizontalLayout);
            
            MainWindow->setCentralWidget(centralWidget);
        }
    };
    #endif // UI_MAINWINDOW_H
    

    四、高级功能扩展

    4.1 批量生成工具

    // BatchQRCodeGenerator.h
    #ifndef BATCHQRCODEGENERATOR_H
    #define BATCHQRCODEGENERATOR_H
    
    #include 
    #include 
    #include 
    #include 
    
    class BatchQRCodeGenerator : public QObject, public QRunnable
    {
        Q_OBJECT
        
    public:
        struct BatchItem {
            QString id;
            QString content;
            QString filename;
            int version = 5;
            int eccLevel = 1;
            int scale = 4;
        };
        
        explicit BatchQRCodeGenerator(QObject *parent = nullptr);
        
        void addBatch(const QList& items);
        void clear();
        
        void run() override;
        
        void setOutputDir(const QString& dir) { m_outputDir = dir; }
        void setThreadCount(int count);
        
    signals:
        void progress(int current, int total, const QString& id);
        void finished(int successCount, int failedCount);
        void error(const QString& id, const QString& error);
        
    private:
        QList m_items;
        QString m_outputDir;
        QThreadPool m_threadPool;
    };
    #endif // BATCHQRCODEGENERATOR_H
    

    4.2 二维码解码功能

    // QRCodeDecoder.h
    #ifndef QRCODEDECODER_H
    #define QRCODEDECODER_H
    
    #include 
    #include 
    #include 
    
    class QRCodeDecoder : public QObject
    {
        Q_OBJECT
        
    public:
        explicit QRCodeDecoder(QObject *parent = nullptr);
        
        // 从图片文件解码
        QString decodeFromFile(const QString& filename);
        
        // 从QImage解码
        QString decodeFromImage(const QImage& image);
        
        // 从剪贴板解码
        QString decodeFromClipboard();
        
        // 从摄像头捕获
        void startCameraCapture();
        void stopCameraCapture();
        
    signals:
        void decoded(const QString& result);
        void cameraFrameCaptured(const QImage& frame);
        
    private:
        QZXing m_decoder;
    };
    #endif // QRCODEDECODER_H
    

    4.3 样式化二维码

    // StyledQRCodeGenerator.h
    #ifndef STYLEDQRCODEGENERATOR_H
    #define STYLEDQRCODEGENERATOR_H
    
    #include 
    
    class StyledQRCodeGenerator
    {
    public:
        enum PatternStyle {
            StyleDefault,
            StyleDots,
            StyleRounded,
            StyleStars,
            StyleHearts
        };
        
        struct StyleOptions {
            PatternStyle patternStyle = StyleDefault;
            QColor primaryColor = Qt::black;
            QColor secondaryColor = Qt::white;
            QColor gradientStart = Qt::black;
            QColor gradientEnd = Qt::darkGray;
            bool useGradient = false;
            int cornerRadius = 5;
        };
        
        static QImage generateStyledQRCode(const QString& text, 
                                          const QSize& size,
                                          const StyleOptions& options);
        
    private:
        static void applyPattern(QImage& image, const QImage& pattern, 
                                const QColor& color, int moduleSize);
        static QImage createDotPattern(int size);
        static QImage createStarPattern(int size);
        static QImage createHeartPattern(int size);
    };
    #endif // STYLEDQRCODEGENERATOR_H
    

    五、项目配置

    5.1 CMakeLists.txt

    cmake_minimum_required(VERSION 3.16)
    project(QRCodeGenerator)
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    # 查找Qt
    find_package(Qt6 COMPONENTS Core Widgets REQUIRED)
    # 包含目录
    include_directories(${CMAKE_CURRENT_SOURCE_DIR}/qrcode)
    # 源文件
    set(SOURCES
        main.cpp
        QRCodeWidget.cpp
        MainWindow.cpp
        QRCodeGenerator.cpp
    )
    # 头文件
    set(HEADERS
        QRCodeWidget.h
        MainWindow.h
        QRCodeGenerator.h
    )
    # UI文件
    set(FORMS
        MainWindow.ui
    )
    # 资源文件
    set(RESOURCES
        resources.qrc
    )
    # 生成MOC文件
    qt6_wrap_cpp(MOC_SOURCES ${HEADERS})
    qt6_wrap_ui(UI_SOURCES ${FORMS})
    qt6_add_resources(RES_SOURCES ${RESOURCES})
    # 可执行文件
    add_executable(${PROJECT_NAME}
        ${SOURCES}
        ${MOC_SOURCES}
        ${UI_SOURCES}
        ${RES_SOURCES}
    )
    # 链接库
    target_link_libraries(${PROJECT_NAME}
        Qt6::Core
        Qt6::Widgets
    )

    5.2 .pro 文件 (qmake)

    # QRCodeGenerator.pro
    QT       += core gui
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    TARGET = QRCodeGenerator
    TEMPLATE = app
    # 源文件
    SOURCES += 
        main.cpp 
        QRCodeWidget.cpp 
        MainWindow.cpp
    HEADERS += 
        QRCodeWidget.h 
        MainWindow.h
    FORMS += 
        MainWindow.ui
    # 包含qrcode库
    INCLUDEPATH += $$PWD/qrcode
    # 编译选项
    QMAKE_CXXFLAGS += -std=c++17
    CONFIG += c++17
    # 发布配置
    CONFIG(release, debug|release) {
        DEFINES += QT_NO_DEBUG_OUTPUT
        QMAKE_CXXFLAGS += -O2
    }
    # 调试配置
    CONFIG(debug, debug|release) {
        DEFINES += QT_DEBUG
        QMAKE_CXXFLAGS += -g
    }

    5.3 资源文件

    
    
        
            
            icons/app.png
            icons/generate.png
            icons/sa ve.png
            icons/clear.png
            icons/logo.png
            
            styles/style.qss
            
            logo/default.png
        
    
    /* styles/style.qss */
    QMainWindow {
        background-color: #f5f5f5;
    }
    QGroupBox {
        font-weight: bold;
        border: 1px solid #ccc;
        border-radius: 5px;
        margin-top: 10px;
        padding-top: 10px;
    }
    QGroupBox::title {
        subcontrol-origin: margin;
        left: 10px;
        padding: 0 5px 0 5px;
    }
    QPushButton {
        padding: 8px 16px;
        border-radius: 4px;
        font-weight: bold;
    }
    QPushButton:hover {
        background-color: #e0e0e0;
    }
    QTextEdit {
        border: 1px solid #ccc;
        border-radius: 4px;
        padding: 8px;
        font-family: "Microsoft YaHei", "SimSun";
    }
    QProgressBar {
        border: 1px solid #ccc;
        border-radius: 4px;
        text-align: center;
    }
    QProgressBar::chunk {
        background-color: #4CAF50;
        border-radius: 4px;
    }

    六、使用示例

    6.1 基本使用

    #include "QRCodeGenerator.h"
    #include 
    #include 
    
    int main(int argc, char *argv[]) {
        QApplication app(argc, argv);
        
        // 创建二维码生成器
        QRCodeGenerator generator;
        
        // 生成基本二维码
        QImage qrCode = generator.generateQRCode("https://www.example.com", 
                                                QSize(200, 200));
        
        if (!qrCode.isNull()) {
            // 保存到文件
            qrCode.sa ve("qrcode.png");
            
            // 显示二维码
            QLabel label;
            label.setPixmap(QPixmap::fromImage(qrCode));
            label.show();
            
            return app.exec();
        }
        
        return 0;
    }
    

    6.2 高级功能

    // 高级使用示例
    void advancedExample() {
        QRCodeGenerator generator;
        
        // 1. 生成带Logo的二维码
        QImage logo(":/logo/company.png");
        QImage qrWithLogo = generator.generateQRCodeWithLogo(
            "https://www.company.com", logo, QSize(300, 300));
        
        // 2. 生成样式化二维码
        StyledQRCodeGenerator::StyleOptions options;
        options.patternStyle = StyledQRCodeGenerator::StyleDots;
        options.useGradient = true;
        options.gradientStart = QColor("#FF5722");
        options.gradientEnd = QColor("#FF9800");
        
        QImage styledQR = generator.generateStyledQRCode(
            "特殊样式", QSize(250, 250), options);
        
        // 3. 批量生成
        QList items;
        for (int i = 0; i < 10; i++) {
            BatchQRCodeGenerator::BatchItem item;
            item.id = QString("QR%1").arg(i+1);
            item.content = QString("https://example.com/item/%1").arg(i+1);
            item.filename = QString("qrcode_%1.png").arg(i+1);
            items.append(item);
        }
        
        BatchQRCodeGenerator batchGenerator;
        batchGenerator.addBatch(items);
        batchGenerator.setOutputDir("./qrcodes");
        
        QObject::connect(&batchGenerator, &BatchQRCodeGenerator::progress,
            int current, int total, const QString& id {
                qDebug() << "进度:" << current << "/" << total << id;
            });
        
        batchGenerator.run();
    }
    

    6.3 命令行工具

    // QRCodeCLI.cpp - 命令行工具
    #include "QRCodeGenerator.h"
    #include 
    #include 
    #include 
    
    int main(int argc, char *argv[]) {
        QCoreApplication app(argc, argv);
        app.setApplicationName("QR Code CLI");
        app.setApplicationVersion("1.0.0");
        
        QCommandLineParser parser;
        parser.setApplicationDescription("命令行二维码生成器");
        parser.addHelpOption();
        parser.addVersionOption();
        
        // 定义参数
        parser.addPositionalArgument("content", "要编码的内容");
        parser.addPositionalArgument("output", "输出文件", "[output.png]");
        
        QCommandLineOption sizeOption("s", "图片大小", "size", "200");
        parser.addOption(sizeOption);
        
        QCommandLineOption versionOption("v", "二维码版本", "version", "5");
        parser.addOption(versionOption);
        
        QCommandLineOption eccOption("e", "纠错等级", "ecc", "1");
        parser.addOption(eccOption);
        
        QCommandLineOption logoOption("l", "Logo文件", "logo");
        parser.addOption(logoOption);
        
        parser.process(app);
        
        // 获取参数
        QStringList args = parser.positionalArguments();
        if (args.isEmpty()) {
            parser.showHelp(1);
        }
        
        QString content = args.at(0);
        QString output = args.value(1, "qrcode.png");
        int size = parser.value(sizeOption).toInt();
        int version = parser.value(versionOption).toInt();
        int ecc = parser.value(eccOption).toInt();
        QString logoFile = parser.value(logoOption);
        
        // 生成二维码
        QRCodeGenerator generator;
        QImage qrCode;
        
        if (!logoFile.isEmpty()) {
            QImage logo(logoFile);
            if (logo.isNull()) {
                qCritical() << "无法加载Logo文件:" << logoFile;
                return 1;
            }
            qrCode = generator.generateQRCodeWithLogo(content, logo, QSize(size, size));
        } else {
            qrCode = generator.generateQRCode(content, QSize(size, size), version, ecc);
        }
        
        if (qrCode.isNull()) {
            qCritical() << "生成二维码失败";
            return 1;
        }
        
        if (qrCode.sa ve(output)) {
            qInfo() << "二维码已保存到:" << output;
            return 0;
        } else {
            qCritical() << "保存失败:" << output;
            return 1;
        }
    }
    
    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 解决方案
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw macOS版
    AionClaw macOS版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy macOS版
    Loomy macOS版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirBuddy 3 macOS版
    AirBuddy 3 macOS版

    AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

    AirServer macOS版
    AirServer macOS版

    AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

    AnyDesk macOS版
    AnyDesk macOS版

    AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。

    讯飞绘文 网页版
    讯飞绘文 网页版

    讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

    Maya(Autodesk Maya) Windows版
    Maya(Autodesk Maya) Windows版

    Autodesk Maya 是面向影视、电视、动画和游戏行业的专业三维制作软件,集多边形与 NURBS 建模、角色绑定、关键帧和动作捕捉动画、Bifrost 特效模拟、材质开发及 Arnold 渲染于一体,

    Aperty Windows版
    Aperty Windows版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw Windows版
    AionClaw Windows版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy Windows版
    Loomy Windows版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。