一.連接設置,注意里面藍牙服務和特征需要根據(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ā)布平臺,僅提供信息存儲服務。