借鉴的内容
斑马打印机图片打印的逻辑
public class ZplImage {
// private static List<Map<String,Integer>> compressDictionary =new ArrayList<>();//ZPL压缩字典
private static int[] dictionary=new int[39];//存放数值
private static String[] compressDictionary=new String[39];//存放对应的字符
//初始化数据字典
private static void InitCompressCode()
{
//G H I J K L M N O P Q R S T U V W X Y 对应1,2,3,4……18,19。
//g h i j k l m n o p q r s t u v w x y z 对应20,40,60,80……340,360,380,400。
for (int i = 0; i < 19; i++)
{ dictionary[i]=i+1;
char character=(char)(71+i);
compressDictionary[i]=String.valueOf(character);
Log.d(TAG, "InitCompressCode: "+compressDictionary[i]);
}
for (int i = 0; i < 20; i++)
{
dictionary[i+19]=(i + 1) * 20;
char character=(char)(103+i);
compressDictionary[i+19]=String.valueOf(character);
}
}
// public static Bitmap uploadImage(String param1,String param2,String param3,String param4,String param5,String param6){//去网上下载图片
// try {
// URL url = new URL("");
// HttpURLConnection con = (HttpURLConnection)url.openConnection();
//
// // 允许Input、Output,不使用Cache
// con.setDoInput(true);
// con.setDoOutput(true);
// con.setUseCaches(false);
// con.setConnectTimeout(50000);
// con.setReadTimeout(50000);
// // 设置传送的method=POST
// con.setRequestMethod("POST");
// //在一次TCP连接中可以持续发送多份数据而不会断开连接
// con.setRequestProperty("Connection", "Keep-Alive");
// //设置编码
// con.setRequestProperty("Charset", "UTF-8");
// //text/plain能上传纯文本文件的编码格式
// con.setRequestProperty("Content-Type", "image/jpeg");
// DataOutputStream ds = new DataOutputStream(con.getOutputStream());
// Bitmap bmp = BitmapFactory.decodeStream(con.getInputStream());//获取输入流
// return bmp;
// } catch (Exception e) {
// e.printStackTrace();
// return null;
// }
// }
/**
* 主要将24位图变成单色图,也就是从三个字节代表一个像素转化为
* 将一个像素用1bit来表示,然后将它转化为16进制的String
* 除了纯白的都当做是黑色来进行处理,主要用在热敏打印机的标签打印上
* @return 返回拼接好的模版指令
*/
public static String getHexByChange2bit(Bitmap bm) {
// BitmapFactory.Options bfoOptions = new BitmapFactory.Options();
// bfoOptions.inScaled = false;
// Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.ff,bfoOptions);
int w=bm.getWidth();//图片的实际像素宽度
int h=bm.getHeight();//图片的实际像素高度
Log.d(TAG, "getHexByChange2bit: 实际的宽度:"+w+"高度:"+h);
int width = (bm.getWidth() / 8 + ((bm.getWidth() % 8 == 0) ? 0 : 1));//一个像素点代表1bit,每8bit是一个字节。所以即使多一个像素,也要多打一个字节,换算后的宽度字节
int offset;
if ((bm.getWidth()%8)==0){
offset=0;//不需要补位
}else{
offset=8-bm.getWidth()%8;//凑完整的一个字节需要补足的bit数
}
Log.d(TAG, "getHexByChange2bit: 换算后的字节宽度:"+width+"补位:"+offset);
String begain="~DGR:ZLOGO.GRF,"+width*h+","+width+",";//模版的头指令,ZLOGO.GRF名字,width*h总的字节数,width一行的字节数
StringBuilder stringBuilder=new StringBuilder();//用来存储zpl
// stringBuilder.append("~DGR:ZLOGO.GRF,"+width*h+","+width+",");
int result=0;//用来存储16进制
int x;
for (int i=0;i<h;i++){
for (int j=0;j<w;j++){//第几行第几列的像素点,实际存在的像素点
int realColor = bm.getPixel(j, i);//实际上这个像素点的颜色
int color=0;//用来储存换算后的像素的颜色,打印机0代表白色,1代表黑色
if (realColor<=-10000000){//如果不是纯白色就全部当成黑色处理,这里的-1代表实际图片颜色的纯白色
color=1;
}else{
color=0;
}
x=(j+1)%4;//代表是16进制中的第几位,1个16进制是4位
result=result+change2hex(x,color);//相加
if (x==0){
String hex=Integer.toHexString(result);//把int转化为16进制的字符
stringBuilder.append(hex);//将字符拼接起来
result=0;//清空
}
if (j==(w-1)&&offset!=0){//如果需要补位的话,在最后一个像素换算过后补位
String hex=Integer.toHexString(result);//把int转化为16进制的字符
stringBuilder.append(hex);//将字符拼接起来
result=0;//清空
}
}
if (offset>4){//说明要补一个16进制的0
stringBuilder.append("0");//补上一个16进制
}
}
InitCompressCode();//初始化
Log.d(TAG, "getHexByChange2bit初始化完成");
String hex=CompressLZ77(stringBuilder.toString());
Log.d(TAG, "getHexByChange2bit:计算出来的长度"+(width*h));
Log.d(TAG, "getHexByChange2bit:压缩后hex长度"+hex.length()/2);
Log.d(TAG, "getHexByChange2bit: 完整版"+begain+hex);
return begain+hex;//获取存储模版的指令
}
/**
*
* @param x 表示第几个位置上
* @param color 当前的颜色
* @return String 按照位置转化成相应的 例如在第一位上的1 代表的是 16进制的最高位的1
*/
public static int change2hex(int x,int color){
switch (x){
case 1:
color=color*8;
break;
case 2:
color=color*4;
break;
case 3:
color=color*2;
break;
case 4:
color=color*1;
break;
}
return color;
}
//zpl压缩指令代码
private static String CompressLZ77(String text)
{
//将转成16进制的文本进行压缩
String result = "";
char[] arrChar = text.toCharArray();
int count = 1;
for (int i = 1; i < text.length(); i++)
{
if (arrChar[i - 1] == arrChar[i])//前面的值和后面的值是相等的
{
count++;//个数加1
}
else
{
result += convertNumber(count) + arrChar[i - 1];//遇到后面和前面不一样的值
count = 1;
}
if (i == text.length() - 1)//最后一个字符
{
result += convertNumber(count) + arrChar[i];
}
}
return result;
}
private static String convertNumber(int count)
{
//将连续的数字转换成LZ77压缩代码,如000可用I0表示。
String result = "";
if (count > 1)//只有当有连续的时候才有转化的必要
{
while (count > 0)
{
for (int i = dictionary.length-1; i >= 0; i--)
{
if (count >=dictionary[i])
{
result += compressDictionary[i];
count -= dictionary[i];
break;
}
}
}
}
return result;
}
/**
* 创建二维码
*
* @param content content
* @param widthPix widthPix
* @param heightPix heightPix
* @return 二维码
*/
public static Bitmap createQRCode(String content, int widthPix, int heightPix) {
try {
if (content == null || "".equals(content)) {
return null;
}
// 配置参数
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
// 容错级别
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 图像数据转换,使用了矩阵转换
BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, widthPix,
heightPix, hints);
int[] pixels = new int[widthPix * heightPix];
// 下面这里按照二维码的算法,逐个生成二维码的图片,
// 两个for循环是图片横列扫描的结果
for (int y = 0; y < heightPix; y++) {
for (int x = 0; x < widthPix; x++) {
if (bitMatrix.get(x, y)) {
pixels[y * widthPix + x] = 0xff000000;
} else {
pixels[y * widthPix + x] = 0xffffffff;
}
}
}
// 生成二维码图片的格式,使用ARGB_8888
Bitmap bitmap = Bitmap.createBitmap(widthPix, heightPix, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, widthPix, 0, 0, widthPix, heightPix);
Matrix matrix = new Matrix();
matrix.postScale(1,1);
bitmap=Bitmap.createBitmap(bitmap,0,0,widthPix,heightPix,matrix,true);
// if (logoBm != null) {
// bitmap = addLogo(bitmap, logoBm);
// }
//必须使用compress方法将bitmap保存到文件中再进行读取。直接返回的bitmap是没有任何压缩的,内存消耗巨大!
return bitmap;
} catch (WriterException e) {
e.printStackTrace();
}
return null;
}
/**
* 生成条形码(不支持中文)
*
* @param content
* @return
*/
public static Bitmap createBarcode(String content,int widthPix, int heightPix) {
try {
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.CODE_128, widthPix, heightPix);
int width = bitMatrix.getWidth();
int height = bitMatrix.getHeight();
int[] pixels = new int[width * height];
for (int y = 0; y < height; y++) {
int offset = y * width;
for (int x = 0; x < width; x++) {
pixels[offset + x] = bitMatrix.get(x, y) ? 0xff000000 : 0xFFFFFFFF;
}
}
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
} catch (WriterException e) {
e.printStackTrace();
}
return null;
}
}
蓝牙连接打印机并打印
public class PrintTemplate {
private static final String TAG = "PrintTemplate";
private BluetoothSocket mBluetoothSocket;
private static final int CONNECTFAILURE=1;
private static final int CONNECTSUCCESS=2;
Message message=new Message();
AlertDialog alertDialog=null;
private Context context;
private Handler handler=new Handler(){
public void handleMessage(Message message){
switch (message.what){
case CONNECTFAILURE:
MSG.say(context,"连接失败");
break;
case CONNECTSUCCESS:
MSG.say(context,"连接成功开始打印");
break;
default:
break;
}
}
};
public void printConnect(final Context context, final int type) {
this.context=context;
//判断是否选择了打印机
SharedPreferences sharedPreferences=context.getSharedPreferences("print",MODE_PRIVATE);
final String printeraddress=sharedPreferences.getString("PRINTERADDRESS","");//调试的时候可以自己先存一个打印机的地址进去
if (Util.isNull(printeraddress)){
DialogMessage.show(context,"请前往打印设置,选择打印设备");
return;
}
//查看蓝牙有没有打开
final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();//获取蓝牙的适配器
if (bluetoothAdapter != null && !bluetoothAdapter.isEnabled()) {//适配器不为空,且蓝牙没有打开
final Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
enableBtIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(enableBtIntent);
}
bluetoothAdapter.cancelDiscovery();
alertDialog=new AlertDialog.Builder(context)
.setTitle("提示")
.setMessage("正在连接")
.setCancelable(false)
.create();
alertDialog.show();
new Thread(new Runnable() {
@Override
public void run() {
try {
UUID uuid=UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
Log.d(TAG, "print: "+bluetoothAdapter.getRemoteDevice(printeraddress).getName());
mBluetoothSocket = bluetoothAdapter.getRemoteDevice(printeraddress).createRfcommSocketToServiceRecord(uuid);
mBluetoothSocket.connect();
if (!mBluetoothSocket.isConnected()){
alertDialog.dismiss();
message.what=CONNECTFAILURE;
handler.sendMessage(message);
return;
}else{
alertDialog.dismiss();
message.what=CONNECTSUCCESS;
handler.sendMessage(message);
print(type);//进行打印
}
} catch (IOException e) {
e.printStackTrace();
alertDialog.dismiss();
message.what=CONNECTFAILURE;
handler.sendMessage(message);
}
}
}).start();
}
/****************************打印*********************/
private void print(final int type){
new Thread(new Runnable() {
@Override
public void run() {
try {
if (mBluetoothSocket.isConnected()){
OutputStream mOutputStream = mBluetoothSocket.getOutputStream();
OutputStreamWriter outputStreamWriter=new OutputStreamWriter(mOutputStream);
Bitmap bm=null;
switch (type){
case 1:
bm= draw(Util.replaceNullByBackspace("CG0055949400026550002"),Util.replaceNullByBackspace("G-596809"),Util.replaceNullByBackspace("20170906"),Util.replaceNullByBackspace("3pcs*12CTV"),Util.replaceNullByBackspace("12"),Util.replaceNullByBackspace("36"),Util.replaceNullByBackspace("9343864-04"),Util.replaceNullByBackspace("北京金佰利公司"),Util.replaceNullByBackspace("01.01.01.01.00"));
break;
case 2:
bm=draw2(Util.replaceNullByBackspace("CG0055949400026550002"),Util.replaceNullByBackspace("G-596809"),Util.replaceNullByBackspace("20170906"),Util.replaceNullByBackspace("3pcs*12CTV"),Util.replaceNullByBackspace("12"),Util.replaceNullByBackspace("36"),Util.replaceNullByBackspace("9343864-04"));
break;
case 3:
bm=draw2(Util.replaceNullByBackspace("CG0055949400026550002"),Util.replaceNullByBackspace("G-596809"),Util.replaceNullByBackspace("20170906"),Util.replaceNullByBackspace("3pcs*12CTV"),Util.replaceNullByBackspace("12"),Util.replaceNullByBackspace("36"),Util.replaceNullByBackspace("9343864-04"));
break;
default:
break;
}
String content= ZplImage.getHexByChange2bit(bm);
content=content+"^XA^XGR:ZLOGO.GRF,1,1^XZ";//增加打印指令
String str=content;
int j=content.length()/2000;
int i=0;
while (i<j){
str=content.substring(2000*i,2000*(i+1));
outputStreamWriter.write(str);
outputStreamWriter.flush();
i++;
}
outputStreamWriter.write(content,2000*i,content.length()-2000*i);
outputStreamWriter.flush();
outputStreamWriter.close();
mBluetoothSocket.close();
}
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
mBluetoothSocket.close();
Log.d(TAG, "run: 关闭连接!");
} catch (IOException closeException) { }
return;
}
try {
mBluetoothSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
/**
* 入库标识标签的绘制
* @param parameter0 二维码
* @param parameter1 机种号
* @param parameter2 批号
* @param parameter3 捆包明细
* @param parameter4 箱数
* @param parameter5 数量
* @param parameter6 下方条形码
*@param parameter7 最终客户
*@param parameter8 产品代码
* @return
*/
private Bitmap draw(String parameter0, String parameter1, String parameter2, String parameter3, String parameter4, String parameter5, String parameter6, String parameter7, String parameter8){
Bitmap mbmpTest = Bitmap.createBitmap(660,420, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mbmpTest);
Paint mPaint=new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLACK);
canvas.drawColor(Color.WHITE);
Paint textPaint = new Paint(); // 创建画笔
textPaint.setColor(Color.BLACK); // 设置颜色
String familyName = "楷体";
Typeface font = Typeface.create(familyName,Typeface.NORMAL);
textPaint.setTextSize(37);
textPaint.setTypeface(font);
Paint barcodeTextPaint1 = new Paint(); // 创建画笔
barcodeTextPaint1.setColor(Color.BLACK); // 设置颜色
barcodeTextPaint1.setTextSize(27);
barcodeTextPaint1.setTypeface(font);
Paint QRCodePaint= new Paint(); // 创建画笔
QRCodePaint.setColor(Color.BLACK); // 设置颜色
QRCodePaint.setTextSize(22);
QRCodePaint.setTypeface(font);
Bitmap bitmap=ZplImage.createQRCode(parameter0,150,150);//二维码
Bitmap barcodeBitmap1=ZplImage.createBarcode(parameter6,300,40);//条形码
String str7="最终客户: "+parameter7;
String str8="产品代码: "+parameter8;
String str1 = "机 种 号 : "+parameter1;
String str2="批 号: "+parameter2;
String str3="捆 绑 明 细 : "+parameter3;
String str4="箱 数: "+parameter4;
String str5="数 量 : "+parameter5;
Paint paint1=new Paint();//二维码和条形码画笔
paint1.setColor(Color.BLACK);
paint1.setStyle(Paint.Style.STROKE);
canvas.drawBitmap(bitmap,460,10,paint1);//画二维码
canvas.drawText(parameter0,380,170, QRCodePaint);
canvas.drawText(str7,10,30,textPaint);
canvas.drawText(str8,10,80,textPaint);
canvas.drawText(str1,10,130,textPaint);
canvas.drawText(str2,10,180,textPaint);
canvas.drawText(str3,10,230,textPaint);
canvas.drawText(str4,10,280,textPaint);
canvas.drawText(str5,10,330,textPaint);
canvas.drawBitmap(barcodeBitmap1,-10,340,paint1);//画条形码
canvas.drawText(parameter6,50,400,barcodeTextPaint1);
return mbmpTest;
}
/**
* 入库标识标签的绘制
* @param parameter0 二维码
* @param parameter1 机种号
* @param parameter2 批号
* @param parameter3 捆包明细
* @param parameter4 箱数
* @param parameter5 数量
* @param parameter6 下方条形码
* @return
*/
private Bitmap draw2(String parameter0,String parameter1,String parameter2,String parameter3,String parameter4,String parameter5,String parameter6){
Bitmap mbmpTest = Bitmap.createBitmap(660,420, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mbmpTest);
Paint mPaint=new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLACK);
canvas.drawColor(Color.WHITE);
Paint textPaint = new Paint(); // 创建画笔
textPaint.setColor(Color.BLACK); // 设置颜色
String familyName = "楷体";
Typeface font = Typeface.create(familyName,Typeface.NORMAL);
textPaint.setTextSize(37);
textPaint.setTypeface(font);
Paint barcodeTextPaint = new Paint(); // 创建画笔
barcodeTextPaint .setColor(Color.BLACK); // 设置颜色
barcodeTextPaint .setTextSize(30);
barcodeTextPaint.setTypeface(font);
Paint barcodeTextPaint1 = new Paint(); // 创建画笔
barcodeTextPaint1.setColor(Color.BLACK); // 设置颜色
barcodeTextPaint1.setTextSize(27);
barcodeTextPaint1.setTypeface(font);
Paint QRCodePaint= new Paint(); // 创建画笔
QRCodePaint.setColor(Color.BLACK); // 设置颜色
QRCodePaint.setTextSize(22);
QRCodePaint.setTypeface(font);
Bitmap bitmap=ZplImage.createQRCode(parameter0,150,150);//二维码
Bitmap barcodeBitmap=ZplImage.createBarcode(parameter1,300,40);//条形码
Bitmap barcodeBitmap1=ZplImage.createBarcode(parameter6,300,40);//条形码
String str1 = "机 种 号 : "+parameter1;
String str2="批 号: "+parameter2;
String str3="捆 绑 明 细 : "+parameter3;
String str4="箱 数: "+parameter4;
String str5="数 量 : "+parameter5;
Paint paint1=new Paint();//二维码和条形码画笔
paint1.setColor(Color.BLACK);
paint1.setStyle(Paint.Style.STROKE);
canvas.drawBitmap(bitmap,460,10,paint1);//画二维码
canvas.drawText(parameter0,400,170, QRCodePaint);
canvas.drawBitmap(barcodeBitmap,-35,10,paint1);//画条形码
canvas.drawText(parameter1,50,75,barcodeTextPaint);
canvas.drawText(str1,10,120,textPaint);
canvas.drawText(str2,10,170,textPaint);
canvas.drawText(str3,10,220,textPaint);
canvas.drawText(str4,10,270,textPaint);
canvas.drawText(str5,10,320,textPaint);
canvas.drawBitmap(barcodeBitmap1,-15,340,paint1);//画条形码
canvas.drawText(parameter6,50,400,barcodeTextPaint1);
return mbmpTest;
}
}
具体调用的方法
PrintTemplate printTemplate=new PrintTemplate();
printTemplate.printConnect(context,1);
打印出来的效果图
相关资料
()
相关指令的介绍:比较全的斑马打印机指令合集
~DG(下载图象)执行以下功能。
1.置打印机为图象模式。
2.命名图形。(这个名字将用来在标签中调用)
3.定义图象尺寸
4.下载十六进制字符串到打印机
指令的格式:
~DGd:o.x,t,w,DATA
~DG | 设置打印机为下载图形模式 |
d | 贮存图象的目标设备。 缺省值:R: (DRAM) 其它值:B: (内存选件) |
o | 图象名,1-8字符,(缺省时,用UNKNOWN作字体名) |
x | 扩展名,3字符 ( 固定的,始终是:GRF) |
t | 图象总的字节数 |
w | 每行字节数 |
DATA | ASCII十六进制串图象定义 |
如目标名省略,就用UNKNOWN.GRF作为字图象名。数据串使用ASCII十六进制串图象定义,每个字符表示水平方向的四个点。
以下是一个用~DG指令加载图象到DRAM的例子。贮存图象名叫SAMPLE.GRF。
~DGR:SAMPLE.GRF,00080,010,
FFFFFFFFFFFFFFFFFFFF
8000FFFF0000FFFF0001
8000FFFF0000FFFF0001
8000FFFF0000FFFF0001
FFFF0000FFFF0000FFFF
FFFF0000FFFF0000FFFF
FFFF0000FFFF0000FFFF
FFFFFFFFFFFFFFFFFFFF
参数t(图形总字节数)用以下公式计算:
X (毫米)×打印机分辨率(点/毫米) × Y(毫米) ×打印机分辨(点/毫米)/8(点/字节)= 总字节
X 是单位毫米的图象宽度。Y是单位毫米的图象高度。点/毫米打印机编程的打印分辨率。
例如,确定图象8毫米宽,16毫米高,打印分辨率8点/毫米的正确t参数其公式是:
8×8×16×8/8=1024字节
参数w(每行字节数)用以下公式计算:
X (毫米)×打印机分辨率(点/毫米) /8(点/字节)= 每行字节数
x是单位毫米的图象宽充,点/毫米是打印机偏移打印分辨率。
例如,确定图象8毫米宽,打印分辨率8点/毫米的正确w参数,其公式是:
8×8/8 = 8字节
注意:
所有字节中一行的字节
w是t参数计算的第一个值
参数是一串十六进制数作为图象表示送打印机。每一十六进制字符代表水平方向四个点。如图象前四个点是白的,后四个点是黑的。二进制码的点00001111。十六进制表示二进制值将是OF。完整的图象码就是这样。完整图象被送打印机是一长连续十六制值。
相关代码
相关思路:获取到bitmap图片后,查询每一像素点的颜色的int值,如果不是纯白色(-1),就当作黑色处理,(我是图方便,这样其实会出现很多不该出现的小黑点,其实应该是用中间的灰色当作分界线会好一点,如果比灰色的数值大,那么当作白色,比灰色的数值小,当作黑色)
(我采用的热敏打印机打印标签)
打印机是一个字节的代表八个点,一个点只有两种颜色,要不是黑色不是白色(0为白色,1为黑色)。每获取到4个像素点,就将他们拼接成一个16进制。
我采用的是TD-2130N的打印机,基本上好像智能接受8000字节左右,所以相当于8000*8=640000个像素点。当然实际情况可以比它大,毕竟可以采用压缩指令。但是这个像素点是基本上安全可以打印的。得到了相应的hex之后,就利用指令码进行压缩