求ZPL的Binary B64与压缩Z64编码的C#实现示例
ZPL Z64编码C#实现及~DY命令参数说明
一、~DY命令参数t和w的明确说明
在ZPL命令~DYd:f,b,x,t,w,data中:
t(文件总字节数):必须填写压缩前的原始位图数据总字节数w(每行总字节数):必须填写压缩前的原始位图每行字节数(即(位图宽度 +7)/8的计算值)
打印机依赖这两个原始参数确定图像的尺寸和像素排列规则,压缩仅针对data部分,不影响图像基础属性的定义。
二、Z64编码完整实现代码
以下是可直接运行的C#代码,实现从位图(文件或内存对象)生成Z64编码的GRF数据,并输出正确的ZPL命令:
1. CRC16-CCITT校验类(Z64要求的校验算法)
public class Crc16Ccitt { private const ushort Polynomial = 0x1021; private readonly ushort _initialValue; private ushort _crc; public enum InitialCrcValue { Zeros, NonZero } public Crc16Ccitt(InitialCrcValue initialValue) { _initialValue = initialValue == InitialCrcValue.Zeros ? (ushort)0 : (ushort)0xFFFF; Reset(); } public void Reset() { _crc = _initialValue; } public ushort ComputeChecksum(byte[] bytes) { foreach (byte b in bytes) { for (int i = 0; i < 8; i++) { bool bit = ((b >> (7 - i) & 1) == 1); bool c15 = ((_crc >> 15 & 1) == 1); _crc <<= 1; if (c15 ^ bit) _crc ^= Polynomial; } } return _crc; } }
2. 位图转Z64编码核心方法
using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Runtime.InteropServices; using System.Globalization; [SupportedOSPlatform("windows")] private static string BitmapToZ64Grf(Bitmap bitmap, out int originalTotalBytes, out int originalRowWidth, out ushort crcValue) { BitmapData bitmapData = null; try { // 锁定1bpp索引格式的位图数据(ZPL仅支持单色位图) bitmapData = bitmap.LockBits( new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed); // 计算原始数据的每行字节数和总字节数 originalRowWidth = (bitmap.Width + 7) / 8; int stride = Math.Abs(bitmapData.Stride); originalTotalBytes = stride * bitmap.Height; // 读取原始像素数据并反色(ZPL中0代表黑色,1代表白色,与.NET位图逻辑相反) byte[] originalData = new byte[originalTotalBytes]; IntPtr scanPtr = bitmapData.Scan0; for (int y = 0; y < bitmap.Height; y++) { byte[] rowData = new byte[stride]; Marshal.Copy(scanPtr, rowData, 0, stride); // 仅保留有效行数据(stride因内存对齐可能大于originalRowWidth) for (int x = 0; x < originalRowWidth; x++) { originalData[y * originalRowWidth + x] = (byte)~rowData[x]; } scanPtr = (IntPtr)(scanPtr.ToInt64() + bitmapData.Stride); } // 使用Deflate压缩原始数据(Z64的压缩标准) byte[] compressedData; using (MemoryStream msCompress = new MemoryStream()) { using (DeflateStream deflateStream = new DeflateStream(msCompress, CompressionMode.Compress, leaveOpen: true)) { deflateStream.Write(originalData, 0, originalData.Length); } compressedData = msCompress.ToArray(); } // 转换为Base64编码,得到Z64格式数据 string z64Data = Convert.ToBase64String(compressedData); // 计算CRC校验值(针对压缩后的字节数组) Crc16Ccitt crc = new Crc16Ccitt(Crc16Ccitt.InitialCrcValue.Zeros); crcValue = crc.ComputeChecksum(compressedData); return z64Data; } finally { // 释放资源 if (bitmapData != null) { bitmap.UnlockBits(bitmapData); } bitmap.Dispose(); } }
三、生成ZPL输出示例
调用上述方法生成完整的ZPL打印命令:
// 加载位图(示例:从文件加载) using Bitmap bmp = new Bitmap("test.bmp"); string z64Data = BitmapToZ64Grf(bmp, out int originalTotalBytes, out int originalRowWidth, out ushort crc); // 构造~DY命令:D:表示存储在打印机DRAM,TEST.GRF是文件名,Z代表Z64编码 string zplCommand = $"^XA~DYD:TEST.GRF,Z,{originalTotalBytes},{originalRowWidth},{crc:X4},{z64Data}^XZ"; // 输出或发送ZPL到打印机 Console.WriteLine(zplCommand);
四、对用户提供代码的修正说明
用户原代码存在几个关键问题:
- 未将
bitmapData中的像素数据复制到处理数组,导致处理空数据 - 压缩后未关闭
DeflateStream,无法获取完整压缩数据 - CRC校验错误计算Base64字符串的ASCII字节,正确校验对象是压缩后的原始字节数组
- 未处理位图反色逻辑,会导致打印图像颜色反转
内容的提问来源于stack exchange,提问作者Chris Ward
相关产品推荐
相关产品推荐

