当前位置:   article > 正文

uniapp调试ESC指令热敏打印机 打印图片 以及 打印途中报10007特性不支持解决方案_esc打印图像

esc打印图像

图片需要通过 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) => {},
            });
          }
        },
      });
    },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

设置完图片后 我们就可以开始连接蓝牙打印机了

连接打印机

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137

思路就是
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: () => {},
      });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

打印

获取完图片后 调用打印 打印代码如下:

// 将打印内容进行转换 区分逐行打印和整体打印
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
    )
  );
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172

遇到部分错误解决方法

  1. 如果设备特性 write=true 的打印中途 有报错 10007 进行重新发当前数据包(有很多种原因会导致失败 如果重新发数据包可以继续 那么就可以忽略这个报错) 并限制重试次数;
  2. 如果遇到查找不到蓝牙设备 可以尝试开启定位在重试,因为安卓版本高了需要开启定位;

案例参照:https://juejin.cn/post/7002878986472652830

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/887300
推荐阅读
相关标签
  

闽ICP备14008679号