在剛接觸熱敏打印機的時候,覺得這玩兒意還挺神奇的,這麼小個東西,完全擺脫了我之前對打印機笨笨的映像,更神奇的是這東西不需要墨,於是去度娘了下,才發現跟普通的噴墨打印機有本質不同,它是通過打印頭加熱,使得紙上顯示想要的圖案,因此這個紙也不一般,表層有特殊的化學塗料,所以以後去超時,飯店吃飯,可不要隨隨便便的把各種小票放嘴裡,其連接方式又可分為網絡,藍牙,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 }
熱敏打印機指令集中很多不一定用得到,而且感覺國內生產的這些打印機,對個別指令支持並不是特別好,要想做到完全兼容,還需要個性化的去適配。