编程爱好者联盟 2016-11-25
在刚接触热敏打印机的时候,觉得这玩儿意还挺神奇的,这么小个东西,完全摆脱了我之前对打印机笨笨的映像,更神奇的是这东西不需要墨,于是去度娘了下,才发现跟普通的喷墨打印机有本质不同,它是通过打印头加热,使得纸上显示想要的图案,因此这个纸也不一般,表层有特殊的化学涂料,所以以后去超时,饭店吃饭,可不要随随便便的把各种小票放嘴里,其连接方式又可分为网络,蓝牙,USB,串口等等,作为码农来说连接方式与我何干,我只关心如何按照指令打印出我想要的东西,下面逐一介绍。
1.指令集
几乎看到的所有的热敏打印机都支持EPSON的ESC POS指令,因此首先可以去度娘上找一份热敏打印机指令集,阅读一番
2.打印纸宽度
目前市面上主要有两种宽度的打印机,58mm和80mm,这是指打印纸的宽度,其中80mm对应384pt,80mm对应586pt
2.打印方式
(1) 位图模式打印,通过文档发现支持位图打印模式,可以打印图片,就意味着我们可以通过随意定制html模板,然后填充数据,最后渲染成图片,对于打印机来说,就是打印图片,一个接口就可以搞定所有问题,这里只是提供一种思路,具体细节实现不在这里发散,感兴趣可以私信我,通过我们的实践,这种打印方式打印出来的效果最好,字体不受打印机限制,可以打印的特别清楚,这也是最为推荐的一种方式,有几个坑需要注意:
a.通过渲染成图片打印并不适应于串口打印机,原因是渲染成图片数据量较大,而串口的传输速度明显不能满足,实测完美支持网口和USB打印机,没有测过蓝牙打印机
b.谨防打印机内存溢出,不停的打印乱码,当图片很长的时候,需要进行截断打印,例如一张图片是576*10240,可以截成10章576*1024
(2) 通过指令集进行打印,按照指令集文档进行打印,这种打印的优点就是数据量小,非常适合串口打印机,缺点是格式受限制,字体受限制,打出来的小票没有图片打印方式好看,下面是我们在打印过程中的一些常用命令的实现
printerprotocal.h
1 #ifndef PRINTERPROTOCAL_H
2 #define PRINTERPROTOCAL_H
3 #include <vector>
4 #include <string>
5 #define SERIAL_SIZE 8
6 class PrinterProtocal {
7 private:
8 std::vector<std::string> data_;
9 std::string tmp_data_;
10 PrinterProtocal &writeString(std::string str);
11 PrinterProtocal &writeByte(std::initializer_list<uint8_t>);
12 public:
13 PrinterProtocal();
14 enum CharacterSet {
15 USA,
16 FRANCE,
17 GERMANY,
18 UK,
19 DENMARK,
20 SWEDEN,
21 ITALY,
22 SPAIN,
23 JAPAN,
24 NORWAY,
25 DENMARK2,
26 SPAIN2,
27 LATINAMERICA,
28 KOREA,
29 Slovenia,
30 Chinese
31 };
32
33 enum CodeTable {
34 PC437,
35 PC850,
36 CHINESE = 30
37 };
38
39 enum AlignMode {
40 LEFT,
41 MIDDLE,
42 RIGHT
43 };
44
45 enum PrintReadable {
46 NONE,
47 ABOVE,
48 BELOW,
49 BOTH
50 };
51
52 enum BarcodeType {
53 UPCA,
54 UPCE,
55 EAN13,
56 EAN8,
57 CODE39,
58 I25,
59 CODEBAR,
60 CODE93,
61 CODE128,
62 CODE11,
63 MSI
64 };
65
66
67 PrinterProtocal &write(std::string str, int32_t size = 0, char ch = ' ');
68 PrinterProtocal &init();
69 PrinterProtocal &reset();
70 PrinterProtocal &setFontSize(uint8_t);
71 PrinterProtocal &setControlParameter(uint8_t heatingDots = 20,
72 uint8_t heatingTime = 255, uint8_t heatingInterval = 250);
73 PrinterProtocal &setSleepTime(uint8_t seconds = 0);
74 PrinterProtocal &setStatus(bool state = true);
75 PrinterProtocal &setPrintDensity(uint8_t printDensity = 14,
76 uint8_t printBreakTime = 4);
77
78 PrinterProtocal &setDoubleWidth(bool state = false);
79 PrinterProtocal &setBold(bool state = false);
80 PrinterProtocal &setReverse(bool state = false);
81 PrinterProtocal &setUpDown(bool state = false);
82 PrinterProtocal &setUnderline(bool state = false);
83 PrinterProtocal &setKeyPanel(bool state = false);
84
85 PrinterProtocal &setCharacterSet(CharacterSet set = USA);
86 PrinterProtocal &setCodeTable(CodeTable table = PC437);
87 PrinterProtocal &feed();
88 PrinterProtocal &feed(uint8_t lines);
89 PrinterProtocal &setLineSpacing(uint8_t spacing = 32);
90 PrinterProtocal &setAlign(AlignMode align = LEFT);
91 PrinterProtocal &setLeftBlankCharNums(uint8_t space = 0);
92 PrinterProtocal &setMarginBottom(uint8_t lines = 100);
93 std::vector<std::string> getResult();
94 PrinterProtocal &done();
95 };
96
97 #endif // PRINTERPROTOCAL_H printerprotocal.cpp
1 #include "printerprotocal.h"
2 #include <unistd.h>
3 #include "base/string_helper.h"
4 PrinterProtocal::PrinterProtocal() {
5 reset();
6 }
7
8
9 // write single byte
10 PrinterProtocal &PrinterProtocal::writeByte(std::initializer_list<uint8_t>
11 params) {
12 //先清理
13 if ((params.size() + tmp_data_.size()) > SERIAL_SIZE) {
14 done();
15 }
16 for (auto ch : params) {
17 tmp_data_.push_back(ch);
18 }
19 return *this;
20 }
21
22 // write a string
23 PrinterProtocal &PrinterProtocal::writeString(std::string str) {
24 for (auto ch : str) {
25 if (tmp_data_.size() >= SERIAL_SIZE) {
26 done();
27 }
28 tmp_data_.push_back(ch);
29 }
30 return *this;
31 }
32 //输入str,如果长度小于size,不足的部分用空格填充
33 PrinterProtocal &PrinterProtocal::write(std::string str, int32_t size,
34 char ch) {
35 std::string gbk_str = StringHelper::GetGBK(str);
36 while (static_cast<int>(gbk_str.size()) < size) {
37 gbk_str.push_back(ch);
38 }
39 writeString(gbk_str);
40 return *this;
41 }
42 PrinterProtocal &PrinterProtocal::done() {
43 if (tmp_data_.size() > 0) {
44 data_.push_back(tmp_data_);
45 tmp_data_.clear();
46 }
47 return *this;
48 }
49
50 // initialize the printer
51 PrinterProtocal &PrinterProtocal::init() {
52 writeByte({27, 64}).done();
53 return *this;
54 }
55
56 // reset the printer
57 PrinterProtocal &PrinterProtocal::reset() {
58 data_.clear();
59 return *this;
60 }
61
62 // sets the printer online (true) or ofline (false)
63 PrinterProtocal &PrinterProtocal::setStatus(bool state) {
64 writeByte({27, 61, (uint8_t)state}).done();
65 return *this;
66 }
67
68 // set control parameters: heatingDots, heatingTime, heatingInterval
69 PrinterProtocal &PrinterProtocal::setControlParameter(uint8_t heatingDots,
70 uint8_t heatingTime, uint8_t heatingInterval) {
71 writeByte({27, 55, heatingDots, heatingTime, heatingInterval}).done();
72 return *this;
73 }
74
75
76 //width,height均表示倍数
77 PrinterProtocal &PrinterProtocal::setFontSize(uint8_t size) {
78 //低4位表示高度,高4位表示宽度
79 uint8_t ret = (0x0f & (2 * size)) | (0xf0 & (16 * size));
80 writeByte({29, 33, ret}).done();
81 return *this;
82 }
83
84 // set the used character set
85 PrinterProtocal &PrinterProtocal::setCharacterSet(CharacterSet set) {
86 writeByte({27, 82, (uint8_t)set}).done();
87 return *this;
88 }
89
90 // set the used code table
91 PrinterProtocal &PrinterProtocal::setCodeTable(CodeTable table) {
92 writeByte({27, 116, (uint8_t)table}).done();
93 return *this;
94 }
95
96 //打印并换行
97 PrinterProtocal &PrinterProtocal::feed() {
98 writeByte({10}).done();
99 return *this;
100 }
101
102 //打印并换lines行
103 PrinterProtocal &PrinterProtocal::feed(uint8_t lines) {
104 writeByte({27, 74, lines}).done();
105 return *this;
106 }
107
108 //设置行间距
109 PrinterProtocal &PrinterProtocal::setLineSpacing(uint8_t spacing) {
110 writeByte({27, 51, spacing}).done();
111 return *this;
112 }
113
114 // set Align Mode: LEFT, MIDDLE, RIGHT
115 PrinterProtocal &PrinterProtocal::setAlign(AlignMode align) {
116 writeByte({27, 97, (uint8_t)align}).done();
117 return *this;
118 }
119
120 //设置左边空白间距
121 PrinterProtocal &PrinterProtocal::setLeftBlankCharNums(uint8_t space) {
122 if (space >= 47) {
123 space = 47;
124 }
125 writeByte({29, 76, space}).done();
126 return *this;
127 }
128
129
130
131 // set Bold Mode: on=true, off=false
132 PrinterProtocal &PrinterProtocal::setBold(bool state) {
133 writeByte({27, 69, (uint8_t)state}).done();
134 return *this;
135 }
136 //设定/解除反白打印模式
137 // set Reverse printing Mode
138 PrinterProtocal &PrinterProtocal::setReverse(bool state) {
139 writeByte({29, 66, (uint8_t)state}).done();
140 return *this;
141 }
142 //设置/解除颠倒打印模式
143 // set Up/Down Mode
144 PrinterProtocal &PrinterProtocal::setUpDown(bool state) {
145 writeByte({27, 123, (uint8_t)state}).done();
146 return *this;
147 }
148
149 //设置/取消汉字字符下划线模式
150 PrinterProtocal &PrinterProtocal::setUnderline(bool state) {
151 writeByte({28, 45, (uint8_t)state}).done();
152 return *this;
153 }
154
155 // enable / disable the key on the frontpanel
156 //激活/禁止面板按键
157 PrinterProtocal &PrinterProtocal::setKeyPanel(bool state) {
158 writeByte({27, 99, 53, (uint8_t)state}).done();
159 return *this;
160 }
161
162 PrinterProtocal &PrinterProtocal::setMarginBottom(uint8_t lines) {
163 writeByte({27, 74, lines}).done();
164 return *this;
165 }
166
167 std::vector<std::string> PrinterProtocal::getResult() {
168 return data_;
169 } 热敏打印机指令集中很多不一定用得到,而且感觉国内生产的这些打印机,对个别指令支持并不是特别好,要想做到完全兼容,还需要个性化的去适配。