【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
- 【Qt】条形码制作器(Code39编码)
- Code39条形码编程简单实现(C#)
- 自绘条形码(code39 + code128A+C奇偶数)
- 显示code39条形码的类
- C#生成Code39条形码【非条形码字体】
- C#生成Code39条形码【非条形码字体】
- C#生成Code39条形码【非条形码字体】
- C#生成Code39条形码【非条形码字体】
- C#生成Code39条形码【非条形码字体】
- C#生成Code39条形码【非条形码字体】
- C#生成Code39条形码【非条形码字体】
- C#生成Code39条形码【非条形码字体】
- C#生成Code39条形码【非条形码字体】
- C#生成Code39条形码【非条形码字体】
- C#生成Code39条形码【非条形码字体】
- C#生成Code39条形码【非条形码字体】
- C#生成Code39条形码【非条形码字体】
- C#生成Code39条形码【非条形码字体】
- VS2012 从字符串转换日期和/或时间时,转换失败
- PHP学习笔记之命名空间//待完善V1.0
- 发送邮件
- R语言的数据结构
- 数字字体
- 【Qt】条形码制作器(Code39编码)
- 经典编程笔试题1
- android开发真机调试(MAC环境下)
- Wing IDE5.1.8-1体验(一)
- Android中事件分发机制详解
- [Leetcode]Merge Sorted Array
- UVA - 1152 4 Values whose Sum is 0
- Linux下*.tar.gz文件解压缩命令
- Spine输出资源一键入Unity3D工具代码