一.连接设置,注意里面蓝牙服务和特征需要根据实际情况替换,一般可写的服务特征都能发送打印,
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辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。