鴻蒙ArkTS連接無線藍牙打印機,并打印文字圖片

一.連接設置,注意里面藍牙服務和特征需要根據(jù)實際情況替換,一般可寫的服務特征都能發(fā)送打印,

1定義變量
   //定義分段發(fā)送數(shù)據(jù)字節(jié)大小, 鴻蒙最大支持512字節(jié)
  @Trace sliceLength: number = 256
  @Trace gattClient?: ble.GattClientDevice
   // 圖片pixmap
  @Trace pixmap: image.PixelMap | undefined = undefined;
2連接設備藍牙打印機
  connectBel(deviceId: string): void {
    try {
      // 創(chuàng)建一個可使用的GattClientDevice實例。
      // 對端設備地址, 例如:"XX:XX:XX:XX:XX:XX"。
      let gattClient: ble.GattClientDevice = ble.createGattClientDevice(deviceId);
      // client端發(fā)起連接遠端藍牙低功耗設備。
      gattClient.connect();
      // 監(jiān)聽藍牙連接狀態(tài)
      gattClient.on('BLEConnectionStateChange', (state: ble.BLEConnectionChangeState) => {
        let connectState: ble.ProfileConnectionState = state.state;
        console.info(`bluetooth connect state changed:${connectState}`);
        if (connectState === 2) {
          this.gattClient = gattClient;

          gattClient.on('BLEMtuChange', (mtu) => {
            //這個和初開始設置的可能不一樣,
            this.sliceLength = mtu
            console.info(`bluetooth BLEMtuChange:${mtu}`);
            // client端獲取藍牙低功耗設備的所有服務,即服務發(fā)現(xiàn)。
            gattClient.getServices().then((result: Array<ble.GattService>) => {
              YLog('getServices successfully:' + JSON.stringify(result));
              this.sendData()
            });

          })
          //這里要設置最大發(fā)送大小,否則有時會報錯
          gattClient.setBLEMtuSize(this.sliceLength)
        }
      });

    } catch (err) {
      console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }

  }
3發(fā)送數(shù)據(jù)
  async sendData() {
    //2900007表示接口調(diào)用超時。
    let writeBLECharacteristicValue = (sendloop: number[][], index: number) => {
      const data = sendloop[index];
      if (data == null) {
        LogUtil.info("data == null 不打印")
        return
      }
      let buffer = new ArrayBuffer(data.length);
      let descV = new Uint8Array(buffer)
      for (let index = 0; index < data.length; index++) {
        descV[index] = data[index]
      }
      //請更改真實服務id和特征id
      let characteristic: ble.BLECharacteristic = {
        serviceUuid: '000018F0-0000-1000-8000-00805F9B34FB',
        characteristicUuid: '00002AF1-0000-1000-8000-00805F9B34FB',
        characteristicValue: buffer,
        descriptors: []
      };
      this.gattClient?.writeCharacteristicValue(characteristic, ble.GattWriteType.WRITE,
        (code: BusinessError) => {
          if (code != null) {
            //error:2900007  Inner error. 超時
            console.info(`bluetooth writeCharacteristicValue error:${code.code}  ${code.message}`);
            setTimeout(() => {
              this.gattClient?.disconnect()
            },1000)
            return;
          }
          index += 1
        if (index < sendloop.length) {
          //遞歸調(diào)用打印
          writeBLECharacteristicValue(sendloop, index)
          LogUtil.info(`發(fā)送成功一次:${index}`)
        } else {
          setTimeout(() => {
            this.gattClient?.disconnect()
          },1000)
        }
          console.info('bluetooth writeCharacteristicValue success');
        });
    }

    try {
      //初始化
      let data: number[] = [27, 64]

      let textEncoder = new util.TextEncoder('gb18030')
      let text = textEncoder.encodeInto('劉德華(Andy Lau),1961年9月27日出生于中國香港;');
      //ESC d 打印并走紙 n 行 27 100 n
      for (let index = 0; index < text.length; index++) {
        data.push(text[index])
      }
      //ESC d 打印并走紙 n 行 27 100 n
      data.push(27)
      data.push(100)
      data.push(2)
      ///2打印圖片
      if (this.pixmap == null) {
        return
      }
      let imageBits = await BluTool.convertImage2BitMap(this.pixmap)
      data = data.concat(imageBits)
      data.push(27)
      data.push(100)
      data.push(10)

      let sendloop: number[][] = []
      for (let index = 0; index < data.length; index += this.sliceLength) {
        //數(shù)據(jù)分段
        sendloop.push(data.slice(index, index + this.sliceLength))
      }
      LogUtil.info('開始打印1')
      writeBLECharacteristicValue(sendloop,0)
    } catch (err) {
      console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }
4圖片轉二進制位圖方法
export class BluTool {
  static convertImage2BitMap(pixmap: image.PixelMap): Promise<Array<number>> {

    let size = pixmap.getImageInfoSync().size
    //width:1156 height:93 density:0 stride:4624
    // 578
    const width = size.width
    const height = size.height;
    LogUtil.info(`width:${size.width} height:${size.height}`)
    // rgb 一般4個字節(jié)一個像素

    const arrayBuffer = new ArrayBuffer(pixmap.getPixelBytesNumber());
    // 獲取像素數(shù)據(jù)
    pixmap.readPixelsToBufferSync(arrayBuffer)
    // 將像素數(shù)據(jù)復制到ArrayBuffer
    // uint8Array.set(pixelBytes);
    const uint32Array = new Uint32Array(arrayBuffer);
    let data: number[] = []
    //光柵位圖固定格式
    data[0] = 29
    data[1] = 118
    data[2] = 48
    data[3] = 0
    // 要發(fā)送位圖的寬度 (告訴打印機下面數(shù)據(jù)寬高數(shù))
    const widthByte = Math.floor((size.width + 7) / 8)
    data[4] = widthByte % 256
    data[5] = Math.floor(widthByte / 256)
    data[6] = size.height % 256
    data[7] = Math.floor(size.height / 256)
    //指的是要發(fā)送的數(shù)據(jù)位圖的寬和高。因為一個字節(jié)最大是255,所以用兩個字節(jié)分別表示寬和高,寬高分別最大為65535。
    // 其中xL代表低16位,xH代表高16位,yL, yH同理。
    // 計算方式:(W代表寬度)
    // 位運算 xL = W&0xFF, xH= W>>16&0xFF
    // 除法 xL=W%256, xH = w/256
    //位圖1行字節(jié)數(shù)
    for (let y = 0; y < height; y++) {
      let rowData: number[] = []
      let temp: number = 0
      let offset: number = 0
      for (let x = 0; x < width; x++) {
        //四個字節(jié)一個像素, a在最后  位圖一個字節(jié)可以表示8個點
        //32代表一個像素  347 * 98
        const pixel = uint32Array[y * width + x]
        const red = pixel >> 24 & 0xFF
        const green = pixel >> 16 & 0xFF
        const blue = pixel >> 8 & 0xFF
        const alpha = pixel & 0xFF
        ////透明和經(jīng)驗值>127的都認為是白色
        let value: number = 0
        if (alpha == 0) {
          value = 0
        } else {
          // value = (red * 0.3 + green * 0.59 + blue * 0.11) > 127 ? 0 : 1
          value = (red * 0.2 + green * 0.29 + blue * 0.05) > 127 ? 0 : 1
        }
        //因為我們用一個字節(jié)表示8個點,那么每一個bit,從高位到低位依次表示從左到右的一個點的二值化值,offset表示當前點在一個字節(jié)里的下標
        offset = x % 8;

        if (value == 1) {
          ////0x80是0b1000 0000,點在byte中的下標是幾,向右位移幾,和這個字節(jié)做或運算。
          // 第一個點放在最低位,第七個放在最高位
          // 比如一個字節(jié)A中從高向低第二個點是1,那么A=A|0b01000000,A的從高向低第二位就是1了,表示這個位置繪制黑點。
          temp |= (0x80 >> (7 - offset))
        }
        if (offset == 7 || x >= (width - 1)) {
          //如果是一個字節(jié)最后一個點,或者是這一行的最后一個點,這個字節(jié)數(shù)據(jù)就滿了,
          // 存儲到對應位置,將temp復原為0。如果最后一個字節(jié)不足8個點,剩下的位數(shù)自然補0.
          rowData[Math.floor(x / 8)] = temp
          temp = 0
        }
      }
      data = data.concat(rowData)
    }
    return Promise.resolve(data)
  }
}

二.這個適用于通用藍牙打印機,如果是定制藍牙打印機的可能打印不了圖片

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容