C# 将 PNG 图像打印到 zebra 网络打印机
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8818688/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Printing PNG images to a zebra network printer
提问by jb.
I am trying to find a way of printing images to a zebra and having a lot of trouble.
我试图找到一种将图像打印到斑马的方法,但遇到了很多麻烦。
According to the docs:
根据文档:
The first encoding, known as B64, encodes the data using the MIME Base64 scheme. Base64 is used to encode e-mail atachedments ...
Base64 encodes six bits to the byte, for an expantion of 33 percent over the un-enclosed data.
The second encoding, known as Z64, first compresses the data using the LZ77 algorithm to reduce its size. (This algorithm is used by the PKZIP and is intergral to the PNG graphics format.)
The compressed data is then encoded using the MIME Base64 scheme as described above.
A CRC will be calculated accross the Base64-encoded data.
第一种编码称为 B64,使用 MIME Base64 方案对数据进行编码。Base64 用于对电子邮件附件进行编码……
Base64 将 6 位编码为字节,比未封装的数据扩展 33%。
第二种编码称为 Z64,首先使用 LZ77 算法压缩数据以减小其大小。(该算法由 PKZIP 使用,并与 PNG 图形格式集成。)
然后使用上述 MIME Base64 方案对压缩数据进行编码。
将根据 Base64 编码数据计算 CRC。
But it doesn't have a great deal more info.
但它没有更多的信息。
Basically I was trying encoding with
基本上我正在尝试编码
private byte[] GetItemFromPath(string filepath)
{
using (MemoryStream ms = new MemoryStream())
{
using (Image img = Image.FromFile(filepath))
{
img.Save(ms, ImageFormat.Png);
return ms.ToArray();
}
}
}
Then trying to print with something like:
然后尝试使用以下内容进行打印:
var initialArray = GetItemFromPath("C:\RED.png");
string converted = Convert.ToBase64String(b);
PrintThis(string.Format(@"~DYRED.PNG,P,P,{1},0,:B64:
{0}
^XA
^F0200,200^XGRED.PNG,1,1^FS
^XZ", converted .ToString(), initialArray.Length));
From the sounds of it, either B64 or Z64 are both accepted.
从它的声音来看,B64或Z64都可以接受。
I've tried a few variations, and a couple of methods for generating the CRC and calculating the 'size'. But none seem to work and the download of the graphics to the printer is always getting aborted.
我尝试了一些变体,以及几种生成 CRC 和计算“大小”的方法。但是似乎没有任何工作,并且将图形下载到打印机总是中止。
Has anyone managed to accomplish something like this? Or knows where I am going wrong?
有没有人设法完成这样的事情?或者知道我哪里出错了?
回答by Ethan
After looking at the ZPL manual you need to calculate the Cyclic Redundancy Check(CRC) for the image. Here is some C Code that calculates the CRC (source):
查看 ZPL 手册后,您需要计算图像的循环冗余校验(CRC)。这是一些计算 CRC 的 C 代码(源代码):
// Update the CRC for transmitted and received data using
// the CCITT 16bit algorithm (X^16 + X^12 + X^5 + 1).
unsigned char ser_data;
static unsigned int crc;
crc = (unsigned char)(crc >> 8) | (crc << 8);
crc ^= ser_data;
crc ^= (unsigned char)(crc & 0xff) >> 4;
crc ^= (crc << 8) << 4;
crc ^= ((crc & 0xff) << 4) << 1;
You can also refer to Wikipedia's page on CRC, as it contains other code examples as well.
您还可以参考维基百科关于 CRC 的页面,因为它也包含其他代码示例。
https://en.wikipedia.org/wiki/Cyclic_redundancy_check
https://en.wikipedia.org/wiki/Cyclic_redundancy_check
Everything else you are sending down looks good. I would look into using one of the Zebra SDKs. I know the Android one will send an image to the printer and save it for you.
您发送的其他所有内容看起来都不错。我会考虑使用 Zebra SDK 之一。我知道 Android 会向打印机发送图像并为您保存。
回答by Warren
All credit for me coming to this answer was from LabView Forumuser Raydur. He posts a LabView solution that can be opened up in LabView to send images down. I personally didn't run it with my printer, I just used it to figure out the correct image code so I could replicate it in my code. The big thing that I was missing was padding my Hexadecimal code. For example: 1A is fine, but if you have just A, you need to pad a 0 in front of it to send 0A. The size of the file in the ZPL you are sending is also the original size of the byte array, not the final string representation of the data.
我得到这个答案的所有功劳都来自LabView 论坛用户 Raydur。他发布了一个 LabView 解决方案,可以在 LabView 中打开该解决方案以向下发送图像。我个人没有用我的打印机运行它,我只是用它来找出正确的图像代码,以便我可以在我的代码中复制它。我错过的重要事情是填充我的十六进制代码。例如:1A 可以,但是如果只有 A,则需要在其前面填充 0 才能发送 0A。您发送的 ZPL 中文件的大小也是字节数组的原始大小,而不是数据的最终字符串表示形式。
I've scoured many, many, many forums and Stackoverflow posts trying to figure this out because it seems like such a simple thing to do. I've tried every single solution posted elsewhere but I really wanted to just print a .PNG because the manual for my printer(Mobile QLN320) has support for it built in. It says to either send it in Base64 or Hexadecimal, and I tried both to no avail. For anyone wanting to do Base64, I found in a older manual that you need to manually calculate CRC codes for each packet you send so I chose to go with the easier Hexadecimal route. So here is the code I got to work!
我已经搜索了很多很多论坛和 Stackoverflow 帖子试图解决这个问题,因为这似乎是一件很简单的事情。我已经尝试了其他地方发布的所有解决方案,但我真的只想打印 .PNG,因为我的打印机(Mobile QLN320)手册内置了对它的支持。它说以 Base64 或十六进制发送,我试过了两者都无济于事。对于想要使用 Base64 的任何人,我在较旧的手册中发现您需要为发送的每个数据包手动计算 CRC 代码,因此我选择使用更简单的十六进制路由。所以这是我开始工作的代码!
string ipAddress = "192.168.1.30";
int port = 6101;
string zplImageData = string.Empty;
//Make sure no transparency exists. I had some trouble with this. This PNG has a white background
string filePath = @"C:\Users\Path\To\Logo.png";
byte[] binaryData = System.IO.File.ReadAllBytes(filePath);
foreach (Byte b in binaryData)
{
string hexRep = String.Format("{0:X}", b);
if (hexRep.Length == 1)
hexRep = "0" + hexRep;
zplImageData += hexRep;
}
string zplToSend = "^XA" + "^MNN" + "^LL500" + "~DYE:LOGO,P,P," + binaryData.Length + ",," + zplImageData+"^XZ";
string printImage = "^XA^FO115,50^IME:LOGO.PNG^FS^XZ";
try
{
// Open connection
System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient();
client.Connect(ipAddress, port);
// Write ZPL String to connection
System.IO.StreamWriter writer = new System.IO.StreamWriter(client.GetStream(),Encoding.UTF8);
writer.Write(zplToSend);
writer.Flush();
writer.Write(printImage);
writer.Flush();
// Close Connection
writer.Close();
client.Close();
}
catch (Exception ex)
{
// Catch Exception
}
回答by Mitch
The ZPL II Programming Guidedocuments the ~DGcommand and GRF format (page 124) to download images. Volume Twoadds details on an optional compression format (page 52).
该ZPL II编程指南文档的~DG命令和GRF格式(第124页)下载图像。第二卷添加了有关可选压缩格式的详细信息(第 52 页)。
First, you have to convert the image to a 1bpp bi-level image, then convert it to a hex-encoded string. You can further compress the image to reduce transmission time. You can then print the image with the ^IDcommand.
首先,您必须将图像转换为 1bpp 双层图像,然后将其转换为十六进制编码的字符串。您可以进一步压缩图像以减少传输时间。然后,您可以使用该^ID命令打印图像。
While there is inherent support for PNG images in the ~DYcommand, it is poorly documented and does not seem to work on certain models of printers. The ZB64 format is basically not documented, and attempts to get more information from Zebra support have been fruitless. If you have your heart set on ZB64, you can use the Java based Zebralink SDK(look to ImagePrintDemo.javaand com.zebra.sdk.printer.internal.GraphicsConversionUtilZpl.sendImageToStream).
虽然~DY命令中固有地支持 PNG 图像,但它的文档很差,似乎不适用于某些型号的打印机。ZB64 格式基本上没有文档记录,尝试从 Zebra 支持获取更多信息也没有结果。如果您对 ZB64 充满信心,则可以使用基于 Java 的 Zebralink SDK(查看ImagePrintDemo.java和com.zebra.sdk.printer.internal.GraphicsConversionUtilZpl.sendImageToStream)。
Once you have the command data, it can be sent via TCP/IP if the printer has a print-server, or it can be sent by writing in RAWformat to the printer.
一旦您拥有命令数据,如果打印机有打印服务器,它可以通过 TCP/IP 发送,或者可以通过写入RAW格式发送到打印机。
The code below prints a 5 kB PNG as a 13 kB compressed GRF (60 kB uncompressed):
下面的代码将 5 kB PNG 打印为 13 kB 压缩 GRF(60 kB 未压缩):
class Program
{
static unsafe void Main(string[] args)
{
var baseStream = new MemoryStream();
var tw = new StreamWriter(baseStream, Encoding.UTF8);
using (var bmpSrc = new Bitmap(Image.FromFile(@"label.png")))
{
tw.WriteLine(ZplImage.GetGrfStoreCommand("R:LBLRA2.GRF", bmpSrc));
}
tw.WriteLine(ZplImage.GetGrfPrintCommand("R:LBLRA2.GRF"));
tw.WriteLine(ZplImage.GetGrfDeleteCommand("R:LBLRA2.GRF"));
tw.Flush();
baseStream.Position = 0;
var gdipj = new GdiPrintJob("ZEBRA S4M-200dpi ZPL", GdiPrintJobDataType.Raw, "Raw print", null);
gdipj.WritePage(baseStream);
gdipj.CompleteJob();
}
}
class ZplImage
{
public static string GetGrfStoreCommand(string filename, Bitmap bmpSource)
{
if (bmpSource == null)
{
throw new ArgumentNullException("bmpSource");
}
validateFilename(filename);
var dim = new Rectangle(Point.Empty, bmpSource.Size);
var stride = ((dim.Width + 7) / 8);
var bytes = stride * dim.Height;
using (var bmpCompressed = bmpSource.Clone(dim, PixelFormat.Format1bppIndexed))
{
var result = new StringBuilder();
result.AppendFormat("^XA~DG{2},{0},{1},", stride * dim.Height, stride, filename);
byte[][] imageData = GetImageData(dim, stride, bmpCompressed);
byte[] previousRow = null;
foreach (var row in imageData)
{
appendLine(row, previousRow, result);
previousRow = row;
}
result.Append(@"^FS^XZ");
return result.ToString();
}
}
public static string GetGrfDeleteCommand(string filename)
{
validateFilename(filename);
return string.Format("^XA^ID{0}^FS^XZ", filename);
}
public static string GetGrfPrintCommand(string filename)
{
validateFilename(filename);
return string.Format("^XA^FO0,0^XG{0},1,1^FS^XZ", filename);
}
static Regex regexFilename = new Regex("^[REBA]:[A-Z0-9]{1,8}\.GRF$");
private static void validateFilename(string filename)
{
if (!regexFilename.IsMatch(filename))
{
throw new ArgumentException("Filename must be in the format "
+ "R:XXXXXXXX.GRF. Drives are R, E, B, A. Filename can "
+ "be alphanumeric between 1 and 8 characters.", "filename");
}
}
unsafe private static byte[][] GetImageData(Rectangle dim, int stride, Bitmap bmpCompressed)
{
byte[][] imageData;
var data = bmpCompressed.LockBits(dim, ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed);
try
{
byte* pixelData = (byte*)data.Scan0.ToPointer();
byte rightMask = (byte)(0xff << (data.Stride * 8 - dim.Width));
imageData = new byte[dim.Height][];
for (int row = 0; row < dim.Height; row++)
{
byte* rowStart = pixelData + row * data.Stride;
imageData[row] = new byte[stride];
for (int col = 0; col < stride; col++)
{
byte f = (byte)(0xff ^ rowStart[col]);
f = (col == stride - 1) ? (byte)(f & rightMask) : f;
imageData[row][col] = f;
}
}
}
finally
{
bmpCompressed.UnlockBits(data);
}
return imageData;
}
private static void appendLine(byte[] row, byte[] previousRow, StringBuilder baseStream)
{
if (row.All(r => r == 0))
{
baseStream.Append(",");
return;
}
if (row.All(r => r == 0xff))
{
baseStream.Append("!");
return;
}
if (previousRow != null && MatchByteArray(row, previousRow))
{
baseStream.Append(":");
return;
}
byte[] nibbles = new byte[row.Length * 2];
for (int i = 0; i < row.Length; i++)
{
nibbles[i * 2] = (byte)(row[i] >> 4);
nibbles[i * 2 + 1] = (byte)(row[i] & 0x0f);
}
for (int i = 0; i < nibbles.Length; i++)
{
byte cPixel = nibbles[i];
int repeatCount = 0;
for (int j = i; j < nibbles.Length && repeatCount <= 400; j++)
{
if (cPixel == nibbles[j])
{
repeatCount++;
}
else
{
break;
}
}
if (repeatCount > 2)
{
if (repeatCount == nibbles.Length - i
&& (cPixel == 0 || cPixel == 0xf))
{
if (cPixel == 0)
{
if (i % 2 == 1)
{
baseStream.Append("0");
}
baseStream.Append(",");
return;
}
else if (cPixel == 0xf)
{
if (i % 2 == 1)
{
baseStream.Append("F");
}
baseStream.Append("!");
return;
}
}
else
{
baseStream.Append(getRepeatCode(repeatCount));
i += repeatCount - 1;
}
}
baseStream.Append(cPixel.ToString("X"));
}
}
private static string getRepeatCode(int repeatCount)
{
if (repeatCount > 419)
throw new ArgumentOutOfRangeException();
int high = repeatCount / 20;
int low = repeatCount % 20;
const string lowString = " GHIJKLMNOPQRSTUVWXY";
const string highString = " ghijklmnopqrstuvwxyz";
string repeatStr = "";
if (high > 0)
{
repeatStr += highString[high];
}
if (low > 0)
{
repeatStr += lowString[low];
}
return repeatStr;
}
private static bool MatchByteArray(byte[] row, byte[] previousRow)
{
for (int i = 0; i < row.Length; i++)
{
if (row[i] != previousRow[i])
{
return false;
}
}
return true;
}
}
internal static class NativeMethods
{
#region winspool.drv
#region P/Invokes
[DllImport("winspool.Drv", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool OpenPrinter(string szPrinter, out IntPtr hPrinter, IntPtr pd);
[DllImport("winspool.Drv", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern UInt32 StartDocPrinter(IntPtr hPrinter, Int32 level, IntPtr di);
[DllImport("winspool.Drv", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool WritePrinter(
// 0
IntPtr hPrinter,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] pBytes,
// 2
UInt32 dwCount,
out UInt32 dwWritten);
#endregion
#region Structs
[StructLayout(LayoutKind.Sequential)]
internal struct DOC_INFO_1
{
[MarshalAs(UnmanagedType.LPWStr)]
public string DocName;
[MarshalAs(UnmanagedType.LPWStr)]
public string OutputFile;
[MarshalAs(UnmanagedType.LPWStr)]
public string Datatype;
}
#endregion
#endregion
}
/// <summary>
/// Represents a print job in a spooler queue
/// </summary>
public class GdiPrintJob
{
IntPtr PrinterHandle;
IntPtr DocHandle;
/// <summary>
/// The ID assigned by the print spooler to identify the job
/// </summary>
public UInt32 PrintJobID { get; private set; }
/// <summary>
/// Create a print job with a enumerated datatype
/// </summary>
/// <param name="PrinterName"></param>
/// <param name="dataType"></param>
/// <param name="jobName"></param>
/// <param name="outputFileName"></param>
public GdiPrintJob(string PrinterName, GdiPrintJobDataType dataType, string jobName, string outputFileName)
: this(PrinterName, translateType(dataType), jobName, outputFileName)
{
}
/// <summary>
/// Create a print job with a string datatype
/// </summary>
/// <param name="PrinterName"></param>
/// <param name="dataType"></param>
/// <param name="jobName"></param>
/// <param name="outputFileName"></param>
public GdiPrintJob(string PrinterName, string dataType, string jobName, string outputFileName)
{
if (string.IsNullOrWhiteSpace(PrinterName))
throw new ArgumentNullException("PrinterName");
if (string.IsNullOrWhiteSpace(dataType))
throw new ArgumentNullException("PrinterName");
IntPtr hPrinter;
if (!NativeMethods.OpenPrinter(PrinterName, out hPrinter, IntPtr.Zero))
throw new Win32Exception();
this.PrinterHandle = hPrinter;
NativeMethods.DOC_INFO_1 docInfo = new NativeMethods.DOC_INFO_1()
{
DocName = jobName,
Datatype = dataType,
OutputFile = outputFileName
};
IntPtr pDocInfo = Marshal.AllocHGlobal(Marshal.SizeOf(docInfo));
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Marshal.StructureToPtr(docInfo, pDocInfo, false);
UInt32 docid = NativeMethods.StartDocPrinter(hPrinter, 1, pDocInfo);
if (docid == 0)
throw new Win32Exception();
this.PrintJobID = docid;
}
finally
{
Marshal.FreeHGlobal(pDocInfo);
}
}
/// <summary>
/// Write the data of a single page or a precomposed PCL document
/// </summary>
/// <param name="data"></param>
public void WritePage(Stream data)
{
if (data == null)
throw new ArgumentNullException("data");
if (!data.CanRead && !data.CanWrite)
throw new ObjectDisposedException("data");
if (!data.CanRead)
throw new NotSupportedException("stream is not readable");
if (!NativeMethods.StartPagePrinter(this.PrinterHandle))
throw new Win32Exception();
byte[] buffer = new byte[0x14000]; /* 80k is Stream.CopyTo default */
uint read = 1;
while ((read = (uint)data.Read(buffer, 0, buffer.Length)) != 0)
{
UInt32 written;
if (!NativeMethods.WritePrinter(this.PrinterHandle, buffer, read, out written))
throw new Win32Exception();
if (written != read)
throw new InvalidOperationException("Error while writing to stream");
}
if (!NativeMethods.EndPagePrinter(this.PrinterHandle))
throw new Win32Exception();
}
/// <summary>
/// Complete the current job
/// </summary>
public void CompleteJob()
{
if (!NativeMethods.EndDocPrinter(this.PrinterHandle))
throw new Win32Exception();
}
#region datatypes
private readonly static string[] dataTypes = new string[]
{
// 0
null,
"RAW",
// 2
"RAW [FF appended]",
"RAW [FF auto]",
// 4
"NT EMF 1.003",
"NT EMF 1.006",
// 6
"NT EMF 1.007",
"NT EMF 1.008",
// 8
"TEXT",
"XPS_PASS",
// 10
"XPS2GDI"
};
private static string translateType(GdiPrintJobDataType type)
{
return dataTypes[(int)type];
}
#endregion
}
public enum GdiPrintJobDataType
{
Unknown = 0,
Raw = 1,
RawAppendFF = 2,
RawAuto = 3,
NtEmf1003 = 4,
NtEmf1006 = 5,
NtEmf1007 = 6,
NtEmf1008 = 7,
Text = 8,
XpsPass = 9,
Xps2Gdi = 10
}
回答by hector-j-rivas
For some reason I cannot get B64 to work, but luckily I was able to Google my way into making Z64 work (in 3 soul-searching days or so) using plain old JavaScript.
出于某种原因,我无法让 B64 工作,但幸运的是,我能够使用普通的旧 JavaScript 谷歌使 Z64 工作(在 3 天左右的自我反省中)。
Somewhere else on the ZPL programming Guide you stumble upon the The CISDFCRC16 command--let's be cryptic, why not--section, which states:
在 ZPL 编程指南的其他地方,您偶然发现了 CISDFCRC16 命令——让我们神秘一点,为什么不——部分,其中指出:
"The value of the field is calculated the CRC-16 for the contents of a specified file using the CRC16-CCITT polynomial which is x^16 + x^12 + x^5 + 1. It is calculated using an initial CRC of 0x0000."
“该字段的值是使用 CRC16-CCITT 多项式计算指定文件内容的 CRC-16,即 x^16 + x^12 + x^5 + 1。它是使用 0x0000 的初始 CRC 计算的.”
Japanglish aside, you can now check out the Catalogue of parametrised CRC algorithms with 16 bits(http://reveng.sourceforge.net/crc-catalogue/16.htm) and look for the XMODEM algorithm, which happens to be
除了 Japanglish,您现在可以查看16 位参数化 CRC 算法目录( http://reveng.sourceforge.net/crc-catalogue/16.htm) 并查找 XMODEM 算法,它恰好是
width=16 poly=0x1021 init=0x0000 refin=false refout=false
xorout=0x0000 check=0x31c3 name="XMODEM"
Aha. I then started looking for the rest of the code I needed and stumbled upon the following:
啊哈。然后我开始寻找我需要的其余代码并偶然发现以下内容:
- LZ77-Algorithm-Based JavaScript Compressor (http://lab.polygonpla.net/js/tinylz77.html)
- base-64.js (https://github.com/beatgammit/base64-js/blob/master/lib/b64.js)
- Lammert Bies' 2008 CRC Library (http://www.lammertbies.nl/comm/info/crc-calculation.html) ported from ANSI C--with the precaution to bitwise-AND with 0xffff the update function return value since JavaScript treats every number as a 32-bit signed integer.
- LZ77-基于算法的 JavaScript 压缩器 ( http://lab.polygonpla.net/js/tinylz77.html)
- base-64.js ( https://github.com/beatgammit/base64-js/blob/master/lib/b64.js)
- Lammert Bies 的 2008 年 CRC 库 ( http://www.lammertbies.nl/comm/info/crc-calculation.html) 从 ANSI C 移植过来 - 小心地使用 0xffff 按位与更新函数返回值,因为 JavaScript 处理每个数字作为 32 位有符号整数。
So I read the file as a byte array (Uint8Array), parse it as a string, compress it with LZ77, turn that back into a byte array and encode it using base64, at which point I calculate the CRC and paste it all into my ZPL ~DT command for savings of about 40%. Beautiful.
所以我将文件作为字节数组(Uint8Array)读取,将其解析为字符串,用 LZ77 压缩它,将其转换回字节数组并使用 base64 对其进行编码,此时我计算 CRC 并将其全部粘贴到我的ZPL ~DT 命令可节省约 40%。美丽的。
Unfortunately I'm developing a proprietary solution so I cannot post any code.
不幸的是,我正在开发一个专有解决方案,所以我不能发布任何代码。
Good luck!
祝你好运!
-What one man did another can do.
- 一个人做的另一个人可以做。
回答by Cody G
Although this question has the C# tag, several other answers are not strictly C#, so here is an answer using Node 8.5+ (javascript), using java and the Zebra SDK. The same steps are very similar for any .NET language that can also use the SDK and perform a POST request.
虽然这个问题有 C# 标签,但其他几个答案并不是严格的 C#,所以这里是一个使用 Node 8.5+ (javascript),使用 java 和Zebra SDK的答案。对于也可以使用 SDK 并执行 POST 请求的任何 .NET 语言,相同的步骤非常相似。
const { promisify } = require('util');
const java = require('java');
java.asyncOptions = {
asyncSuffix: "",
syncSuffix: "Sync",
promiseSuffix: "Promise", // Generate methods returning promises, using the suffix Promise.
promisify
};
// Include all .jar's under C:\Program Files\Zebra Technologies\link_os_sdk\PC\v2.14.5198\lib
// in your lib folder
java.classpath.push(__dirname + "/lib/ZSDK_API.jar");
var ByteArrayOutputStream = java.import('java.io.ByteArrayOutputStream');
var ZebraImageFactory = java.import('com.zebra.sdk.graphics.ZebraImageFactory');
var PrinterUtil = java.import('com.zebra.sdk.printer.PrinterUtil');
const main = async function () {
let path = `C:\images\yourimage.png`;
let os = new ByteArrayOutputStream();
let image = await ZebraImageFactory.getImagePromise(path);
PrinterUtil.convertGraphicPromise("E:IMAGE.PNG", image, os);
console.log(os.toStringSync()); // junk:Z64:~:CRC
console.log('done');
};
main();
Then you can print the image via ZPL like:
然后您可以通过 ZPL 打印图像,例如:
^XA
~DYE:IMAGE,P,P,1,,:B64:<YOURB64>:<YOURCRC>
^FO0,0^IME:IMAGE.PNG
^XZ
Using something like
使用类似的东西
await axios.post(`${printer.ip}/pstprnt`, zpl);

