国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 系統(tǒng) > Android > 正文

Android 藍(lán)牙連接 ESC/POS 熱敏打印機(jī)打印實(shí)例(ESC/POS指令篇)

2019-12-12 03:07:04
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

上一篇 主要介紹了如何通過(guò)藍(lán)牙連接到打印機(jī)。這一篇,我們就介紹如何向打印機(jī)發(fā)送打印指令,來(lái)打印字符和圖片。

1. 構(gòu)造輸出流

首先要明確一點(diǎn),就是藍(lán)牙連接打印機(jī)這種場(chǎng)景下,手機(jī)是 Client 端,打印機(jī)是 Server 端。

在上一篇的最后,我們從 BluetoothSocket 得到了一個(gè)OutputStream。這里我們做一層包裝,得到一個(gè)OutputStreamWriter 對(duì)象:

OutputStreamWriter writer = new OutputStreamWriter(outputStream, "GBK");

這樣做主要是為了后面可以直接輸出字符串,不然只能輸出 int 或 byte 數(shù)據(jù);

2. 常用打印指令

手機(jī)通過(guò)藍(lán)牙向打印機(jī)發(fā)送的都是純字節(jié)流,那么打印機(jī)如何知道該打印的是一個(gè)文本,還是條形碼,還是圖片數(shù)據(jù)呢?

初始化打印機(jī) :

在每次打印開(kāi)始之前要調(diào)用該指令對(duì)打印機(jī)進(jìn)行初始化。向打印機(jī)發(fā)送這條指令對(duì)應(yīng)的代碼就是:

 protected void initPrinter() throws IOException {     writer.write(0x1B);     writer.write(0x40);     writer.flush();  }

打印文本:

沒(méi)有對(duì)應(yīng)指令,直接輸出

protected void printText(String text) throws IOException {    writer.write(text);   writer.flush(); }

設(shè)置文本對(duì)齊方式:

對(duì)應(yīng)的發(fā)送指令的代碼:

  /* 設(shè)置文本對(duì)齊方式   * @param align 打印位置 0:居左(默認(rèn)) 1:居中 2:居右    * @throws IOException    */   protected void setAlignPosition(int align) throws IOException {     writer.write(0x1B);     writer.write(0x61);     writer.write(align);     writer.flush();   }

與初始化指令不同的是,這條指令帶有一個(gè)參數(shù)n。

換行和制表符:

直接輸出對(duì)應(yīng)的字符:

 protected void nextLine() throws IOException {    writer.write("/n");    writer.flush();  } protected void printTab(int length) throws IOException {    for (int i = 0; i < length; i++) {      writer.write("/t");    }    writer.flush();  }

這兩個(gè)指令在打印訂單詳情的時(shí)候使用最多。尤其是制表符,可以讓每一列的文字對(duì)齊。

設(shè)置行間距:

n表示行間距為n個(gè)像素點(diǎn),最大值256

protected void setLineGap(int gap) throws IOException {     writer.write(0x1B);     writer.write(0x33);     writer.write(gap);     writer.flush(); }

這個(gè)指令在后面打印圖片的時(shí)候會(huì)用到。

3. 打印圖片

很多小票上面都會(huì)附上一個(gè)二維碼,用戶掃描之后,可以獲得更多的信息。因?yàn)闊崦舸蛴C(jī)只能打印黑白兩色,所以首先把圖片轉(zhuǎn)成純黑白的,再調(diào)用圖片打印指令進(jìn)行打印。

3.1 打印圖片指令


這個(gè)指令的參數(shù)很多,一個(gè)一個(gè)來(lái)說(shuō):

  1. m:取值十進(jìn)制 0、1、32、33。設(shè)置打印精度,0、1對(duì)應(yīng)每行8個(gè)點(diǎn),32、33對(duì)應(yīng)每行24個(gè)點(diǎn),對(duì)應(yīng)最高的打印精度(其實(shí)這里也沒(méi)太搞清楚取值0、1或者取值32、33的區(qū)別,只要記住取值33,對(duì)應(yīng)每行24個(gè)點(diǎn),后面還有用)
  2. n1, n2 : 表示圖片的寬度,為什么有兩個(gè)?其實(shí)只是分成了高位和低位兩部分,因?yàn)槊坎糠种挥?bit,最大表示256。所以 n1 = 圖片寬度 % 256,n2 = 圖片寬度 / 256。假設(shè)圖片寬300,那么n1=1,n2=44
  3. d1 d2 ... dk 這部分就是轉(zhuǎn)換成字節(jié)流的圖像數(shù)據(jù)了

3.2 圖片分辨率調(diào)整

如果分辨率過(guò)大,超過(guò)了打印機(jī)可打印的最大寬度,那么超出的部分將無(wú)法打印。我試驗(yàn)的這臺(tái)最大寬度是 384 個(gè)像素點(diǎn),超過(guò)這個(gè)寬度的數(shù)據(jù)無(wú)法被打印出來(lái)。所以在開(kāi)始打印之前,我們需要調(diào)整圖片的分辨率。代碼如下:

  /**   * 對(duì)圖片進(jìn)行壓縮(去除透明度)   *   * @param bitmapOrg   */  public static Bitmap compressPic(Bitmap bitmap) {    // 獲取這個(gè)圖片的寬和高    int width = bitmap.getWidth();    int height = bitmap.getHeight();    // 指定調(diào)整后的寬度和高度    int newWidth = 240;    int newHeight = 240;    Bitmap targetBmp = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);    Canvas targetCanvas = new Canvas(targetBmp);    targetCanvas.drawColor(0xffffffff);    targetCanvas.drawBitmap(bitmap, new Rect(0, 0, width, height), new Rect(0, 0, newWidth, newHeight), null);    return targetBmp;  }

3.2 圖片黑白化處理

因?yàn)槟軌虼蛴〉膱D像只有黑白兩色,所以需要先做黑白化的處理。這一部分其實(shí)又細(xì)分為彩色圖片->灰度圖片,灰度圖片->黑白圖片兩步。直接上代碼:

  /**   * 灰度圖片黑白化,黑色是1,白色是0   *   * @param x  橫坐標(biāo)   * @param y  縱坐標(biāo)   * @param bit 位圖   * @return   */  public static byte px2Byte(int x, int y, Bitmap bit) {    if (x < bit.getWidth() && y < bit.getHeight()) {      byte b;      int pixel = bit.getPixel(x, y);      int red = (pixel & 0x00ff0000) >> 16; // 取高兩位      int green = (pixel & 0x0000ff00) >> 8; // 取中兩位      int blue = pixel & 0x000000ff; // 取低兩位      int gray = RGB2Gray(red, green, blue);      if (gray < 128) {        b = 1;      } else {        b = 0;      }      return b;    }    return 0;  }  /**   * 圖片灰度的轉(zhuǎn)化   */  private static int RGB2Gray(int r, int g, int b) {    int gray = (int) (0.29900 * r + 0.58700 * g + 0.11400 * b); //灰度轉(zhuǎn)化公式    return gray;  }

其中的灰度化轉(zhuǎn)換公式是一個(gè)廣為流傳的公式,具體原理不明。我們直接看灰度轉(zhuǎn)化為黑白的函數(shù) px2Byte(int x, int y, Bitmap bit)。對(duì)于一個(gè) Bitmap 中的任意一個(gè)坐標(biāo)點(diǎn),取出其 RGB 三色信息后做灰度化處理,然后對(duì)于灰度小于128的,用黑色表示,灰度大于128的,用白色表示。

3.3 逐行打印圖片

其實(shí)打印圖片和打印文本是一樣的,也是一行一行的打印。直接上代碼吧,注釋已經(jīng)盡量詳細(xì)了。

  /*************************************************************************   * 假設(shè)一個(gè)240*240的圖片,分辨率設(shè)為24, 共分10行打印   * 每一行,是一個(gè) 240*24 的點(diǎn)陣, 每一列有24個(gè)點(diǎn),存儲(chǔ)在3個(gè)byte里面。   * 每個(gè)byte存儲(chǔ)8個(gè)像素點(diǎn)信息。因?yàn)橹挥泻诎變缮詫?duì)應(yīng)為1的位是黑色,對(duì)應(yīng)為0的位是白色   **************************************************************************/  /**   * 把一張Bitmap圖片轉(zhuǎn)化為打印機(jī)可以打印的字節(jié)流   *   * @param bmp   * @return   */  public static byte[] draw2PxPoint(Bitmap bmp) {    //用來(lái)存儲(chǔ)轉(zhuǎn)換后的 bitmap 數(shù)據(jù)。為什么要再加1000,這是為了應(yīng)對(duì)當(dāng)圖片高度無(wú)法       //整除24時(shí)的情況。比如bitmap 分辨率為 240 * 250,占用 7500 byte,    //但是實(shí)際上要存儲(chǔ)11行數(shù)據(jù),每一行需要 24 * 240 / 8 =720byte 的空間。再加上一些指令存儲(chǔ)的開(kāi)銷,    //所以多申請(qǐng) 1000byte 的空間是穩(wěn)妥的,不然運(yùn)行時(shí)會(huì)拋出數(shù)組訪問(wèn)越界的異常。    int size = bmp.getWidth() * bmp.getHeight() / 8 + 1000;    byte[] data = new byte[size];    int k = 0;    //設(shè)置行距為0的指令    data[k++] = 0x1B;    data[k++] = 0x33;    data[k++] = 0x00;    // 逐行打印    for (int j = 0; j < bmp.getHeight() / 24f; j++) {      //打印圖片的指令      data[k++] = 0x1B;      data[k++] = 0x2A;      data[k++] = 33;       data[k++] = (byte) (bmp.getWidth() % 256); //nL      data[k++] = (byte) (bmp.getWidth() / 256); //nH      //對(duì)于每一行,逐列打印      for (int i = 0; i < bmp.getWidth(); i++) {        //每一列24個(gè)像素點(diǎn),分為3個(gè)字節(jié)存儲(chǔ)        for (int m = 0; m < 3; m++) {          //每個(gè)字節(jié)表示8個(gè)像素點(diǎn),0表示白色,1表示黑色          for (int n = 0; n < 8; n++) {            byte b = px2Byte(i, j * 24 + m * 8 + n, bmp);            data[k] += data[k] + b;          }          k++;        }      }      data[k++] = 10;//換行    }    return data;  }

4. 總結(jié)

用兩篇介紹了一個(gè)比較冷門(mén)的應(yīng)用,純粹是因?yàn)樽约夯撕芏鄷r(shí)間去搞懂原理,所以希望記錄下來(lái)。尤其是圖片打印部分,廢了好多紙啊哈哈哈,一個(gè)字節(jié)操作錯(cuò)誤,打印出來(lái)就是一堆亂碼。感覺(jué)和 java 的 .class 文件很像,每一個(gè)指令占用多少位,每一位表示什么都是嚴(yán)格規(guī)定好的,不能超出也不能缺少。

最后希望能幫到需要的人吧,感覺(jué)網(wǎng)上這部分資料還是比較少的。也希望大家多多支持武林網(wǎng)。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 辽中县| 友谊县| 玛多县| 济宁市| 紫金县| 彭阳县| 汝州市| 韶关市| 海丰县| 梅州市| 常宁市| 潮州市| 高碑店市| 孟州市| 弥渡县| 江西省| 伽师县| 栾川县| 华亭县| 海安县| 百色市| 阳城县| 武宣县| 眉山市| 湟源县| 永济市| 西盟| 凤城市| 铁力市| 莲花县| 油尖旺区| 沂源县| 兰西县| 恭城| 汽车| 赣榆县| 朝阳县| 文水县| 卢龙县| 原平市| 泾川县|