C#通過標簽軟件Bartender的ZPL命令打印條碼
注:
由于工作需要, 也是第一次接觸到打印機的相關內(nèi)容, 湊巧, 通過找了很多資料和幫助后, 也順利的解決了打印標簽的問題
(標簽的表面信息[二維碼,條形碼, 文字] 和 RFID標簽的EPC寫入)
解決方案
1. 由于開發(fā)準備的前期工作, 手里面是有很多的原廠API。

2.熟之, 斑馬打印機官方是由一套自己的打印語言, 簡稱ZPL語言, 然后各種費解找到官方的SBPL API, 大概就是這樣/

通過閱讀大概閱讀了這些API文檔(盡管看不懂...) ,大概知道原理是通過ZPL命令發(fā)送至打印機執(zhí)行。
所以,順藤摸瓜, 我直接就去搜索ZPL的操作命令, 自己嘗試了編寫ZPL命令操作打印機。在這里,先講一下什么是ZPL命令~~
Zebra Programming Language (printer language) 簡稱ZPL是由斑馬公司發(fā)明的一種用于打印機通信的命令。
3. 在ZPL API 文檔種, 會用很詳細的介紹, 從是怎樣開始, 到各個指令的作用都會介紹, 如下圖



根據(jù)官方的說明, 每個完整的ZPL 指令, 它都是 ^XA 開始, 以^Z 結(jié)束。 而^則是一個標記頭, 后面跟著的字母,則是對應的作用功能, 例如:
- ^LH : 定義標簽的起始位置
- ^LL : 定義標簽的長度
- ^PW : 打印寬度
- ^LS : 標簽的位移
- ^......
實現(xiàn)
那么現(xiàn)在自己組成自己想要打印的ZPL指令, 該如何發(fā)送到打印機?
1.Demo(示例), 這里以打印一串字符 12345678 生成的ZPL指令演示如何發(fā)送到打印機
* 12345678所生成的ZPL指令如下: ^ XA ^ FO50,50 ^ A0N,36,20 ^ FD12345678 ^ FS ^ PQ1,0,1,Y ^ XZ 注釋: ^XA/^XZ 分別代表ZPL的開始與結(jié)束, 始終固定 ^FO :代表字段的起始位置, 50,50代表具體的坐標位置 ^AON,36,20: 可縮放/位圖字體 O代表字體, N代表字段的方向, 36代表字符的高度,20代表寬度 ^FD12345678^FS: 字符內(nèi)容, 代表輸出的字符 12345678 標準以^FS結(jié)束 ^PQ1,0,1,Y: 打印數(shù)量, 1打印數(shù)量,0暫停和切紙值,1每個序列號的副本數(shù),Y代表覆蓋暫停計數(shù)

2.核心代碼( 將ZPL轉(zhuǎn)換成IntPtr 然后調(diào)用 SendBytesToPrinter 方法)
//ZPL命令測試方法
public bool PrintZPL(string zpl)
{
return SendStringToPrinter("ZDesigner R110Xi4 300 dpi", zpl);
}
注: ZDesigner R110Xi4 300 dpi 是打印機的名稱 /// <summary>
/// 內(nèi)容打印
/// </summary>
/// <param name="szPrinterName">打印機名稱</param>
/// <param name="szString">打印的SBPL指令</param>
/// <returns></returns>
public bool SendStringToPrinter(string szPrinterName, string szString)
{
IntPtr pBytes;
int dwCount;
dwCount = szString.Length;
pBytes = Marshal.StringToCoTaskMemAnsi(szString);
SendBytesToPrinter(szPrinterName, pBytes, dwCount);
Marshal.FreeCoTaskMem(pBytes);
return true;
} // Structure and API declarions:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOCINFOA
{
[MarshalAs(UnmanagedType.LPStr)]
public string pDocName;
[MarshalAs(UnmanagedType.LPStr)]
public string pOutputFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pDataType;
}
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, int pd);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);
[DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);
public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
{
Int32 dwError = 0, dwWritten = 0;
IntPtr hPrinter = new IntPtr(0);
DOCINFOA di = new DOCINFOA();
bool bSuccess = false; // Assume failure unless you specifically succeed.
di.pDocName = "labelprint";
di.pDataType = "RAW";
// Open the printer.
if (OpenPrinter(szPrinterName, out hPrinter, 0))
{
// Start a document.
if (StartDocPrinter(hPrinter, 1, di))
{
// Start a page.
if (StartPagePrinter(hPrinter))
{
// Write your bytes.
bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
EndPagePrinter(hPrinter);
}
EndDocPrinter(hPrinter);
}
ClosePrinter(hPrinter);
}
// If you did not succeed, GetLastError may give more information
// about why not.
if (bSuccess == false)
{
dwError = Marshal.GetLastWin32Error();
}
return bSuccess;
}3.最終效果

原理
*: 看官方的API沒有實際的例子不好學習和了解怎么辦? 同時, 官方提供的標簽設計軟件(bartender)是可以將數(shù)據(jù)預先設置好,
導出本地文件的,這樣更加方便學習。
1.打開已經(jīng)破解版本的Bartender9.4演示如何將設計的標簽導出本地文件,然后查看ZPL指令.
>1.打開Bartender9.4

>2..選擇一個新的標簽格式即可, 一直下一步, 直到進入主界面, 給標簽添加一個文本數(shù)據(jù): 12345678 為例

>3.然后選擇打印按鈕

>4.勾選打印至文件, 保存至本地文件。

>5.打開剛才保存的文件, 找到里面的內(nèi)容

里面的內(nèi)容, 由兩個 ^XA ~ ^XZ 組成, 還有一些XML標簽組成。 很明顯, 第二個 ^XA-^XZ 是我們打印的實際內(nèi)容指令;
>6. 像圖中的 <xpml>標簽 <page>標簽, 這些應該是軟件里面的數(shù)據(jù)格式, 肯定沒用處的, 所以我們找到需要的內(nèi)容即可, 然后放在測試程序里面。


注: 調(diào)用代碼
/// <summary>
/// 測試ZPL命令執(zhí)行
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_print_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(txt_zpl.Text)) return;
SendStringToPrinte("ZDesigner R110Xi4 300 dpi",txt_zpl.Text);
} public static bool SendStringToPrinter(string szPrinterName, string szString)
{
IntPtr pBytes;
Int32 dwCount;
dwCount = szString.Length;
pBytes = Marshal.StringToCoTaskMemAnsi(szString);
SendBytesToPrinter(szPrinterName, pBytes, dwCount);
Marshal.FreeCoTaskMem(pBytes);
return true;
}注: 由于標簽紙的大小問題, 在設置標簽模板的時候, 我是選定了標簽的長寬, 如果出現(xiàn)打印不出來
或者顯示不全的, 可以在標簽模板設置好長寬和條碼的位置即可
模板打印
代碼貼了這么多, 可能還不知道引用了什么DLL, 指令也是剛剛接觸,可能只有博主自己懂, 那還有沒有更好更簡單的方法實現(xiàn)呢?
解決方案: 《模板打印》
1.設置好打印的標簽模板
工具:Bartender9.4
2.用代碼給調(diào)用模板賦值
3.調(diào)用打印
Bartender
1. Bartender 官方提供的標簽設計軟件, 同時具體所有的打印功能。
Bartender標簽軟件內(nèi)部原理也無非一樣:1.設計好標簽數(shù)據(jù)。2.打印的時候生成指令的語言發(fā)送至打印機打印。
同時Bartender也可以將設計好的樣式導出模板,用于外部賦值參數(shù)打印。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
VS2019配置OpenCV4.1.0詳細教程與測試代碼(推薦)
這篇文章主要介紹了VS2019配置OpenCV4.1.0詳細教程與測試代碼,本文通過截圖實例代碼相結(jié)合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03
unity自帶尋路(導航)系統(tǒng) Nav Mesh導航網(wǎng)格
這篇文章主要為大家詳細介紹了unity自帶尋路(導航)系統(tǒng),Nav Mesh導航網(wǎng)格,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11
C#/VB.NET實現(xiàn)在 Word 中插入水印?
這篇文章主要介紹了C#/VB.NET實現(xiàn)在 Word 中插入水印,水印是指在 Word 文檔的背景中以淡色或灰色顯示的文本或圖像。文章圍繞主題展開介紹,需要的朋友可以參考一下2022-08-08

