我想通过android应用程序中的zebra打印机打印图像以及其他一些文本。我能够为文本数据创建zpl代码,但是我不得不为图像创建zpl代码。 zpl不支持base64代码。需要将图像转换为十六进制ASCII,并使用^ GF命令进行打印。
this Pastebin link
上提供了包含文本和图像的原始数据,并且可以在labelary viewer上查看。
有图像转换过程吗?
答案 0 :(得分:3)
我解决了问题,并发布了答案,以便其他人可以从该解决方案中受益。可以使用以下转换器类将位图图像转换为zpl代码。
public class ZPLConverter {
private int blackLimit = 380;
private int total;
private int widthBytes;
private boolean compressHex = false;
private static Map<Integer, String> mapCode = new HashMap<Integer, String>();
{
mapCode.put(1, "G");
mapCode.put(2, "H");
mapCode.put(3, "I");
mapCode.put(4, "J");
mapCode.put(5, "K");
mapCode.put(6, "L");
mapCode.put(7, "M");
mapCode.put(8, "N");
mapCode.put(9, "O");
mapCode.put(10, "P");
mapCode.put(11, "Q");
mapCode.put(12, "R");
mapCode.put(13, "S");
mapCode.put(14, "T");
mapCode.put(15, "U");
mapCode.put(16, "V");
mapCode.put(17, "W");
mapCode.put(18, "X");
mapCode.put(19, "Y");
mapCode.put(20, "g");
mapCode.put(40, "h");
mapCode.put(60, "i");
mapCode.put(80, "j");
mapCode.put(100, "k");
mapCode.put(120, "l");
mapCode.put(140, "m");
mapCode.put(160, "n");
mapCode.put(180, "o");
mapCode.put(200, "p");
mapCode.put(220, "q");
mapCode.put(240, "r");
mapCode.put(260, "s");
mapCode.put(280, "t");
mapCode.put(300, "u");
mapCode.put(320, "v");
mapCode.put(340, "w");
mapCode.put(360, "x");
mapCode.put(380, "y");
mapCode.put(400, "z");
}
public String convertFromImage(Bitmap image, Boolean addHeaderFooter) {
String hexAscii = createBody(image);
if (compressHex) {
hexAscii = encodeHexAscii(hexAscii);
}
String zplCode = "^GFA," + total + "," + total + "," + widthBytes + ", " + hexAscii;
if (addHeaderFooter) {
String header = "^XA " + "^FO0,0^GFA," + total + "," + total + "," + widthBytes + ", ";
String footer = "^FS" + "^XZ";
zplCode = header + zplCode + footer;
}
return zplCode;
}
private String createBody(Bitmap bitmapImage) {
StringBuilder sb = new StringBuilder();
int height = bitmapImage.getHeight();
int width = bitmapImage.getWidth();
int rgb, red, green, blue, index = 0;
char auxBinaryChar[] = {'0', '0', '0', '0', '0', '0', '0', '0'};
widthBytes = width / 8;
if (width % 8 > 0) {
widthBytes = (((int) (width / 8)) + 1);
} else {
widthBytes = width / 8;
}
this.total = widthBytes * height;
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++) {
rgb = bitmapImage.getPixel(w, h);
red = (rgb >> 16) & 0x000000FF;
green = (rgb >> 8) & 0x000000FF;
blue = (rgb) & 0x000000FF;
char auxChar = '1';
int totalColor = red + green + blue;
if (totalColor > blackLimit) {
auxChar = '0';
}
auxBinaryChar[index] = auxChar;
index++;
if (index == 8 || w == (width - 1)) {
sb.append(fourByteBinary(new String(auxBinaryChar)));
auxBinaryChar = new char[]{'0', '0', '0', '0', '0', '0', '0', '0'};
index = 0;
}
}
sb.append("\n");
}
return sb.toString();
}
private String fourByteBinary(String binaryStr) {
int decimal = Integer.parseInt(binaryStr, 2);
if (decimal > 15) {
return Integer.toString(decimal, 16).toUpperCase();
} else {
return "0" + Integer.toString(decimal, 16).toUpperCase();
}
}
private String encodeHexAscii(String code) {
int maxlinea = widthBytes * 2;
StringBuilder sbCode = new StringBuilder();
StringBuilder sbLinea = new StringBuilder();
String previousLine = null;
int counter = 1;
char aux = code.charAt(0);
boolean firstChar = false;
for (int i = 1; i < code.length(); i++) {
if (firstChar) {
aux = code.charAt(i);
firstChar = false;
continue;
}
if (code.charAt(i) == '\n') {
if (counter >= maxlinea && aux == '0') {
sbLinea.append(",");
} else if (counter >= maxlinea && aux == 'F') {
sbLinea.append("!");
} else if (counter > 20) {
int multi20 = (counter / 20) * 20;
int resto20 = (counter % 20);
sbLinea.append(mapCode.get(multi20));
if (resto20 != 0) {
sbLinea.append(mapCode.get(resto20)).append(aux);
} else {
sbLinea.append(aux);
}
} else {
sbLinea.append(mapCode.get(counter)).append(aux);
}
counter = 1;
firstChar = true;
if (sbLinea.toString().equals(previousLine)) {
sbCode.append(":");
} else {
sbCode.append(sbLinea.toString());
}
previousLine = sbLinea.toString();
sbLinea.setLength(0);
continue;
}
if (aux == code.charAt(i)) {
counter++;
} else {
if (counter > 20) {
int multi20 = (counter / 20) * 20;
int resto20 = (counter % 20);
sbLinea.append(mapCode.get(multi20));
if (resto20 != 0) {
sbLinea.append(mapCode.get(resto20)).append(aux);
} else {
sbLinea.append(aux);
}
} else {
sbLinea.append(mapCode.get(counter)).append(aux);
}
counter = 1;
aux = code.charAt(i);
}
}
return sbCode.toString();
}
public void setCompressHex(boolean compressHex) {
this.compressHex = compressHex;
}
public void setBlacknessLimitPercentage(int percentage) {
blackLimit = (percentage * 768 / 100);
}
}
用法示例: 您需要将图像转换为位图,转换为单色图像,然后进行十六进制acii转换。可以在labelary viewer处检查生成的zpl代码。
public class Utils {
public static String getZplCode(Bitmap bitmap, Boolean addHeaderFooter) {
ZPLConverter zp = new ZPLConverter();
zp.setCompressHex(true);
zp.setBlacknessLimitPercentage(50);
Bitmap grayBitmap = toGrayScale(bitmap);
return zp.convertFromImage(grayBitmap, addHeaderFooter);
}
public static Bitmap toGrayScale(Bitmap bmpOriginal) {
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap grayScale = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(grayScale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return grayScale;
}
}
here已引用了转换器代码,并增加了对Android使用的支持。
答案 1 :(得分:1)
我知道这已经完成了,但是我仍然对当前的答案感到很困惑。我想与可能需要的人分享我的经验。
首先,^ GFA代表像素的十六进制表示形式,但必须将其转换为可读文本(ASCII)。这是一个例子: 像素,白色= 1,黑色= 1
1011 0100转换为0xB4
在^ GFA的数据部分中,您需要使用B4作为数据。
如果我们选择
像素线1:1011 0100 1001 1100 = 0xBA 0x9C 像素行2:0011 0110 0001 1111 = 0x36 0x1F
生成的ZPL代码为:
^ XA(需要启动ZPL文件)
^ F10,0(水平偏移10像素,垂直偏移0像素)
^ GFA,4,4,2,BA9C361F(4是总字节数,2是每行的字节数)
^ F0 ^ XZ(文件结尾)
现在,有趣的一点。如何编写代码:
您需要一个灰度位图。您需要按像素访问位图。换句话说,一个包含整数的数组,其值在0到255之间变化。
使用该数组,您将每束8个像素,将其转换为十六进制值,然后转换为这些十六进制的文本表示形式。这是用Borland制作的c ++代码:
Graphics::TBitmap *imageFax = new Graphics::TBitmap();
unsigned char r;
unsigned char b;
ofstream outFile;
char listeHex[16];
int lineByteWidth;
int j;
int bytesCount = 0;
int widthHeight;
AnsiString testOut;
listeHex[0] = '0';
listeHex[1] = '1';
listeHex[2] = '2';
listeHex[3] = '3';
listeHex[4] = '4';
listeHex[5] = '5';
listeHex[6] = '6';
listeHex[7] = '7';
listeHex[8] = '8';
listeHex[9] = '9';
listeHex[10] = 'A';
listeHex[11] = 'B';
listeHex[12] = 'C';
listeHex[13] = 'D';
listeHex[14] = 'E';
listeHex[15] = 'F';
imageFax->Monochrome = true;
imageFax->PixelFormat = pf8bit;
imageFax->LoadFromFile("c:/testEtiquette/test.bmp"); //1200x300pixels bitmap test image
testOut = "c:/testEtiquette/outputfile.txt";
outFile.open(testOut.c_str());
imageFax->PixelFormat = pf8bit;
lineByteWidth = imageFax->Width/8;//Number of byte per line
widthHeight = lineByteWidth*imageFax->Height;//number of total byte to be written into the output file
testOut = "^XA^FO10,0^GFA,";
outFile << testOut.c_str() << widthHeight << ',' << widthHeight << ',' << lineByteWidth << ',' ;
for(int i = 0; i < imageFax->Height; i++)
{
unsigned char * pixel = (unsigned char *)imageFax->ScanLine[i];
bytesCount = 0;
b=0x00;
for(j = 0; j < imageFax->Width; j++)
{
//Here is the "switch" : what is not white (255) bit = 0, is black bit = 1.
//You can set your switch at whatever value you think is best. 0, 255 or anything between.
//I think 255 (white) is a good for my application
if(pixel[j] != 255)
{
b = b<<1;
//It is not white (hence black), we force value 1 into current position
b = b|0x01;
}
else
{
//Since it white, we move 1 bit to the left, pushing 0 into current position
b = b<<1;
b = b&0xFE;//Forcing a 0 in the current position
}
//If we've got a full byte (8-bits), we write it into the file
//This will lead into cutting off part of images that width is not a multiple of 8
if(j%8 == 7)
{
bytesCount++;
r = b;
r = r&0xF0; //Cleaning last digits
r=r>>4; //Moving the bits to the left 0xF0 => 0x0F
outFile << listeHex[r%16]; //Reaching into the conversion array listeHex, ASCII representation of hex value
r = listeHex[r%16]; //For debug only
r = b;
r = r&0x0F;//Cleaning first digits
outFile << listeHex[r%16];//Reaching into the conversion array listeHex, ASCII representation of hex value
r = listeHex[r%16]; //For debug only
b = 0x00; //Reseting for next Byte
}
}
}
testOut = "^F0^XZ";
outFile << testOut.c_str();
outFile.close();
delete imageFax;
这是我多年来关于Stackoverflow的第一篇文章。如果愿意,请投票!
:)
一些链接: ZPL PDF文档(有关图形转换,请参见第191页)https://www.zebra.com/content/dam/zebra/manuals/printers/common/programming/zpl-zbi2-pm-en.pdf (如果链接无效,请尝试在Google上尝试“ zpl-zbi2-pm-en.pdf”)
https://www.rapidtables.com/convert/number/binary-to-hex.html
答案 2 :(得分:0)
这是IP打印机的完整工作代码(型号GK420t ZPL,您可以访问任何IP打印机)。只需替换三件事 1)添加您 IP 地址 2)添加您的端口号 3) 将您添加为 PNG 文件路径
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Management;
using System.Net.Http;
using System.ServiceModel.Channels;
using System.Web;
using System.Web.Http;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.IO;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Printing;
using System.Net.NetworkInformation;
using System.Drawing.Imaging;
using System.Text.RegularExpressions;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Printing;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string ipAddress = "Your IP address";
int port = Your port number;
string zplImageData = string.Empty;
string filePath = @"your png file path";
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" + "^FO50" + "50^GFA,120000,120000,100" + 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
}
}
}
}