【Qt】条形码制作器(Code39编码)

来源:互联网 发布:西安淘宝大学讲师 编辑:程序博客网 时间:2024/04/29 18:47

环境:Qt5.3 MSVC2010

编译器:Qt Creator


描述:

        最近公司项目卡在了POS机打印小票上,因为涉及打印机太多,很多打印机对ESC/POS指令集支持又不是特别好,所以直接用ESC指令集打不出需要的条形码。唯一的方式只有先生成需要的条形码图片,再解析图片把数据发送给POS小票机打印。

主要问题就是生成条形码算法了。

        现在最常见的条形码有两种编码格式,一种是39码(code39),一种是128码(code128)。

        最初打算使用的是39码,代码做完之后,发现39码的编码规则虽然简单,但是不适合太长的条形码,一般码数超过8位图片就显得很长,再长一些甚至就会超出POS打印机的最大宽度。相对于39码,128码的编码规则虽然复杂,字符集庞大,但是能把纯数字的条形码长度压缩近一倍(相对于39码),所以后来又重做了128码图片生成。

        由于128码支持的字符集太多,但是公司项目目前只针对纯数字的条形码,所以128码的代码只写了极小部分的字符集支持,就不贴上来。

        只贴39码的算法。


解析:

       关于39码,遵循以下规则(不少资料中会总结为5条规则,但是并不好理解,我总结为一下几条)

1.支持0~9 A~Z(大写字母) + - * / % ¥[空格]其中*只作为起始终止符,不出现在条码中)

        2.每个字符对应一个12位的二进制逻辑码(对照表见后)

        3.对应逻辑码中,1代表条形码的黑线,0代表条形码白线(不少资料也会约束11为粗黑线,00为粗白线,1为细黑线,0为细白线)

        4.条形码的开头与结尾必须使用*做标识符


PS:

        第一次做出代码生成图片时,扫描不成功,这个问题纠结了很长时间,后来把合法的条形码和自己生成的条形码挨个对比,才发现问题。

       实际上,每个字符对应的条形码之间,还有一个单位的白线。

       也就是说,在QString Code39::CodeBinary(QString)中,每转换一个二进制逻辑码后,都要加一个“0”来分割两个字符的二进制逻辑码。这点非常重要!


Code39.cpp(头文件略)

#include "Code39.h"#include <QDebug>#include <QDateTime>#include <QMessageBox>#include <QFont>Code39::Code39(QString BarCode,QString SavePath){    barcode=BarCode;    path=SavePath;    InitMap();    start(barcode);}void Code39::start(QString barcode){    //校验字符是否合法    QString com="0123456789ABCDEFGHIJKLMNOPQISTUVWXWZ+-*/%$. ";//合法字符模版    for(int i=0;i<barcode.size();i++)    {        if(!com.contains(barcode.at(i)))        {            QMessageBox msg;            msg.setText(QStringLiteral("条形码字符不合法!\n合法字符:A~Z 0~9 +-/%$[空格]"));            msg.exec();            return;        }    }    draw(CodeBinary(barcode),barcode);}void Code39::draw(QString BinaryNum,QString barcode){    int MAXWIDTH;    int MAXHEIGHT=100;    int FONTHEIGHT=30;    //设定条码线条宽度px    int LineWidth=3;    //预留10px的左右空白;    MAXWIDTH=LineWidth*BinaryNum.size()+10;    //计算条线宽度时,精度丢失造成条码右边空白,进行右移居中    int move=(MAXWIDTH-LineWidth*BinaryNum.size())/2;    QBitmap bmp(MAXWIDTH,MAXHEIGHT+FONTHEIGHT);    QPainter painter(&bmp);    QPen white,black;//    painter.setRenderHint(QPainter::Antialiasing,true);//弧线圆润    white.setColor(QColor(255,255,255));    black.setColor(QColor(0,0,0));    white.setWidth(LineWidth);    black.setWidth(LineWidth);    //背景充填白色    painter.setPen(white);    painter.drawRect(0,0,MAXWIDTH,MAXHEIGHT+FONTHEIGHT);    //画线    for(int i=0;i<BinaryNum.size();i++)    {        if(BinaryNum.at(i)=="1") painter.setPen(black);        else painter.setPen(white);        painter.drawLine(i*LineWidth+LineWidth/2+move,0,i*LineWidth+LineWidth/2+move,MAXHEIGHT);    }    //添加底部条形码字符    painter.setPen(black);    painter.setRenderHint(QPainter::Antialiasing,true);    painter.setRenderHint(QPainter::TextAntialiasing,true);    painter.setRenderHint(QPainter::HighQualityAntialiasing,true);    QFont font;    font.setFamily("Impact");    font.setPixelSize(20);    font.setWeight(50);    painter.setFont(font);    painter.drawText(10,100,MAXWIDTH,30,Qt::AlignCenter,barcode);    bmp.save(path+QDateTime::currentDateTime().toString("MM-dd-hh-mm-ss-zz")+".bmp");}QString Code39::CodeBinary(QString barcode){    barcode="*"+barcode+"*";    QString str="";    for(int i=0;i<barcode.size();i++)    {        str+=map[barcode.at(i)]+"0";//每个字符的二进制逻辑码之间,用“0”隔开(加一条白线)    }    return str;}void Code39::InitMap(){    map.insert("A","110101001011");    map.insert("B","101101001011");    map.insert("C","110110100101");    map.insert("D","101011001011");    map.insert("E","110101100101");    map.insert("F","101101100101");    map.insert("G","101010011011");    map.insert("H","110101001101");    map.insert("I","101101001101");    map.insert("J","101011001101");    map.insert("K","110101010011");    map.insert("L","101101010011");    map.insert("M","110110101001");    map.insert("N","101011010011");    map.insert("O","110101101001");    map.insert("P","101101101001");    map.insert("Q","101010110011");    map.insert("R","110101011001");    map.insert("S","101101011001");    map.insert("T","101011011001");    map.insert("U","110010101011");    map.insert("V","100110101011");    map.insert("W","110011010101");    map.insert("X","100101101011");    map.insert("Y","110010110101");    map.insert("Z","100110110101");    map.insert("0","101001101101");    map.insert("1","110100101011");    map.insert("2","101100101011");    map.insert("3","110110010101");    map.insert("4","101001101011");    map.insert("5","110100110101");    map.insert("6","101100110101");    map.insert("7","101001011011");    map.insert("8","110100101101");    map.insert("9","101100101101");    map.insert("+","100101001001");    map.insert("-","100101011011");    map.insert("*","100101101101");    map.insert("/","100100101001");    map.insert("%","101001001001");    map.insert("$","100100100101");    map.insert(".","110010101101");    map.insert(" ","100110101101");}


对照表

39码的字符编码方式

(一) 英文字母部分

字符

逻辑型态

字符

逻辑型态

A

110101001011

N

101011010011

B

101101001011

O

110101101001

C

110110100101

P

101101101001

D

101011001011

Q

101010110011

E

110101100101

R

110101011001

F

101101100101

S

101101011001

G

101010011011

T

101011011001

H

110101001101

U

110010101011

I

101101001101

V

100110101011

J

101011001101

W

110011010101

K

110101010011

X

100101101011

L

101101010011

Y

110010110101

M

110110101001

Z

100110110101

 

(二) 数字与特殊符号部分

字符

逻辑型态

字符

逻辑型态

0

101001101101

100101001001

1

110100101011

100101011011

2

101100101011

100101101101

3

110110010101

100100101001

4

101001101011

101001001001

5

110100110101

100100100101

6

101100110101

110010101101

7

101001011011

空白

100110101101

8

110100101101

 

 

9

101100101101

 

 

 


0 0
原创粉丝点击