Zebra 打印机 - 不打印 PNG 流 *提供了我自己的答案*

Zebra Printer - Not Printing PNG Stream *Provided my own answer*

我想我已经非常接近打印了。然而它仍然不是。没有抛出异常,它似乎确实击中了斑马打印机,但没有。这是一个远景,因为我认为大多数人都处于与我相同的位置并且对此知之甚少。任何人都可以提供任何帮助,无论多么小,我都会失去生活的意志

using (var response = request.GetResponse())
            {
                using (var responseStream = response.GetResponseStream())
                {
                    using (var stream = new MemoryStream())
                    {
                        if (responseStream == null)
                        {
                            return;
                        }

                        responseStream.CopyTo(stream);
                        stream.Position = 0;

                        using (var zipout = ZipFile.Read(stream))
                        {
                            using (var ms = new MemoryStream())
                            {
                                foreach (var e in zipout.Where(e => e.FileName.Contains(".png")))
                                {
                                    e.Extract(ms);
                                }

                                if (ms.Length <= 0)
                                {
                                    return;
                                }

                                var binaryData = ms.ToArray();

                                byte[] compressedFileData;

                                //  Compress the data using the LZ77 algorithm.
                                using (var outStream = new MemoryStream())
                                {
                                    using (var compress = new DeflateStream(outStream, CompressionMode.Compress, true))
                                    {
                                        compress.Write(binaryData, 0, binaryData.Length);
                                        compress.Flush();
                                        compress.Close();
                                    }
                                    compressedFileData = outStream.ToArray();
                                }

                                //  Encode the compressed data using the MIME Base64 algorithm.
                                var base64 = Convert.ToBase64String(compressedFileData);

                                //  Calculate a CRC across the encoded data.
                                var crc = Calc(Convert.FromBase64String(base64));

                                //  Add a unique header to differentiate the new format from the existing ASCII hexadecimal encoding.
                                var finalData = string.Format(":Z64:{0}:{1}", base64, crc);

                                var zplToSend = "~DYR:LOGO,P,P," + finalData.Length + ",," + finalData;
                                const string PrintImage = "^XA^FO0,0^IMR:LOGO.PNG^FS^XZ";

                                try
                                {
                                    var client = new System.Net.Sockets.TcpClient();
                                    client.Connect(IpAddress, Port);

                                    var writer = new StreamWriter(client.GetStream(), Encoding.UTF8);
                                    writer.Write(zplToSend);
                                    writer.Flush();
                                    writer.Write(PrintImage);
                                    writer.Close();
                                    client.Close();
                                }
                                catch (Exception ex)
                                {
                                    // Catch Exception
                                }
                            }
                        }
                    }
                }
            }

    private static ushort Calc(byte[] data)
    {
        ushort wCrc = 0;

        for (var i = 0; i < data.Length; i++)
        {
            wCrc ^= (ushort)(data[i] << 8);

            for (var j = 0; j < 8; j++)
            {
                if ((wCrc & 0x8000) != 0)
                {
                    wCrc = (ushort)((wCrc << 1) ^ 0x1021);
                }
                else
                {
                    wCrc <<= 1;
                }
            }
        }

        return wCrc;
    }

以下代码对我有用。问题是命令,这些非常非常重要!下面是我用过的命令概览,更多可以参考here

PrintImage

^XA 开始格式说明 ^XA 命令用于 ZPL II 代码的开头。它是左括号,表示新标签格式的开始。此命令替换为单个 ASCII 控制字符 STX(control-B,十六进制 02)。格式 ^XA 注释 有效的 ZPL II 格式要求标签格式应以 ^XA 命令开始并以 ^XZ 命令结束。

^FO 字段原点描述 ^FO 命令设置字段原点,相对于标签原点 (^LH) 位置。 ^FO 通过定义与旋转无关的沿 x 轴和 y 轴的点来设置字段区域的左上角。格式 ^FOx,y,z

  • x = x 轴位置(以点为单位)接受的值:0 到 32000 默认值 值:0
  • y = y 轴位置(以点为单位)接受的值:0 到 32000 默认值:0
  • z = justification z参数只是 固件版本 V60.14.x、V50.14.x 或更高版本支持。公认 值:0 = 左对齐 1 = 右对齐 2 = 自动 理由(取决于脚本)默认值:最后接受 ^FW 值或 ^FW 默认值

^IM 图像移动 描述 ^IM 命令将图像从存储区域直接移动到位图中。该命令与 ^XG 命令(调用图形)相同,只是没有尺寸参数。格式 ^IMd:o.x

  • d = 存储对象的位置接受值:R:、E:、B: 和 A:默认值:搜索优先级
  • o = 对象名称接受值:1 到 8 个字母数字字符默认值:如果未指定名称,则使用 UNKNOWN
  • x = 扩展名固定值:.GRF、.PNG

^FS 字段分隔符说明 ^FS 命令表示字段定义的结尾。或者,^FS 命令也可以作为单个 ASCII 控制代码 SI(Control-O,十六进制 0F)发出。格式 ^FS

^XZ 结束格式说明 ^XZ 命令是结束(结束)括号。它指示标签格式的结束。收到此命令时,将打印标签。此命令也可以作为单个 ASCII 控制字符 ETX(Control-C,十六进制 03)发出。 Format ^XZ Comments 标签格式必须以 ^XA 命令开始并以 ^XZ 命令结束才能成为有效的 ZPL II 格式。

zplToSend

^MN 媒体跟踪 说明 此命令指定正在使用的媒体类型和以点为单位的黑标偏移量。此项目符号列表显示与此命令关联的媒体类型:

  • 连续介质 – 这种介质没有物理特征(例如网状物、缺口、穿孔、黑标)来分隔标签。标签长度由 ^LL 命令确定。
  • Continuous Media,可变长度 – 与 Continuous Media 相同,但如果打印标签的部分超出定义的标签长度​​,标签尺寸将自动扩展以包含它们。此标签长度扩展仅适用于当前标签。请注意,^MNV 仍然需要使用 ^LL 命令来定义所需的初始标签长度。
  • 非连续介质 – 这种介质具有某种类型的物理特征(例如网状、凹口、穿孔、黑标)来分隔标签。

格式 ^MNa,b

  • a = media being used 接受值:N = continuous media Y = non-continuous media web sensing d, e W = non-continuous media web sensing d, e M = non-continuous media mark sensing A = auto - 在校准期间检测介质类型 d, f V = 连续介质,可变长度 g 默认值:必须输入值或忽略命令
  • b = 黑色标记偏移量(以点为单位) 这设置了介质标记相对于文档分隔点的预期位置。如果设置为 0,则应在分离点找到介质标记。 (即穿孔、切割点等)所有值都以点列出。除非 a 参数设置为 M,否则忽略此参数。如果缺少此参数,则使用默认值。可接受的值: -80 到 283 对于热敏打印机 -240 到 566 对于 600 dpi 打印机 -75 到 283 对于 KR403 打印机 -120 到 283 对于所有其他打印机默认值:0

~DY 下载对象 描述 ~DY 命令以任何支持的格式下载到打印机图形对象或字体。可以使用此命令代替 ~DG 以获得更多保存和加载选项。 ~DY 是在固件高于 X.13 的打印机上下载 TrueType 字体的首选命令。它比 ~DU 快。 ~DY 命令还支持下载无线证书文件。格式 ~DYd:f,b,x,t,w,data

备注 使用证书文件时,您的打印机支持: - 使用隐私增强邮件 (PEM) 格式的证书文件。 - 使用客户端证书和私钥作为两个文件,分别下载。 - 为 EAP-FAST 使用可导出的 PAC 文件。 - Zebra 建议使用 Linear sty

  • d = 文件位置 在固件版本 V60.15.x、V50.15.x 或更高版本中,.NRD 和 .PAC 文件位于 E:。接受值:R:、E:、B: 和 A:默认值:R:
  • f = 文件名接受值:1 到 8 个字母数字字符默认值:如果未指定名称,则使用 UNKNOWN
  • b = 数据字段中下载的格式 .TTE 和 .TTF 仅在固件版本 V60.14.x、V50.14.x 或更高版本中受支持。可接受的值: A = 未压缩(ZB64、ASCII) B = 未压缩(.TTE、.TTF、二进制) C = AR 压缩(仅由 Zebra 的 BAR-ONE® v5 使用) P = 便携式网络图形 (.PNG) - ZB64编码默认值:必须指定一个值

clearDownLabel

^ID 说明 ^ID 命令从存储区中删除对象、图形、字体和存储格式。可以有选择地或成组地删除对象。此命令可在打印格式中用于在保存新对象之前删除对象,或在独立格式中用于删除对象。

图像名称和扩展名支持使用星号 (*) 作为通配符。这使您可以轻松删除选定的对象组。格式 ^IDd:o.x

  • d = 存储对象的位置接受值:R:、E:、B: 和 A:默认值:R:
  • o = 对象名称接受值:任何 1 到 8 个字符的名称默认值:如果未指定名称,则使用 UNKNOWN
  • x = extension Accepted Values: 任何符合 Zebra 约定的扩展名 默认值:.GRF

        const string PrintImage = "^XA^FO0,0,0^IME:LOGO.PNG^FS^XZ";
        var zplImageData = string.Empty;
    
            using (var response = request.GetResponse())
            {
                using (var responseStream = response.GetResponseStream())
                {
                    using (var stream = new MemoryStream())
                    {
                        if (responseStream == null)
                        {
                            return;
                        }
    
                        responseStream.CopyTo(stream);
                        stream.Position = 0;
    
                        using (var zipout = ZipFile.Read(stream))
                        {
                            using (var ms = new MemoryStream())
                            {
                                foreach (var e in zipout.Where(e => e.FileName.Contains(".png")))
                                {
                                    e.Extract(ms);
                                }
    
                                if (ms.Length <= 0)
                                {
                                    return;
                                }
    
                                var binaryData = ms.ToArray();
    
                                foreach (var b in binaryData)
                                {
                                    var hexRep = string.Format("{0:X}", b);
                                    if (hexRep.Length == 1)
                                    {
                                        hexRep = "0" + hexRep;
                                    }
    
                                    zplImageData += hexRep;
                                }
    
                                var zplToSend = "^XA" + "^FO0,0,0" + "^MNN" + "~DYE:LOGO,P,P," + binaryData.Length + ",," + zplImageData + "^XZ";
    
                                var label = GenerateStreamFromString(zplToSend);
    
                                var client = new System.Net.Sockets.TcpClient();
                                client.Connect(IpAddress, Port);
    
                                label.CopyTo(client.GetStream());
                                label.Flush();
    
                                client.Close();
    
                                var cmd = GenerateStreamFromString(PrintImage);
    
                                var client2 = new System.Net.Sockets.TcpClient();
                                client2.Connect(IpAddress, Port);
    
                                cmd.CopyTo(client2.GetStream());
                                cmd.Flush();
    
                                client2.Close();var clearDownLabel = GenerateStreamFromString("^XA^IDR:LOGO.PNG^FS^XZ");
    
                                var client3 = new System.Net.Sockets.TcpClient();
                                client3.Connect(IpAddress, Port);
    
                                clearDownLabel.CopyTo(client3.GetStream());
                                clearDownLabel.Flush();
    
                                client3.Close();
                            }
                        }
                    }
                }
            }
        }
    

一旦你知道怎么做就很容易了。 base64 中的 Zebra ZPL 徽标示例

Python3

import crcmod
import base64
crc16 = crcmod.predefined.mkCrcFun('xmodem')
s = hex(crc16(ZPL_LOGO.encode()))[2:]
print (f"crc16: {s}")

至少我可以这么说