24 changed files with 5107 additions and 3448 deletions
Binary file not shown.
|
Before Width: | Height: | Size: 42 KiB |
@ -1,413 +0,0 @@ |
|||||
import gbk from '@/components/kk-printer/utils/printUtil-GBK.js'; |
|
||||
import * as blesdk from './utils/bluetoolth'; |
|
||||
import util from './utils/util.js'; |
|
||||
|
|
||||
var bufferData = [] |
|
||||
var deviceType = 'ios' |
|
||||
export default { |
|
||||
|
|
||||
onPrint() { |
|
||||
let that = this |
|
||||
that.yNum = 10 |
|
||||
let strCmd = blesdk.CreatCPCLPage(440, 1000, 1, 0); |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(2, 2) |
|
||||
strCmd += blesdk.addCPCLLocation(2); |
|
||||
strCmd += blesdk.addCPCLSETBOLD('400'); |
|
||||
// strCmd += blesdk.addCPCLText('0', that.yNum, '24', '2', 0, getApp().globalData.printData[0].order_id)
|
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum, '24', '2', 0, "#0112 外卖单") |
|
||||
|
|
||||
strCmd += blesdk.addCPCLLocation(0); |
|
||||
strCmd += blesdk.addCPCLSETBOLD('0') |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(1, 1) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum+=60, '24', '0', 0, '七里香快餐明珠精品馆') |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(1, 1) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 30, '24', '0', 0, "预计时间:2026-02-01 13:14:00") |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(1, 1) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 30, '24', '0', 0, "*********") |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(2, 2) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 30, '24', '1', 0, '王 先生') |
|
||||
|
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(1, 1) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 50, '24', '0', 0, '联系电话: *******0775') |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(2, 2) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 50, '24', '0', 0, '地址:河北东川建设集团有限公司(河北省沧州市运河区)******') |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(1, 1) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 50, '24', '0', 0, '为保护隐私,顾客电话及地址已隐藏,') |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(1, 1) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 30, '24', '0', 0, '您可登陆商家端或骑手端查看') |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(1, 1) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 30, '24', '0', 0, '*******************************************') |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(2, 2) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 30, '24', '0', 0, '1、红烧黛玉') |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(2, 2) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 50, '24', '0', 0, 'X1 16元') |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(1, 1) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 50, '24', '0', 0, '*******************************************') |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(1, 1) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 30, '24', '0', 0, '配送费: 1元') |
|
||||
strCmd += blesdk.addCPCLSETMAG(1, 1) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 30, '24', '0', 0, '合计金额: 17元') |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(1, 1) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 30, '24', '0', 0, '*******************************************') |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(1, 1) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 30, '24', '0', 0, '商品取到后,如有任何商品问题,请') |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(1, 1) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 30, '24', '0', 0, '联系商家或平台,客服将为您服务客') |
|
||||
|
|
||||
strCmd += blesdk.addCPCLSETMAG(1, 1) |
|
||||
strCmd += blesdk.addCPCLText('0', that.yNum += 30, '24', '0', 0, '服电话13521030702,谢谢您的惠顾') |
|
||||
|
|
||||
|
|
||||
strCmd += blesdk.addCPCLPrint(); |
|
||||
bufferData.push(strCmd); |
|
||||
this.handlePrintTap() |
|
||||
}, |
|
||||
//点击打印按钮
|
|
||||
handlePrintTap() { |
|
||||
let that = this |
|
||||
uni.showLoading({ |
|
||||
mask: true, |
|
||||
title: '打印中...' |
|
||||
}); |
|
||||
uni.getSystemInfo({ |
|
||||
success(res) { |
|
||||
console.log('设备类型',res.osName) |
|
||||
deviceType = res.osName |
|
||||
},fail(err){ |
|
||||
console.log('getSystemInfo失败') |
|
||||
} |
|
||||
}) |
|
||||
// 初始化蓝牙模块
|
|
||||
uni.openBluetoothAdapter({ //111
|
|
||||
mode: 'central', |
|
||||
success: (res2) => { |
|
||||
console.log('openBluetoothAdapter成功') |
|
||||
that.jiantingshebei() |
|
||||
}, |
|
||||
fail: (res) => { |
|
||||
console.log('openBluetoothAdapter失败') |
|
||||
if (res.errCode == '10001') { |
|
||||
uni.showToast({ |
|
||||
duration: 2000, |
|
||||
title: "请打开蓝牙后,再进行连接", |
|
||||
icon: 'none', |
|
||||
mask: true |
|
||||
}) |
|
||||
} else { |
|
||||
that.tui.toast('连接失败,请重启蓝牙或删除小程序重新进入-1') |
|
||||
that.isShowSearch = true |
|
||||
} |
|
||||
setTimeout(res => { |
|
||||
uni.hideLoading(); |
|
||||
}, 2000) |
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* jiantingshebei方法,判断缓存中有没有deviceId等数据的时候, |
|
||||
* 有: 直接拿到缓存中的deviceId等,直接请求 uni.createBLEConnection |
|
||||
* 没有:才会调用 uni.onBluetoothDeviceFound 搜索 |
|
||||
*/ |
|
||||
jiantingshebei() { |
|
||||
let that = this; |
|
||||
console.log('jiantingshebei设备',uni.getStorageSync('deviceId')) |
|
||||
if (uni.getStorageSync('deviceId')) { |
|
||||
// that.huoqufuwu(uni.getStorageSync('deviceId'))
|
|
||||
|
|
||||
that.lianejieshebei(uni.getStorageSync('deviceId')) |
|
||||
} else { |
|
||||
uni.showToast({ |
|
||||
duration: 2000, |
|
||||
title: "蓝牙连接失败,请去商家主页尝试重新连接", |
|
||||
icon: 'none', |
|
||||
mask: true |
|
||||
}) |
|
||||
// uni.hideLoading();
|
|
||||
// that.isShowSearch = true
|
|
||||
// // 监听扫描到新设备事件
|
|
||||
// uni.onBluetoothDeviceFound((res4) => { //333
|
|
||||
// res4.devices.forEach((device) => {
|
|
||||
// if (!device.name && !device.localName) {
|
|
||||
// return
|
|
||||
// }
|
|
||||
// that.devicesList.push(device)
|
|
||||
// })
|
|
||||
// })
|
|
||||
} |
|
||||
|
|
||||
}, |
|
||||
lianejieshebei(deviceId) { |
|
||||
let that = this; |
|
||||
uni.showLoading({ |
|
||||
mask: true, |
|
||||
title: '加载中...' |
|
||||
}); |
|
||||
// let timerId = setTimeout(() => {
|
|
||||
// uni.closeBLEConnection({
|
|
||||
// deviceId: deviceId,
|
|
||||
// success(res2) {
|
|
||||
|
|
||||
// },fail(err1){
|
|
||||
|
|
||||
// }
|
|
||||
// })
|
|
||||
// uni.closeBluetoothAdapter({
|
|
||||
// success(res) {
|
|
||||
|
|
||||
// },fail(err2){
|
|
||||
|
|
||||
// }
|
|
||||
// })
|
|
||||
// uni.removeStorageSync('deviceId')
|
|
||||
// that.handlePrintTap()
|
|
||||
// that.isShowSearch = true
|
|
||||
// return
|
|
||||
// }, 5000);
|
|
||||
|
|
||||
// 连接设备
|
|
||||
uni.createBLEConnection({ //555
|
|
||||
deviceId: deviceId, // 搜索到设备的 deviceId
|
|
||||
success: () => { |
|
||||
console.log('createBLEConnection成功') |
|
||||
// 连接成功就清除定时器
|
|
||||
// clearTimeout(timerId);
|
|
||||
// that.isShowSearch = false
|
|
||||
that.huoqufuwu(deviceId) |
|
||||
}, |
|
||||
fail: (res) => { |
|
||||
uni.showToast({ |
|
||||
duration: 2000, |
|
||||
title: "蓝牙连接失败,请查看打印机状态或重新连接", |
|
||||
icon: 'none', |
|
||||
mask: true |
|
||||
}) |
|
||||
// console.log('deviceId对吗?',deviceId)
|
|
||||
// console.log('createBLEConnection失败',res)
|
|
||||
// clearTimeout(timerId);
|
|
||||
// // if(res.errno == '1509007'){
|
|
||||
// that.huoqufuwu(deviceId)
|
|
||||
// // }
|
|
||||
// if(res.errno == '1509003'){
|
|
||||
// that.lianejieshebei(deviceId)
|
|
||||
// }
|
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
huoqufuwu(deviceId) { |
|
||||
let that = this; |
|
||||
//获取服务
|
|
||||
uni.getBLEDeviceServices({ //666
|
|
||||
deviceId: deviceId, // 搜索到设备的 deviceId
|
|
||||
success: (res5) => { |
|
||||
console.log('getBLEDeviceServices成功') |
|
||||
that.duxietezhengzhi(deviceId, res5) |
|
||||
}, |
|
||||
fail: (res) => { |
|
||||
|
|
||||
uni.showToast({ |
|
||||
duration: 2000, |
|
||||
title: "蓝牙连接失败,请查看打印机状态或重新连接", |
|
||||
icon: 'none', |
|
||||
mask: true |
|
||||
}) |
|
||||
// console.log('getBLEDeviceServices失败')
|
|
||||
// that.tui.toast('连接失败,请重启蓝牙或删除小程序重新进入-4',res)
|
|
||||
|
|
||||
// uni.closeBLEConnection({
|
|
||||
// deviceId: uni.getStorageSync('deviceId'),
|
|
||||
// success(res1) {
|
|
||||
|
|
||||
// }
|
|
||||
// })
|
|
||||
// uni.removeStorageSync('deviceId')
|
|
||||
// that.sousuo()
|
|
||||
// that.isShowSearch = true
|
|
||||
// setTimeout(res => {
|
|
||||
// uni.hideLoading();
|
|
||||
// }, 2000)
|
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
duxietezhengzhi(deviceId, res5) { |
|
||||
let that = this; |
|
||||
//读写特征值
|
|
||||
uni.getBLEDeviceCharacteristics({ //777
|
|
||||
deviceId: deviceId, // 搜索到设备的 deviceId
|
|
||||
serviceId: res5.services[2].uuid, // 上一步中找到的某个服务
|
|
||||
success: (res6) => { |
|
||||
console.log('getBLEDeviceCharacteristics成功',res6) |
|
||||
for (let i = 0; i < res6.characteristics.length; i++) { |
|
||||
let item = res6.characteristics[i] |
|
||||
|
|
||||
if (item.properties.write) { // 该特征值可写
|
|
||||
|
|
||||
that.startNoticeBle(deviceId, res5.services[2].uuid, res6.characteristics[2].uuid) |
|
||||
uni.setStorageSync('deviceId', deviceId); |
|
||||
uni.setStorageSync('serviceId', res5.services[2].uuid); |
|
||||
uni.setStorageSync('characteristicId', item.uuid); |
|
||||
that.xierushuju() |
|
||||
return; |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
fail: (res) => { |
|
||||
uni.showToast({ |
|
||||
duration: 2000, |
|
||||
title: "蓝牙连接失败,请查看打印机状态或重新连接", |
|
||||
icon: 'none', |
|
||||
mask: true |
|
||||
}) |
|
||||
// console.log('getBLEDeviceCharacteristics失败')
|
|
||||
// that.tui.toast('连接失败,请重启蓝牙或删除小程序重新进入-5',res)
|
|
||||
|
|
||||
// uni.closeBLEConnection({
|
|
||||
// deviceId: uni.getStorageSync('deviceId'),
|
|
||||
// success(res) {
|
|
||||
|
|
||||
// }
|
|
||||
// })
|
|
||||
// uni.removeStorageSync('deviceId')
|
|
||||
// that.sousuo()
|
|
||||
// that.isShowSearch = true
|
|
||||
// setTimeout(res => {
|
|
||||
// uni.hideLoading();
|
|
||||
// }, 2000)
|
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
// 开启蓝牙数据监听
|
|
||||
startNoticeBle(deviceId, serviceId, characteristicId) { |
|
||||
let that = this |
|
||||
uni.notifyBLECharacteristicValueChange({ |
|
||||
state: true, // 启用 notify 功能
|
|
||||
deviceId: deviceId, |
|
||||
serviceId: serviceId, |
|
||||
characteristicId: characteristicId, |
|
||||
success(res) { |
|
||||
console.log("监听成功",res) |
|
||||
that.GetDataFromBle(); |
|
||||
}, |
|
||||
fail: function(err) { |
|
||||
console.log("监听失败了") |
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
// 设备返回的数据接收
|
|
||||
GetDataFromBle() { |
|
||||
var that = this; |
|
||||
console.log('哈希之前2222222222222222'); |
|
||||
uni.onBLECharacteristicValueChange((res) => { |
|
||||
// 此时可以拿到蓝牙设备返回来的数据是一个ArrayBuffer类型数据,所以需要通过一个方法转换成字符串
|
|
||||
console.log('哈希之前111111111111',res); |
|
||||
var bleData = that.ab2hex(res.value) |
|
||||
console.log('哈希了吗?',bleData) |
|
||||
|
|
||||
uni.hideLoading() |
|
||||
setTimeout(res=>{ |
|
||||
uni.closeBLEConnection({ |
|
||||
deviceId: uni.getStorageSync('deviceId'), |
|
||||
success(res) {}, |
|
||||
fail(err) {} |
|
||||
}) |
|
||||
// that.getIsData("0")
|
|
||||
bufferData = [] |
|
||||
},1000) |
|
||||
|
|
||||
}) |
|
||||
}, |
|
||||
ab2hex(buffer) { |
|
||||
return Array.from(new Uint8Array(buffer)) |
|
||||
.map(byte => ('00' + byte.toString(16)).slice(-2)) |
|
||||
.join(''); |
|
||||
}, |
|
||||
xierushuju() { |
|
||||
let that = this; |
|
||||
//写入数据
|
|
||||
|
|
||||
console.log("22222222222222",bufferData) |
|
||||
|
|
||||
var dataStr = '' |
|
||||
for (let m = 0; m < bufferData.length; m++) { |
|
||||
dataStr += bufferData[m] |
|
||||
} |
|
||||
const maxChunk = deviceType == 'android' ? 20 : 180; |
|
||||
const delay = deviceType == 'android' ? 20 : 180; |
|
||||
|
|
||||
let buffer = gbk.strToGBKByte(dataStr) |
|
||||
|
|
||||
for (let i = 0, j = 0, length = buffer.byteLength; i < length; i += maxChunk, j++) { |
|
||||
let subPackage = buffer.slice(i, i + maxChunk <= length ? (i + maxChunk) : length); |
|
||||
setTimeout(that._writeBLECharacteristicValue, j * delay, subPackage); |
|
||||
} |
|
||||
return; |
|
||||
}, |
|
||||
_writeBLECharacteristicValue(buffer) { |
|
||||
let that = this; |
|
||||
uni.writeBLECharacteristicValue({ |
|
||||
deviceId: uni.getStorageSync('deviceId'), |
|
||||
serviceId: uni.getStorageSync('serviceId'), |
|
||||
characteristicId: uni.getStorageSync('characteristicId'), |
|
||||
value: buffer, |
|
||||
success(res) { |
|
||||
console.log("66666666666") |
|
||||
}, |
|
||||
fail(res) { |
|
||||
console.log("777777777",res) |
|
||||
uni.showToast({ |
|
||||
duration: 2000, |
|
||||
title: "打印失败,请查看打印机状态或重新连接", |
|
||||
icon: 'none', |
|
||||
mask: true |
|
||||
}) |
|
||||
uni.closeBLEConnection({ |
|
||||
deviceId: uni.getStorageSync('deviceId'), |
|
||||
success(res) { |
|
||||
|
|
||||
} |
|
||||
}) |
|
||||
// if (uni.getStorageSync('deviceId')) {
|
|
||||
// // that.xierushuju()
|
|
||||
// } else {
|
|
||||
// that.jiantingshebei()
|
|
||||
// }
|
|
||||
// uni.hideLoading();
|
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
}, |
|
||||
handleSearchClose() { |
|
||||
uni.closeBluetoothAdapter({ |
|
||||
success(res) { |
|
||||
|
|
||||
} |
|
||||
}) |
|
||||
this.isShowSearch = false |
|
||||
}, |
|
||||
getIsData(type){ |
|
||||
if(type == 0){ |
|
||||
// 删除数组中第一个元素
|
|
||||
getApp().globalData.printData.shift(); |
|
||||
} |
|
||||
if(getApp().globalData.printData.length>0){ |
|
||||
this.onPrint() |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,613 +0,0 @@ |
|||||
<template> |
|
||||
<view class="kk-printer"> |
|
||||
<view class="kk-printer-btn" @tap="handlePrintTap" style="color:#FFF;"> |
|
||||
{{isPrinting?printingText:defaultText}} |
|
||||
</view> |
|
||||
<view class="kk-shadow" :class="isShowSearch?'show':''" @tap="handleSearchClose"> |
|
||||
<view class="kk-modal" @tap.stop="doNothing"> |
|
||||
<view class="kk-search-device"> |
|
||||
<view class="kk-btn-wrap"> |
|
||||
<view class="kk-btn-item confirm-btn" @tap="sousuo" v-if="!isSearching"> |
|
||||
搜索设备 |
|
||||
</view> |
|
||||
<view class="kk-btn-item confirm-btn" v-else> |
|
||||
搜索中... |
|
||||
</view> |
|
||||
<view class="kk-btn-item" @tap="stopSearchBtnTap"> |
|
||||
停止搜索 |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="kk-devices-wrap"> |
|
||||
<view class="empty-wrap" v-if="devicesList.length <= 0"> |
|
||||
<view class="empty-icon"></view> |
|
||||
<view class="empty-text">无可搜索到的设备</view> |
|
||||
</view> |
|
||||
<view class="" v-else> |
|
||||
<view class="kk-devices-item" v-for="(item,index) in devicesList" :key="index" |
|
||||
@tap="lianejieshebei(item.deviceId)"> |
|
||||
<view class="name" style="color:#000;display: flex;flex-direction: column;"> |
|
||||
<text>设备名称:</text> |
|
||||
<text>{{item.name?item.name:'未命名'}}</text> |
|
||||
</view> |
|
||||
<!-- <view class="rssi"> |
|
||||
<text>信号强度:</text> |
|
||||
<text>({{item.RSSI}})</text> |
|
||||
</view> --> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import gbk from '@/components/kk-printer/utils/printUtil-GBK.js'; |
|
||||
import * as blesdk from './utils/bluetoolth'; |
|
||||
import util from './utils/util.js'; |
|
||||
export default { |
|
||||
data() { |
|
||||
return { |
|
||||
//是否正在打印 |
|
||||
isPrinting: false, |
|
||||
//是否正在搜索设备 |
|
||||
isSearching: false, |
|
||||
//是否显示蓝牙列表 |
|
||||
isShowSearch: false, |
|
||||
//按蓝牙名过滤 |
|
||||
filterName: '', |
|
||||
//按信号过滤 |
|
||||
filterRSSI: -95, |
|
||||
//设备列表 |
|
||||
devicesList: [], |
|
||||
//打印图片断开连接等待时间 |
|
||||
picWaitTime:0, |
|
||||
//连接的设备ID |
|
||||
deviceId: '', |
|
||||
//根据设备ID获取的服务 |
|
||||
services: '', |
|
||||
//获取特征值时返回的三要素 |
|
||||
serviceId: '', |
|
||||
writeId: '', |
|
||||
readId: '', |
|
||||
iosNo: false, |
|
||||
deviceType: 'ios' |
|
||||
} |
|
||||
}, |
|
||||
props: { |
|
||||
//按钮默认文字 |
|
||||
defaultText: { |
|
||||
type: String, |
|
||||
default: '连接蓝牙' |
|
||||
}, |
|
||||
//按钮打印中的文字 |
|
||||
printingText: { |
|
||||
type: String, |
|
||||
default: '打印中...' |
|
||||
}, |
|
||||
bufferData: { |
|
||||
type: Array, |
|
||||
require: true |
|
||||
}, |
|
||||
roomcode: { |
|
||||
type: String, |
|
||||
require: true |
|
||||
}, |
|
||||
CustName: { |
|
||||
type: String, |
|
||||
require: true |
|
||||
}, |
|
||||
roomid: { |
|
||||
type: String, |
|
||||
require: true |
|
||||
} |
|
||||
}, |
|
||||
mounted() { |
|
||||
|
|
||||
}, |
|
||||
onLoad() { |
|
||||
|
|
||||
}, |
|
||||
beforeDestroy() { |
|
||||
|
|
||||
this.stopSearchBtnTap(); |
|
||||
}, |
|
||||
methods: { |
|
||||
doNothing() { |
|
||||
return; |
|
||||
}, |
|
||||
//点击打印按钮 |
|
||||
handlePrintTap() { |
|
||||
let that = this |
|
||||
uni.showLoading({ |
|
||||
mask: true, |
|
||||
title: '打印中...' |
|
||||
}); |
|
||||
uni.getSystemInfo({ |
|
||||
success(res) { |
|
||||
console.log('设备类型',res.osName) |
|
||||
that.deviceType = res.osName |
|
||||
},fail(err){ |
|
||||
|
|
||||
} |
|
||||
}) |
|
||||
// 初始化蓝牙模块 |
|
||||
uni.openBluetoothAdapter({ //111 |
|
||||
mode: 'central', |
|
||||
success: (res2) => { |
|
||||
that.sousuo() |
|
||||
}, |
|
||||
fail: (res) => { |
|
||||
|
|
||||
if (res.errCode == '10001') { |
|
||||
uni.showToast({ |
|
||||
duration: 2000, |
|
||||
title: "请打开蓝牙后,再进行连接", |
|
||||
icon: 'none', |
|
||||
mask: true |
|
||||
}) |
|
||||
} else { |
|
||||
that.tui.toast('连接失败,请重启蓝牙或删除小程序重新进入-1') |
|
||||
that.isShowSearch = true |
|
||||
} |
|
||||
setTimeout(res => { |
|
||||
uni.hideLoading(); |
|
||||
}, 2000) |
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
// 开始搜索附近的蓝牙外围设备 |
|
||||
sousuo() { |
|
||||
let that = this; |
|
||||
this.devicesList = [] |
|
||||
uni.startBluetoothDevicesDiscovery({ //222 |
|
||||
success(res3) { |
|
||||
|
|
||||
that.jiantingshebei() |
|
||||
}, |
|
||||
fail(err) { |
|
||||
that.tui.toast('连接失败,请重启蓝牙或删除小程序重新进入-2',err) |
|
||||
|
|
||||
uni.closeBLEConnection({ |
|
||||
deviceId: uni.getStorageSync('deviceId'), |
|
||||
success(res2) { |
|
||||
|
|
||||
},fail(err1){ |
|
||||
|
|
||||
} |
|
||||
}) |
|
||||
uni.closeBluetoothAdapter({ |
|
||||
success(res) { |
|
||||
|
|
||||
},fail(err2){ |
|
||||
|
|
||||
} |
|
||||
}) |
|
||||
uni.removeStorageSync('deviceId') |
|
||||
that.handlePrintTap() |
|
||||
that.isShowSearch = true |
|
||||
setTimeout(res => { |
|
||||
uni.hideLoading(); |
|
||||
}, 2000) |
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
//停止搜索蓝牙设备 |
|
||||
stopSearchBtnTap() { |
|
||||
uni.stopBluetoothDevicesDiscovery() |
|
||||
}, |
|
||||
/** |
|
||||
* jiantingshebei方法,判断缓存中有没有deviceId等数据的时候, |
|
||||
* 有: 直接拿到缓存中的deviceId等,直接请求 uni.createBLEConnection |
|
||||
* 没有:才会调用 uni.onBluetoothDeviceFound 搜索 |
|
||||
*/ |
|
||||
jiantingshebei() { |
|
||||
let that = this; |
|
||||
if (uni.getStorageSync('deviceId')) { |
|
||||
// that.huoqufuwu(uni.getStorageSync('deviceId')) |
|
||||
|
|
||||
that.lianejieshebei(uni.getStorageSync('deviceId')) |
|
||||
} else { |
|
||||
uni.hideLoading(); |
|
||||
that.isShowSearch = true |
|
||||
// 监听扫描到新设备事件 |
|
||||
uni.onBluetoothDeviceFound((res4) => { //333 |
|
||||
res4.devices.forEach((device) => { |
|
||||
if (!device.name && !device.localName) { |
|
||||
return |
|
||||
} |
|
||||
that.devicesList.push(device) |
|
||||
}) |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
}, |
|
||||
lianejieshebei(deviceId) { |
|
||||
let that = this; |
|
||||
uni.showLoading({ |
|
||||
mask: true, |
|
||||
title: '加载中...' |
|
||||
}); |
|
||||
let timerId = setTimeout(() => { |
|
||||
uni.closeBLEConnection({ |
|
||||
deviceId: deviceId, |
|
||||
success(res2) { |
|
||||
|
|
||||
},fail(err1){ |
|
||||
|
|
||||
} |
|
||||
}) |
|
||||
uni.closeBluetoothAdapter({ |
|
||||
success(res) { |
|
||||
|
|
||||
},fail(err2){ |
|
||||
|
|
||||
} |
|
||||
}) |
|
||||
uni.removeStorageSync('deviceId') |
|
||||
that.handlePrintTap() |
|
||||
that.isShowSearch = true |
|
||||
return |
|
||||
}, 5000); |
|
||||
|
|
||||
// 连接设备 |
|
||||
uni.createBLEConnection({ //555 |
|
||||
deviceId: deviceId, // 搜索到设备的 deviceId |
|
||||
success: () => { |
|
||||
// 连接成功就清除定时器 |
|
||||
clearTimeout(timerId); |
|
||||
that.isShowSearch = false |
|
||||
uni.setStorageSync('deviceId', deviceId); |
|
||||
uni.showToast({ |
|
||||
duration: 2000, |
|
||||
title: "蓝牙连接成功", |
|
||||
icon: 'none', |
|
||||
mask: true |
|
||||
}) |
|
||||
that.$emit('statusChange') |
|
||||
setTimeout(res=>{ |
|
||||
uni.closeBLEConnection({ |
|
||||
deviceId:uni.getStorageSync('deviceId') |
|
||||
}) |
|
||||
},1000) |
|
||||
// that.huoqufuwu(deviceId) |
|
||||
}, |
|
||||
fail: (res) => { |
|
||||
|
|
||||
clearTimeout(timerId); |
|
||||
if(res.errno == '1509007'){ |
|
||||
that.huoqufuwu(deviceId) |
|
||||
} |
|
||||
if(res.errno == '1509003'){ |
|
||||
that.lianejieshebei(deviceId) |
|
||||
} |
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
huoqufuwu(deviceId) { |
|
||||
let that = this; |
|
||||
//获取服务 |
|
||||
uni.getBLEDeviceServices({ //666 |
|
||||
deviceId: deviceId, // 搜索到设备的 deviceId |
|
||||
success: (res5) => { |
|
||||
that.duxietezhengzhi(deviceId, res5) |
|
||||
}, |
|
||||
fail: (res) => { |
|
||||
that.tui.toast('连接失败,请重启蓝牙或删除小程序重新进入-4',res) |
|
||||
|
|
||||
uni.closeBLEConnection({ |
|
||||
deviceId: uni.getStorageSync('deviceId'), |
|
||||
success(res1) { |
|
||||
|
|
||||
} |
|
||||
}) |
|
||||
uni.removeStorageSync('deviceId') |
|
||||
that.sousuo() |
|
||||
that.isShowSearch = true |
|
||||
setTimeout(res => { |
|
||||
uni.hideLoading(); |
|
||||
}, 2000) |
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
duxietezhengzhi(deviceId, res5) { |
|
||||
let that = this; |
|
||||
//读写特征值 |
|
||||
uni.getBLEDeviceCharacteristics({ //777 |
|
||||
deviceId: deviceId, // 搜索到设备的 deviceId |
|
||||
serviceId: res5.services[2].uuid, // 上一步中找到的某个服务 |
|
||||
success: (res6) => { |
|
||||
for (let i = 0; i < res6.characteristics.length; i++) { |
|
||||
let item = res6.characteristics[i] |
|
||||
|
|
||||
if (item.properties.write && item.properties.notify) { // 该特征值可写 |
|
||||
|
|
||||
// that.startNoticeBle(deviceId, res5.services[2].uuid, item.uuid) |
|
||||
uni.setStorageSync('deviceId', deviceId); |
|
||||
uni.setStorageSync('serviceId', res5.services[2].uuid); |
|
||||
uni.setStorageSync('characteristicId', item.uuid); |
|
||||
// that.xierushuju() |
|
||||
return; |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
fail: (res) => { |
|
||||
that.tui.toast('连接失败,请重启蓝牙或删除小程序重新进入-5',res) |
|
||||
|
|
||||
uni.closeBLEConnection({ |
|
||||
deviceId: uni.getStorageSync('deviceId'), |
|
||||
success(res) { |
|
||||
|
|
||||
} |
|
||||
}) |
|
||||
uni.removeStorageSync('deviceId') |
|
||||
that.sousuo() |
|
||||
that.isShowSearch = true |
|
||||
setTimeout(res => { |
|
||||
uni.hideLoading(); |
|
||||
}, 2000) |
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
// 开启蓝牙数据监听 |
|
||||
startNoticeBle(deviceId, serviceId, characteristicId) { |
|
||||
let that = this |
|
||||
uni.notifyBLECharacteristicValueChange({ |
|
||||
state: true, // 启用 notify 功能 |
|
||||
deviceId: deviceId, |
|
||||
serviceId: serviceId, |
|
||||
characteristicId: characteristicId, |
|
||||
success(res) { |
|
||||
console.log("监听成功") |
|
||||
that.GetDataFromBle(); |
|
||||
}, |
|
||||
fail: function(err) { |
|
||||
console.log("监听失败了") |
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
// 设备返回的数据接收 |
|
||||
GetDataFromBle() { |
|
||||
var that = this; |
|
||||
uni.onBLECharacteristicValueChange((res) => { |
|
||||
// 此时可以拿到蓝牙设备返回来的数据是一个ArrayBuffer类型数据,所以需要通过一个方法转换成字符串 |
|
||||
|
|
||||
that.bleData = that.ab2hex(res.value) |
|
||||
console.log('哈希了吗?',that.bleData) |
|
||||
uni.hideLoading() |
|
||||
setTimeout(res=>{ |
|
||||
uni.closeBLEConnection({ |
|
||||
deviceId: uni.getStorageSync('deviceId'), |
|
||||
success(res) {}, |
|
||||
fail(err) {} |
|
||||
}) |
|
||||
},that.picWaitTime) |
|
||||
|
|
||||
}) |
|
||||
}, |
|
||||
ab2hex(buffer) { |
|
||||
const hexArr = Array.prototype.map.call( |
|
||||
new Uint8Array(buffer), |
|
||||
function(bit) { |
|
||||
return ('00' + bit.toString(16)).slice(-2) |
|
||||
} |
|
||||
) |
|
||||
return hexArr.join('') |
|
||||
}, |
|
||||
xierushuju() { |
|
||||
let that = this; |
|
||||
//写入数据 |
|
||||
|
|
||||
that.$emit('onPrint'); |
|
||||
|
|
||||
console.log("22222222222222",that.bufferData) |
|
||||
that.$nextTick(() => { |
|
||||
var dataStr = '' |
|
||||
for (let m = 0; m < that.bufferData.length; m++) { |
|
||||
dataStr += that.bufferData[m] |
|
||||
} |
|
||||
const maxChunk = that.deviceType == 'android' ? 20 : 180; |
|
||||
const delay = that.deviceType == 'android' ? 180 : 180; |
|
||||
|
|
||||
let buffer = gbk.strToGBKByte(dataStr) |
|
||||
|
|
||||
if(dataStr.indexOf('EG ') != -1){ |
|
||||
that.picWaitTime = buffer.byteLength + 200 |
|
||||
} |
|
||||
for (let i = 0, j = 0, length = buffer.byteLength; i < length; i += maxChunk, j++) { |
|
||||
let subPackage = buffer.slice(i, i + maxChunk <= length ? (i + maxChunk) : length); |
|
||||
setTimeout(that._writeBLECharacteristicValue, j * delay, subPackage); |
|
||||
} |
|
||||
|
|
||||
}) |
|
||||
return; |
|
||||
}, |
|
||||
_writeBLECharacteristicValue(buffer) { |
|
||||
|
|
||||
let that = this; |
|
||||
uni.writeBLECharacteristicValue({ |
|
||||
deviceId: uni.getStorageSync('deviceId'), |
|
||||
serviceId: uni.getStorageSync('serviceId'), |
|
||||
characteristicId: uni.getStorageSync('characteristicId'), |
|
||||
value: buffer, |
|
||||
success(res) { |
|
||||
console.log("66666666666") |
|
||||
}, |
|
||||
fail(res) { |
|
||||
console.log("777777777",res) |
|
||||
uni.closeBLEConnection({ |
|
||||
deviceId: uni.getStorageSync('deviceId'), |
|
||||
success(res) { |
|
||||
|
|
||||
} |
|
||||
}) |
|
||||
if (uni.getStorageSync('deviceId')) { |
|
||||
// that.xierushuju() |
|
||||
} else { |
|
||||
that.jiantingshebei() |
|
||||
} |
|
||||
uni.hideLoading(); |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
}, |
|
||||
handleSearchClose() { |
|
||||
uni.closeBluetoothAdapter({ |
|
||||
success(res) { |
|
||||
|
|
||||
} |
|
||||
}) |
|
||||
this.isShowSearch = false |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
.kk-printer { |
|
||||
&-btn { |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
} |
|
||||
|
|
||||
.kk-shadow { |
|
||||
display: none; |
|
||||
z-index: 999; |
|
||||
|
|
||||
&.show { |
|
||||
display: block; |
|
||||
width: 100vw; |
|
||||
height: 100vh; |
|
||||
background: rgba(0, 0, 0, 0.4); |
|
||||
position: fixed; |
|
||||
top: 0; |
|
||||
left: 0; |
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
|
|
||||
.kk-modal { |
|
||||
width: 420rpx; |
|
||||
height: 600rpx; |
|
||||
padding: 24rpx; |
|
||||
box-sizing: border-box; |
|
||||
overflow-y: auto; |
|
||||
border-radius: 20rpx; |
|
||||
background: #ffffff; |
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
|
|
||||
.kk-search-device { |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
|
|
||||
.kk-filter-wrap { |
|
||||
width: 100%; |
|
||||
height: 160rpx; |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
justify-content: flex-start; |
|
||||
align-items: flex-start; |
|
||||
|
|
||||
&>slider { |
|
||||
width: 90%; |
|
||||
height: 90rpx; |
|
||||
} |
|
||||
|
|
||||
&>input { |
|
||||
padding: 0 20rpx; |
|
||||
box-sizing: border-box; |
|
||||
border-radius: 10rpx; |
|
||||
height: 90rpx; |
|
||||
width: 100%; |
|
||||
border: 1rpx solid #ebebeb; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.kk-btn-wrap { |
|
||||
width: 100%; |
|
||||
height: 90rpx; |
|
||||
display: flex; |
|
||||
justify-content: space-between; |
|
||||
align-items: center; |
|
||||
padding: 20rpx; |
|
||||
|
|
||||
&>view { |
|
||||
flex: 1 1 auto; |
|
||||
height: 60rpx; |
|
||||
line-height: 60rpx; |
|
||||
border-radius: 16rpx; |
|
||||
text-align: center; |
|
||||
color: #ffffff; |
|
||||
font-size: 26rpx; |
|
||||
|
|
||||
&.confirm-btn { |
|
||||
background: #007AFF; |
|
||||
margin-right: 30rpx; |
|
||||
} |
|
||||
|
|
||||
&:nth-last-child(1) { |
|
||||
background: #DD524D; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.kk-devices-wrap { |
|
||||
height: calc(100% - 80rpx); |
|
||||
overflow-y: auto; |
|
||||
padding: 10rpx 20rpx; |
|
||||
box-sizing: border-box; |
|
||||
border: 1rpx solid #ebebeb; |
|
||||
box-sizing: border-box; |
|
||||
border-radius: 20rpx; |
|
||||
|
|
||||
.empty-wrap { |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
|
|
||||
.empty-icon { |
|
||||
width: 268rpx; |
|
||||
height: 240rpx; |
|
||||
background-size: 100% 100%; |
|
||||
margin-bottom: 26rpx; |
|
||||
} |
|
||||
|
|
||||
.empty-text { |
|
||||
width: 100%; |
|
||||
line-height: 50rpx; |
|
||||
font-size: 30rpx; |
|
||||
text-align: center; |
|
||||
color: #999999; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.kk-devices-item { |
|
||||
width: 100%; |
|
||||
border-bottom: 1rpx solid #ebebeb; |
|
||||
padding: 10rpx 0; |
|
||||
box-sizing: border-box; |
|
||||
z-index: 500; |
|
||||
|
|
||||
&:nth-last-child(1) { |
|
||||
border-bottom: none; |
|
||||
} |
|
||||
|
|
||||
&>view { |
|
||||
width: 100%; |
|
||||
font-size: 30rpx; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
Binary file not shown.
@ -1,402 +0,0 @@ |
|||||
var CHAR_TILDE = 126; |
|
||||
var CODE_FNC1 = 102; |
|
||||
|
|
||||
var SET_STARTA = 103; |
|
||||
var SET_STARTB = 104; |
|
||||
var SET_STARTC = 105; |
|
||||
var SET_SHIFT = 98; |
|
||||
var SET_CODEA = 101; |
|
||||
var SET_CODEB = 100; |
|
||||
var SET_STOP = 106; |
|
||||
|
|
||||
|
|
||||
var REPLACE_CODES = { |
|
||||
CHAR_TILDE: CODE_FNC1 //~ corresponds to FNC1 in GS1-128 standard
|
|
||||
} |
|
||||
|
|
||||
var CODESET = { |
|
||||
ANY: 1, |
|
||||
AB: 2, |
|
||||
A: 3, |
|
||||
B: 4, |
|
||||
C: 5 |
|
||||
}; |
|
||||
|
|
||||
function getBytes(str) { |
|
||||
var bytes = []; |
|
||||
for (var i = 0; i < str.length; i++) { |
|
||||
bytes.push(str.charCodeAt(i)); |
|
||||
} |
|
||||
return bytes; |
|
||||
} |
|
||||
|
|
||||
exports.code128 = function (ctx, text, width, height) { |
|
||||
|
|
||||
width = parseInt(width); |
|
||||
|
|
||||
height = parseInt(height); |
|
||||
|
|
||||
var codes = stringToCode128(text); |
|
||||
|
|
||||
var g = new Graphics(ctx, width, height); |
|
||||
|
|
||||
var barWeight = g.area.width / ((codes.length - 3) * 11 + 35); |
|
||||
|
|
||||
var x = g.area.left; |
|
||||
var y = g.area.top; |
|
||||
for (var i = 0; i < codes.length; i++) { |
|
||||
var c = codes[i]; |
|
||||
//two bars at a time: 1 black and 1 white
|
|
||||
for (var bar = 0; bar < 8; bar += 2) { |
|
||||
var barW = PATTERNS[c][bar] * barWeight; |
|
||||
// var barH = height - y - this.border;
|
|
||||
var barH = height - y; |
|
||||
var spcW = PATTERNS[c][bar + 1] * barWeight; |
|
||||
|
|
||||
//no need to draw if 0 width
|
|
||||
if (barW > 0) { |
|
||||
g.fillFgRect(x, y, barW, barH); |
|
||||
} |
|
||||
|
|
||||
x += barW + spcW; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
ctx.draw(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
function stringToCode128(text) { |
|
||||
|
|
||||
var barc = { |
|
||||
currcs: CODESET.C |
|
||||
}; |
|
||||
|
|
||||
var bytes = getBytes(text); |
|
||||
//decide starting codeset
|
|
||||
var index = bytes[0] == CHAR_TILDE ? 1 : 0; |
|
||||
|
|
||||
var csa1 = bytes.length > 0 ? codeSetAllowedFor(bytes[index++]) : CODESET.AB; |
|
||||
var csa2 = bytes.length > 0 ? codeSetAllowedFor(bytes[index++]) : CODESET.AB; |
|
||||
barc.currcs = getBestStartSet(csa1, csa2); |
|
||||
barc.currcs = perhapsCodeC(bytes, barc.currcs); |
|
||||
|
|
||||
//if no codeset changes this will end up with bytes.length+3
|
|
||||
//start, checksum and stop
|
|
||||
var codes = new Array(); |
|
||||
|
|
||||
switch (barc.currcs) { |
|
||||
case CODESET.A: |
|
||||
codes.push(SET_STARTA); |
|
||||
break; |
|
||||
case CODESET.B: |
|
||||
codes.push(SET_STARTB); |
|
||||
break; |
|
||||
default: |
|
||||
codes.push(SET_STARTC); |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
for (var i = 0; i < bytes.length; i++) { |
|
||||
var b1 = bytes[i]; //get the first of a pair
|
|
||||
//should we translate/replace
|
|
||||
if (b1 in REPLACE_CODES) { |
|
||||
codes.push(REPLACE_CODES[b1]); |
|
||||
i++ //jump to next
|
|
||||
b1 = bytes[i]; |
|
||||
} |
|
||||
|
|
||||
//get the next in the pair if possible
|
|
||||
var b2 = bytes.length > (i + 1) ? bytes[i + 1] : -1; |
|
||||
|
|
||||
codes = codes.concat(codesForChar(b1, b2, barc.currcs)); |
|
||||
//code C takes 2 chars each time
|
|
||||
if (barc.currcs == CODESET.C) i++; |
|
||||
} |
|
||||
|
|
||||
//calculate checksum according to Code 128 standards
|
|
||||
var checksum = codes[0]; |
|
||||
for (var weight = 1; weight < codes.length; weight++) { |
|
||||
checksum += (weight * codes[weight]); |
|
||||
} |
|
||||
codes.push(checksum % 103); |
|
||||
|
|
||||
codes.push(SET_STOP); |
|
||||
|
|
||||
//encoding should now be complete
|
|
||||
return codes; |
|
||||
|
|
||||
function getBestStartSet(csa1, csa2) { |
|
||||
//tries to figure out the best codeset
|
|
||||
//to start with to get the most compact code
|
|
||||
var vote = 0; |
|
||||
vote += csa1 == CODESET.A ? 1 : 0; |
|
||||
vote += csa1 == CODESET.B ? -1 : 0; |
|
||||
vote += csa2 == CODESET.A ? 1 : 0; |
|
||||
vote += csa2 == CODESET.B ? -1 : 0; |
|
||||
//tie goes to B due to my own predudices
|
|
||||
return vote > 0 ? CODESET.A : CODESET.B; |
|
||||
} |
|
||||
|
|
||||
function perhapsCodeC(bytes, codeset) { |
|
||||
for (var i = 0; i < bytes.length; i++) { |
|
||||
var b = bytes[i] |
|
||||
if ((b < 48 || b > 57) && b != CHAR_TILDE) |
|
||||
return codeset; |
|
||||
} |
|
||||
return CODESET.C; |
|
||||
} |
|
||||
|
|
||||
//chr1 is current byte
|
|
||||
//chr2 is the next byte to process. looks ahead.
|
|
||||
function codesForChar(chr1, chr2, currcs) { |
|
||||
var result = []; |
|
||||
var shifter = -1; |
|
||||
|
|
||||
if (charCompatible(chr1, currcs)) { |
|
||||
if (currcs == CODESET.C) { |
|
||||
if (chr2 == -1) { |
|
||||
shifter = SET_CODEB; |
|
||||
currcs = CODESET.B; |
|
||||
} |
|
||||
else if ((chr2 != -1) && !charCompatible(chr2, currcs)) { |
|
||||
//need to check ahead as well
|
|
||||
if (charCompatible(chr2, CODESET.A)) { |
|
||||
shifter = SET_CODEA; |
|
||||
currcs = CODESET.A; |
|
||||
} |
|
||||
else { |
|
||||
shifter = SET_CODEB; |
|
||||
currcs = CODESET.B; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
else { |
|
||||
//if there is a next char AND that next char is also not compatible
|
|
||||
if ((chr2 != -1) && !charCompatible(chr2, currcs)) { |
|
||||
//need to switch code sets
|
|
||||
switch (currcs) { |
|
||||
case CODESET.A: |
|
||||
shifter = SET_CODEB; |
|
||||
currcs = CODESET.B; |
|
||||
break; |
|
||||
case CODESET.B: |
|
||||
shifter = SET_CODEA; |
|
||||
currcs = CODESET.A; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
else { |
|
||||
//no need to shift code sets, a temporary SHIFT will suffice
|
|
||||
shifter = SET_SHIFT; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
//ok some type of shift is nessecary
|
|
||||
if (shifter != -1) { |
|
||||
result.push(shifter); |
|
||||
result.push(codeValue(chr2)); |
|
||||
} |
|
||||
else { |
|
||||
if (currcs == CODESET.C) { |
|
||||
//include next as well
|
|
||||
result.push(codeValue(chr1, chr2)); |
|
||||
} |
|
||||
else { |
|
||||
result.push(codeValue(chr1)); |
|
||||
} |
|
||||
} |
|
||||
barc.currcs = currcs; |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
//reduce the ascii code to fit into the Code128 char table
|
|
||||
function codeValue(chr1, chr2) { |
|
||||
if (typeof chr2 == "undefined") { |
|
||||
return chr1 >= 32 ? chr1 - 32 : chr1 + 64; |
|
||||
} |
|
||||
else { |
|
||||
return parseInt(String.fromCharCode(chr1) + String.fromCharCode(chr2)); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function charCompatible(chr, codeset) { |
|
||||
var csa = codeSetAllowedFor(chr); |
|
||||
if (csa == CODESET.ANY) return true; |
|
||||
//if we need to change from current
|
|
||||
if (csa == CODESET.AB) return true; |
|
||||
if (csa == CODESET.A && codeset == CODESET.A) return true; |
|
||||
if (csa == CODESET.B && codeset == CODESET.B) return true; |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
function codeSetAllowedFor(chr) { |
|
||||
if (chr >= 48 && chr <= 57) { |
|
||||
//0-9
|
|
||||
return CODESET.ANY; |
|
||||
} |
|
||||
else if (chr >= 32 && chr <= 95) { |
|
||||
//0-9 A-Z
|
|
||||
return CODESET.AB; |
|
||||
} |
|
||||
else { |
|
||||
//if non printable
|
|
||||
return chr < 32 ? CODESET.A : CODESET.B; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
var Graphics = function(ctx, width, height) { |
|
||||
|
|
||||
this.width = width; |
|
||||
this.height = height; |
|
||||
this.quiet = Math.round(this.width / 40); |
|
||||
|
|
||||
this.border_size = 0; |
|
||||
this.padding_width = 0; |
|
||||
|
|
||||
this.area = { |
|
||||
width : width - this.padding_width * 2 - this.quiet * 2, |
|
||||
height: height - this.border_size * 2, |
|
||||
top : this.border_size - 4, |
|
||||
left : this.padding_width + this.quiet |
|
||||
}; |
|
||||
|
|
||||
this.ctx = ctx; |
|
||||
this.fg = "#000000"; |
|
||||
this.bg = "#ffffff"; |
|
||||
|
|
||||
// fill background
|
|
||||
this.fillBgRect(0,0, width, height); |
|
||||
|
|
||||
// fill center to create border
|
|
||||
this.fillBgRect(0, this.border_size, width, height - this.border_size * 2); |
|
||||
} |
|
||||
|
|
||||
//use native color
|
|
||||
Graphics.prototype._fillRect = function(x, y, width, height, color) { |
|
||||
this.ctx.setFillStyle(color) |
|
||||
this.ctx.fillRect(x, y, width, height) |
|
||||
} |
|
||||
|
|
||||
Graphics.prototype.fillFgRect = function(x,y, width, height) { |
|
||||
this._fillRect(x, y, width, height, this.fg); |
|
||||
} |
|
||||
|
|
||||
Graphics.prototype.fillBgRect = function(x,y, width, height) { |
|
||||
this._fillRect(x, y, width, height, this.bg); |
|
||||
} |
|
||||
|
|
||||
var PATTERNS = [ |
|
||||
[2, 1, 2, 2, 2, 2, 0, 0], // 0
|
|
||||
[2, 2, 2, 1, 2, 2, 0, 0], // 1
|
|
||||
[2, 2, 2, 2, 2, 1, 0, 0], // 2
|
|
||||
[1, 2, 1, 2, 2, 3, 0, 0], // 3
|
|
||||
[1, 2, 1, 3, 2, 2, 0, 0], // 4
|
|
||||
[1, 3, 1, 2, 2, 2, 0, 0], // 5
|
|
||||
[1, 2, 2, 2, 1, 3, 0, 0], // 6
|
|
||||
[1, 2, 2, 3, 1, 2, 0, 0], // 7
|
|
||||
[1, 3, 2, 2, 1, 2, 0, 0], // 8
|
|
||||
[2, 2, 1, 2, 1, 3, 0, 0], // 9
|
|
||||
[2, 2, 1, 3, 1, 2, 0, 0], // 10
|
|
||||
[2, 3, 1, 2, 1, 2, 0, 0], // 11
|
|
||||
[1, 1, 2, 2, 3, 2, 0, 0], // 12
|
|
||||
[1, 2, 2, 1, 3, 2, 0, 0], // 13
|
|
||||
[1, 2, 2, 2, 3, 1, 0, 0], // 14
|
|
||||
[1, 1, 3, 2, 2, 2, 0, 0], // 15
|
|
||||
[1, 2, 3, 1, 2, 2, 0, 0], // 16
|
|
||||
[1, 2, 3, 2, 2, 1, 0, 0], // 17
|
|
||||
[2, 2, 3, 2, 1, 1, 0, 0], // 18
|
|
||||
[2, 2, 1, 1, 3, 2, 0, 0], // 19
|
|
||||
[2, 2, 1, 2, 3, 1, 0, 0], // 20
|
|
||||
[2, 1, 3, 2, 1, 2, 0, 0], // 21
|
|
||||
[2, 2, 3, 1, 1, 2, 0, 0], // 22
|
|
||||
[3, 1, 2, 1, 3, 1, 0, 0], // 23
|
|
||||
[3, 1, 1, 2, 2, 2, 0, 0], // 24
|
|
||||
[3, 2, 1, 1, 2, 2, 0, 0], // 25
|
|
||||
[3, 2, 1, 2, 2, 1, 0, 0], // 26
|
|
||||
[3, 1, 2, 2, 1, 2, 0, 0], // 27
|
|
||||
[3, 2, 2, 1, 1, 2, 0, 0], // 28
|
|
||||
[3, 2, 2, 2, 1, 1, 0, 0], // 29
|
|
||||
[2, 1, 2, 1, 2, 3, 0, 0], // 30
|
|
||||
[2, 1, 2, 3, 2, 1, 0, 0], // 31
|
|
||||
[2, 3, 2, 1, 2, 1, 0, 0], // 32
|
|
||||
[1, 1, 1, 3, 2, 3, 0, 0], // 33
|
|
||||
[1, 3, 1, 1, 2, 3, 0, 0], // 34
|
|
||||
[1, 3, 1, 3, 2, 1, 0, 0], // 35
|
|
||||
[1, 1, 2, 3, 1, 3, 0, 0], // 36
|
|
||||
[1, 3, 2, 1, 1, 3, 0, 0], // 37
|
|
||||
[1, 3, 2, 3, 1, 1, 0, 0], // 38
|
|
||||
[2, 1, 1, 3, 1, 3, 0, 0], // 39
|
|
||||
[2, 3, 1, 1, 1, 3, 0, 0], // 40
|
|
||||
[2, 3, 1, 3, 1, 1, 0, 0], // 41
|
|
||||
[1, 1, 2, 1, 3, 3, 0, 0], // 42
|
|
||||
[1, 1, 2, 3, 3, 1, 0, 0], // 43
|
|
||||
[1, 3, 2, 1, 3, 1, 0, 0], // 44
|
|
||||
[1, 1, 3, 1, 2, 3, 0, 0], // 45
|
|
||||
[1, 1, 3, 3, 2, 1, 0, 0], // 46
|
|
||||
[1, 3, 3, 1, 2, 1, 0, 0], // 47
|
|
||||
[3, 1, 3, 1, 2, 1, 0, 0], // 48
|
|
||||
[2, 1, 1, 3, 3, 1, 0, 0], // 49
|
|
||||
[2, 3, 1, 1, 3, 1, 0, 0], // 50
|
|
||||
[2, 1, 3, 1, 1, 3, 0, 0], // 51
|
|
||||
[2, 1, 3, 3, 1, 1, 0, 0], // 52
|
|
||||
[2, 1, 3, 1, 3, 1, 0, 0], // 53
|
|
||||
[3, 1, 1, 1, 2, 3, 0, 0], // 54
|
|
||||
[3, 1, 1, 3, 2, 1, 0, 0], // 55
|
|
||||
[3, 3, 1, 1, 2, 1, 0, 0], // 56
|
|
||||
[3, 1, 2, 1, 1, 3, 0, 0], // 57
|
|
||||
[3, 1, 2, 3, 1, 1, 0, 0], // 58
|
|
||||
[3, 3, 2, 1, 1, 1, 0, 0], // 59
|
|
||||
[3, 1, 4, 1, 1, 1, 0, 0], // 60
|
|
||||
[2, 2, 1, 4, 1, 1, 0, 0], // 61
|
|
||||
[4, 3, 1, 1, 1, 1, 0, 0], // 62
|
|
||||
[1, 1, 1, 2, 2, 4, 0, 0], // 63
|
|
||||
[1, 1, 1, 4, 2, 2, 0, 0], // 64
|
|
||||
[1, 2, 1, 1, 2, 4, 0, 0], // 65
|
|
||||
[1, 2, 1, 4, 2, 1, 0, 0], // 66
|
|
||||
[1, 4, 1, 1, 2, 2, 0, 0], // 67
|
|
||||
[1, 4, 1, 2, 2, 1, 0, 0], // 68
|
|
||||
[1, 1, 2, 2, 1, 4, 0, 0], // 69
|
|
||||
[1, 1, 2, 4, 1, 2, 0, 0], // 70
|
|
||||
[1, 2, 2, 1, 1, 4, 0, 0], // 71
|
|
||||
[1, 2, 2, 4, 1, 1, 0, 0], // 72
|
|
||||
[1, 4, 2, 1, 1, 2, 0, 0], // 73
|
|
||||
[1, 4, 2, 2, 1, 1, 0, 0], // 74
|
|
||||
[2, 4, 1, 2, 1, 1, 0, 0], // 75
|
|
||||
[2, 2, 1, 1, 1, 4, 0, 0], // 76
|
|
||||
[4, 1, 3, 1, 1, 1, 0, 0], // 77
|
|
||||
[2, 4, 1, 1, 1, 2, 0, 0], // 78
|
|
||||
[1, 3, 4, 1, 1, 1, 0, 0], // 79
|
|
||||
[1, 1, 1, 2, 4, 2, 0, 0], // 80
|
|
||||
[1, 2, 1, 1, 4, 2, 0, 0], // 81
|
|
||||
[1, 2, 1, 2, 4, 1, 0, 0], // 82
|
|
||||
[1, 1, 4, 2, 1, 2, 0, 0], // 83
|
|
||||
[1, 2, 4, 1, 1, 2, 0, 0], // 84
|
|
||||
[1, 2, 4, 2, 1, 1, 0, 0], // 85
|
|
||||
[4, 1, 1, 2, 1, 2, 0, 0], // 86
|
|
||||
[4, 2, 1, 1, 1, 2, 0, 0], // 87
|
|
||||
[4, 2, 1, 2, 1, 1, 0, 0], // 88
|
|
||||
[2, 1, 2, 1, 4, 1, 0, 0], // 89
|
|
||||
[2, 1, 4, 1, 2, 1, 0, 0], // 90
|
|
||||
[4, 1, 2, 1, 2, 1, 0, 0], // 91
|
|
||||
[1, 1, 1, 1, 4, 3, 0, 0], // 92
|
|
||||
[1, 1, 1, 3, 4, 1, 0, 0], // 93
|
|
||||
[1, 3, 1, 1, 4, 1, 0, 0], // 94
|
|
||||
[1, 1, 4, 1, 1, 3, 0, 0], // 95
|
|
||||
[1, 1, 4, 3, 1, 1, 0, 0], // 96
|
|
||||
[4, 1, 1, 1, 1, 3, 0, 0], // 97
|
|
||||
[4, 1, 1, 3, 1, 1, 0, 0], // 98
|
|
||||
[1, 1, 3, 1, 4, 1, 0, 0], // 99
|
|
||||
[1, 1, 4, 1, 3, 1, 0, 0], // 100
|
|
||||
[3, 1, 1, 1, 4, 1, 0, 0], // 101
|
|
||||
[4, 1, 1, 1, 3, 1, 0, 0], // 102
|
|
||||
[2, 1, 1, 4, 1, 2, 0, 0], // 103
|
|
||||
[2, 1, 1, 2, 1, 4, 0, 0], // 104
|
|
||||
[2, 1, 1, 2, 3, 2, 0, 0], // 105
|
|
||||
[2, 3, 3, 1, 1, 1, 2, 0] // 106
|
|
||||
] |
|
||||
|
|
||||
@ -1,695 +0,0 @@ |
|||||
/** |
|
||||
* @export |
|
||||
* @param {string} name 微信api的名称 ,如 uniAsyncPromise("getSystemInfo",options) |
|
||||
* @param {object} options 除了success 和 fail 的其他参数 |
|
||||
* @returns |
|
||||
*/ |
|
||||
export function uniAsyncPromise(name, options) { |
|
||||
return new Promise((resolve, reject) => { |
|
||||
uni[name]({ |
|
||||
...(options || {}), |
|
||||
// ...options,
|
|
||||
success: (res) => { |
|
||||
resolve(res); |
|
||||
}, |
|
||||
fail: (err) => { |
|
||||
reject(err); |
|
||||
} |
|
||||
}); |
|
||||
}); |
|
||||
} |
|
||||
//微信小程序向蓝牙打印机发送数据进行打印的坑:
|
|
||||
//小程序api向蓝牙打印机发送数据打印,发送的任何内容都应该要转成二进制数据,而且蓝牙打印的文本编码是GBK的,发送中文需转成GBK编码再转成二进制数据发送
|
|
||||
//发送打印机指令也要转成二进制数据发送
|
|
||||
//蓝牙打印机一次接收的二级制数据有限制,不同的系统不同的蓝牙设备限制可能不同,微信建议一次20个字节,需做递归分包发送
|
|
||||
//发送完要打印的内容后,一定要发送一个打印的指令才能顺利打印 (有些指令就不需要)
|
|
||||
|
|
||||
//一、初始化蓝牙、开始检索蓝牙设备
|
|
||||
// { allowDuplicatesKey: true, interval: 500}
|
|
||||
export function openBlue() { |
|
||||
return uniAsyncPromise('openBluetoothAdapter') |
|
||||
} |
|
||||
|
|
||||
//搜索蓝牙设备
|
|
||||
export function startBluetoothDevicesDiscovery(option) { |
|
||||
uniAsyncPromise('startBluetoothDevicesDiscovery', option).then((res) => { |
|
||||
|
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
export function getConnectedBluetoothDevices(option) { |
|
||||
return uniAsyncPromise('getConnectedBluetoothDevices', option) |
|
||||
} |
|
||||
//二、
|
|
||||
/** |
|
||||
* |
|
||||
* |
|
||||
* @export |
|
||||
* @param {function} getDevices uni.getBluetoothDevices的监听回调函数 |
|
||||
*/ |
|
||||
export function onfindBlueDevices(getDevices) { |
|
||||
//监听寻找到新设备的事件
|
|
||||
uni.onBluetoothDeviceFound((devices)=>{ |
|
||||
//获取在蓝牙模块生效期间所有已发现的蓝牙设备
|
|
||||
uniAsyncPromise('getBluetoothDevices').then((res) => { |
|
||||
|
|
||||
getDevices && getDevices(res.devices); |
|
||||
}); |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* @export |
|
||||
* @param {function} stopBlueDevicesDiscovery 关闭蓝牙扫描 |
|
||||
*/ |
|
||||
export function stopBlueDevicesDiscovery() { |
|
||||
//监听寻找到新设备的事件
|
|
||||
return uniAsyncPromise('stopBluetoothDevicesDiscovery').then((res) => { |
|
||||
|
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
//三、连接蓝牙设备
|
|
||||
/** |
|
||||
* @export |
|
||||
* @param {function} createBLEConnection |
|
||||
* @param {number} deviceId 蓝牙设备id |
|
||||
*/ |
|
||||
export function createBLEConnection(deviceId, sucess, fail) { |
|
||||
//连接蓝牙设备
|
|
||||
uniAsyncPromise("createBLEConnection", { |
|
||||
deviceId |
|
||||
}) |
|
||||
.then(res => { |
|
||||
//连接成功可选择停止搜索蓝牙
|
|
||||
//stopBlueDevicesDiscovery();
|
|
||||
|
|
||||
sucess && sucess({ |
|
||||
res: res, |
|
||||
}); |
|
||||
}) |
|
||||
.catch(res => { |
|
||||
|
|
||||
fail && fail({ |
|
||||
res: res, |
|
||||
}); |
|
||||
}) |
|
||||
} |
|
||||
//关闭蓝牙连接
|
|
||||
export function closeBLEConnection(deviceId) { |
|
||||
|
|
||||
uniAsyncPromise("closeBLEConnection", { |
|
||||
deviceId |
|
||||
}) |
|
||||
.then(res => { |
|
||||
|
|
||||
}) |
|
||||
.catch(res => { |
|
||||
|
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
//四、连接成功后, 获取蓝牙设备的service服务
|
|
||||
// uniAsyncPromise("getBLEDeviceServices",{deviceId:""}).then(res=>{})
|
|
||||
export function getBLEDeviceServices(deviceId, success, fail) { |
|
||||
|
|
||||
//加延迟避免取不到service
|
|
||||
setTimeout(()=>{ |
|
||||
uniAsyncPromise("getBLEDeviceServices", { |
|
||||
deviceId: uni.getStorageSync('deviceId')?uni.getStorageSync('deviceId'):deviceId |
|
||||
}) |
|
||||
.then(res => { |
|
||||
|
|
||||
success && success({ |
|
||||
serviceId: res.services, |
|
||||
}); |
|
||||
}) |
|
||||
.catch((res) => { |
|
||||
//getBLEDeviceServices(deviceId, success, fail);
|
|
||||
|
|
||||
fail && fail({ |
|
||||
res: res, |
|
||||
}); |
|
||||
}); |
|
||||
},1000) |
|
||||
} |
|
||||
|
|
||||
//五、获取的service服务可能有多个,递归获取特征值(最后要用的是能读,能写,能监听的那个值的uuid作为特征值id)
|
|
||||
/** |
|
||||
* |
|
||||
* |
|
||||
* @export |
|
||||
* @param {number} deviceId 蓝牙设备id |
|
||||
* @param {array} services uniAsyncPromise("getBLEDeviceServices",{deviceId:""}).then(res=>{})获取的res.services |
|
||||
* @param {function} success 成功取得有用特征值uuid的回调函数 |
|
||||
*/ |
|
||||
export function getDeviceCharacteristics(deviceId, services, success, fail) { |
|
||||
//services = services.slice(0);
|
|
||||
|
|
||||
if (services.length) { |
|
||||
const serviceId = services.shift().uuid; |
|
||||
|
|
||||
uniAsyncPromise('getBLEDeviceCharacteristics', { |
|
||||
deviceId, |
|
||||
serviceId, |
|
||||
}).then((res) => { |
|
||||
var readId; |
|
||||
var writeId; |
|
||||
for (var i = 0; i < res.characteristics.length; i++) { |
|
||||
if ((res.characteristics[i].properties.notify || res.characteristics[i].properties.indicate) && res.characteristics[i].properties.write) { |
|
||||
readId = res.characteristics[i].uuid; |
|
||||
writeId = res.characteristics[i].uuid; |
|
||||
/* 获取蓝牙特征值uuid */ |
|
||||
success && |
|
||||
success({ |
|
||||
serviceId, |
|
||||
writeId: writeId, |
|
||||
readId: readId, |
|
||||
}); |
|
||||
finished = true; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
}) |
|
||||
.catch((res) => { |
|
||||
uni.showToast({ |
|
||||
title: res.message, |
|
||||
icon: 'error' |
|
||||
}) |
|
||||
getDeviceCharacteristics(deviceId, services, success, fail); |
|
||||
}); |
|
||||
} else { |
|
||||
fail && fail(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
//六、启动notify 蓝牙监听功能 然后使用 uni.onBLECharacteristicValueChange用来监听蓝牙设备传递数据
|
|
||||
/** |
|
||||
* @export |
|
||||
* @param {object} options |
|
||||
* { |
|
||||
deviceId,//蓝牙设备id
|
|
||||
serviceId,//服务id
|
|
||||
characteristicId,//可用特征值uuid
|
|
||||
} |
|
||||
* @param {function} onChange 监听蓝牙设备传递数据回调函数 |
|
||||
*/ |
|
||||
export function onGetBLECharacteristicValueChange(options, onChange = function() {}) { |
|
||||
uniAsyncPromise('notifyBLECharacteristicValueChange', { |
|
||||
state: true, |
|
||||
...options, |
|
||||
}).then((res) => { |
|
||||
uni.onBLECharacteristicValueChange(onChange); |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
//七、发送数据(递归分包发送)
|
|
||||
/** |
|
||||
* @export |
|
||||
* @param {object} options |
|
||||
* { |
|
||||
deviceId, |
|
||||
serviceId, |
|
||||
characteristicId, |
|
||||
value [ArrayBuffer], |
|
||||
lasterSuccess, |
|
||||
onceLength |
|
||||
} |
|
||||
*/ |
|
||||
|
|
||||
export function sendDataToDevice(options) { |
|
||||
let byteLength = options.value.byteLength; |
|
||||
//这里默认一次20个字节发送
|
|
||||
const speed = options.onceLength; //20;
|
|
||||
|
|
||||
if (byteLength > 0) { |
|
||||
uniAsyncPromise('writeBLECharacteristicValue', { |
|
||||
...options, |
|
||||
value: options.value.slice(0, byteLength > speed ? speed : byteLength), |
|
||||
}) |
|
||||
.then((res) => { |
|
||||
|
|
||||
if (byteLength > speed) { |
|
||||
sendDataToDevice({ |
|
||||
...options, |
|
||||
value: options.value.slice(speed, byteLength), |
|
||||
}); |
|
||||
} else { |
|
||||
|
|
||||
options.lasterSuccess && options.lasterSuccess(); |
|
||||
} |
|
||||
}) |
|
||||
.catch((res) => { |
|
||||
|
|
||||
uni.showToast({ |
|
||||
title: res, |
|
||||
icon: 'none' |
|
||||
}) |
|
||||
}); |
|
||||
}else{ |
|
||||
uni.showToast({ |
|
||||
title: '没数据', |
|
||||
icon: 'none' |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
export function charToArrayBuffer(str) { |
|
||||
var out = new ArrayBuffer(str.length); |
|
||||
var uint8 = new Uint8Array(out); |
|
||||
var strs = str.split(''); |
|
||||
for (var i = 0; i < strs.length; i++) { |
|
||||
uint8[i] = strs[i].charCodeAt(); |
|
||||
} |
|
||||
return uint8; |
|
||||
} |
|
||||
export function charToArray(str) { |
|
||||
var arr = []; |
|
||||
var strs = str.split(''); |
|
||||
for (var i = 0; i < strs.length; i++) { |
|
||||
arr[i] = strs[i].charCodeAt(); |
|
||||
} |
|
||||
return arr; |
|
||||
} |
|
||||
//打印二维码
|
|
||||
/** |
|
||||
* @export |
|
||||
* @param {object} options |
|
||||
* { |
|
||||
deviceId, |
|
||||
serviceId, |
|
||||
characteristicId, |
|
||||
value,//ArrayBuffer:二维码的数据
|
|
||||
} |
|
||||
*/ |
|
||||
export function printQR(options) { |
|
||||
//打印二维码的十进制指令data:
|
|
||||
let data = [29, 107, 97, 7, 4, options.value.byteLength, 0]; |
|
||||
sendDataToDevice({ |
|
||||
...options, |
|
||||
value: new Uint8Array(data).buffer, |
|
||||
lasterSuccess: () => { |
|
||||
//指令发送成功后,发送二维码的数据
|
|
||||
sendDataToDevice(options); |
|
||||
}, |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
function grayPixle(pix) { |
|
||||
return pix[0] * 0.299 + pix[1] * 0.587 + pix[2] * 0.114; |
|
||||
} |
|
||||
|
|
||||
export 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) { |
|
||||
//灰度值大于threshold位 白色 为第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, |
|
||||
}; |
|
||||
} |
|
||||
/** |
|
||||
* printImage |
|
||||
* @param {object} opt |
|
||||
* { |
|
||||
deviceId,//蓝牙设备id
|
|
||||
serviceId,//服务id
|
|
||||
characteristicId,//可用特征值uuid
|
|
||||
lasterSuccess , //最后完成的回调
|
|
||||
} |
|
||||
*/ |
|
||||
export function printImage(opt = {}, imageInfo = {}) { |
|
||||
let arr = imageInfo.array, |
|
||||
width = imageInfo.width; |
|
||||
const writeArray = []; |
|
||||
const xl = width % 256; |
|
||||
const xh = width / 256; |
|
||||
//分行发送图片数据,用的十进制指令
|
|
||||
const command = [29, 118, 48, 0, xl, xh, 1, 0]; //1D 76 30 00 w h
|
|
||||
const enter = [13, 10]; |
|
||||
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)); |
|
||||
} |
|
||||
writeArray.push(new Uint8Array(enter)); |
|
||||
|
|
||||
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(); |
|
||||
} |
|
||||
}, |
|
||||
}); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
print(opt, writeArray); |
|
||||
} |
|
||||
|
|
||||
/* 16hex insert 0 */ |
|
||||
function Hex2Str(num) { |
|
||||
if (num.toString(16).length < 2) return "0" + num.toString(16); |
|
||||
else |
|
||||
return num.toString(16); |
|
||||
} |
|
||||
/*****CPCL指令接口****/ |
|
||||
|
|
||||
/** |
|
||||
* 配置项如下 |
|
||||
* |
|
||||
* width: 标签纸的宽度,单位像素點 |
|
||||
* height: 标签纸的高度,单位像素點 |
|
||||
* 8像素=1mm |
|
||||
* printNum: 打印张数,默认为1 |
|
||||
* rotation:页面整体旋转 1-90度 2-180度 3-270度 其他-不旋转 |
|
||||
* back: 页面回退 back单位像素 退纸1mm,给back 8 |
|
||||
*/ |
|
||||
export function CreatCPCLPage(width, height, printNum, rotation, back, offset = 0) { |
|
||||
var strCmd = '! ' + offset + ' 200 200 ' + height + ' ' + printNum + '\n'; |
|
||||
strCmd += "PAGE-WIDTH " + width + '\n'; |
|
||||
strCmd += "BF "+ back + "\n"; |
|
||||
if (rotation == 1) |
|
||||
strCmd += "ZPROTATE90\n"; |
|
||||
else if (rotation == 2) |
|
||||
strCmd += "ZPROTATE180\n"; |
|
||||
else if (rotation == 3) |
|
||||
strCmd += "ZPROTATE270\n"; |
|
||||
else |
|
||||
strCmd += "ZPROTATE0\n"; |
|
||||
return strCmd; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 打印文字 |
|
||||
* x: 文字方块左上角X座标,单位dot |
|
||||
* y: 文字方块左上角Y座标,单位dot |
|
||||
* fontName,fontSize: 字体,取值: 參考文檔 |
|
||||
* rotation: 旋转 1-90度 2-180度 3-270度 其他-不旋转 |
|
||||
* content: 文字内容 |
|
||||
*/ |
|
||||
export function addCPCLText(x, y, fontName, fontSize, rotation, content) { |
|
||||
|
|
||||
// alert(content);
|
|
||||
var strCmd = ''; |
|
||||
if (rotation == 1) { |
|
||||
strCmd += 'T90 '; |
|
||||
} |
|
||||
if (rotation == 2) { |
|
||||
strCmd += 'T180 '; |
|
||||
} |
|
||||
if (rotation == 3) { |
|
||||
strCmd += 'T270 '; |
|
||||
} else { |
|
||||
strCmd += 'T '; |
|
||||
} |
|
||||
strCmd += fontName + ' ' + fontSize + ' ' + x + ' ' + y + ' ' + content + '\n'; |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 打印一维码 |
|
||||
* |
|
||||
* x: 文字方块左上角X座标,单位dot |
|
||||
* y: 文字方块左上角Y座标,单位dot |
|
||||
* codeType: 条码类型,取值为128、UPCA、UPCA2、UPCA5、UPCE、UPCE2、UPC5、EAN13、EAN13+2、EAN13+5、 |
|
||||
* EAN8、EAN8+2、EAN8+5、39、39C、F39、F39C、93、CODABAR、CODABAR16、ITF、I2OF5 |
|
||||
* h: 条码高度,单位dot |
|
||||
* rotation: 顺时针旋转角度,取值如下: |
|
||||
* - 0 不旋转 |
|
||||
* - 1 顺时针旋转90度 |
|
||||
* |
|
||||
* narrow: 窄条码比例因子(dot) 取值: 參考文檔 |
|
||||
* wide: 宽条码比例因子(dot) 取值: 參考文檔 |
|
||||
* content: 文字内容 |
|
||||
* |
|
||||
*/ |
|
||||
export function addCPCLBarCode(x, y, codeType, h, rotation, narrow, wide, content) { |
|
||||
var strCmd = ''; |
|
||||
if (rotation == 0) |
|
||||
strCmd += 'B '; |
|
||||
else |
|
||||
strCmd += 'VB '; |
|
||||
strCmd += codeType + ' ' + narrow + ' ' + wide + ' ' + h + ' ' + x + ' ' + y + ' ' + content + '\n' |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 打印二维码 |
|
||||
* |
|
||||
* x: 文字方块左上角X座标,单位dot |
|
||||
* y: 文字方块左上角Y座标,单位dot |
|
||||
* level: 错误纠正能力等级,取值为L(7%)、M(15%)、Q(25%)、H(30%) |
|
||||
* ver: 1-10 版本,根据内容调整以获取合适容量 |
|
||||
* scale: 1-10 放大倍数 |
|
||||
* content: 文字内容 |
|
||||
* |
|
||||
*/ |
|
||||
export function addCPCLQRCode(x, y, level, ver, scale, content) { |
|
||||
var strCmd = 'B QR ' + x + ' ' + y + ' M ' + ver + ' U ' + scale + '\n' + level + 'A,' + content + '\n'; |
|
||||
strCmd += 'ENDQR\n'; |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 放大指令 |
|
||||
* scaleX: 横向放大倍数 1,2,3等整数 |
|
||||
* scaleY: 纵向放大倍数 1,2,3等整数 |
|
||||
*/ |
|
||||
export function addCPCLSETMAG(scaleX, scaleY) { |
|
||||
var strCmd = 'SETMAG ' + scaleX + ' ' + scaleY + '\n'; |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 对齐指令 0-左对齐 1-右对齐 2-居中 |
|
||||
*/ |
|
||||
export function addCPCLLocation(set) { |
|
||||
var strCmd = ''; |
|
||||
if (set == 1) { |
|
||||
strCmd += 'RIGHT\n'; |
|
||||
} else if (set == 2) { |
|
||||
strCmd += 'CENTER\n'; |
|
||||
} else { |
|
||||
strCmd += 'LEFT\n'; |
|
||||
} |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 反白线 x0,y0,x1,y1,width |
|
||||
*/ |
|
||||
export function addCPCLInverseLine(x0, y0, x1, y1, width) { |
|
||||
var strCmd = 'IL ' + x0 + ' ' + y0 + ' ' + x1 + ' ' + y1 + ' ' + width + '\n'; |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 画线 x0,y0,x1,y1,width |
|
||||
*/ |
|
||||
export function addCPCLLine(x0, y0, x1, y1, width) { |
|
||||
var strCmd = 'L ' + x0 + ' ' + y0 + ' ' + x1 + ' ' + y1 + ' ' + width + '\n'; |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 画框 x0,y0,x1,y1,width |
|
||||
*/ |
|
||||
export function addCPCLBox(x0, y0, x1, y1, width) { |
|
||||
var strCmd = 'BOX ' + x0 + ' ' + y0 + ' ' + x1 + ' ' + y1 + ' ' + width + '\n'; |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 字体加粗 |
|
||||
*/ |
|
||||
export function addCPCLSETBOLD(bold) { |
|
||||
var strCmd = 'SETBOLD ' + bold + '\n'; |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 字体下划线 |
|
||||
*/ |
|
||||
export function addCPCLUNDERLINE(c) { |
|
||||
var strCmd = 'UNDERLINE '; |
|
||||
if (c) strCmd += 'ON\n'; |
|
||||
else if (c) strCmd += 'OFF\n'; |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 水印打印灰度等级 0-255 |
|
||||
*/ |
|
||||
export function addCPCLBACKGROUND(level) { |
|
||||
var strCmd = 'BACKGROUND '; |
|
||||
if (level > 255 || level < 0) level = 255; |
|
||||
strCmd += level + '\n'; |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 打印水印文字 |
|
||||
* x: 文字方块左上角X座标,单位dot |
|
||||
* y: 文字方块左上角Y座标,单位dot |
|
||||
* fontName,fontSize: 字体,取值: 參考文檔 |
|
||||
* rotation: 旋转 1-90度 2-180度 3-270度 其他-不旋转 |
|
||||
* content: 文字内容 |
|
||||
*/ |
|
||||
export function addCPCLBKVText(x, y, fontName, fontSize, rotation, content) { |
|
||||
|
|
||||
var strCmd = ''; |
|
||||
if (rotation == 1) { |
|
||||
strCmd += 'BKT90 '; |
|
||||
} |
|
||||
if (rotation == 2) { |
|
||||
strCmd += 'BKT180 '; |
|
||||
} |
|
||||
if (rotation == 3) { |
|
||||
strCmd += 'BKT270 '; |
|
||||
} else { |
|
||||
strCmd += 'BKT '; |
|
||||
} |
|
||||
strCmd += fontName + ' ' + fontSize + ' ' + x + ' ' + y + ' ' + content + '\n'; |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* 标签缝隙定位指令 |
|
||||
*/ |
|
||||
export function addCPCLGAP() { |
|
||||
var strCmd = 'GAP-SENSE\nFORM\n'; |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 标签右黑标检测指令 |
|
||||
*/ |
|
||||
export function addCPCLSENSE() { |
|
||||
var strCmd = 'BAR-SENSE\nFORM\n'; |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 标签左黑标检测指令 |
|
||||
*/ |
|
||||
export function addCPCLSENSELEFT() { |
|
||||
var strCmd = 'BAR-SENSE LEFT\nFORM\n'; |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 打印指令 |
|
||||
*/ |
|
||||
export function addCPCLPrint() { |
|
||||
var strCmd = 'PRINT\n'; |
|
||||
return strCmd; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 图片打印指令 |
|
||||
* x: 文字方块左上角X座标,单位dot |
|
||||
* y: 文字方块左上角Y座标,单位dot |
|
||||
* data{ |
|
||||
threshold,//0/1提取的灰度级
|
|
||||
width,//图像宽度
|
|
||||
height,//图像高度
|
|
||||
imageData , //图像数据
|
|
||||
} |
|
||||
*/ |
|
||||
export function addCPCLImageCmd(x, y, data) { |
|
||||
var strImgCmd = ''; |
|
||||
const threshold = data.threshold || 180; // 默认阈值设为128
|
|
||||
let myBitmapWidth = data.width, |
|
||||
myBitmapHeight = data.height; |
|
||||
let len = Math.ceil(myBitmapWidth / 8); // 确保宽度是对齐到8的倍数
|
|
||||
|
|
||||
// 使用 Uint8Array 而不是 Uint16Array
|
|
||||
let sendImageData = new Uint8Array(len * myBitmapHeight); |
|
||||
let pix = data.imageData; |
|
||||
|
|
||||
for (let i = 0; i < myBitmapHeight; i++) { |
|
||||
for (let j = 0; j < myBitmapWidth; j++) { |
|
||||
const avg = (pix[i * myBitmapWidth * 4 + j * 4] + |
|
||||
pix[i * myBitmapWidth * 4 + j * 4 + 1] + |
|
||||
pix[i * myBitmapWidth * 4 + j * 4 + 2]) / 3; |
|
||||
if (avg < threshold) { |
|
||||
sendImageData[i * len + Math.floor(j / 8)] |= (0x80 >> (j % 8)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// CPCL指令图片数据
|
|
||||
strImgCmd += 'EG ' + len + ' ' + myBitmapHeight + ' ' + x + ' ' + y + ' '; |
|
||||
for (let i = 0; i < sendImageData.length; i++) { |
|
||||
strImgCmd += ('0' + sendImageData[i].toString(16)).slice(-2).toUpperCase(); // 确保两位十六进制数
|
|
||||
} |
|
||||
strImgCmd += '\n'; |
|
||||
return strImgCmd; |
|
||||
} |
|
||||
/** |
|
||||
* toast显示捕获的蓝牙异常 |
|
||||
*/ |
|
||||
export function catchToast(err) { |
|
||||
const errMsg = { |
|
||||
10000: '未初始化蓝牙模块', |
|
||||
10001: '蓝牙未打开', |
|
||||
10002: '没有找到指定设备', |
|
||||
10003: '连接失败', |
|
||||
10004: '没有找到指定服务', |
|
||||
10005: '没有找到指定特征值', |
|
||||
10006: '当前连接已断开', |
|
||||
10007: '当前特征值不支持此操作', |
|
||||
10008: '系统上报异常', |
|
||||
10009: '系统版本低于 4.3 不支持BLE' |
|
||||
}; |
|
||||
let coode = err.errCode ? err.errCode.toString() : ''; |
|
||||
let msg = errMsg[coode]; |
|
||||
plus.nativeUI.toast(msg || coode, { |
|
||||
align: 'center', |
|
||||
verticalAlign: 'center' |
|
||||
}); |
|
||||
} |
|
||||
@ -1,23 +0,0 @@ |
|||||
var barcode = require('./barcode'); |
|
||||
var qrcode = require('./qrcode'); |
|
||||
|
|
||||
function convert_length(length) { |
|
||||
return Math.round(wx.getSystemInfoSync().windowWidth * length / 750); |
|
||||
} |
|
||||
|
|
||||
function barc(id, code, width, height) { |
|
||||
barcode.code128(wx.createCanvasContext(id), code, convert_length(width), convert_length(height)) |
|
||||
} |
|
||||
|
|
||||
function qrc(id, code, width, height) { |
|
||||
qrcode.api.draw(code, { |
|
||||
ctx: wx.createCanvasContext(id), |
|
||||
width: convert_length(width), |
|
||||
height: convert_length(height) |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
module.exports = { |
|
||||
barcode: barc, |
|
||||
qrcode: qrc |
|
||||
} |
|
||||
File diff suppressed because one or more lines are too long
@ -1,778 +0,0 @@ |
|||||
var QR = (function () { |
|
||||
|
|
||||
// alignment pattern
|
|
||||
var adelta = [ |
|
||||
0, 11, 15, 19, 23, 27, 31, // force 1 pat
|
|
||||
16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24, |
|
||||
26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26, 26, 26, 28, 28 |
|
||||
]; |
|
||||
|
|
||||
// version block
|
|
||||
var vpat = [ |
|
||||
0xc94, 0x5bc, 0xa99, 0x4d3, 0xbf6, 0x762, 0x847, 0x60d, |
|
||||
0x928, 0xb78, 0x45d, 0xa17, 0x532, 0x9a6, 0x683, 0x8c9, |
|
||||
0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e, 0xc1a, 0x33f, 0xd75, |
|
||||
0x250, 0x9d5, 0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64, |
|
||||
0x541, 0xc69 |
|
||||
]; |
|
||||
|
|
||||
// final format bits with mask: level << 3 | mask
|
|
||||
var fmtword = [ |
|
||||
0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976, //L
|
|
||||
0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, //M
|
|
||||
0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed, //Q
|
|
||||
0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b //H
|
|
||||
]; |
|
||||
|
|
||||
// 4 per version: number of blocks 1,2; data width; ecc width
|
|
||||
var eccblocks = [ |
|
||||
1, 0, 19, 7, 1, 0, 16, 10, 1, 0, 13, 13, 1, 0, 9, 17, |
|
||||
1, 0, 34, 10, 1, 0, 28, 16, 1, 0, 22, 22, 1, 0, 16, 28, |
|
||||
1, 0, 55, 15, 1, 0, 44, 26, 2, 0, 17, 18, 2, 0, 13, 22, |
|
||||
1, 0, 80, 20, 2, 0, 32, 18, 2, 0, 24, 26, 4, 0, 9, 16, |
|
||||
1, 0, 108, 26, 2, 0, 43, 24, 2, 2, 15, 18, 2, 2, 11, 22, |
|
||||
2, 0, 68, 18, 4, 0, 27, 16, 4, 0, 19, 24, 4, 0, 15, 28, |
|
||||
2, 0, 78, 20, 4, 0, 31, 18, 2, 4, 14, 18, 4, 1, 13, 26, |
|
||||
2, 0, 97, 24, 2, 2, 38, 22, 4, 2, 18, 22, 4, 2, 14, 26, |
|
||||
2, 0, 116, 30, 3, 2, 36, 22, 4, 4, 16, 20, 4, 4, 12, 24, |
|
||||
2, 2, 68, 18, 4, 1, 43, 26, 6, 2, 19, 24, 6, 2, 15, 28, |
|
||||
4, 0, 81, 20, 1, 4, 50, 30, 4, 4, 22, 28, 3, 8, 12, 24, |
|
||||
2, 2, 92, 24, 6, 2, 36, 22, 4, 6, 20, 26, 7, 4, 14, 28, |
|
||||
4, 0, 107, 26, 8, 1, 37, 22, 8, 4, 20, 24, 12, 4, 11, 22, |
|
||||
3, 1, 115, 30, 4, 5, 40, 24, 11, 5, 16, 20, 11, 5, 12, 24, |
|
||||
5, 1, 87, 22, 5, 5, 41, 24, 5, 7, 24, 30, 11, 7, 12, 24, |
|
||||
5, 1, 98, 24, 7, 3, 45, 28, 15, 2, 19, 24, 3, 13, 15, 30, |
|
||||
1, 5, 107, 28, 10, 1, 46, 28, 1, 15, 22, 28, 2, 17, 14, 28, |
|
||||
5, 1, 120, 30, 9, 4, 43, 26, 17, 1, 22, 28, 2, 19, 14, 28, |
|
||||
3, 4, 113, 28, 3, 11, 44, 26, 17, 4, 21, 26, 9, 16, 13, 26, |
|
||||
3, 5, 107, 28, 3, 13, 41, 26, 15, 5, 24, 30, 15, 10, 15, 28, |
|
||||
4, 4, 116, 28, 17, 0, 42, 26, 17, 6, 22, 28, 19, 6, 16, 30, |
|
||||
2, 7, 111, 28, 17, 0, 46, 28, 7, 16, 24, 30, 34, 0, 13, 24, |
|
||||
4, 5, 121, 30, 4, 14, 47, 28, 11, 14, 24, 30, 16, 14, 15, 30, |
|
||||
6, 4, 117, 30, 6, 14, 45, 28, 11, 16, 24, 30, 30, 2, 16, 30, |
|
||||
8, 4, 106, 26, 8, 13, 47, 28, 7, 22, 24, 30, 22, 13, 15, 30, |
|
||||
10, 2, 114, 28, 19, 4, 46, 28, 28, 6, 22, 28, 33, 4, 16, 30, |
|
||||
8, 4, 122, 30, 22, 3, 45, 28, 8, 26, 23, 30, 12, 28, 15, 30, |
|
||||
3, 10, 117, 30, 3, 23, 45, 28, 4, 31, 24, 30, 11, 31, 15, 30, |
|
||||
7, 7, 116, 30, 21, 7, 45, 28, 1, 37, 23, 30, 19, 26, 15, 30, |
|
||||
5, 10, 115, 30, 19, 10, 47, 28, 15, 25, 24, 30, 23, 25, 15, 30, |
|
||||
13, 3, 115, 30, 2, 29, 46, 28, 42, 1, 24, 30, 23, 28, 15, 30, |
|
||||
17, 0, 115, 30, 10, 23, 46, 28, 10, 35, 24, 30, 19, 35, 15, 30, |
|
||||
17, 1, 115, 30, 14, 21, 46, 28, 29, 19, 24, 30, 11, 46, 15, 30, |
|
||||
13, 6, 115, 30, 14, 23, 46, 28, 44, 7, 24, 30, 59, 1, 16, 30, |
|
||||
12, 7, 121, 30, 12, 26, 47, 28, 39, 14, 24, 30, 22, 41, 15, 30, |
|
||||
6, 14, 121, 30, 6, 34, 47, 28, 46, 10, 24, 30, 2, 64, 15, 30, |
|
||||
17, 4, 122, 30, 29, 14, 46, 28, 49, 10, 24, 30, 24, 46, 15, 30, |
|
||||
4, 18, 122, 30, 13, 32, 46, 28, 48, 14, 24, 30, 42, 32, 15, 30, |
|
||||
20, 4, 117, 30, 40, 7, 47, 28, 43, 22, 24, 30, 10, 67, 15, 30, |
|
||||
19, 6, 118, 30, 18, 31, 47, 28, 34, 34, 24, 30, 20, 61, 15, 30 |
|
||||
]; |
|
||||
|
|
||||
// Galois field log table
|
|
||||
var glog = [ |
|
||||
0xff, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b, |
|
||||
0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71, |
|
||||
0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45, |
|
||||
0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6, |
|
||||
0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88, |
|
||||
0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40, |
|
||||
0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d, |
|
||||
0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57, |
|
||||
0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18, |
|
||||
0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e, |
|
||||
0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61, |
|
||||
0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2, |
|
||||
0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6, |
|
||||
0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a, |
|
||||
0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7, |
|
||||
0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf |
|
||||
]; |
|
||||
|
|
||||
// Galios field exponent table
|
|
||||
var gexp = [ |
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, |
|
||||
0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, |
|
||||
0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23, |
|
||||
0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1, |
|
||||
0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, |
|
||||
0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2, |
|
||||
0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce, |
|
||||
0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc, |
|
||||
0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54, |
|
||||
0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73, |
|
||||
0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff, |
|
||||
0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41, |
|
||||
0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6, |
|
||||
0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09, |
|
||||
0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16, |
|
||||
0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x00 |
|
||||
]; |
|
||||
|
|
||||
// Working buffers:
|
|
||||
// data input and ecc append, image working buffer, fixed part of image, run lengths for badness
|
|
||||
var strinbuf=[], eccbuf=[], qrframe=[], framask=[], rlens=[]; |
|
||||
// Control values - width is based on version, last 4 are from table.
|
|
||||
var version, width, neccblk1, neccblk2, datablkw, eccblkwid; |
|
||||
var ecclevel = 2; |
|
||||
// set bit to indicate cell in qrframe is immutable. symmetric around diagonal
|
|
||||
function setmask(x, y) |
|
||||
{ |
|
||||
var bt; |
|
||||
if (x > y) { |
|
||||
bt = x; |
|
||||
x = y; |
|
||||
y = bt; |
|
||||
} |
|
||||
// y*y = 1+3+5...
|
|
||||
bt = y; |
|
||||
bt *= y; |
|
||||
bt += y; |
|
||||
bt >>= 1; |
|
||||
bt += x; |
|
||||
framask[bt] = 1; |
|
||||
} |
|
||||
|
|
||||
// enter alignment pattern - black to qrframe, white to mask (later black frame merged to mask)
|
|
||||
function putalign(x, y) |
|
||||
{ |
|
||||
var j; |
|
||||
|
|
||||
qrframe[x + width * y] = 1; |
|
||||
for (j = -2; j < 2; j++) { |
|
||||
qrframe[(x + j) + width * (y - 2)] = 1; |
|
||||
qrframe[(x - 2) + width * (y + j + 1)] = 1; |
|
||||
qrframe[(x + 2) + width * (y + j)] = 1; |
|
||||
qrframe[(x + j + 1) + width * (y + 2)] = 1; |
|
||||
} |
|
||||
for (j = 0; j < 2; j++) { |
|
||||
setmask(x - 1, y + j); |
|
||||
setmask(x + 1, y - j); |
|
||||
setmask(x - j, y - 1); |
|
||||
setmask(x + j, y + 1); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
//========================================================================
|
|
||||
// Reed Solomon error correction
|
|
||||
// exponentiation mod N
|
|
||||
function modnn(x) |
|
||||
{ |
|
||||
while (x >= 255) { |
|
||||
x -= 255; |
|
||||
x = (x >> 8) + (x & 255); |
|
||||
} |
|
||||
return x; |
|
||||
} |
|
||||
|
|
||||
var genpoly = []; |
|
||||
|
|
||||
// Calculate and append ECC data to data block. Block is in strinbuf, indexes to buffers given.
|
|
||||
function appendrs(data, dlen, ecbuf, eclen) |
|
||||
{ |
|
||||
var i, j, fb; |
|
||||
|
|
||||
for (i = 0; i < eclen; i++) |
|
||||
strinbuf[ecbuf + i] = 0; |
|
||||
for (i = 0; i < dlen; i++) { |
|
||||
fb = glog[strinbuf[data + i] ^ strinbuf[ecbuf]]; |
|
||||
if (fb != 255) /* fb term is non-zero */ |
|
||||
for (j = 1; j < eclen; j++) |
|
||||
strinbuf[ecbuf + j - 1] = strinbuf[ecbuf + j] ^ gexp[modnn(fb + genpoly[eclen - j])]; |
|
||||
else |
|
||||
for( j = ecbuf ; j < ecbuf + eclen; j++ ) |
|
||||
strinbuf[j] = strinbuf[j + 1]; |
|
||||
strinbuf[ ecbuf + eclen - 1] = fb == 255 ? 0 : gexp[modnn(fb + genpoly[0])]; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
//========================================================================
|
|
||||
// Frame data insert following the path rules
|
|
||||
|
|
||||
// check mask - since symmetrical use half.
|
|
||||
function ismasked(x, y) |
|
||||
{ |
|
||||
var bt; |
|
||||
if (x > y) { |
|
||||
bt = x; |
|
||||
x = y; |
|
||||
y = bt; |
|
||||
} |
|
||||
bt = y; |
|
||||
bt += y * y; |
|
||||
bt >>= 1; |
|
||||
bt += x; |
|
||||
return framask[bt]; |
|
||||
} |
|
||||
|
|
||||
//========================================================================
|
|
||||
// Apply the selected mask out of the 8.
|
|
||||
function applymask(m) |
|
||||
{ |
|
||||
var x, y, r3x, r3y; |
|
||||
|
|
||||
switch (m) { |
|
||||
case 0: |
|
||||
for (y = 0; y < width; y++) |
|
||||
for (x = 0; x < width; x++) |
|
||||
if (!((x + y) & 1) && !ismasked(x, y)) |
|
||||
qrframe[x + y * width] ^= 1; |
|
||||
break; |
|
||||
case 1: |
|
||||
for (y = 0; y < width; y++) |
|
||||
for (x = 0; x < width; x++) |
|
||||
if (!(y & 1) && !ismasked(x, y)) |
|
||||
qrframe[x + y * width] ^= 1; |
|
||||
break; |
|
||||
case 2: |
|
||||
for (y = 0; y < width; y++) |
|
||||
for (r3x = 0, x = 0; x < width; x++, r3x++) { |
|
||||
if (r3x == 3) |
|
||||
r3x = 0; |
|
||||
if (!r3x && !ismasked(x, y)) |
|
||||
qrframe[x + y * width] ^= 1; |
|
||||
} |
|
||||
break; |
|
||||
case 3: |
|
||||
for (r3y = 0, y = 0; y < width; y++, r3y++) { |
|
||||
if (r3y == 3) |
|
||||
r3y = 0; |
|
||||
for (r3x = r3y, x = 0; x < width; x++, r3x++) { |
|
||||
if (r3x == 3) |
|
||||
r3x = 0; |
|
||||
if (!r3x && !ismasked(x, y)) |
|
||||
qrframe[x + y * width] ^= 1; |
|
||||
} |
|
||||
} |
|
||||
break; |
|
||||
case 4: |
|
||||
for (y = 0; y < width; y++) |
|
||||
for (r3x = 0, r3y = ((y >> 1) & 1), x = 0; x < width; x++, r3x++) { |
|
||||
if (r3x == 3) { |
|
||||
r3x = 0; |
|
||||
r3y = !r3y; |
|
||||
} |
|
||||
if (!r3y && !ismasked(x, y)) |
|
||||
qrframe[x + y * width] ^= 1; |
|
||||
} |
|
||||
break; |
|
||||
case 5: |
|
||||
for (r3y = 0, y = 0; y < width; y++, r3y++) { |
|
||||
if (r3y == 3) |
|
||||
r3y = 0; |
|
||||
for (r3x = 0, x = 0; x < width; x++, r3x++) { |
|
||||
if (r3x == 3) |
|
||||
r3x = 0; |
|
||||
if (!((x & y & 1) + !(!r3x | !r3y)) && !ismasked(x, y)) |
|
||||
qrframe[x + y * width] ^= 1; |
|
||||
} |
|
||||
} |
|
||||
break; |
|
||||
case 6: |
|
||||
for (r3y = 0, y = 0; y < width; y++, r3y++) { |
|
||||
if (r3y == 3) |
|
||||
r3y = 0; |
|
||||
for (r3x = 0, x = 0; x < width; x++, r3x++) { |
|
||||
if (r3x == 3) |
|
||||
r3x = 0; |
|
||||
if (!(((x & y & 1) + (r3x && (r3x == r3y))) & 1) && !ismasked(x, y)) |
|
||||
qrframe[x + y * width] ^= 1; |
|
||||
} |
|
||||
} |
|
||||
break; |
|
||||
case 7: |
|
||||
for (r3y = 0, y = 0; y < width; y++, r3y++) { |
|
||||
if (r3y == 3) |
|
||||
r3y = 0; |
|
||||
for (r3x = 0, x = 0; x < width; x++, r3x++) { |
|
||||
if (r3x == 3) |
|
||||
r3x = 0; |
|
||||
if (!(((r3x && (r3x == r3y)) + ((x + y) & 1)) & 1) && !ismasked(x, y)) |
|
||||
qrframe[x + y * width] ^= 1; |
|
||||
} |
|
||||
} |
|
||||
break; |
|
||||
} |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
// Badness coefficients.
|
|
||||
var N1 = 3, N2 = 3, N3 = 40, N4 = 10; |
|
||||
|
|
||||
// Using the table of the length of each run, calculate the amount of bad image
|
|
||||
// - long runs or those that look like finders; called twice, once each for X and Y
|
|
||||
function badruns(length) |
|
||||
{ |
|
||||
var i; |
|
||||
var runsbad = 0; |
|
||||
for (i = 0; i <= length; i++) |
|
||||
if (rlens[i] >= 5) |
|
||||
runsbad += N1 + rlens[i] - 5; |
|
||||
// BwBBBwB as in finder
|
|
||||
for (i = 3; i < length - 1; i += 2) |
|
||||
if (rlens[i - 2] == rlens[i + 2] |
|
||||
&& rlens[i + 2] == rlens[i - 1] |
|
||||
&& rlens[i - 1] == rlens[i + 1] |
|
||||
&& rlens[i - 1] * 3 == rlens[i] |
|
||||
// white around the black pattern? Not part of spec
|
|
||||
&& (rlens[i - 3] == 0 // beginning
|
|
||||
|| i + 3 > length // end
|
|
||||
|| rlens[i - 3] * 3 >= rlens[i] * 4 || rlens[i + 3] * 3 >= rlens[i] * 4) |
|
||||
) |
|
||||
runsbad += N3; |
|
||||
return runsbad; |
|
||||
} |
|
||||
|
|
||||
// Calculate how bad the masked image is - blocks, imbalance, runs, or finders.
|
|
||||
function badcheck() |
|
||||
{ |
|
||||
var x, y, h, b, b1; |
|
||||
var thisbad = 0; |
|
||||
var bw = 0; |
|
||||
|
|
||||
// blocks of same color.
|
|
||||
for (y = 0; y < width - 1; y++) |
|
||||
for (x = 0; x < width - 1; x++) |
|
||||
if ((qrframe[x + width * y] && qrframe[(x + 1) + width * y] |
|
||||
&& qrframe[x + width * (y + 1)] && qrframe[(x + 1) + width * (y + 1)]) // all black
|
|
||||
|| !(qrframe[x + width * y] || qrframe[(x + 1) + width * y] |
|
||||
|| qrframe[x + width * (y + 1)] || qrframe[(x + 1) + width * (y + 1)])) // all white
|
|
||||
thisbad += N2; |
|
||||
|
|
||||
// X runs
|
|
||||
for (y = 0; y < width; y++) { |
|
||||
rlens[0] = 0; |
|
||||
for (h = b = x = 0; x < width; x++) { |
|
||||
if ((b1 = qrframe[x + width * y]) == b) |
|
||||
rlens[h]++; |
|
||||
else |
|
||||
rlens[++h] = 1; |
|
||||
b = b1; |
|
||||
bw += b ? 1 : -1; |
|
||||
} |
|
||||
thisbad += badruns(h); |
|
||||
} |
|
||||
|
|
||||
// black/white imbalance
|
|
||||
if (bw < 0) |
|
||||
bw = -bw; |
|
||||
|
|
||||
var big = bw; |
|
||||
var count = 0; |
|
||||
big += big << 2; |
|
||||
big <<= 1; |
|
||||
while (big > width * width) |
|
||||
big -= width * width, count++; |
|
||||
thisbad += count * N4; |
|
||||
|
|
||||
// Y runs
|
|
||||
for (x = 0; x < width; x++) { |
|
||||
rlens[0] = 0; |
|
||||
for (h = b = y = 0; y < width; y++) { |
|
||||
if ((b1 = qrframe[x + width * y]) == b) |
|
||||
rlens[h]++; |
|
||||
else |
|
||||
rlens[++h] = 1; |
|
||||
b = b1; |
|
||||
} |
|
||||
thisbad += badruns(h); |
|
||||
} |
|
||||
return thisbad; |
|
||||
} |
|
||||
|
|
||||
function genframe(instring) |
|
||||
{ |
|
||||
var x, y, k, t, v, i, j, m; |
|
||||
|
|
||||
// find the smallest version that fits the string
|
|
||||
t = instring.length; |
|
||||
version = 0; |
|
||||
do { |
|
||||
version++; |
|
||||
k = (ecclevel - 1) * 4 + (version - 1) * 16; |
|
||||
neccblk1 = eccblocks[k++]; |
|
||||
neccblk2 = eccblocks[k++]; |
|
||||
datablkw = eccblocks[k++]; |
|
||||
eccblkwid = eccblocks[k]; |
|
||||
k = datablkw * (neccblk1 + neccblk2) + neccblk2 - 3 + (version <= 9); |
|
||||
if (t <= k) |
|
||||
break; |
|
||||
} while (version < 40); |
|
||||
|
|
||||
// FIXME - insure that it fits insted of being truncated
|
|
||||
width = 17 + 4 * version; |
|
||||
|
|
||||
// allocate, clear and setup data structures
|
|
||||
v = datablkw + (datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2; |
|
||||
for( t = 0; t < v; t++ ) |
|
||||
eccbuf[t] = 0; |
|
||||
strinbuf = instring.slice(0); |
|
||||
|
|
||||
for( t = 0; t < width * width; t++ ) |
|
||||
qrframe[t] = 0; |
|
||||
|
|
||||
for( t = 0 ; t < (width * (width + 1) + 1) / 2; t++) |
|
||||
framask[t] = 0; |
|
||||
|
|
||||
// insert finders - black to frame, white to mask
|
|
||||
for (t = 0; t < 3; t++) { |
|
||||
k = 0; |
|
||||
y = 0; |
|
||||
if (t == 1) |
|
||||
k = (width - 7); |
|
||||
if (t == 2) |
|
||||
y = (width - 7); |
|
||||
qrframe[(y + 3) + width * (k + 3)] = 1; |
|
||||
for (x = 0; x < 6; x++) { |
|
||||
qrframe[(y + x) + width * k] = 1; |
|
||||
qrframe[y + width * (k + x + 1)] = 1; |
|
||||
qrframe[(y + 6) + width * (k + x)] = 1; |
|
||||
qrframe[(y + x + 1) + width * (k + 6)] = 1; |
|
||||
} |
|
||||
for (x = 1; x < 5; x++) { |
|
||||
setmask(y + x, k + 1); |
|
||||
setmask(y + 1, k + x + 1); |
|
||||
setmask(y + 5, k + x); |
|
||||
setmask(y + x + 1, k + 5); |
|
||||
} |
|
||||
for (x = 2; x < 4; x++) { |
|
||||
qrframe[(y + x) + width * (k + 2)] = 1; |
|
||||
qrframe[(y + 2) + width * (k + x + 1)] = 1; |
|
||||
qrframe[(y + 4) + width * (k + x)] = 1; |
|
||||
qrframe[(y + x + 1) + width * (k + 4)] = 1; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// alignment blocks
|
|
||||
if (version > 1) { |
|
||||
t = adelta[version]; |
|
||||
y = width - 7; |
|
||||
for (;;) { |
|
||||
x = width - 7; |
|
||||
while (x > t - 3) { |
|
||||
putalign(x, y); |
|
||||
if (x < t) |
|
||||
break; |
|
||||
x -= t; |
|
||||
} |
|
||||
if (y <= t + 9) |
|
||||
break; |
|
||||
y -= t; |
|
||||
putalign(6, y); |
|
||||
putalign(y, 6); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// single black
|
|
||||
qrframe[8 + width * (width - 8)] = 1; |
|
||||
|
|
||||
// timing gap - mask only
|
|
||||
for (y = 0; y < 7; y++) { |
|
||||
setmask(7, y); |
|
||||
setmask(width - 8, y); |
|
||||
setmask(7, y + width - 7); |
|
||||
} |
|
||||
for (x = 0; x < 8; x++) { |
|
||||
setmask(x, 7); |
|
||||
setmask(x + width - 8, 7); |
|
||||
setmask(x, width - 8); |
|
||||
} |
|
||||
|
|
||||
// reserve mask-format area
|
|
||||
for (x = 0; x < 9; x++) |
|
||||
setmask(x, 8); |
|
||||
for (x = 0; x < 8; x++) { |
|
||||
setmask(x + width - 8, 8); |
|
||||
setmask(8, x); |
|
||||
} |
|
||||
for (y = 0; y < 7; y++) |
|
||||
setmask(8, y + width - 7); |
|
||||
|
|
||||
// timing row/col
|
|
||||
for (x = 0; x < width - 14; x++) |
|
||||
if (x & 1) { |
|
||||
setmask(8 + x, 6); |
|
||||
setmask(6, 8 + x); |
|
||||
} |
|
||||
else { |
|
||||
qrframe[(8 + x) + width * 6] = 1; |
|
||||
qrframe[6 + width * (8 + x)] = 1; |
|
||||
} |
|
||||
|
|
||||
// version block
|
|
||||
if (version > 6) { |
|
||||
t = vpat[version - 7]; |
|
||||
k = 17; |
|
||||
for (x = 0; x < 6; x++) |
|
||||
for (y = 0; y < 3; y++, k--) |
|
||||
if (1 & (k > 11 ? version >> (k - 12) : t >> k)) { |
|
||||
qrframe[(5 - x) + width * (2 - y + width - 11)] = 1; |
|
||||
qrframe[(2 - y + width - 11) + width * (5 - x)] = 1; |
|
||||
} |
|
||||
else { |
|
||||
setmask(5 - x, 2 - y + width - 11); |
|
||||
setmask(2 - y + width - 11, 5 - x); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// sync mask bits - only set above for white spaces, so add in black bits
|
|
||||
for (y = 0; y < width; y++) |
|
||||
for (x = 0; x <= y; x++) |
|
||||
if (qrframe[x + width * y]) |
|
||||
setmask(x, y); |
|
||||
|
|
||||
// convert string to bitstream
|
|
||||
// 8 bit data to QR-coded 8 bit data (numeric or alphanum, or kanji not supported)
|
|
||||
v = strinbuf.length; |
|
||||
|
|
||||
// string to array
|
|
||||
for( i = 0 ; i < v; i++ ) |
|
||||
eccbuf[i] = strinbuf.charCodeAt(i); |
|
||||
strinbuf = eccbuf.slice(0); |
|
||||
|
|
||||
// calculate max string length
|
|
||||
x = datablkw * (neccblk1 + neccblk2) + neccblk2; |
|
||||
if (v >= x - 2) { |
|
||||
v = x - 2; |
|
||||
if (version > 9) |
|
||||
v--; |
|
||||
} |
|
||||
|
|
||||
// shift and repack to insert length prefix
|
|
||||
i = v; |
|
||||
if (version > 9) { |
|
||||
strinbuf[i + 2] = 0; |
|
||||
strinbuf[i + 3] = 0; |
|
||||
while (i--) { |
|
||||
t = strinbuf[i]; |
|
||||
strinbuf[i + 3] |= 255 & (t << 4); |
|
||||
strinbuf[i + 2] = t >> 4; |
|
||||
} |
|
||||
strinbuf[2] |= 255 & (v << 4); |
|
||||
strinbuf[1] = v >> 4; |
|
||||
strinbuf[0] = 0x40 | (v >> 12); |
|
||||
} |
|
||||
else { |
|
||||
strinbuf[i + 1] = 0; |
|
||||
strinbuf[i + 2] = 0; |
|
||||
while (i--) { |
|
||||
t = strinbuf[i]; |
|
||||
strinbuf[i + 2] |= 255 & (t << 4); |
|
||||
strinbuf[i + 1] = t >> 4; |
|
||||
} |
|
||||
strinbuf[1] |= 255 & (v << 4); |
|
||||
strinbuf[0] = 0x40 | (v >> 4); |
|
||||
} |
|
||||
// fill to end with pad pattern
|
|
||||
i = v + 3 - (version < 10); |
|
||||
while (i < x) { |
|
||||
strinbuf[i++] = 0xec; |
|
||||
// buffer has room if (i == x) break;
|
|
||||
strinbuf[i++] = 0x11; |
|
||||
} |
|
||||
|
|
||||
// calculate and append ECC
|
|
||||
|
|
||||
// calculate generator polynomial
|
|
||||
genpoly[0] = 1; |
|
||||
for (i = 0; i < eccblkwid; i++) { |
|
||||
genpoly[i + 1] = 1; |
|
||||
for (j = i; j > 0; j--) |
|
||||
genpoly[j] = genpoly[j] |
|
||||
? genpoly[j - 1] ^ gexp[modnn(glog[genpoly[j]] + i)] : genpoly[j - 1]; |
|
||||
genpoly[0] = gexp[modnn(glog[genpoly[0]] + i)]; |
|
||||
} |
|
||||
for (i = 0; i <= eccblkwid; i++) |
|
||||
genpoly[i] = glog[genpoly[i]]; // use logs for genpoly[] to save calc step
|
|
||||
|
|
||||
// append ecc to data buffer
|
|
||||
k = x; |
|
||||
y = 0; |
|
||||
for (i = 0; i < neccblk1; i++) { |
|
||||
appendrs(y, datablkw, k, eccblkwid); |
|
||||
y += datablkw; |
|
||||
k += eccblkwid; |
|
||||
} |
|
||||
for (i = 0; i < neccblk2; i++) { |
|
||||
appendrs(y, datablkw + 1, k, eccblkwid); |
|
||||
y += datablkw + 1; |
|
||||
k += eccblkwid; |
|
||||
} |
|
||||
// interleave blocks
|
|
||||
y = 0; |
|
||||
for (i = 0; i < datablkw; i++) { |
|
||||
for (j = 0; j < neccblk1; j++) |
|
||||
eccbuf[y++] = strinbuf[i + j * datablkw]; |
|
||||
for (j = 0; j < neccblk2; j++) |
|
||||
eccbuf[y++] = strinbuf[(neccblk1 * datablkw) + i + (j * (datablkw + 1))]; |
|
||||
} |
|
||||
for (j = 0; j < neccblk2; j++) |
|
||||
eccbuf[y++] = strinbuf[(neccblk1 * datablkw) + i + (j * (datablkw + 1))]; |
|
||||
for (i = 0; i < eccblkwid; i++) |
|
||||
for (j = 0; j < neccblk1 + neccblk2; j++) |
|
||||
eccbuf[y++] = strinbuf[x + i + j * eccblkwid]; |
|
||||
strinbuf = eccbuf; |
|
||||
|
|
||||
// pack bits into frame avoiding masked area.
|
|
||||
x = y = width - 1; |
|
||||
k = v = 1; // up, minus
|
|
||||
/* inteleaved data and ecc codes */ |
|
||||
m = (datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2; |
|
||||
for (i = 0; i < m; i++) { |
|
||||
t = strinbuf[i]; |
|
||||
for (j = 0; j < 8; j++, t <<= 1) { |
|
||||
if (0x80 & t) |
|
||||
qrframe[x + width * y] = 1; |
|
||||
do { // find next fill position
|
|
||||
if (v) |
|
||||
x--; |
|
||||
else { |
|
||||
x++; |
|
||||
if (k) { |
|
||||
if (y != 0) |
|
||||
y--; |
|
||||
else { |
|
||||
x -= 2; |
|
||||
k = !k; |
|
||||
if (x == 6) { |
|
||||
x--; |
|
||||
y = 9; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
else { |
|
||||
if (y != width - 1) |
|
||||
y++; |
|
||||
else { |
|
||||
x -= 2; |
|
||||
k = !k; |
|
||||
if (x == 6) { |
|
||||
x--; |
|
||||
y -= 8; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
v = !v; |
|
||||
} while (ismasked(x, y)); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// save pre-mask copy of frame
|
|
||||
strinbuf = qrframe.slice(0); |
|
||||
t = 0; // best
|
|
||||
y = 30000; // demerit
|
|
||||
// for instead of while since in original arduino code
|
|
||||
// if an early mask was "good enough" it wouldn't try for a better one
|
|
||||
// since they get more complex and take longer.
|
|
||||
for (k = 0; k < 8; k++) { |
|
||||
applymask(k); // returns black-white imbalance
|
|
||||
x = badcheck(); |
|
||||
if (x < y) { // current mask better than previous best?
|
|
||||
y = x; |
|
||||
t = k; |
|
||||
} |
|
||||
if (t == 7) |
|
||||
break; // don't increment i to a void redoing mask
|
|
||||
qrframe = strinbuf.slice(0); // reset for next pass
|
|
||||
} |
|
||||
if (t != k) // redo best mask - none good enough, last wasn't t
|
|
||||
applymask(t); |
|
||||
|
|
||||
// add in final mask/ecclevel bytes
|
|
||||
y = fmtword[t + ((ecclevel - 1) << 3)]; |
|
||||
// low byte
|
|
||||
for (k = 0; k < 8; k++, y >>= 1) |
|
||||
if (y & 1) { |
|
||||
qrframe[(width - 1 - k) + width * 8] = 1; |
|
||||
if (k < 6) |
|
||||
qrframe[8 + width * k] = 1; |
|
||||
else |
|
||||
qrframe[8 + width * (k + 1)] = 1; |
|
||||
} |
|
||||
// high byte
|
|
||||
for (k = 0; k < 7; k++, y >>= 1) |
|
||||
if (y & 1) { |
|
||||
qrframe[8 + width * (width - 7 + k)] = 1; |
|
||||
if (k) |
|
||||
qrframe[(6 - k) + width * 8] = 1; |
|
||||
else |
|
||||
qrframe[7 + width * 8] = 1; |
|
||||
} |
|
||||
|
|
||||
// return image
|
|
||||
return qrframe; |
|
||||
} |
|
||||
|
|
||||
var _canvas = null, |
|
||||
_size = null; |
|
||||
|
|
||||
var api = { |
|
||||
|
|
||||
get ecclevel () { |
|
||||
return ecclevel; |
|
||||
}, |
|
||||
|
|
||||
set ecclevel (val) { |
|
||||
ecclevel = val; |
|
||||
}, |
|
||||
|
|
||||
get size () { |
|
||||
return _size; |
|
||||
}, |
|
||||
|
|
||||
set size (val) { |
|
||||
_size = val |
|
||||
}, |
|
||||
|
|
||||
get canvas () { |
|
||||
return _canvas; |
|
||||
}, |
|
||||
|
|
||||
set canvas (el) { |
|
||||
_canvas = el; |
|
||||
}, |
|
||||
|
|
||||
getFrame: function (string) { |
|
||||
return genframe(string); |
|
||||
}, |
|
||||
|
|
||||
draw: function (string, canvas, size, ecc) { |
|
||||
|
|
||||
ecclevel = ecc || ecclevel; |
|
||||
canvas = canvas || _canvas; |
|
||||
|
|
||||
if (!canvas) { |
|
||||
console.warn('No canvas provided to draw QR code in!') |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
size = size || _size || Math.min(canvas.width, canvas.height); |
|
||||
|
|
||||
var frame = genframe(string), |
|
||||
ctx = canvas.ctx, |
|
||||
px = Math.round(size / (width + 8)); |
|
||||
|
|
||||
var roundedSize = px * (width + 8), |
|
||||
offset = Math.floor((size - roundedSize) / 2); |
|
||||
|
|
||||
size = roundedSize; |
|
||||
|
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height); |
|
||||
ctx.setFillStyle('#000000'); |
|
||||
|
|
||||
for (var i = 0; i < width; i++) { |
|
||||
for (var j = 0; j < width; j++) { |
|
||||
if (frame[j * width + i]) { |
|
||||
ctx.fillRect(px * (4 + i) + offset, px * (4 + j) + offset, px, px); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
ctx.draw(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
module.exports = { |
|
||||
api: api |
|
||||
} |
|
||||
|
|
||||
})() |
|
||||
@ -1,145 +0,0 @@ |
|||||
|
|
||||
const formatTime = date => { |
|
||||
const year = date.getFullYear() |
|
||||
const month = date.getMonth() + 1 |
|
||||
const day = date.getDate() |
|
||||
const hour = date.getHours() |
|
||||
const minute = date.getMinutes() |
|
||||
const second = date.getSeconds() |
|
||||
|
|
||||
return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') |
|
||||
} |
|
||||
|
|
||||
const formatNumber = n => { |
|
||||
n = n.toString() |
|
||||
return n[1] ? n : '0' + n |
|
||||
} |
|
||||
|
|
||||
function toUnicode(s) { |
|
||||
var str = ""; |
|
||||
for (var i = 0; i < s.length; i++) { |
|
||||
str += "\\u" + s.charCodeAt(i).toString(16) + "\t"; |
|
||||
} |
|
||||
return str; |
|
||||
} |
|
||||
|
|
||||
function strToHexCharCode(str) { |
|
||||
if (str === "") |
|
||||
return ""; |
|
||||
var hexCharCode = []; |
|
||||
hexCharCode.push("0x"); |
|
||||
for (var i = 0; i < str.length; i++) { |
|
||||
hexCharCode.push((str.charCodeAt(i)).toString(16)); |
|
||||
} |
|
||||
return hexCharCode.join(""); |
|
||||
} |
|
||||
|
|
||||
function sumStrLength(str) { |
|
||||
var length = 0; |
|
||||
var data = str.toString(); |
|
||||
for (var i = 0; i < data.length; i++) { |
|
||||
if (isCN(data[i])) { //是中文
|
|
||||
length += 2; |
|
||||
} else { |
|
||||
length += 1; |
|
||||
} |
|
||||
} |
|
||||
return length; |
|
||||
} |
|
||||
|
|
||||
function isCN(str) { |
|
||||
if (/^[\u3220-\uFA29]+$/.test(str)) { |
|
||||
return true; |
|
||||
} else { |
|
||||
return false; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
//汉字转码
|
|
||||
function hexStringToArrayBuffer(str) { |
|
||||
const buffer = new ArrayBuffer((str.length / 2) + 1) |
|
||||
const dataView = new DataView(buffer) |
|
||||
for (var i = 0; i < str.length / 2; i++) { |
|
||||
var temp = parseInt(str[i * 2] + str[i * 2 + 1], 16) |
|
||||
dataView.setUint8(i, temp) |
|
||||
} |
|
||||
dataView.setUint8((str.length / 2), 0x0a) |
|
||||
return buffer; |
|
||||
} |
|
||||
|
|
||||
//返回八位数组
|
|
||||
function subString(str) { |
|
||||
var arr = []; |
|
||||
if (str.length > 8) { //大于8
|
|
||||
for (var i = 0; |
|
||||
(i * 8) < str.length; i++) { |
|
||||
var temp = str.substring(i * 8, 8 * i + 8); |
|
||||
arr.push(temp) |
|
||||
} |
|
||||
return arr; |
|
||||
} else { |
|
||||
return str |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
//不带有汉字
|
|
||||
function hexStringToArrayBufferstr(str) { |
|
||||
let val = "" |
|
||||
for (let i = 0; i < str.length; i++) { |
|
||||
if (val === '') { |
|
||||
val = str.charCodeAt(i).toString(16) |
|
||||
} else { |
|
||||
val += ',' + str.charCodeAt(i).toString(16) |
|
||||
} |
|
||||
} |
|
||||
val += "," + "0x0a"; |
|
||||
|
|
||||
// 将16进制转化为ArrayBuffer
|
|
||||
return new Uint8Array(val.match(/[\da-f]{2}/gi).map(function(h) { |
|
||||
return parseInt(h, 16) |
|
||||
})).buffer |
|
||||
} |
|
||||
|
|
||||
function ab2hex(buffer) { |
|
||||
let hexArr = Array.prototype.map.call( |
|
||||
new Uint8Array(buffer), |
|
||||
function (bit) { |
|
||||
return ('00' + bit.toString(16)).slice(-2) |
|
||||
}) |
|
||||
return hexArr.join(''); |
|
||||
} |
|
||||
|
|
||||
// ArrayBuffer转为字符串,参数为ArrayBuffer对象
|
|
||||
function ab2str(buf) { |
|
||||
return String.fromCharCode.apply(null, new Uint8Array(buf)); |
|
||||
} |
|
||||
|
|
||||
// 字符串转为ArrayBuffer对象,参数为字符串
|
|
||||
function str2ab(str) { |
|
||||
var buf = new ArrayBuffer(str.length+1); // 补充/0
|
|
||||
var bufView = new Uint8Array(buf); |
|
||||
for (var i = 0, strLen = str.length; i < strLen; i++) { |
|
||||
bufView[i] = str.charCodeAt(i); |
|
||||
} |
|
||||
return buf; |
|
||||
} |
|
||||
|
|
||||
function send0X0A() { |
|
||||
const buffer = new ArrayBuffer(1) |
|
||||
const dataView = new DataView(buffer) |
|
||||
dataView.setUint8(0, 0x0a) |
|
||||
return buffer; |
|
||||
} |
|
||||
|
|
||||
function buf2hex(buffer) { |
|
||||
return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join(''); |
|
||||
} |
|
||||
|
|
||||
module.exports = { |
|
||||
hexStringToArrayBuffer: hexStringToArrayBuffer, |
|
||||
send0X0A: send0X0A, |
|
||||
ab2hex: ab2hex, |
|
||||
str2ab: str2ab, |
|
||||
ab2str: ab2str, |
|
||||
buf2hex: buf2hex |
|
||||
} |
|
||||
@ -0,0 +1,294 @@ |
|||||
|
class Bluetooth { |
||||
|
|
||||
|
constructor() { |
||||
|
this.isOpenBle = false; |
||||
|
this.deviceId = ""; |
||||
|
this.serviceId = ""; |
||||
|
this.writeId = ""; |
||||
|
this.notifyId = ""; |
||||
|
this.num = 0; |
||||
|
this.serviceList = []; |
||||
|
this.openBluetoothAdapter(); |
||||
|
} |
||||
|
|
||||
|
showToast(title) { |
||||
|
uni.showToast({ |
||||
|
title: title, |
||||
|
icon: 'none', |
||||
|
'duration': 2000 |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
openBluetoothAdapter() { |
||||
|
return new Promise((resolve, reject) => { |
||||
|
uni.openBluetoothAdapter({ |
||||
|
success: res => { |
||||
|
this.isOpenBle = true; |
||||
|
// this.showToast("初始化蓝牙模块成功");
|
||||
|
resolve(res); |
||||
|
}, |
||||
|
fail: err => { |
||||
|
this.showToast('蓝牙状态读取失败,请检查是否打开蓝牙'); |
||||
|
reject(err); |
||||
|
}, |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
startBluetoothDevicesDiscovery() { |
||||
|
if (!this.isOpenBle) { |
||||
|
this.showToast(`初始化蓝牙模块失败`) |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
let self = this; |
||||
|
uni.showLoading({ |
||||
|
title: '蓝牙搜索中' |
||||
|
}) |
||||
|
return new Promise((resolve, reject) => { |
||||
|
setTimeout(() => { |
||||
|
uni.startBluetoothDevicesDiscovery({ |
||||
|
success: res => { |
||||
|
resolve(res) |
||||
|
}, |
||||
|
fail: res => { |
||||
|
self.showToast(`搜索设备失败` + JSON.stringify(err)); |
||||
|
reject(err); |
||||
|
} |
||||
|
}) |
||||
|
}, 300); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
stopBluetoothDevicesDiscovery() { |
||||
|
let self = this; |
||||
|
return new Promise((resolve, reject) => { |
||||
|
uni.stopBluetoothDevicesDiscovery({ |
||||
|
success: e => { |
||||
|
uni.hideLoading(); |
||||
|
}, |
||||
|
fail: e => { |
||||
|
uni.hideLoading(); |
||||
|
self.showToast(`停止搜索蓝牙设备失败` + JSON.stringify(err)); |
||||
|
} |
||||
|
}) |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
createBLEConnection(deviceId) { |
||||
|
//设备deviceId
|
||||
|
let self = this; |
||||
|
|
||||
|
uni.showLoading({ |
||||
|
mask: true, |
||||
|
title: '设别连接中,请稍候...' |
||||
|
}) |
||||
|
console.log(deviceId); |
||||
|
return new Promise((resolve, reject) => { |
||||
|
uni.createBLEConnection({ |
||||
|
deviceId, |
||||
|
timeout: 5000, |
||||
|
success: (res) => { |
||||
|
console.log(res) |
||||
|
resolve(res) |
||||
|
}, |
||||
|
fail: err => { |
||||
|
console.log(err) |
||||
|
if (err.errMsg == "createBLEConnection:fail already connect") { |
||||
|
resolve(err) |
||||
|
return true; |
||||
|
} |
||||
|
if (err.errCode == 10012) { |
||||
|
self.showToast(`蓝牙连接超时`); |
||||
|
} else { |
||||
|
self.showToast(`停止搜索蓝牙设备失败` + JSON.stringify(err)); |
||||
|
} |
||||
|
reject(err); |
||||
|
}, |
||||
|
complete() { |
||||
|
uni.hideLoading(); |
||||
|
} |
||||
|
}) |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
//获取蓝牙设备所有服务(service)
|
||||
|
getBLEDeviceServices() { |
||||
|
let _serviceList = []; |
||||
|
let deviceId = this.deviceId; |
||||
|
let self = this; |
||||
|
return new Promise((resolve, reject) => { |
||||
|
setTimeout(() => { |
||||
|
uni.getBLEDeviceServices({ |
||||
|
deviceId, |
||||
|
success: res => { |
||||
|
for (let service of res.services) { |
||||
|
if (service.isPrimary) { |
||||
|
_serviceList.push(service); |
||||
|
} |
||||
|
} |
||||
|
uni.hideLoading(); |
||||
|
resolve(_serviceList) |
||||
|
}, |
||||
|
fail: err => { |
||||
|
uni.hideLoading(); |
||||
|
self.showToast(`获取设备Services` + JSON.stringify(err)); |
||||
|
reject(err); |
||||
|
}, |
||||
|
}) |
||||
|
}, 500); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
//获取蓝牙设备某个服务中所有特征值(characteristic)
|
||||
|
getBLEDeviceCharacteristics() { |
||||
|
let self = this; |
||||
|
let deviceId = self.deviceId; |
||||
|
let service = self.serviceList; |
||||
|
var uuid = service[self.num].uuid; |
||||
|
return new Promise((resolve, reject) => { |
||||
|
uni.getBLEDeviceCharacteristics({ |
||||
|
deviceId: deviceId, |
||||
|
serviceId: uuid, |
||||
|
success: res => { |
||||
|
console.log(res) |
||||
|
for (let _obj of res.characteristics) { |
||||
|
//获取notify
|
||||
|
if (_obj.properties.notify) { |
||||
|
self.notifyId = _obj.uuid; |
||||
|
uni.setStorageSync('notifyId', self.notifyId); |
||||
|
} |
||||
|
//获取writeId
|
||||
|
if (_obj.properties.write) { |
||||
|
self.writeId = _obj.uuid; |
||||
|
uni.setStorageSync('writeId', self.writeId); |
||||
|
} |
||||
|
} |
||||
|
console.log("notifyId:" + self.notifyId) |
||||
|
console.log("writeId:" + self.writeId) |
||||
|
if (!self.writeId || !self.notifyId) { |
||||
|
self.num++ |
||||
|
if (self.num == service.length) { |
||||
|
console.log('找不到该读写的特征值') |
||||
|
reject('找不到该读写的特征值'); |
||||
|
return false; |
||||
|
} else { |
||||
|
self.getBLEDeviceCharacteristics() |
||||
|
} |
||||
|
} else { |
||||
|
self.serviceId = uuid; |
||||
|
} |
||||
|
let result = { |
||||
|
'notifyId': self.notifyId, |
||||
|
'writeId': self.writeId |
||||
|
}; |
||||
|
// self.showToast(`获取服务中所有特征值OK,${JSON.stringify(result)}`);
|
||||
|
resolve(result) |
||||
|
}, |
||||
|
fail: err => { |
||||
|
self.showToast(`getBLEDeviceCharacteristics` + JSON.stringify(err)); |
||||
|
reject(err); |
||||
|
} |
||||
|
}) |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
//断开联链接
|
||||
|
closeBLEConnection() { |
||||
|
let deviceId = this.deviceId; |
||||
|
uni.closeBLEConnection({ |
||||
|
deviceId, |
||||
|
success(res) { |
||||
|
console.log(res) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
notifyBLECharacteristicValue() { |
||||
|
let deviceId = this.deviceId; |
||||
|
let serviceId = this.serviceId; |
||||
|
let characteristicId = this.notifyId; |
||||
|
console.log('----notifyBLECharacteristicValue----') |
||||
|
console.log(characteristicId) |
||||
|
console.log(serviceId) |
||||
|
console.log(deviceId) |
||||
|
uni.notifyBLECharacteristicValueChange({ |
||||
|
state: true, // 启用 notify 功能
|
||||
|
deviceId, |
||||
|
serviceId, |
||||
|
characteristicId, |
||||
|
success(res) { |
||||
|
console.log(res); |
||||
|
uni.onBLECharacteristicValueChange(function(res) { |
||||
|
console.log(res); |
||||
|
}); |
||||
|
}, |
||||
|
fail(res) { |
||||
|
console.log('notifyBLECharacteristicValueChange failed:' + res.errMsg); |
||||
|
|
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
writeBLECharacteristicValue(buffer) { |
||||
|
let deviceId = this.deviceId; |
||||
|
let serviceId = this.serviceId; |
||||
|
let characteristicId = this.writeId; |
||||
|
console.log('----writeBLECharacteristicValue----') |
||||
|
console.log(characteristicId) |
||||
|
console.log(serviceId) |
||||
|
console.log(deviceId) |
||||
|
console.log("this: " + JSON.stringify(this)); |
||||
|
return new Promise((resolve, reject) => { |
||||
|
uni.writeBLECharacteristicValue({ |
||||
|
deviceId, |
||||
|
serviceId, |
||||
|
characteristicId, |
||||
|
value: buffer, |
||||
|
success(res) { |
||||
|
console.log('message发送成功', JSON.stringify(res)); |
||||
|
resolve(res); |
||||
|
}, |
||||
|
fail(err) { |
||||
|
console.log('message发送失败', JSON.stringify(err)); |
||||
|
reject(err); |
||||
|
} |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
closeBluetoothAdapter() { |
||||
|
uni.closeBluetoothAdapter({ |
||||
|
success: res => { |
||||
|
console.log(res) |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
//若APP在之前已有搜索过某个蓝牙设备,并成功建立连接,可直接传入之前搜索获取的 deviceId 直接尝试连接该设备,无需进行搜索操作。
|
||||
|
reconnect() { |
||||
|
(async () => { |
||||
|
try { |
||||
|
this.deviceId = this.deviceId || uni.getStorageSync("deviceId"); |
||||
|
this.serviceId = this.serviceId || uni.getStorageSync("serviceId"); |
||||
|
|
||||
|
let result1 = await this.createBLEConnection(); |
||||
|
console.log("createBLEConnection: " + JSON.stringify(result1)); |
||||
|
|
||||
|
let result2 = await this.getBLEDeviceServices(); |
||||
|
console.log("getBLEDeviceServices: " + JSON.stringify(result2)); |
||||
|
|
||||
|
let result3 = await this.getBLEDeviceCharacteristics(); |
||||
|
console.log("getBLEDeviceCharacteristics: " + JSON.stringify(result3)); |
||||
|
|
||||
|
|
||||
|
} catch (err) { |
||||
|
console.log("err: " + JSON.stringify(err)); |
||||
|
} |
||||
|
|
||||
|
})(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default Bluetooth; |
||||
@ -0,0 +1,42 @@ |
|||||
|
|
||||
|
function getCode128(val) { |
||||
|
// 开始位为固定格式 str.charCodeAt()
|
||||
|
let code128A = [0x7B, 0x41] |
||||
|
let code128B = [0x7B, 0x42] |
||||
|
let code128C = [0x7B, 0x43] |
||||
|
let ret = []; |
||||
|
let n67 = 0; |
||||
|
for (let i = 0; i < val.length; i += 2) { |
||||
|
let tmp = val.substr(i, 2); |
||||
|
if (tmp == '00') { |
||||
|
if(i==0){ |
||||
|
ret.push(123); |
||||
|
ret.push(66); |
||||
|
n67 = 66; |
||||
|
}else if(n67==67){ |
||||
|
ret.push(123); |
||||
|
ret.push(66); |
||||
|
n67 = 66; |
||||
|
} |
||||
|
|
||||
|
ret.push(48); |
||||
|
ret.push(48); |
||||
|
} else { |
||||
|
if(i==0){ |
||||
|
ret.push(123); |
||||
|
ret.push(67); |
||||
|
n67 = 67; |
||||
|
}else if(n67==66){ |
||||
|
ret.push(123); |
||||
|
ret.push(67); |
||||
|
n67 = 67; |
||||
|
} |
||||
|
ret.push(parseInt(tmp)); |
||||
|
} |
||||
|
} |
||||
|
ret.unshift(ret.length) |
||||
|
|
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
module.exports = getCode128; |
||||
@ -0,0 +1,241 @@ |
|||||
|
/** |
||||
|
* 修改自https://github.com/song940/node-escpos/blob/master/commands.js
|
||||
|
* ESC/POS _ (Constants) |
||||
|
*/ |
||||
|
var _ = { |
||||
|
LF: [0x0a], |
||||
|
FS: [0x1c], |
||||
|
FF: [0x0c], |
||||
|
GS: [0x1d], |
||||
|
DLE: [0x10], |
||||
|
EOT: [0x04], |
||||
|
NUL: [0x00], |
||||
|
ESC: [0x1b], |
||||
|
EOL: '\n', |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [FEED_CONTROL_SEQUENCES Feed control sequences] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.FEED_CONTROL_SEQUENCES = { |
||||
|
CTL_LF: [0x0a], // Print and line feed
|
||||
|
CTL_GLF: [0x4a, 0x00], // Print and feed paper (without spaces between lines)
|
||||
|
CTL_FF: [0x0c], // Form feed
|
||||
|
CTL_CR: [0x0d], // Carriage return
|
||||
|
CTL_HT: [0x09], // Horizontal tab
|
||||
|
CTL_VT: [0x0b], // Vertical tab
|
||||
|
}; |
||||
|
|
||||
|
_.CHARACTER_SPACING = { |
||||
|
CS_DEFAULT: [0x1b, 0x20, 0x00], |
||||
|
CS_SET: [0x1b, 0x20] |
||||
|
}; |
||||
|
|
||||
|
_.LINE_SPACING = { |
||||
|
LS_DEFAULT: [0x1b, 0x32], |
||||
|
LS_SET: [0x1b, 0x33] |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [HARDWARE Printer hardware] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.HARDWARE = { |
||||
|
HW_INIT: [0x1b, 0x40], // Clear data in buffer and reset modes
|
||||
|
HW_SELECT: [0x1b, 0x3d, 0x01], // Printer select
|
||||
|
HW_RESET: [0x1b, 0x3f, 0x0a, 0x00], // Reset printer hardware
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [CASH_DRAWER Cash Drawer] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.CASH_DRAWER = { |
||||
|
CD_KICK_2: [0x1b, 0x70, 0x00], // Sends a pulse to pin 2 []
|
||||
|
CD_KICK_5: [0x1b, 0x70, 0x01], // Sends a pulse to pin 5 []
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [MARGINS Margins sizes] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.MARGINS = { |
||||
|
BOTTOM: [0x1b, 0x4f], // Fix bottom size
|
||||
|
LEFT: [0x1b, 0x6c], // Fix left size
|
||||
|
RIGHT: [0x1b, 0x51], // Fix right size
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [PAPER Paper] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.PAPER = { |
||||
|
PAPER_FULL_CUT: [0x1d, 0x56, 0x00], // Full cut paper
|
||||
|
PAPER_PART_CUT: [0x1d, 0x56, 0x01], // Partial cut paper
|
||||
|
PAPER_CUT_A: [0x1d, 0x56, 0x41], // Partial cut paper
|
||||
|
PAPER_CUT_B: [0x1d, 0x56, 0x42], // Partial cut paper
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [TEXT_FORMAT Text format] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.TEXT_FORMAT = { |
||||
|
TXT_NORMAL: [0x1b, 0x21, 0x00], // Normal text
|
||||
|
TXT_2HEIGHT: [0x1b, 0x21, 0x10], // Double height text
|
||||
|
TXT_2WIDTH: [0x1b, 0x21, 0x20], // Double width text
|
||||
|
TXT_4SQUARE: [0x1b, 0x21, 0x30], // Double width & height text
|
||||
|
|
||||
|
TXT_UNDERL_OFF: [0x1b, 0x2d, 0x00], // Underline font OFF
|
||||
|
TXT_UNDERL_ON: [0x1b, 0x2d, 0x01], // Underline font 1-dot ON
|
||||
|
TXT_UNDERL2_ON: [0x1b, 0x2d, 0x02], // Underline font 2-dot ON
|
||||
|
TXT_BOLD_OFF: [0x1b, 0x45, 0x00], // Bold font OFF
|
||||
|
TXT_BOLD_ON: [0x1b, 0x45, 0x01], // Bold font ON
|
||||
|
TXT_ITALIC_OFF: [0x1b, 0x35], // Italic font ON
|
||||
|
TXT_ITALIC_ON: [0x1b, 0x34], // Italic font ON
|
||||
|
|
||||
|
TXT_FONT_A: [0x1b, 0x4d, 0x00], // Font type A
|
||||
|
TXT_FONT_B: [0x1b, 0x4d, 0x01], // Font type B
|
||||
|
TXT_FONT_C: [0x1b, 0x4d, 0x02], // Font type C
|
||||
|
|
||||
|
TXT_ALIGN_LT: [0x1b, 0x61, 0x00], // Left justification
|
||||
|
TXT_ALIGN_CT: [0x1b, 0x61, 0x01], // Centering
|
||||
|
TXT_ALIGN_RT: [0x1b, 0x61, 0x02], // Right justification
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [BARCODE_FORMAT Barcode format] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.BARCODE_FORMAT = { |
||||
|
BARCODE_TXT_OFF: [0x1d, 0x48, 0x00], // HRI barcode chars OFF
|
||||
|
BARCODE_TXT_ABV: [0x1d, 0x48, 0x01], // HRI barcode chars above
|
||||
|
BARCODE_TXT_BLW: [0x1d, 0x48, 0x02], // HRI barcode chars below
|
||||
|
BARCODE_TXT_BTH: [0x1d, 0x48, 0x03], // HRI barcode chars both above and below
|
||||
|
|
||||
|
BARCODE_FONT_A: [0x1d, 0x66, 0x00], // Font type A for HRI barcode chars
|
||||
|
BARCODE_FONT_B: [0x1d, 0x66, 0x01], // Font type B for HRI barcode chars
|
||||
|
|
||||
|
BARCODE_HEIGHT: function (height) { // Barcode Height [1-255]
|
||||
|
return [0x1d, 0x68, height]; |
||||
|
}, |
||||
|
BARCODE_WIDTH: function (width) { // Barcode Width [2-6]
|
||||
|
return [0x1d, 0x77, width]; |
||||
|
}, |
||||
|
BARCODE_HEIGHT_DEFAULT: [0x1d, 0x68, 0x64], // Barcode height default:100
|
||||
|
BARCODE_WIDTH_DEFAULT: [0x1d, 0x77, 0x01], // Barcode width default:1
|
||||
|
|
||||
|
BARCODE_UPC_A: [0x1d, 0x6b, 0x00], // Barcode type UPC-A
|
||||
|
BARCODE_UPC_E: [0x1d, 0x6b, 0x01], // Barcode type UPC-E
|
||||
|
BARCODE_EAN13: [0x1d, 0x6b, 0x02], // Barcode type EAN13
|
||||
|
BARCODE_EAN8: [0x1d, 0x6b, 0x03], // Barcode type EAN8
|
||||
|
BARCODE_CODE39: [0x1d, 0x6b, 0x04], // Barcode type CODE39
|
||||
|
BARCODE_ITF: [0x1d, 0x6b, 0x05], // Barcode type ITF
|
||||
|
BARCODE_NW7: [0x1d, 0x6b, 0x06], // Barcode type NW7
|
||||
|
BARCODE_CODE93: [0x1d, 0x6b, 0x48], // Barcode type CODE93
|
||||
|
BARCODE_CODE128: [0x1d, 0x6b, 0x49], // Barcode type CODE128
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [QRCODE_FORMAT qrcode format二维码] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.QRCODE_FORMAT = { |
||||
|
QRCODE_SIZE: function(n) { // 设置二维码大小
|
||||
|
let data = [29,40,107,3,0,49,67] |
||||
|
if (n > 15) { |
||||
|
n = 15 |
||||
|
} |
||||
|
if (n < 1) { |
||||
|
n = 1 |
||||
|
} |
||||
|
data.push(n) |
||||
|
return data; |
||||
|
}, |
||||
|
QRCODE_ERROR: function(n) { // 设置纠错等级
|
||||
|
/* |
||||
|
n 功能 纠错能力 |
||||
|
48 选择纠错等级 L 7 |
||||
|
49 选择纠错等级 M 15 |
||||
|
50 选择纠错等级 Q 25 |
||||
|
51 选择纠错等级 H 30 |
||||
|
*/ |
||||
|
let data = [29,40,107,3,0,49,69] |
||||
|
data.push(n) |
||||
|
return data; |
||||
|
}, |
||||
|
QRCODE_DATA: function(content) { // 设置二维码内容
|
||||
|
let data = [29,40,107] |
||||
|
var code = new encode.TextEncoder( |
||||
|
'gb18030', { |
||||
|
NONSTANDARD_allowLegacyEncoding: true |
||||
|
}).encode(content) |
||||
|
data.push(parseInt((code.length + 3) % 256)) |
||||
|
data.push(parseInt((code.length + 3) / 256)) |
||||
|
data.push(49) |
||||
|
data.push(80) |
||||
|
data.push(48) |
||||
|
|
||||
|
for (var i = 0; i < code.length; ++i) { |
||||
|
data.push(code[i]) |
||||
|
} |
||||
|
return data; |
||||
|
}, |
||||
|
QRCODE_PRINT:[29,40,107,3,0,49,81,48],// 打印二维码
|
||||
|
|
||||
|
}; |
||||
|
/** |
||||
|
* [IMAGE_FORMAT Image format] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.IMAGE_FORMAT = { |
||||
|
S_RASTER_N: [0x1d, 0x76, 0x30, 0x00], // Set raster image normal size
|
||||
|
S_RASTER_2W: [0x1d, 0x76, 0x30, 0x01], // Set raster image double width
|
||||
|
S_RASTER_2H: [0x1d, 0x76, 0x30, 0x02], // Set raster image double height
|
||||
|
S_RASTER_Q: [0x1d, 0x76, 0x30, 0x03], // Set raster image quadruple
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [BITMAP_FORMAT description] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.BITMAP_FORMAT = { |
||||
|
BITMAP_S8: [0x1b, 0x2a, 0x00], |
||||
|
BITMAP_D8: [0x1b, 0x2a, 0x01], |
||||
|
BITMAP_S24: [0x1b, 0x2a, 0x20], |
||||
|
BITMAP_D24: [0x1b, 0x2a, 0x21] |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [GSV0_FORMAT description] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.GSV0_FORMAT = { |
||||
|
GSV0_NORMAL: [0x1d, 0x76, 0x30, 0x00], |
||||
|
GSV0_DW: [0x1d, 0x76, 0x30, 0x01], |
||||
|
GSV0_DH: [0x1d, 0x76, 0x30, 0x02], |
||||
|
GSV0_DWDH: [0x1d, 0x76, 0x30, 0x03] |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [BEEP description] |
||||
|
* @type {string} |
||||
|
*/ |
||||
|
_.BEEP = [0x1b, 0x42]; // Printer Buzzer pre hex
|
||||
|
|
||||
|
/** |
||||
|
* [COLOR description] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
|
||||
|
_.COLOR = { |
||||
|
0: [0x1b, 0x72, 0x00], // black
|
||||
|
1: [0x1b, 0x72, 0x01] // red
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [exports description] |
||||
|
* @type {[type]} |
||||
|
*/ |
||||
|
module.exports = _; |
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
@ -0,0 +1,246 @@ |
|||||
|
/** |
||||
|
* 修改自https://github.com/song940/node-escpos/blob/master/commands.js
|
||||
|
* ESC/POS _ (Constants) |
||||
|
*/ |
||||
|
const encode = require('./encoding'); |
||||
|
var _ = { |
||||
|
LF: [0x0a], |
||||
|
FS: [0x1c], |
||||
|
FF: [0x0c], |
||||
|
GS: [0x1d], |
||||
|
DLE: [0x10], |
||||
|
EOT: [0x04], |
||||
|
NUL: [0x00], |
||||
|
ESC: [0x1b], |
||||
|
EOL: '\n', |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [FEED_CONTROL_SEQUENCES Feed control sequences走纸] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.FEED_CONTROL_SEQUENCES = { |
||||
|
CTL_LF: [0x0a], // Print and line feed
|
||||
|
CTL_GLF: [0x4a, 0x00], // Print and feed paper (without spaces between lines)
|
||||
|
CTL_FF: [0x0c], // Form feed
|
||||
|
CTL_CR: [0x0d], // Carriage return
|
||||
|
CTL_HT: [0x09], // Horizontal tab
|
||||
|
CTL_VT: [0x0b], // Vertical tab
|
||||
|
}; |
||||
|
|
||||
|
_.CHARACTER_SPACING = { |
||||
|
CS_DEFAULT: [0x1b, 0x20, 0x00], |
||||
|
CS_SET: [0x1b, 0x20] |
||||
|
}; |
||||
|
|
||||
|
_.LINE_SPACING = { |
||||
|
LS_DEFAULT: [0x1b, 0x32], |
||||
|
LS_SET: [0x1b, 0x33] |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [HARDWARE Printer hardware] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.HARDWARE = { |
||||
|
HW_INIT: [0x1b, 0x40], // Clear data in buffer and reset modes
|
||||
|
HW_SELECT: [0x1b, 0x3d, 0x01], // Printer select
|
||||
|
HW_RESET: [0x1b, 0x3f, 0x0a, 0x00], // Reset printer hardware
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [CASH_DRAWER Cash Drawer 钱箱] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.CASH_DRAWER = { |
||||
|
CD_KICK_2: [0x1b, 0x70, 0x00], // Sends a pulse to pin 2 []
|
||||
|
CD_KICK_5: [0x1b, 0x70, 0x01], // Sends a pulse to pin 5 []
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [MARGINS Margins sizes边缘] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.MARGINS = { |
||||
|
BOTTOM: [0x1b, 0x4f], // Fix bottom size
|
||||
|
LEFT: [0x1b, 0x6c], // Fix left size
|
||||
|
RIGHT: [0x1b, 0x51], // Fix right size
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [PAPER Paper切纸] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.PAPER = { |
||||
|
PAPER_FULL_CUT: [0x1d, 0x56, 0x00], // Full cut paper
|
||||
|
PAPER_PART_CUT: [0x1d, 0x56, 0x01], // Partial cut paper
|
||||
|
PAPER_CUT_A: [0x1d, 0x56, 0x41], // Partial cut paper
|
||||
|
PAPER_CUT_B: [0x1d, 0x56, 0x42], // Partial cut paper
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [TEXT_FORMAT Text format文本格式] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.TEXT_FORMAT = { |
||||
|
TXT_NORMAL: [0x1b, 0x21, 0x00], // Normal text
|
||||
|
TXT_2HEIGHT: [0x1b, 0x21, 0x10], // Double height text
|
||||
|
TXT_2WIDTH: [0x1b, 0x21, 0x20], // Double width text
|
||||
|
TXT_4SQUARE: [0x1b, 0x21, 0x30], // Double width & height text
|
||||
|
|
||||
|
TXT_UNDERL_OFF: [0x1b, 0x2d, 0x00], // Underline font OFF
|
||||
|
TXT_UNDERL_ON: [0x1b, 0x2d, 0x01], // Underline font 1-dot ON
|
||||
|
TXT_UNDERL2_ON: [0x1b, 0x2d, 0x02], // Underline font 2-dot ON
|
||||
|
TXT_BOLD_OFF: [0x1b, 0x45, 0x00], // Bold font OFF
|
||||
|
TXT_BOLD_ON: [0x1b, 0x45, 0x01], // Bold font ON
|
||||
|
TXT_ITALIC_OFF: [0x1b, 0x35], // Italic font ON
|
||||
|
TXT_ITALIC_ON: [0x1b, 0x34], // Italic font ON
|
||||
|
|
||||
|
TXT_FONT_A: [0x1b, 0x4d, 0x00], // Font type A
|
||||
|
TXT_FONT_B: [0x1b, 0x4d, 0x01], // Font type B
|
||||
|
TXT_FONT_C: [0x1b, 0x4d, 0x02], // Font type C
|
||||
|
|
||||
|
TXT_ALIGN_LT: [0x1b, 0x61, 0x00], // Left justification
|
||||
|
TXT_ALIGN_CT: [0x1b, 0x61, 0x01], // Centering
|
||||
|
TXT_ALIGN_RT: [0x1b, 0x61, 0x02], // Right justification
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [BARCODE_FORMAT Barcode format条码] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.BARCODE_FORMAT = { |
||||
|
BARCODE_TXT_OFF: [0x1d, 0x48, 0x00], // HRI barcode chars OFF
|
||||
|
BARCODE_TXT_ABV: [0x1d, 0x48, 0x01], // HRI barcode chars above
|
||||
|
BARCODE_TXT_BLW: [0x1d, 0x48, 0x02], // HRI barcode chars below
|
||||
|
BARCODE_TXT_BTH: [0x1d, 0x48, 0x03], // HRI barcode chars both above and below
|
||||
|
|
||||
|
BARCODE_FONT_A: [0x1d, 0x66, 0x00], // Font type A for HRI barcode chars
|
||||
|
BARCODE_FONT_B: [0x1d, 0x66, 0x01], // Font type B for HRI barcode chars
|
||||
|
|
||||
|
BARCODE_HEIGHT: function(height) { // Barcode Height [1-255]
|
||||
|
return [0x1d, 0x68, height]; |
||||
|
}, |
||||
|
BARCODE_WIDTH: function(width) { // Barcode Width [2-6]
|
||||
|
return [0x1d, 0x77, width]; |
||||
|
}, |
||||
|
BARCODE_HEIGHT_DEFAULT: [0x1d, 0x68, 0x64], // Barcode height default:100
|
||||
|
BARCODE_WIDTH_1: [0x1d, 0x77, 0x01], // Barcode width default:1
|
||||
|
BARCODE_WIDTH_2: [0x1d, 0x77, 0x02], // Barcode width default:1
|
||||
|
BARCODE_WIDTH_3: [0x1d, 0x77, 0x03], // Barcode width default:1
|
||||
|
BARCODE_WIDTH_4: [0x1d, 0x77, 0x04], // Barcode width default:1
|
||||
|
|
||||
|
BARCODE_UPC_A: [0x1d, 0x6b, 0x00], // Barcode type UPC-A
|
||||
|
BARCODE_UPC_E: [0x1d, 0x6b, 0x01], // Barcode type UPC-E
|
||||
|
BARCODE_EAN13: [0x1d, 0x6b, 0x02], // Barcode type EAN13
|
||||
|
BARCODE_EAN8: [0x1d, 0x6b, 0x03], // Barcode type EAN8
|
||||
|
BARCODE_CODE39: [0x1d, 0x6b, 0x04], // Barcode type CODE39
|
||||
|
BARCODE_ITF: [0x1d, 0x6b, 0x05], // Barcode type ITF
|
||||
|
BARCODE_NW7: [0x1d, 0x6b, 0x06], // Barcode type NW7
|
||||
|
BARCODE_CODE93: [0x1d, 0x6b, 0x48], // Barcode type CODE93
|
||||
|
BARCODE_CODE128: [0x1d, 0x6b, 0x49], // Barcode type CODE128
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [QRCODE_FORMAT qrcode format二维码] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.QRCODE_FORMAT = { |
||||
|
QRCODE_SIZE: function(n) { // 设置二维码大小
|
||||
|
let data = [29,40,107,3,0,49,67] |
||||
|
if (n > 15) { |
||||
|
n = 15 |
||||
|
} |
||||
|
if (n < 1) { |
||||
|
n = 1 |
||||
|
} |
||||
|
data.push(n) |
||||
|
return data; |
||||
|
}, |
||||
|
QRCODE_ERROR: function(n) { // 设置纠错等级
|
||||
|
/* |
||||
|
n 功能 纠错能力 |
||||
|
48 选择纠错等级 L 7 |
||||
|
49 选择纠错等级 M 15 |
||||
|
50 选择纠错等级 Q 25 |
||||
|
51 选择纠错等级 H 30 |
||||
|
*/ |
||||
|
let data = [29,40,107,3,0,49,69] |
||||
|
data.push(n) |
||||
|
return data; |
||||
|
}, |
||||
|
QRCODE_DATA: function(content) { // 设置二维码内容
|
||||
|
let data = [29,40,107] |
||||
|
var code = new encode.TextEncoder( |
||||
|
'gb18030', { |
||||
|
NONSTANDARD_allowLegacyEncoding: true |
||||
|
}).encode(content) |
||||
|
data.push(parseInt((code.length + 3) % 256)) |
||||
|
data.push(parseInt((code.length + 3) / 256)) |
||||
|
data.push(49) |
||||
|
data.push(80) |
||||
|
data.push(48) |
||||
|
|
||||
|
for (var i = 0; i < code.length; ++i) { |
||||
|
data.push(code[i]) |
||||
|
} |
||||
|
return data; |
||||
|
}, |
||||
|
QRCODE_PRINT:[29,40,107,3,0,49,81,48],// 打印二维码
|
||||
|
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [IMAGE_FORMAT Image format图像] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.IMAGE_FORMAT = { |
||||
|
S_RASTER_N: [0x1d, 0x76, 0x30, 0x00], // Set raster image normal size
|
||||
|
S_RASTER_2W: [0x1d, 0x76, 0x30, 0x01], // Set raster image double width
|
||||
|
S_RASTER_2H: [0x1d, 0x76, 0x30, 0x02], // Set raster image double height
|
||||
|
S_RASTER_Q: [0x1d, 0x76, 0x30, 0x03], // Set raster image quadruple
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [BITMAP_FORMAT description BMP图片] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.BITMAP_FORMAT = { |
||||
|
BITMAP_S8: [0x1b, 0x2a, 0x00], |
||||
|
BITMAP_D8: [0x1b, 0x2a, 0x01], |
||||
|
BITMAP_S24: [0x1b, 0x2a, 0x20], |
||||
|
BITMAP_D24: [0x1b, 0x2a, 0x21] |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [GSV0_FORMAT description] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
_.GSV0_FORMAT = { |
||||
|
GSV0_NORMAL: [0x1d, 0x76, 0x30, 0x00], |
||||
|
GSV0_DW: [0x1d, 0x76, 0x30, 0x01], |
||||
|
GSV0_DH: [0x1d, 0x76, 0x30, 0x02], |
||||
|
GSV0_DWDH: [0x1d, 0x76, 0x30, 0x03] |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [BEEP description 嗡鸣] |
||||
|
* @type {string} |
||||
|
*/ |
||||
|
_.BEEP = [0x1b, 0x42]; // Printer Buzzer pre hex
|
||||
|
|
||||
|
/** |
||||
|
* [COLOR description] |
||||
|
* @type {Object} |
||||
|
*/ |
||||
|
|
||||
|
_.COLOR = { |
||||
|
0: [0x1b, 0x72, 0x00], // black
|
||||
|
1: [0x1b, 0x72, 0x01] // red
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* [exports description] |
||||
|
* @type {[type]} |
||||
|
*/ |
||||
|
module.exports = _; |
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,206 @@ |
|||||
|
const escCmd = require('./escpos'); |
||||
|
const gbk = require('./gbk'); |
||||
|
|
||||
|
const printerJobs = function() { |
||||
|
this._queue = Array.from(escCmd.HARDWARE.HW_INIT); |
||||
|
this._enqueue = function(cmd) { |
||||
|
this._queue.push.apply(this._queue, cmd); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 增加打印内容 |
||||
|
* @param {string} content 文字内容 |
||||
|
*/ |
||||
|
printerJobs.prototype.text = function(content) { |
||||
|
if (content) { |
||||
|
let uint8Array = gbk.encode(content); |
||||
|
let encoded = Array.from(uint8Array); |
||||
|
this._enqueue(encoded); |
||||
|
} |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 打印文字 |
||||
|
* @param {string} content 文字内容 |
||||
|
*/ |
||||
|
printerJobs.prototype.print = function(content) { |
||||
|
this.text(content); |
||||
|
this._enqueue(escCmd.LF); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 打印条码 |
||||
|
* @param {string} content 条码内容 code128A,B,C可以混合打印在一起 |
||||
|
*/ |
||||
|
printerJobs.prototype.printBarcode = function(content) { |
||||
|
if (content) { |
||||
|
let bar = escCmd.BARCODE_FORMAT; |
||||
|
const cmds = [].concat(bar.BARCODE_TXT_BLW,bar.BARCODE_WIDTH(2),bar.BARCODE_CODE128, content); |
||||
|
this._enqueue(cmds); |
||||
|
this._enqueue(escCmd.LF); |
||||
|
} |
||||
|
|
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 打印二维码 |
||||
|
* @param {string} content 二维码内容 |
||||
|
*/ |
||||
|
printerJobs.prototype.printQrcode = function(content,size) { |
||||
|
if (content) { |
||||
|
let qr = escCmd.QRCODE_FORMAT; |
||||
|
// const cmds = [].concat([27, 97, 1], [29, 118, 48, 0, 30, 0, 240, 0], content, [27, 74, 3], [27, 64]);
|
||||
|
const cmds = [].concat(qr.QRCODE_SIZE(size),qr.QRCODE_ERROR(49),qr.QRCODE_DATA(content),qr.QRCODE_PRINT); |
||||
|
this._enqueue(cmds); |
||||
|
this._enqueue(escCmd.LF); |
||||
|
} |
||||
|
|
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 打印图片 |
||||
|
* @param {string} content bmp内容 |
||||
|
*/ |
||||
|
printerJobs.prototype.printImage = function(content) { |
||||
|
if (content) { |
||||
|
const cmds = [].concat([27, 97, 1], [29, 118, 48, 0, 30, 0, 240, 0], content, [27, 74, 3], [27, 64]); |
||||
|
this._enqueue(cmds); |
||||
|
this._enqueue(escCmd.LF); |
||||
|
} |
||||
|
|
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 打印文字并换行 |
||||
|
* @param {string} content 文字内容 |
||||
|
*/ |
||||
|
printerJobs.prototype.println = function(content = '') { |
||||
|
return this.print(content + escCmd.EOL); |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 设置对齐方式 |
||||
|
* @param {string} align 对齐方式 LT/CT/RT |
||||
|
*/ |
||||
|
printerJobs.prototype.setAlign = function(align) { |
||||
|
this._enqueue(escCmd.TEXT_FORMAT['TXT_ALIGN_' + align.toUpperCase()]); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 设置字体 |
||||
|
* @param {string} family A/B/C |
||||
|
*/ |
||||
|
printerJobs.prototype.setFont = function(family) { |
||||
|
this._enqueue(escCmd.TEXT_FORMAT['TXT_FONT_' + family.toUpperCase()]); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 设定字体尺寸 |
||||
|
* @param {number} width 字体宽度 1~2 |
||||
|
* @param {number} height 字体高度 1~2 |
||||
|
*/ |
||||
|
printerJobs.prototype.setSize = function(width, height) { |
||||
|
if (2 >= width && 2 >= height) { |
||||
|
this._enqueue(escCmd.TEXT_FORMAT.TXT_NORMAL); |
||||
|
if (2 === width && 2 === height) { |
||||
|
this._enqueue(escCmd.TEXT_FORMAT.TXT_4SQUARE); |
||||
|
} else if (1 === width && 2 === height) { |
||||
|
this._enqueue(escCmd.TEXT_FORMAT.TXT_2HEIGHT); |
||||
|
} else if (2 === width && 1 === height) { |
||||
|
this._enqueue(escCmd.TEXT_FORMAT.TXT_2WIDTH); |
||||
|
} |
||||
|
} |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 设定字体是否加粗 |
||||
|
* @param {boolean} bold |
||||
|
*/ |
||||
|
printerJobs.prototype.setBold = function(bold) { |
||||
|
if (typeof bold !== 'boolean') { |
||||
|
bold = true; |
||||
|
} |
||||
|
this._enqueue(bold ? escCmd.TEXT_FORMAT.TXT_BOLD_ON : escCmd.TEXT_FORMAT.TXT_BOLD_OFF); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 设定是否开启下划线 |
||||
|
* @param {boolean} underline |
||||
|
*/ |
||||
|
printerJobs.prototype.setUnderline = function(underline) { |
||||
|
if (typeof underline !== 'boolean') { |
||||
|
underline = true; |
||||
|
} |
||||
|
this._enqueue(underline ? escCmd.TEXT_FORMAT.TXT_UNDERL_ON : escCmd.TEXT_FORMAT.TXT_UNDERL_OFF); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 设置行间距为 n 点行,默认值行间距是 30 点 |
||||
|
* @param {number} n 0≤n≤255 |
||||
|
*/ |
||||
|
printerJobs.prototype.setLineSpacing = function(n) { |
||||
|
if (n === undefined || n === null) { |
||||
|
this._enqueue(escCmd.LINE_SPACING.LS_DEFAULT); |
||||
|
} else { |
||||
|
this._enqueue(escCmd.LINE_SPACING.LS_SET); |
||||
|
this._enqueue([n]); |
||||
|
} |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 打印空行 |
||||
|
* @param {number} n |
||||
|
*/ |
||||
|
printerJobs.prototype.lineFeed = function(n = 1) { |
||||
|
return this.print(new Array(n).fill(escCmd.EOL).join('')); |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 设置字体颜色,需要打印机支持 |
||||
|
* @param {number} color - 0 默认颜色黑色 1 红色 |
||||
|
*/ |
||||
|
printerJobs.prototype.setColor = function(color) { |
||||
|
this._enqueue(escCmd.COLOR[color === 1 ? 1 : 0]); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* https://support.loyverse.com/hardware/printers/use-the-beeper-in-a-escpos-printers
|
||||
|
* 蜂鸣警报,需要打印机支持 |
||||
|
* @param {number} n 蜂鸣次数,1-9 |
||||
|
* @param {number} t 蜂鸣长短,1-9 |
||||
|
*/ |
||||
|
printerJobs.prototype.beep = function(n, t) { |
||||
|
this._enqueue(escCmd.BEEP); |
||||
|
this._enqueue([n, t]); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 清空任务 |
||||
|
*/ |
||||
|
printerJobs.prototype.clear = function() { |
||||
|
this._queue = Array.from(escCmd.HARDWARE.HW_INIT); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 返回ArrayBuffer |
||||
|
*/ |
||||
|
printerJobs.prototype.buffer = function() { |
||||
|
return new Uint8Array(this._queue).buffer; |
||||
|
}; |
||||
|
|
||||
|
module.exports = printerJobs; |
||||
@ -0,0 +1,128 @@ |
|||||
|
// 打印机纸宽58mm,页的宽度384,字符宽度为1,每行最多盛放32个字符
|
||||
|
|
||||
|
const PAGE_WIDTH = 384; |
||||
|
const MAX_CHAR_COUNT_EACH_LINE = 32; |
||||
|
|
||||
|
const PAGE_WIDTH_80 = 576; |
||||
|
const MAX_CHAR_COUNT_EACH_LINE_80 = 48; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* @param str |
||||
|
* @returns {boolean} str是否全是中文 |
||||
|
*/ |
||||
|
function isChinese(str) { |
||||
|
return /^[\u4e00-\u9fa5]$/.test(str); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 返回字符串宽度(1个中文=2个英文字符) |
||||
|
* @param str |
||||
|
* @returns {number} |
||||
|
*/ |
||||
|
function getStringWidth(str) { |
||||
|
let width = 0; |
||||
|
for (let i = 0, len = str.length; i < len; i++) { |
||||
|
width += isChinese(str.charAt(i)) ? 2 : 1; |
||||
|
} |
||||
|
return width; |
||||
|
} |
||||
|
/** |
||||
|
* 同一行输出居左, str2居右 |
||||
|
* @param {string} str1 内容1 |
||||
|
* @param {string} str2 内容2 |
||||
|
* @param {number} fontWidth 字符宽度 1/2 |
||||
|
* @param {string} fillWith str1 str2之间的填充字符 |
||||
|
* |
||||
|
*/ |
||||
|
function inlineArr(arr, fontWidth = 1, max_char = 0) { |
||||
|
var str = ''; |
||||
|
var fillWith = ' '; |
||||
|
for (var i = 0; i < arr.length; i++) { |
||||
|
let fillCount = arr[i].width - (getStringWidth(arr[i].text)) % arr[i].width; |
||||
|
let fillStr = new Array(fillCount).fill(fillWith.charAt(0)).join(''); |
||||
|
str = str + arr[i].text + fillStr; |
||||
|
} |
||||
|
return str; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 同一行输出str1, str2,str1居左, str2居右 |
||||
|
* @param {string} str1 内容1 |
||||
|
* @param {string} str2 内容2 |
||||
|
* @param {number} fontWidth 字符宽度 1/2 |
||||
|
* @param {string} fillWith str1 str2之间的填充字符 |
||||
|
* |
||||
|
*/ |
||||
|
function inline(str1, str2, fillWith = ' ', fontWidth = 1, max_char = 0) { |
||||
|
var char_count = MAX_CHAR_COUNT_EACH_LINE; |
||||
|
if (max_char == 80) { |
||||
|
char_count = MAX_CHAR_COUNT_EACH_LINE_80 |
||||
|
} |
||||
|
const lineWidth = max_char / fontWidth; |
||||
|
// 需要填充的字符数量
|
||||
|
let fillCount = lineWidth - (getStringWidth(str1) + getStringWidth(str2)) % lineWidth; |
||||
|
let fillStr = new Array(fillCount).fill(fillWith.charAt(0)).join(''); |
||||
|
return str1 + fillStr + str2; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 用字符填充一整行 |
||||
|
* @param {string} fillWith 填充字符 |
||||
|
* @param {number} fontWidth 字符宽度 1/2 |
||||
|
*/ |
||||
|
function fillLine(fillWith = '-', fontWidth = 1, max_char = 0) { |
||||
|
var char_count = MAX_CHAR_COUNT_EACH_LINE; |
||||
|
if (max_char == 80) { |
||||
|
char_count = MAX_CHAR_COUNT_EACH_LINE_80 |
||||
|
} |
||||
|
const lineWidth = char_count / fontWidth; |
||||
|
return new Array(lineWidth).fill(fillWith.charAt(0)).join(''); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 文字内容居中,左右用字符填充 |
||||
|
* @param {string} str 文字内容 |
||||
|
* @param {number} fontWidth 字符宽度 1/2 |
||||
|
* @param {string} fillWith str1 str2之间的填充字符 |
||||
|
*/ |
||||
|
function fillAround(str, fillWith = '-', fontWidth = 1, max_char = 0) { |
||||
|
var char_count = MAX_CHAR_COUNT_EACH_LINE; |
||||
|
if (max_char == 80) { |
||||
|
char_count = MAX_CHAR_COUNT_EACH_LINE_80 |
||||
|
} |
||||
|
const lineWidth = char_count / fontWidth; |
||||
|
let strWidth = getStringWidth(str); |
||||
|
// 内容已经超过一行了,没必要填充
|
||||
|
if (strWidth >= lineWidth) { |
||||
|
return str; |
||||
|
} |
||||
|
// 需要填充的字符数量
|
||||
|
let fillCount = lineWidth - strWidth; |
||||
|
// 左侧填充的字符数量
|
||||
|
let leftCount = Math.round(fillCount / 2); |
||||
|
// 两侧的填充字符,需要考虑左边需要填充,右边不需要填充的情况
|
||||
|
let fillStr = new Array(leftCount).fill(fillWith.charAt(0)).join(''); |
||||
|
return fillStr + str + fillStr.substr(0, fillCount - leftCount); |
||||
|
} |
||||
|
|
||||
|
// ArrayBuffer转16进度字符串示例
|
||||
|
function ab2hex(buffer) { |
||||
|
const hexArr = Array.prototype.map.call( |
||||
|
new Uint8Array(buffer), |
||||
|
function(bit) { |
||||
|
return ('00' + bit.toString(16)).slice(-2) |
||||
|
} |
||||
|
) |
||||
|
return hexArr.join(',') |
||||
|
} |
||||
|
|
||||
|
|
||||
|
module.exports = { |
||||
|
inline: inline, |
||||
|
inlineArr: inlineArr, |
||||
|
fillLine: fillLine, |
||||
|
fillAround: fillAround, |
||||
|
ab2hex: ab2hex, |
||||
|
}; |
||||
@ -0,0 +1,66 @@ |
|||||
|
const formatTime = date => { |
||||
|
const year = date.getFullYear() |
||||
|
const month = date.getMonth() + 1 |
||||
|
const day = date.getDate() |
||||
|
const hour = date.getHours() |
||||
|
const minute = date.getMinutes() |
||||
|
const second = date.getSeconds() |
||||
|
|
||||
|
return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') |
||||
|
} |
||||
|
|
||||
|
const formatNumber = n => { |
||||
|
n = n.toString() |
||||
|
return n[1] ? n : '0' + n |
||||
|
} |
||||
|
|
||||
|
|
||||
|
//4合1
|
||||
|
function convert4to1(res) { |
||||
|
let arr = []; |
||||
|
for (let i = 0; i < res.length; i++) { |
||||
|
if (i % 4 == 0) { |
||||
|
let rule = 0.29900 * res[i] + 0.58700 * res[i + 1] + 0.11400 * res[i + 2]; |
||||
|
if (rule > 200) { |
||||
|
res[i] = 0; |
||||
|
} else { |
||||
|
res[i] = 1; |
||||
|
} |
||||
|
arr.push(res[i]); |
||||
|
} |
||||
|
} |
||||
|
return arr; |
||||
|
} |
||||
|
|
||||
|
//8合1
|
||||
|
function convert8to1(arr) { |
||||
|
let data = []; |
||||
|
for (let k = 0; k < arr.length; k += 8) { |
||||
|
let temp = arr[k] * 128 + arr[k + 1] * 64 + arr[k + 2] * 32 + arr[k + 3] * 16 + arr[k + 4] * 8 + arr[k + 5] * 4 + |
||||
|
arr[k + 6] * 2 + arr[k + 7] * 1 |
||||
|
data.push(temp); |
||||
|
} |
||||
|
return data; |
||||
|
} |
||||
|
|
||||
|
//我的图片宽度是240,那么拼接的指令就是[29, 118, 48, 0, 30, 0, 240, 0]
|
||||
|
//我的图片宽度是160,那么拼接的指令就是[29, 118, 48, 0, 20, 0, 160, 0]
|
||||
|
//补充一点,打印非二维码的图片,宽度一定要是24的倍数,不然打印也会出现乱码
|
||||
|
function toArrayBuffer(res) { |
||||
|
let arr = convert4to1(res.data); |
||||
|
let data = convert8to1(arr); |
||||
|
let cmds = [].concat([27, 97, 1], [29, 118, 48, 0, 30, 0, 240, 0], data, [27, 74, 3], [27, 64]); |
||||
|
return new Uint8Array(cmds).buffer; |
||||
|
} |
||||
|
|
||||
|
function zip_image(res) { |
||||
|
let arr = convert4to1(res.data); |
||||
|
let data = convert8to1(arr); |
||||
|
return data; |
||||
|
} |
||||
|
|
||||
|
module.exports = { |
||||
|
formatTime: formatTime, |
||||
|
toArrayBuffer: toArrayBuffer, |
||||
|
zip_image: zip_image, |
||||
|
} |
||||
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue