天天看點

Zint生成多種條碼及二維碼

也許你的苦思冥想,大神們早已有答案。打開CSDN手機App,看到這麼一段話,突然有很多感觸,相信很多小夥伴都有同樣的想法。很多時候,我們都是在幹着重複造輪子的事兒,有時是我們當時認知有限,有時是我們太執着。

還記得當時項目需要根據輸入内容實時生成幾種常用的一維條形碼,當時也沒怎麼多想,找來一本常用條碼編碼規則的書,照着書上介紹的各種條碼的編碼規則,一步一步通過算法實作了,依稀還記得當初每次實作一個條碼後激動的心情。完成後還得到了老闆的表揚,當時心裡别提有多舒暢。

再到後來,項目需要根據輸入内容生成二維碼(QR碼),還是老規矩,找來二維碼的編碼規則,看了好久,發現二維碼的編碼規則相對一位條碼來說,複雜了太多,當時心裡有點沒底。心想看看網上有沒有類似的生成二維碼的算法,在網上搜尋了一下,閱讀了别人寫的一些關于QRcode的文章,最後發現一個qrencode-3.4.4的标準庫。下載下傳後檢視了庫的一些用法,結合項目的實際需求,花了大概半天的時間就生成了符合項目需求的二維碼,能夠調用标準庫裡提供的API來調整二維碼的屬性。當時心裡還在感慨提供這個庫的人真NB,這個庫太好用了!省去了很多二維碼的開發時間。

再後來,項目需要根據輸入内容生成Datamatrix碼,不同以往,我這次連DM碼的編碼規則都沒看,直接在網上搜尋相關Datamatrix碼的相關資訊,果然,我又發現一個libdmtx-0.7.4的标準庫,還支援中文編碼。沒過多久我又把DM碼給鼓搗出來了。

空閑時,我又在網上搜尋了相關條碼以及二維碼生成的相關資訊,最後發現了一個功能更加強大的Zint條碼庫。Zint 條碼庫支援目前市場上主流的條碼類型,包括 QR碼、DM碼、code-128碼、EAN13碼等等。最讓我驚喜的是,有大神基于Qt對zint條碼庫進行了一次簡單的封裝,生成條碼的同時對條碼内容的繪制進行了合理的布局,能夠自适應條碼的縮放,這個功能對我來說太有意義了。分享一下,希望對大家有幫助。

具體實作方式也很簡單,在官網上下載下傳最新的ZINT條碼庫,可以直接編譯成動态連結庫,當然也可以把源碼嵌入到工程檔案直接編譯使用,我使用後者進行測試。

#ifndef BARCODEITEM_H
#define BARCODEITEM_H

#include <QGraphicsItem>
#include <qzint.h>

class BarcodeItem : public QGraphicsItem
{
public:
    explicit BarcodeItem(QGraphicsItem *parent = Q_NULLPTR);
	~BarcodeItem();

	QRectF boundingRect() const;
	void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);

public:
    mutable Zint::QZint barcode;

	Zint::QZint::AspectRatioMode ar;

    QRectF rect() const;
    void setRect(const QRectF &rect);
    inline void setRect(qreal x, qreal y, qreal w, qreal h);

    struct BarcodeItemProp{
        int m_symbol;
        QString m_text;
        QString m_primaryMessage;
        int m_height;
        int m_borderWidth;
        int m_width;
        int m_securityLevel;
        int m_pdf417CodeWords;
        int m_input_mode;
        QColor m_fgColor;
        QColor m_bgColor;
        QString m_lastError;
        int m_error;
        int m_whitespace;
        zint_symbol * m_zintSymbol;
        float m_scale;
        int m_option_3;
        bool m_hidetext;
        float m_dot_size;
    } barcodeItemPara;

    void drawBarcodeItem(BarcodeItemProp barcodeItemPara);


private:
    QRectF m_rect;
    mutable QRectF m_boundingRect;
};

inline void BarcodeItem::setRect(qreal x, qreal y, qreal w, qreal h)
{
    setRect(QRectF(x, y, w, h));
}

#endif
           
#include <QDebug>
#include "barcodeitem.h"

BarcodeItem::BarcodeItem(QGraphicsItem *parent)
        : QGraphicsItem(parent)
{
    setRect(QRectF(0,0,200,200));

    barcodeItemPara.m_symbol = BARCODE_CODE128;
    barcodeItemPara.m_hidetext = false;
    barcodeItemPara.m_text = "6922162891569";
    barcodeItemPara.m_height = 38;
    barcodeItemPara.m_scale = 8.0;
    barcodeItemPara.m_dot_size = 4.0 / 5.0;
    barcodeItemPara.m_pdf417CodeWords = 928;
    barcodeItemPara.m_securityLevel = -1;
    barcodeItemPara.m_input_mode = UNICODE_MODE;
    barcodeItemPara.m_option_3 = 0;
    barcodeItemPara.m_width = 0;
    barcodeItemPara.m_borderWidth = 1;
}

BarcodeItem::~BarcodeItem()
{
}

QRectF BarcodeItem::boundingRect() const
{
    //return QRectF(0, 0, w, h);
    if(m_boundingRect.width() == 0){
        m_boundingRect = QRectF(0,0,800,300);
    }
    return m_boundingRect;
}

void BarcodeItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
    barcode.render(*painter,boundingRect(),ar);
}

QRectF BarcodeItem::rect() const
{
    return m_rect;
}

void BarcodeItem::setRect(const QRectF &rect)
{
    if(m_rect == rect)
        return;
    prepareGeometryChange();
    m_rect = rect;
    m_boundingRect = m_rect;
    update();
}

void BarcodeItem::drawBarcodeItem(BarcodeItem::BarcodeItemProp barcodeItemPara)
{
    barcode.setHeight(barcodeItemPara.m_height);
    barcode.setText(barcodeItemPara.m_text);
    barcode.setScale(barcodeItemPara.m_scale);
    barcode.setInputMode(barcodeItemPara.m_input_mode);
    barcode.setWidth(barcodeItemPara.m_width);
    barcode.setOption3(barcodeItemPara.m_option_3);
    barcode.setHideText(barcodeItemPara.m_hidetext);
    barcode.setDotSize(barcodeItemPara.m_dot_size);
    barcode.setPdf417CodeWords(barcodeItemPara.m_pdf417CodeWords);
    barcode.setSymbol(barcodeItemPara.m_symbol);
    barcode.setSecurityLevel(barcodeItemPara.m_securityLevel);
    barcode.setBorderWidth(barcodeItemPara.m_borderWidth);
    barcode.setBorderType(Zint::QZint::NO_BORDER);

    this->setRect(QRectF(0,0,barcode.width()*barcodeItemPara.m_scale,barcode.height()*barcodeItemPara.m_scale));
    update();
}


           

添加一個繼承QGraphicsItem的類用來繪制條碼及二維碼,主要的是實作方法封裝在qzint類中的render()函數體中,這裡就不貼代碼了。具體的調用方法很簡單,設定條碼内容,條碼類别,以及對應條碼相關屬性後,調用drawBarcodeItem()更新條碼資訊,調用update()執行paint()完成對barcodeItem的重繪,更新條碼顯示。

BarcodeItem *barcode = new BarcodeItem;
    QGraphicsScene *scene = new QGraphicsScene;
    QGraphicsView *view = new QGraphicsView;

    barcode->drawBarcodeItem(barcode->barcodeItemPara);
    scene->addItem(barcode);
    view->setScene(scene);

    QVBoxLayout *vLayout = new QVBoxLayout;
    QLineEdit *input = new QLineEdit;
    QComboBox *box = new QComboBox;
    QStringList barcodeList;
    barcodeList << "Barcode_128"
                << "Barcode_39"
                << "EAN13"
                << "QRcode"
                << "Datamatrix"
                << "Pdf147";
    input->setText(QString("6922162891569"));
    box->addItems(barcodeList);
    input->setFixedHeight(50);
    box->setFixedHeight(50);

    vLayout->addWidget(view);
    vLayout->addWidget(input);
    vLayout->addWidget(box);
    this->setLayout(vLayout);

    connect(input,&QLineEdit::textChanged,this,[=](const QString inputStr){
        barcode->barcodeItemPara.m_text = inputStr;
        barcode->drawBarcodeItem(barcode->barcodeItemPara);
        view->update();
    });

    connect(box,&QComboBox::currentTextChanged,this,[=](const QString comboStr){
        if(comboStr == QString("Barcode_128")){
            barcode->barcodeItemPara.m_symbol = BARCODE_CODE128;
        }
        else if(comboStr == QString("Barcode_39")){
            barcode->barcodeItemPara.m_symbol = BARCODE_CODE39;
        }
        else if(comboStr == QString("EAN13")){
            barcode->barcodeItemPara.m_symbol = BARCODE_EANX;
        }
        else if(comboStr == QString("QRcode")){
            barcode->barcodeItemPara.m_symbol = BARCODE_QRCODE;
        }
        else if(comboStr == QString("Datamatrix")){
            barcode->barcodeItemPara.m_symbol = BARCODE_DATAMATRIX;
        }
        else if(comboStr == QString("Pdf147")){
            barcode->barcodeItemPara.m_symbol = BARCODE_PDF417;
        }
        barcode->drawBarcodeItem(barcode->barcodeItemPara);
        view->update();
    });    
           

這裡測試了code_128,code_39,EAN13,qrcode,datamatrix,pdf417,生成6中條碼如下:

Zint生成多種條碼及二維碼
Zint生成多種條碼及二維碼
Zint生成多種條碼及二維碼
Zint生成多種條碼及二維碼
Zint生成多種條碼及二維碼
Zint生成多種條碼及二維碼

看到這裡相信大家對ZINT條碼庫的強大已經有目共睹了,有相關需求的可以下載下傳一份ZINT條碼庫研究一下,畢竟重複造輪子這種事兒還是少幹為妙。

ps:其實任何事情都要用辨證的角度去看,雖然我當初煞費苦心的研究條碼的編碼規則,通過效率并不高的算法實作了一些常用條碼的生成,但至少我懂了條碼的編碼規則,當客戶需要連續變化的條碼時,我可以很自信的告訴他選擇code_128條碼,當客戶輸入條碼内容和實際生成的條碼掃出來不一緻時,我能很确定的告訴客戶你輸入的條碼内容不标準,條碼校驗碼錯了,或許這些就是我最大的收獲吧。

測試程式下載下傳位址:https://download.csdn.net/download/p154613730/10833507

繼續閱讀