借鉴的内容 /horseroll/article/details/80496091
斑马打印机图片打印的逻辑
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进制的0stringBuilder.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_8888Bitmap 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() {@Overridepublic 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() {@Overridepublic 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("0906"),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("0906"),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("0906"),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 outtry {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);
打印出来的效果图
相关资料
(/rinack/p/4843788.html)
相关指令的介绍:比较全的斑马打印机指令合集
~DG(下载图象)执行以下功能。
1.置打印机为图象模式。
2.命名图形。(这个名字将用来在标签中调用)
3.定义图象尺寸
4.下载十六进制字符串到打印机
指令的格式:
~DGd:o.x,t,w,DATA
如目标名省略,就用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之后,就利用指令码进行压缩