uniapp调试ESC指令热敏打印机 打印图片 以及 打印途中报10007特性不支持解决方案
图片需要通过 canvas进行处理 预先在canvas上绘制然后读取图片打印途中报 10007 特性不支持 解决方案 可以看文章最后的描述设置完图片后 我们就可以开始连接蓝牙打印机了思路就是1.先扫描蓝牙 选中具体的 deviceId后 进行连接蓝牙2.连接蓝牙后 进行连接服务3.服务连接后 进行获取特性分为三步 三步完事后 基本上就连上蓝牙了连完蓝牙 画完图片之后呢 我们就可以获取到具体的点位信
·
图片需要通过 canvas进行处理 预先在canvas上绘制然后读取图片
打印途中报 10007 特性不支持 解决方案 可以看文章最后的描述
设置图片
chooseImage() {
this.clearCanvas();
const ctx = uni.createCanvasContext("secondCanvas", this);
uni.downloadFile({
// uni.chooseImage({
url: "http://xxx.Jpeg", //仅为示例,并非真实的资源
// url: pointDataUrl,
success: (res) => {
console.log("res", res);
if (res.statusCode === 200) {
// const tempFilePath = res.tempFilePaths[0];
const tempFilePath = res.tempFilePath;
uni.getImageInfo({
src: tempFilePath,
success: (res) => {
// 打印宽度须是8的整数倍,这里处理掉多余的,使得宽度合适,不然有可能乱码
// paperWidth 用于设置打印机的宽度 最大打印宽度 产品说明书上有写 我的是576点
const mw = this.paperWidth % 8;
// 计算出宽度以及高度
const w = mw === 0 ? this.paperWidth : this.paperWidth - mw;
// 等比算出图片的高度
const h = Math.floor((res.height * w) / res.width);
// 设置canvas宽高
this.img = tempFilePath;
// 这边是进行设置画布高度
this.canvasHeight = h;
this.canvasWidth = w;
console.log("this.canvasHeight", this.canvasHeight);
console.log("this.canvasWidth", this.canvasWidth);
// 使用nextTick 让canvas宽度生效
this.$nextTick(() => {
// 在canvas 画一张图片
ctx.fillStyle = "rgba(255,255,255,1)";
ctx.clearRect(0, 0, w, h);
ctx.fillRect(0, 0, w, h);
// 进行绘画图片
ctx.drawImage(tempFilePath, 0, 0, w, h);
ctx.draw(false, () => {});
});
},
fail: (res) => {},
});
}
},
});
},
设置完图片后 我们就可以开始连接蓝牙打印机了
连接打印机
function uniAsyncPromise(name, options) {
return new Promise((resolve, reject) => {
uni[name]({
...(options || {}),
// ...options,
success: (res) => {
resolve(res);
},
fail: (err) => {
reject(err);
},
});
});
}
function openBlue() {
return uniAsyncPromise("openBluetoothAdapter");
}
function startBluetoothDevicesDiscovery(option) {
console.log("开始蓝牙扫描");
uniAsyncPromise("startBluetoothDevicesDiscovery", option).then((res) => {
// console.log("正在搜寻蓝牙设备", res);
});
}
function getConnectedBluetoothDevices(option) {
console.log("开始获取已连接设备");
return uniAsyncPromise("getConnectedBluetoothDevices", option);
}
function stopBlueDevicesDiscovery() {
//监听寻找到新设备的事件
console.log("停止蓝牙扫描");
return uniAsyncPromise("stopBluetoothDevicesDiscovery").then((res) => {
// console.log("停止搜寻蓝牙设备", res);
});
}
function createBLEConnection(deviceId, sucess, fail) {
//连接蓝牙设备
console.log("连接蓝牙设备", deviceId);
uniAsyncPromise("createBLEConnection", {
deviceId,
})
.then((res) => {
//连接成功可选择停止搜索蓝牙
//stopBlueDevicesDiscovery();
console.log("连接成功");
sucess &&
sucess({
res: res,
});
})
.catch((res) => {
console.log("连接设备异常" + res);
fail &&
fail({
res: res,
});
});
}
function getBLEDeviceServices(deviceId, success, fail) {
console.log("获取ServiceId", deviceId);
//加延迟避免取不到service
setTimeout(() => {
uniAsyncPromise("getBLEDeviceServices", {
deviceId: deviceId,
})
.then((res) => {
console.log("服务", res);
success &&
success({
serviceId: res.services,
});
})
.catch((res) => {
//getBLEDeviceServices(deviceId, success, fail);
console.log("获取ServiceId异常" + res);
fail &&
fail({
res: res,
});
});
}, 1000);
}
function getDeviceCharacteristics(deviceId, services, success, fail) {
//services = services.slice(0);
console.log("获取Characteristics", deviceId, services);
if (services.length) {
const serviceId = services.shift().uuid;
console.log("ServceID ", serviceId);
uniAsyncPromise("getBLEDeviceCharacteristics", {
deviceId,
serviceId,
})
.then((res) => {
let finished = false;
let write = false;
let notify = false;
let indicate = false;
var readId;
var writeId;
for (var i = 0; i < res.characteristics.length; i++) {
if (!notify) {
notify = res.characteristics[i].properties.notify;
if (notify) readId = res.characteristics[i].uuid;
}
if (!indicate) {
indicate = res.characteristics[i].properties.indicate;
if (indicate) readId = res.characteristics[i].uuid;
}
if (!write) {
write = res.characteristics[i].properties.write;
writeId = res.characteristics[i].uuid;
}
if ((notify || indicate) && write) {
/* 获取蓝牙特征值uuid */
success &&
success({
serviceId,
writeId: writeId,
readId: readId,
});
finished = true;
break;
}
}
if (!finished) {
getDeviceCharacteristics(deviceId, services, success, fail);
}
})
.catch((res) => {
getDeviceCharacteristics(deviceId, services, success, fail);
});
} else {
fail && fail();
}
}
思路就是
1.先扫描蓝牙 选中具体的 deviceId后 进行连接蓝牙
2.连接蓝牙后 进行连接服务
3.服务连接后 进行获取特性
分为三步 三步完事后 基本上就连上蓝牙了
连完蓝牙 画完图片之后呢 我们就可以获取到具体的点位信息了
处理图片信息
//获取画布里的图片数据
uni.canvasGetImageData({
canvasId: "secondCanvas", // canvas 唯一id
x: 0,
y: 0,
width: canvasWidth, // 之前保存的画布宽高
height: canvasHeight,
success: (res) => {
const pix = res.data;
const opt = { // 获取蓝牙配置文件
deviceId: this.deviceId, // 设备id
serviceId: this.serviceId, // 设备服务
characteristicId: this.characteristicId, // 设备特性
printAlign: "left",
lineByLine: true,
onProgress: (percentage) => {
self.percentage = percentage; // 回调的进度
},
lasterSuccess: () => {
console.log("laster success");
self.printing = false;
self.percentage = 0;
uni.showModal({
title: "提示",
content: "数据已发送完,请检查打印的内容是否正常",
showCancel: false,
confirmText: "好的",
});
},
};
this.printing = true;
//打印图片
printImage(
opt,
// 将图片数据转成位图数据
overwriteImageData({
threshold: threshold[0],
imageData: pix,
width: canvasWidth,
height: canvasHeight,
})
);
},
complete: () => {},
});
打印
获取完图片后 调用打印 打印代码如下:
// 将打印内容进行转换 区分逐行打印和整体打印
function getImageCommandArray(opt = {}, imageInfo = {}) {
const lineByLine =
typeof opt.lineByLine !== "boolean" ? true : opt.lineByLine;
const width = imageInfo.width;
const h = imageInfo.height;
const xl = width % 256;
const xh = (width - xl) / 256;
const yl = h % 256;
const yh = (h - yl) / 256;
//打印图片的十进制指令数组
let command = [];
if (lineByLine) {
// 分段逐行的指令
command = command.concat([29, 118, 48, 0, xl, xh, 1, 0]);
} else {
// 非分段逐行的指令
command = command.concat([29, 118, 48, 0, xl, xh, yl, yh]);
}
return command;
}
// 获取图片信息
function overwriteImageData(data) {
let sendWidth = data.width,
sendHeight = data.height;
const threshold = data.threshold || 180;
let sendImageData = new ArrayBuffer((sendWidth * sendHeight) / 8);
sendImageData = new Uint8Array(sendImageData);
let pix = data.imageData;
const part = [];
let index = 0;
for (let i = 0; i < pix.length; i += 32) {
//横向每8个像素点组成一个字节(8位二进制数)。
for (let k = 0; k < 8; k++) {
const grayPixle1 = grayPixle(pix.slice(i + k * 4, i + k * 4 + (4 - 1)));
//阈值调整
if (grayPixle1 > threshold) {
//灰度值大于128位 白色 为第k位0不打印
part[k] = 0;
} else {
part[k] = 1;
}
}
let temp = 0;
for (let a = 0; a < part.length; a++) {
temp += part[a] * Math.pow(2, part.length - 1 - a);
}
//开始不明白以下算法什么意思,了解了字节才知道,一个字节是8位的二进制数,part这个数组存的0和1就是二进制的0和1,传输到打印的位图数据的一个字节是0-255之间的十进制数,以下是用相权相加法转十进制数,理解了这个就用上面的for循环替代了
// const temp =
// part[0] * 128 +
// part[1] * 64 +
// part[2] * 32 +
// part[3] * 16 +
// part[4] * 8 +
// part[5] * 4 +
// part[6] * 2 +
// part[7] * 1;
sendImageData[index++] = temp;
}
return {
array: Array.from(sendImageData),
width: sendWidth / 8,
height: sendHeight,
};
}
function getPrintImageWriteArray(opt = {}, imageInfo = {}) {
const lineByLine =
typeof opt.lineByLine !== "boolean" ? true : opt.lineByLine;
const width = imageInfo.width;
let arr = imageInfo.array;
let writeArray = [];
const iniTcommand = []
.concat(printCommand.clear)
.concat(printCommand[opt.printAlign || "left"]);
const command = getImageCommandArray(opt, imageInfo);
writeArray.push(new Uint8Array(iniTcommand));
// 分段逐行打印的数据
if (lineByLine) {
for (let i = 0; i < arr.length / width; i++) {
const subArr = arr.slice(i * width, i * width + width);
const tempArr = command.concat(subArr);
writeArray.push(new Uint8Array(tempArr));
}
} else {
// 非逐行打印
writeArray.push(new Uint8Array(command.concat(arr)));
}
// writeArray.push(new Uint8Array([27, 74, 3]));
return writeArray;
}
function sendDataToDevice(options) {
let byteLength = options.value.byteLength;
// 这里默认一次20个字发送
const speed = options.onceByleLength || 20;
options.reTry = options.reTry || 20;
if (byteLength > 0) {
uni.writeBLECharacteristicValue({
...options,
// writeType:"writeNoResponse",
value: options.value.slice(0, byteLength > speed ? speed : byteLength),
success: function (res) {
if (byteLength > speed) {
sendDataToDevice({
...options,
value: options.value.slice(speed, byteLength),
});
} else {
options.lasterSuccess && options.lasterSuccess();
}
},
fail: function (res) {
// console.log('options.nowTry', options.nowTry);
options.nowTry = options.nowTry ? (options.nowTry += 1) : 1;
if (options.nowTry < options.reTry && res.errCode === 10007) {
if (byteLength > speed) {
sendDataToDevice({
...options,
value: options.value.slice(speed, byteLength),
});
} else {
options.lasterSuccess && options.lasterSuccess();
}
}
options.onError && options.onError(res);
},
});
}
}
export function sendDataToPrint(options, allUint8Array) {
const allLenth = allUint8Array.length;
const writeArrayCopyer = allUint8Array.slice(0);
const print = (options, writeArray) => {
if (writeArray.length) {
sendDataToDevice({
...options,
value: writeArray.shift().buffer,
lasterSuccess: () => {
if (writeArray.length) {
print(options, writeArray);
} else {
options.lasterSuccess && options.lasterSuccess();
}
// console.log("writeArray.length", writeArray.length);
options.onProgress &&
options.onProgress(Math.floor(((allLenth - writeArray.length) / allLenth) * 100));
},
});
}
};
print(options, writeArrayCopyer);
}
function printImage(opt, imageInfo) {
sendDataToPrint(
opt,
getPrintImageWriteArray(
{
printAlign: opt.printAlign,
lineByLine: opt.lineByLine,
},
imageInfo
)
);
}
遇到部分错误解决方法
- 如果设备特性 write=true 的打印中途 有报错 10007 进行重新发当前数据包(有很多种原因会导致失败 如果重新发数据包可以继续 那么就可以忽略这个报错) 并限制重试次数;
- 如果遇到查找不到蓝牙设备 可以尝试开启定位在重试,因为安卓版本高了需要开启定位;
案例参照:https://juejin.cn/post/7002878986472652830
更多推荐
已为社区贡献2条内容
所有评论(0)