鸿蒙ArkTS连接无线蓝牙打印机,并打印文字图片

一.连接设置,注意里面蓝牙服务和特征需要根据实际情况替换,一般可写的服务特征都能发送打印,

1定义变量
   //定义分段发送数据字节大小, 鸿蒙最大支持512字节
  @Trace sliceLength: number = 256
  @Trace gattClient?: ble.GattClientDevice
   // 图片pixmap
  @Trace pixmap: image.PixelMap | undefined = undefined;
2连接设备蓝牙打印机
  connectBel(deviceId: string): void {
    try {
      // 创建一个可使用的GattClientDevice实例。
      // 对端设备地址, 例如:"XX:XX:XX:XX:XX:XX"。
      let gattClient: ble.GattClientDevice = ble.createGattClientDevice(deviceId);
      // client端发起连接远端蓝牙低功耗设备。
      gattClient.connect();
      // 监听蓝牙连接状态
      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端获取蓝牙低功耗设备的所有服务,即服务发现。
            gattClient.getServices().then((result: Array<ble.GattService>) => {
              YLog('getServices successfully:' + JSON.stringify(result));
              this.sendData()
            });

          })
          //这里要设置最大发送大小,否则有时会报错
          gattClient.setBLEMtuSize(this.sliceLength)
        }
      });

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

  }
3发送数据
  async sendData() {
    //2900007表示接口调用超时。
    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) {
          //递归调用打印
          writeBLECharacteristicValue(sendloop, index)
          LogUtil.info(`发送成功一次:${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) {
        //数据分段
        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个字节一个像素

    const arrayBuffer = new ArrayBuffer(pixmap.getPixelBytesNumber());
    // 获取像素数据
    pixmap.readPixelsToBufferSync(arrayBuffer)
    // 将像素数据复制到ArrayBuffer
    // uint8Array.set(pixelBytes);
    const uint32Array = new Uint32Array(arrayBuffer);
    let data: number[] = []
    //光栅位图固定格式
    data[0] = 29
    data[1] = 118
    data[2] = 48
    data[3] = 0
    // 要发送位图的宽度 (告诉打印机下面数据宽高数)
    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)
    //指的是要发送的数据位图的宽和高。因为一个字节最大是255,所以用两个字节分别表示宽和高,宽高分别最大为65535。
    // 其中xL代表低16位,xH代表高16位,yL, yH同理。
    // 计算方式:(W代表宽度)
    // 位运算 xL = W&0xFF, xH= W>>16&0xFF
    // 除法 xL=W%256, xH = w/256
    //位图1行字节数
    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++) {
        //四个字节一个像素, a在最后  位图一个字节可以表示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
        ////透明和经验值>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
        }
        //因为我们用一个字节表示8个点,那么每一个bit,从高位到低位依次表示从左到右的一个点的二值化值,offset表示当前点在一个字节里的下标
        offset = x % 8;

        if (value == 1) {
          ////0x80是0b1000 0000,点在byte中的下标是几,向右位移几,和这个字节做或运算。
          // 第一个点放在最低位,第七个放在最高位
          // 比如一个字节A中从高向低第二个点是1,那么A=A|0b01000000,A的从高向低第二位就是1了,表示这个位置绘制黑点。
          temp |= (0x80 >> (7 - offset))
        }
        if (offset == 7 || x >= (width - 1)) {
          //如果是一个字节最后一个点,或者是这一行的最后一个点,这个字节数据就满了,
          // 存储到对应位置,将temp复原为0。如果最后一个字节不足8个点,剩下的位数自然补0.
          rowData[Math.floor(x / 8)] = temp
          temp = 0
        }
      }
      data = data.concat(rowData)
    }
    return Promise.resolve(data)
  }
}

二.这个适用于通用蓝牙打印机,如果是定制蓝牙打印机的可能打印不了图片

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容