Java 实现 POS 打印机无驱打印 【转】
生活随笔
收集整理的這篇文章主要介紹了
Java 实现 POS 打印机无驱打印 【转】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Java 對硬件的控制一直以來都不是其強項,特別是打印,Java 很難實現對 POS 打印機的直接控制,并判斷打印是否成功。本文將探討一種方法,講述如何使用 Java 技術與網口的 POS 打印機連接,通過 Socket 技術直接將愛普生指令寫入打印機端口,打印出相應的內容或者條形碼,并實現字體的放大,打印完畢自動走紙等功能。
行業需求
我們是一家專業做酒店餐飲軟件的公司,餐飲軟件一個重要的功能就是后廚打印問題,前臺點菜完畢,后廚立刻打印出單子,這樣就減少人工遞單的麻煩,節省時間,提高翻臺率。這種信息化解決方案對打印技術要求很高,理論上最好 100% 不丟單,也就是每次點菜后廚都會相應出單子,但是實際上行不通,為什么呢?因為網線、打印機、網卡等都有可能有問題,別說打印機等硬件因為廚房油煙問題損壞,我們甚至碰到過網線被老鼠咬斷的情況,總之硬件網絡故障防不勝防,所以只能退而求其次,就是有問題不可怕,程序能夠判斷是否出了問題,并能給出提示,便于服務員處理,及時補單。
如果我們用安裝 Windows 驅動的方法來實現后廚打印,那么肯定是不行的,因為我們只能單向向驅動程序拋包,不能從驅動程序獲得任何返回值,沒有辦法了解是否打印成功。而且更為嚴重的是,有時候因為后廚打印機過多,Windows 驅動甚至會因為網絡堵塞自作主張將包丟棄,沒有任何提示。
這在行業應用中是不行的,會給用戶帶來損失,所以想到了繞過 Windows 驅動,直接寫端口的方法。
無驅打印的可行性
所謂直接寫端口的方法,就是不用安裝打印機驅動,不使用 PrinterJob 獲得打印機的名字的方法進行打印。
眾所周知,之所以安裝打印機驅動,一個重要的原因就是打印機廠商千差萬別,不同的打印機往往都有各自的驅動,很難實現萬能驅動。但是,在 POS 打印機行業卻有一條捷徑,就是現在市面上的 POS 打印機基本上都支持愛普生指令,也就是說,只要將程序和打印機聯通,直接向端口里面寫愛普生指令就可以控制打印機。
打印機接受到愛普生指令以后,自行進行解析,然后打印出相應的內容。
愛普生指令
日本的 EPSON 公司在目前的 POS 打印機市場,尤其是針式打印機市場占有很大一部分份額。它所推行的 ESC 打印控制命令 (EPSON StandardCode for Pr5nter) 已經成為了針式打印機控制語言事實上的工業標準,ESC/POS 打印命令集是 ESC 打印控制命令的簡化版本,現在大多數 POS 打印都采用 ESC/POS 指令集。絕大多數打印機都有 EPSON ESC 的軟件命令仿真功能,而且其它打印控制命令的格式和功能也都與 ESC 代碼集類似。
由于早期的操作系統 DOS 與現在 Windows 的結構不同,在打印機內部軟件和應用軟件之間沒有由硬件廠商提供的打印驅動程序,必須由應用軟件直接通過硬件接口來控制打印機,所以從 ESC 指令出現開始,它就是公開的,否則沒有應用軟件可以使用它,而除了標準的 ESC 指令外,每種型號的打印機其指令又不太一樣,所以在 DOS 軟件中,你可以看到每個應用軟件都只是支持為數不多的幾種常用打印機。
ESC 指令在形式上分為兩種格式,一種是文本方式控制碼,一種是 Escape 轉義序列碼。文本方式控制碼由一字節字符碼表示,實現的是與打印機硬件操作有關的指令,Escape 序列碼由轉義字符和參數字符或打印數據組成。
建立打印連接
通過上面的介紹,了解了實現無驅打印原來只是一層窗戶紙,具體的方法就是首先建立打印機連接,然后寫入愛普生指令即可。那么如何建立打印機連接?以網口 POS 打印機舉例。
第一步,首先要給網口打印機賦一個 IP 地址,例如叫做 192.168.0.18 。
第二步,編寫連接代碼。
Socket client=new java.net.Socket();
PrintWriter socketWriter;
client.connect(new InetSocketAddress("192.168.0.18" , 9100),1000); // 創建一個 socket
socketWriter = new PrintWriter(client.getOutputStream());// 創建輸入輸出數據流
看起來跟一般的 socket 連接沒有很大的區別,就是賦一個 IP 地址和一個端口號,并設置一下超時時間即可,只需要說明的是,一般 POS 打印機的端口都是 9100 。
寫入打印內容
連接建立完畢,寫入內容就非常容易,只要使用 write 或者 println 方法寫入即可,其中 write 方法是寫入數字或字符,println 寫入一行字符串。
例如:寫入數字 socketWriter.write(0);
寫入一行字符串 socketWriter.println( “巧富餐飲軟件后廚單據” );
再入一行字符串 socketWriter.println( “桌位 14 桌,人數 3 ” );
再入一行字符串 socketWriter.println( “跺腳魚頭 1 份” );
您或許有疑問?內容已經成功寫入,好像我們還沒有用到愛普生指令。是的,如果只是普通的寫入內容,不需要用到愛普生指令,愛普生指令主要幫助實現放大字體,自動走紙,打印條形碼等功能。
放大字體
放大字體需要用到愛普生的 0x1c 指令,使用愛普生指令的方法很簡單,只要向端口寫入指令即可,例如:
socketWriter.write(0x1c);
注意 0x1c,是 16 進制的數字,當然也可以轉換成 10 進制來寫。需要說明的是,使用愛普生指令放大字體不能隨意放大,因為它不是圖形化打印,而是文本化打印,所以縱向或者橫向只能按照倍數放大,不能矢量放大。例如在 POS58 打印機上將“巧富餐飲軟件”幾個字放大打印,可以有如下放大方法。
/* 橫向放大一倍 */
socketWriter.write(0x1c);
socketWriter.write(0x21);
socketWriter.write(4);
/* 縱向放大一倍 */
socketWriter.write(0x1c);
socketWriter.write(0x21);
socketWriter.write(8);
/* 橫向縱向都放大一倍 */
socketWriter.write(0x1c);
socketWriter.write(0x21);
socketWriter.write(12);
一般情況下,我們傾向采用縱向放大一倍的方法,放大后的字體看起來有點像仿宋體,視覺效果還不錯。
兼容多種類型打印機
現在知道了使用愛普生指令的方法,所以只要有一本愛普生指令手冊在手里,就可以用 Java 控制打印機進行無驅打印。但是現在問題是,同樣是愛普生指令,不同的 pos 打印機可能不一樣,就拿放大字體來說,pos58 打印機和 pos80 打印機指令就不盡相同。這時候怎么辦呢?如何兼容多種類型打印機?
比如說,有的打印機并不是使用 0x1c 作為放大指令,而是使用 0x1b 作為放大指令,怎么辦?容易。
/* 橫向放大一倍 */
socketWriter.write(0x1c);
socketWriter.write(0x21);
socketWriter.write(4);
socketWriter.write(0x1b);
socketWriter.write(0x21);
socketWriter.write(4);
/* 縱向放大一倍 */
socketWriter.write(0x1c);
socketWriter.write(0x21);
socketWriter.write(8);
socketWriter.write(0x1b);
socketWriter.write(0x21);
socketWriter.write(8);
/* 橫向縱向都放大一倍 */
socketWriter.write(0x1c);
socketWriter.write(0x21);
socketWriter.write(12);
socketWriter.write(0x1b);
socketWriter.write(0x21);
socketWriter.write(12);
看明白了嗎?就是寫兩遍就行,因為如果 0x1b 指令若不存在,打印機自動將其拋棄。
實現自動走紙
POS 打印機因為出紙口有一些深度,打印完畢為了避免撕裂文字內容,一般需要適當走紙才行,當然可以使用愛普生指令來走紙,但是這樣并不穩妥,為什么呢 ? 因為要考慮 POS 機的兼容性,所以一般采用打印空行的方式實現走紙。
for(int i=0;i<10;i++){
socketWriter.println(" ");// 打印完畢自動走紙
}
顯然,打印空行的方式有更好地兼容性。
打印條形碼
條形碼在各個行業中現在有廣泛的應用,所以讓打印機打印條形碼是非常重要的功能,不過你不需要費好多精力去研究條形碼知識,因為愛普生指令中有一個打印條形碼指令,例如我們要打印條形碼“ 091955826335 ”,只要使用如下命令即可。
socketWriter.write(0x1d);
socketWriter.write(0x68);
socketWriter.write(120);
socketWriter.write(0x1d);
socketWriter.write(0x48);
socketWriter.write(0x01);
socketWriter.write(0x1d);
socketWriter.write(0x6B);
socketWriter.write(0x02);
socketWriter.println "091955826335" );
socketWriter.write(0x00);
完整的代碼
好了,下面舉一個完整的例子,我們來建立一個叫做 print 的方法,向某個打印機打印一個字符和條形碼,并實現自動走紙,代碼如下:
private boolean print(String ip, int port, String str,String code,int skip)
throws Exception{
Socket client=new java.net.Socket();
PrintWriter socketWriter;
client.connect(new InetSocketAddress(ip,port),1000); // 創建一個 socket
socketWriter = new PrintWriter(client.getOutputStream());// 創建輸入輸出數據流
/* 縱向放大一倍 */
socketWriter.write(0x1c);
socketWriter.write(0x21);
socketWriter.write(8);
socketWriter.write(0x1b);
socketWriter.write(0x21);
socketWriter.write(8);
socketWriter.println(str);
// 打印條形碼
socketWriter.write(0x1d);
socketWriter.write(0x68);
socketWriter.write(120);
socketWriter.write(0x1d);
socketWriter.write(0x48);
socketWriter.write(0x01);
socketWriter.write(0x1d);
socketWriter.write(0x6B);
socketWriter.write(0x02);
socketWriter.println(code);
socketWriter.write(0x00);
for(int i=0;i<skip;i++){
socketWriter.println(" ");// 打印完畢自動走紙
}
}
小結
本文雖然只是講述了網口打印機的直接寫端口方式,似乎對并口打印機無效,其實不是這樣,并口打印機只要接一個打印服務器就可以用了,缺點就是非一體機,然后還要安裝打印服務器驅動。
這種無驅打印在非常廣泛的范圍內可以得到應用,包括餐飲、超市、醫藥等等其他需要用到 POS 打印機的行業。
行業需求
我們是一家專業做酒店餐飲軟件的公司,餐飲軟件一個重要的功能就是后廚打印問題,前臺點菜完畢,后廚立刻打印出單子,這樣就減少人工遞單的麻煩,節省時間,提高翻臺率。這種信息化解決方案對打印技術要求很高,理論上最好 100% 不丟單,也就是每次點菜后廚都會相應出單子,但是實際上行不通,為什么呢?因為網線、打印機、網卡等都有可能有問題,別說打印機等硬件因為廚房油煙問題損壞,我們甚至碰到過網線被老鼠咬斷的情況,總之硬件網絡故障防不勝防,所以只能退而求其次,就是有問題不可怕,程序能夠判斷是否出了問題,并能給出提示,便于服務員處理,及時補單。
如果我們用安裝 Windows 驅動的方法來實現后廚打印,那么肯定是不行的,因為我們只能單向向驅動程序拋包,不能從驅動程序獲得任何返回值,沒有辦法了解是否打印成功。而且更為嚴重的是,有時候因為后廚打印機過多,Windows 驅動甚至會因為網絡堵塞自作主張將包丟棄,沒有任何提示。
這在行業應用中是不行的,會給用戶帶來損失,所以想到了繞過 Windows 驅動,直接寫端口的方法。
無驅打印的可行性
所謂直接寫端口的方法,就是不用安裝打印機驅動,不使用 PrinterJob 獲得打印機的名字的方法進行打印。
眾所周知,之所以安裝打印機驅動,一個重要的原因就是打印機廠商千差萬別,不同的打印機往往都有各自的驅動,很難實現萬能驅動。但是,在 POS 打印機行業卻有一條捷徑,就是現在市面上的 POS 打印機基本上都支持愛普生指令,也就是說,只要將程序和打印機聯通,直接向端口里面寫愛普生指令就可以控制打印機。
打印機接受到愛普生指令以后,自行進行解析,然后打印出相應的內容。
愛普生指令
日本的 EPSON 公司在目前的 POS 打印機市場,尤其是針式打印機市場占有很大一部分份額。它所推行的 ESC 打印控制命令 (EPSON StandardCode for Pr5nter) 已經成為了針式打印機控制語言事實上的工業標準,ESC/POS 打印命令集是 ESC 打印控制命令的簡化版本,現在大多數 POS 打印都采用 ESC/POS 指令集。絕大多數打印機都有 EPSON ESC 的軟件命令仿真功能,而且其它打印控制命令的格式和功能也都與 ESC 代碼集類似。
由于早期的操作系統 DOS 與現在 Windows 的結構不同,在打印機內部軟件和應用軟件之間沒有由硬件廠商提供的打印驅動程序,必須由應用軟件直接通過硬件接口來控制打印機,所以從 ESC 指令出現開始,它就是公開的,否則沒有應用軟件可以使用它,而除了標準的 ESC 指令外,每種型號的打印機其指令又不太一樣,所以在 DOS 軟件中,你可以看到每個應用軟件都只是支持為數不多的幾種常用打印機。
ESC 指令在形式上分為兩種格式,一種是文本方式控制碼,一種是 Escape 轉義序列碼。文本方式控制碼由一字節字符碼表示,實現的是與打印機硬件操作有關的指令,Escape 序列碼由轉義字符和參數字符或打印數據組成。
建立打印連接
通過上面的介紹,了解了實現無驅打印原來只是一層窗戶紙,具體的方法就是首先建立打印機連接,然后寫入愛普生指令即可。那么如何建立打印機連接?以網口 POS 打印機舉例。
第一步,首先要給網口打印機賦一個 IP 地址,例如叫做 192.168.0.18 。
第二步,編寫連接代碼。
Socket client=new java.net.Socket();
PrintWriter socketWriter;
client.connect(new InetSocketAddress("192.168.0.18" , 9100),1000); // 創建一個 socket
socketWriter = new PrintWriter(client.getOutputStream());// 創建輸入輸出數據流
看起來跟一般的 socket 連接沒有很大的區別,就是賦一個 IP 地址和一個端口號,并設置一下超時時間即可,只需要說明的是,一般 POS 打印機的端口都是 9100 。
寫入打印內容
連接建立完畢,寫入內容就非常容易,只要使用 write 或者 println 方法寫入即可,其中 write 方法是寫入數字或字符,println 寫入一行字符串。
例如:寫入數字 socketWriter.write(0);
寫入一行字符串 socketWriter.println( “巧富餐飲軟件后廚單據” );
再入一行字符串 socketWriter.println( “桌位 14 桌,人數 3 ” );
再入一行字符串 socketWriter.println( “跺腳魚頭 1 份” );
您或許有疑問?內容已經成功寫入,好像我們還沒有用到愛普生指令。是的,如果只是普通的寫入內容,不需要用到愛普生指令,愛普生指令主要幫助實現放大字體,自動走紙,打印條形碼等功能。
放大字體
放大字體需要用到愛普生的 0x1c 指令,使用愛普生指令的方法很簡單,只要向端口寫入指令即可,例如:
socketWriter.write(0x1c);
注意 0x1c,是 16 進制的數字,當然也可以轉換成 10 進制來寫。需要說明的是,使用愛普生指令放大字體不能隨意放大,因為它不是圖形化打印,而是文本化打印,所以縱向或者橫向只能按照倍數放大,不能矢量放大。例如在 POS58 打印機上將“巧富餐飲軟件”幾個字放大打印,可以有如下放大方法。
/* 橫向放大一倍 */
socketWriter.write(0x1c);
socketWriter.write(0x21);
socketWriter.write(4);
/* 縱向放大一倍 */
socketWriter.write(0x1c);
socketWriter.write(0x21);
socketWriter.write(8);
/* 橫向縱向都放大一倍 */
socketWriter.write(0x1c);
socketWriter.write(0x21);
socketWriter.write(12);
一般情況下,我們傾向采用縱向放大一倍的方法,放大后的字體看起來有點像仿宋體,視覺效果還不錯。
兼容多種類型打印機
現在知道了使用愛普生指令的方法,所以只要有一本愛普生指令手冊在手里,就可以用 Java 控制打印機進行無驅打印。但是現在問題是,同樣是愛普生指令,不同的 pos 打印機可能不一樣,就拿放大字體來說,pos58 打印機和 pos80 打印機指令就不盡相同。這時候怎么辦呢?如何兼容多種類型打印機?
比如說,有的打印機并不是使用 0x1c 作為放大指令,而是使用 0x1b 作為放大指令,怎么辦?容易。
/* 橫向放大一倍 */
socketWriter.write(0x1c);
socketWriter.write(0x21);
socketWriter.write(4);
socketWriter.write(0x1b);
socketWriter.write(0x21);
socketWriter.write(4);
/* 縱向放大一倍 */
socketWriter.write(0x1c);
socketWriter.write(0x21);
socketWriter.write(8);
socketWriter.write(0x1b);
socketWriter.write(0x21);
socketWriter.write(8);
/* 橫向縱向都放大一倍 */
socketWriter.write(0x1c);
socketWriter.write(0x21);
socketWriter.write(12);
socketWriter.write(0x1b);
socketWriter.write(0x21);
socketWriter.write(12);
看明白了嗎?就是寫兩遍就行,因為如果 0x1b 指令若不存在,打印機自動將其拋棄。
實現自動走紙
POS 打印機因為出紙口有一些深度,打印完畢為了避免撕裂文字內容,一般需要適當走紙才行,當然可以使用愛普生指令來走紙,但是這樣并不穩妥,為什么呢 ? 因為要考慮 POS 機的兼容性,所以一般采用打印空行的方式實現走紙。
for(int i=0;i<10;i++){
socketWriter.println(" ");// 打印完畢自動走紙
}
顯然,打印空行的方式有更好地兼容性。
打印條形碼
條形碼在各個行業中現在有廣泛的應用,所以讓打印機打印條形碼是非常重要的功能,不過你不需要費好多精力去研究條形碼知識,因為愛普生指令中有一個打印條形碼指令,例如我們要打印條形碼“ 091955826335 ”,只要使用如下命令即可。
socketWriter.write(0x1d);
socketWriter.write(0x68);
socketWriter.write(120);
socketWriter.write(0x1d);
socketWriter.write(0x48);
socketWriter.write(0x01);
socketWriter.write(0x1d);
socketWriter.write(0x6B);
socketWriter.write(0x02);
socketWriter.println "091955826335" );
socketWriter.write(0x00);
完整的代碼
好了,下面舉一個完整的例子,我們來建立一個叫做 print 的方法,向某個打印機打印一個字符和條形碼,并實現自動走紙,代碼如下:
private boolean print(String ip, int port, String str,String code,int skip)
throws Exception{
Socket client=new java.net.Socket();
PrintWriter socketWriter;
client.connect(new InetSocketAddress(ip,port),1000); // 創建一個 socket
socketWriter = new PrintWriter(client.getOutputStream());// 創建輸入輸出數據流
/* 縱向放大一倍 */
socketWriter.write(0x1c);
socketWriter.write(0x21);
socketWriter.write(8);
socketWriter.write(0x1b);
socketWriter.write(0x21);
socketWriter.write(8);
socketWriter.println(str);
// 打印條形碼
socketWriter.write(0x1d);
socketWriter.write(0x68);
socketWriter.write(120);
socketWriter.write(0x1d);
socketWriter.write(0x48);
socketWriter.write(0x01);
socketWriter.write(0x1d);
socketWriter.write(0x6B);
socketWriter.write(0x02);
socketWriter.println(code);
socketWriter.write(0x00);
for(int i=0;i<skip;i++){
socketWriter.println(" ");// 打印完畢自動走紙
}
}
小結
本文雖然只是講述了網口打印機的直接寫端口方式,似乎對并口打印機無效,其實不是這樣,并口打印機只要接一個打印服務器就可以用了,缺點就是非一體機,然后還要安裝打印服務器驅動。
這種無驅打印在非常廣泛的范圍內可以得到應用,包括餐飲、超市、醫藥等等其他需要用到 POS 打印機的行業。
總結
以上是生活随笔為你收集整理的Java 实现 POS 打印机无驱打印 【转】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解决“TypeError: Cannot
- 下一篇: Spring工具包下载