uniapp微信小程序连接蓝牙打印机 打印文字、图片

news2024/10/7 11:24:28

首先感谢几位的文章分享
https://blog.csdn.net/guairena/article/details/127941515
https://blog.csdn.net/qq_37970097/article/details/119148707

效果图:
签名截图请添加图片描述
使用的是 芝柯cc3 蓝牙打印机,
我这里没有存储蓝牙设备相关信息。所以每次打印都会重新初始化并搜索设备,储存相关的代码下面也有,所以代码部分有些冗余代码,可根据自己需求保留或删除

template:

<uni-popup ref="popupPrint" background-color="rgba(0,0,0,0)" type="bottom" :safe-area="false" @change="PrintPoupChange">
	<view class="radius">
		<view v-if="tempDeviceList.length" class="popup_title">请选择打印设备</view>
		<view class="reSignBtn" @click="gotoSignClick">重新签名</view>
		<scroll-view scroll-y="true" style="height: 40vh;">
			<view v-for="(item, index) in tempDeviceList" :key="index">
				<view class="hospitalNameBtn" @click="select_deviceId(item)">{{ item.name }}</view>
			</view>
			<view v-if="!tempDeviceList.length" class="searchBlue">
				<image style="width: 400rpx;height: 400rpx;margin: auto;" :src="imageUrl + 'loading.gif'" mode="widthFix"></image>
			</view>
			<view class="bottomSafe"></view>
		</scroll-view>
	</view>
</uni-popup>

使用到的相关sdk
printerjobs.js:

const pako = require('pako');
/*
 * @Author: zgt / ghd 
 * @FirstEditors: zgt
 * @FirstEditTime: 2019-10-18 18:49:24
 * @LastEditors:ghd
 * @LastEditTime:2020-03-17 16:09:59
 * @Description: file content
 */
//import { wxAsyncPromise } from './index';
/**
 *
 *
 * @export
 * @param {string} name 微信api的名称 ,如 wxAsyncPromise("getSystemInfo",options)
 * @param {object} options 除了success 和 fail 的其他参数
 * @returns
 */
export function wxAsyncPromise(name, options) {
	return new Promise((resolve, reject) => {
		wx[name]({
			//...(options || {}),
			...options,
			success: function(res) {
				resolve(res);
			},
			fail: function(res) {
				reject(res);
			},
		});
	});
}
//微信小程序向蓝牙打印机发送数据进行打印的坑:
//小程序api向蓝牙打印机发送数据打印,发送的任何内容都应该要转成二进制数据,而且蓝牙打印的文本编码是GBK的,发送中文需转成GBK编码再转成二进制数据发送
//发送打印机指令也要转成二进制数据发送
//蓝牙打印机一次接收的二级制数据有限制,不同的系统不同的蓝牙设备限制可能不同,微信建议一次20个字节,需做递归分包发送
//发送完要打印的内容后,一定要发送一个打印的指令才能顺利打印 (有些指令就不需要)

//一、初始化蓝牙、开始检索蓝牙设备
// { allowDuplicatesKey: true, interval: 500}
export function openBlue() {
	return wxAsyncPromise('openBluetoothAdapter').then((res) => {
		console.log('初始化蓝牙成功', res);
	});
}

export function startBluetoothDevicesDiscovery(option) {
	console.log('开始蓝牙扫描');
	wxAsyncPromise('startBluetoothDevicesDiscovery', option).then((res) => {
		console.log('正在搜寻蓝牙设备', res);
	});
}
//二、
/**
 *
 *
 * @export
 * @param {function} getDevices wx.getBluetoothDevices的监听回调函数
 */
export function onfindBlueDevices(getDevices) {
	//监听寻找到新设备的事件
	console.log('onfindBlueDevices...');
	wx.onBluetoothDeviceFound(function(devices) {
		//获取在蓝牙模块生效期间所有已发现的蓝牙设备
		wxAsyncPromise('getBluetoothDevices').then((res) => {
			getDevices && getDevices(res.devices);
		});
	});
}

/**
 * @export
 * @param {function} stopBlueDevicesDiscovery 关闭蓝牙扫描
 */
export function stopBlueDevicesDiscovery() {
	//监听寻找到新设备的事件
	console.log('停止蓝牙扫描');
	return wxAsyncPromise('stopBluetoothDevicesDiscovery').then((res) => {
		console.log('停止搜寻蓝牙设备', res);
	});
}



//三、连接蓝牙设备
/**
 * @export
 * @param {function} createBLEConnection 
 * @param {number} deviceId 蓝牙设备id
 */
export function createBLEConnection(deviceId, sucess, fail) {
	//连接蓝牙设备
	console.log('连接蓝牙设备', deviceId);
	wxAsyncPromise("createBLEConnection", {
			deviceId
		})
		.then(res => {
			//连接成功可选择停止搜索蓝牙
			//stopBlueDevicesDiscovery();
			console.log('连接成功');
			sucess && sucess({
				res: res,
			});
		})
		.catch(res => {
			console.log('连接设备异常' + res);
			fail && fail({
				res: res,
			});
		})
	/*.finally(res=>{
	    console.log('连接成功');
	    sucess && sucess({
	        res: res,
	    });
	});*/
}

export function closeBLEConnection(deviceId) {
	console.log('断开蓝牙设备', deviceId);
	wxAsyncPromise("closeBLEConnection", {
			deviceId
		})
		.then(res => {
			console.log('BLEDisconnect complete', res);
		})
		.catch(res => {
			console.log('断开设备异常' + res);
		})
	/*.finally(res=>{
	    console.log('BLEDisconnect complete', res);            
	});  */
}

//四、连接成功后, 获取蓝牙设备的service服务
// wxAsyncPromise("getBLEDeviceServices",{deviceId:""}).then(res=>{})
export function getBLEDeviceServices(deviceId, success, fail) {
	console.log('获取ServiceId', deviceId);
	wxAsyncPromise("getBLEDeviceServices", {
			deviceId
		})
		.then(res => {
			console.log('服务', res.services);
			success && success({
				serviceId: res.services,
			});
		})
		.catch((res) => {
			//getBLEDeviceServices(deviceId, success, fail);
			console.log('获取ServiceId异常' + res);
			fail && fail({
				res: res,
			});
		});
}

//五、获取的service服务可能有多个,递归获取特征值(最后要用的是能读,能写,能监听的那个值的uuid作为特征值id)
/**
 *
 *
 * @export
 * @param {number} deviceId 蓝牙设备id
 * @param {array} services wxAsyncPromise("getBLEDeviceServices",{deviceId:""}).then(res=>{})获取的res.services
 * @param {function} success 成功取得有用特征值uuid的回调函数
 */
export function getDeviceCharacteristics(deviceId, services, success, fail) {
	//services = services.slice(0);
	console.log('获取Characteristics', deviceId, services);
	if (services.length) {
		const serviceId = services.shift().uuid;
		console.log('ServceID ', serviceId);
		wxAsyncPromise('getBLEDeviceCharacteristics', {
				deviceId,
				serviceId,
			})
			.then((res) => {
				console.log('getBLEDeviceCharacteristics', deviceId, serviceId, res);
				let finished = false;
				let write = false;
				let notify = false;
				let indicate = false;
				var readId;
				var writeId;
				//有斑马品牌的一款打印机中res.characteristics的所有uuid都是相同的,找所有的properties存在(notify || indicate) && write这种情况就说明这个uuid是可用的(不确保所有的打印机都能用这种方式取得uuid,在主要测试得凯盛诺打印机res.characteristic只有一个uuid,所以也能用这个方式)
				for (var i = 0; i < res.characteristics.length; i++) {
					if (!notify) {
						notify = res.characteristics[i].properties.notify;
						if (notify) readId = res.characteristics[i].uuid;
					}
					if (!indicate) {
						indicate = res.characteristics[i].properties.indicate;
						if (indicate) readId = res.characteristics[i].uuid;
					}
					if (!write) {
						write = res.characteristics[i].properties.write;
						writeId = res.characteristics[i].uuid;
					}
					if ((notify || indicate) && write) {
						/* 获取蓝牙特征值uuid */
						success &&
							success({
								serviceId,
								writeId: writeId,
								readId: readId,
							});
						finished = true;
						break;
					}
				}

				if (!finished) {
					getDeviceCharacteristics(deviceId, services, success, fail);
				}
			})
			.catch((res) => {
				getDeviceCharacteristics(deviceId, services, success, fail);
			});
	} else {
		fail && fail();
	}
}

//六、启动notify 蓝牙监听功能 然后使用 wx.onBLECharacteristicValueChange用来监听蓝牙设备传递数据
/**
 *
 *
 * @export
 * @param {object} options
 * {
            deviceId,//蓝牙设备id
            serviceId,//服务id
            characteristicId,//可用特征值uuid
    }
 * @param {function} onChange 监听蓝牙设备传递数据回调函数
 */
export function onGetBLECharacteristicValueChange(options, onChange = function() {}) {
	console.log('deviceId ', options.deviceId);
	console.log('serviceId ', options.serviceId);
	console.log('characteristicId ', options.characteristicId);
	wxAsyncPromise('notifyBLECharacteristicValueChange', {
		state: true,
		...options,
	}).then((res) => {
		console.log('onBLECharacteristicValueChange ');
		wx.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; 
	//console.log("send data 20");
	//console.log(options);
	if (byteLength > 0) {
		wxAsyncPromise('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) => {
				console.log(res);
			});
	}
}
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: parseInt(sendWidth / 8),
		height: parseInt(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));
	//console.log(writeArray);
	const print = (options, writeArray) => {
		if (writeArray.length) {
			console.log("send");
			sendDataToDevice({
				...options,
				value: writeArray.shift().buffer,
				lasterSuccess: () => {
					if (writeArray.length) {
						print(options, writeArray);
					} else {
						options.lasterSuccess && options.lasterSuccess();
					}
				},
			});
		}
	};
	console.log("start print");
	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度 其他-不旋转
 */
export function CreatCPCLPage(width, height, printNum, rotation = 0, offset = 0) {
	var strCmd = '! ' + offset + ' 200 200 ' + height + ' ' + printNum + '\n';
	strCmd += "PAGE-WIDTH " + width + '\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) {
	//console.log(fontName,fontSize,rotation, 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
 * fontName,fontSize: 字体,取值: 參考文檔
 * height: 一行高度
 * content: 文字内容,注意换行需要\r\n,单\n不行
 */
export function addCPCLMLText(x, y, fontName, fontSize, height, content) {
	//console.log(fontName,fontSize,rotation, content);   
	var strCmd = 'ML ' + height + '\n';
	strCmd += 'TEXT ' + fontName + ' ' + fontSize + ' ' + x + ' ' + y + '\n' + content + 'ENDML\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) {
	//console.log(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;
	let myBitmapWidth = data.width,
		myBitmapHeight = data.height;
	// let len = parseInt((myBitmapWidth + 7) / 8); //一行的数据长度
	//console.log('len=',len);
	//console.log('myBitmapWidth=',myBitmapWidth);
	//console.log('myBitmapHeight=',myBitmapHeight);
	// let ndata = 0;
	// let i = 0;
	// let j = 0;
	// let sendImageData = new ArrayBuffer(len * myBitmapHeight);
	let sendImageData = data.imageData;
	// sendImageData = new Uint8Array(sendImageData);
	// let pix = data.imageData;
	// console.log('pix=', pix);

	// for (i = 0; i < myBitmapHeight; i++) {
	// 	for (j = 0; j < len; j++) {
	// 		sendImageData[ndata + j] = 0;
	// 	}
	// 	for (j = 0; j < myBitmapWidth; j++) {
	// 		const grayPixle1 = grayPixle(pix.slice((i * myBitmapWidth + j) * 4, (i * myBitmapWidth + j) * 4 + 3));
	// 		if (grayPixle1 > threshold ){
	// 			sendImageData[ndata + parseInt(j / 8)] |= (0x80 >> (j % 8));
	// 		}

	// 	}
	// 	ndata += len;
	// }

	// console.log('sendImageData=',sendImageData);
	//CPCL指令图片数据 
	strImgCmd += 'EG ' + myBitmapWidth + ' ' + myBitmapHeight + ' ' + x + ' ' + y + ' ';
	for (let i = 0; i < sendImageData.length; i++) {
		strImgCmd += Hex2Str(sendImageData[i]);
	}
	strImgCmd += '\n';
	// console.log(strImgCmd);
	return strImgCmd;
}

function crc32fun(buf, offset, len) {
	const crcTable = new Uint32Array([
		0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
		0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
		0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
		0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
		0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
		0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
		0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
		0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
		0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
		0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
		0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB,
		0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
		0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA,
		0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE,
		0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
		0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
		0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409,
		0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
		0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739,
		0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
		0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268,
		0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0,
		0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8,
		0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
		0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
		0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703,
		0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7,
		0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
		0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE,
		0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
		0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6,
		0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
		0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D,
		0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,
		0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
		0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
		0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
	]);

	let crc = -1;
	for (let i = offset; i < len + offset; i++) {
		crc = (crc >>> 8) ^ crcTable[(crc ^ buf[i]) & 0xFF];
	}
	return (crc ^ (-1));
};

export function myGzip(bytes) {
	var gzipData = pako.gzip(new Uint8Array(bytes));
	gzipData[8] = 0x04;
	gzipData[9] = 0x00;
	var crc = crc32fun(gzipData, 8, gzipData.byteLength - 8 - 4)
	gzipData[4] = ((gzipData.byteLength >> 0) & 0xFF);
	gzipData[5] = ((gzipData.byteLength >> 8) & 0xFF);
	gzipData[6] = ((gzipData.byteLength >> 16) & 0xFF);
	gzipData[7] = ((gzipData.byteLength >> 24) & 0xFF);
	gzipData[gzipData.byteLength - 4] = ((crc >> 0) & 0xFF);
	gzipData[gzipData.byteLength - 3] = ((crc >> 8) & 0xFF);
	gzipData[gzipData.byteLength - 2] = ((crc >> 16) & 0xFF);
	gzipData[gzipData.byteLength - 1] = ((crc >> 24) & 0xFF);
	let bufferGzip = new ArrayBuffer(gzipData.length);
	let dv = new DataView(bufferGzip);
	for (var i = 0; i < bufferGzip.byteLength; i++) {
		dv.setUint8(i, gzipData[i]);
	}
	//console.log(bufferGzip);
	return bufferGzip;
}

gbk.js

module.exports = {
  parseHex: parseHex,//提取十六进制
  stringTrim: stringTrim,//剔除空格回车
  strToGBKHex, strToGBKHex,//字符串转GBK十六进制内码
  asiiStrToHex, asiiStrToHex, //asii码字符串转十六进制字符串  用于图片打印
  stringToByte, stringToByte,
  toUTF8Array, toUTF8Array,
  // test, test,
  strToGBKByte,strToGBKByte,
  utf8ByteToUnicodeStr, utf8ByteToUnicodeStr,
  stringToArrayBuffer,arrayBufferToString,
  // formatUnixtimestamp, formatUnixtimestamp
}

var GBfh = " 、。·ˉˇ¨〃々—~‖…‘’“”〔〕〈〉《》「」『』〖〗【】±×÷∶∧∨∑∏∪∩∈∷√⊥∥∠⌒⊙∫∮≡≌≈∽∝≠≮≯≤≥∞∵∴♂♀°′″℃$¤¢£‰§№☆★○●◎◇◆□■△▲※→←↑↓〓ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹ⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇①②③④⑤⑥⑦⑧⑨⑩㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ!"#¥%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|} ̄ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψω︵︶︹︺︿﹀︽︾﹁﹂﹃﹄︻︼︷︸︱︳︴АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюяāáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜüêɑńňɡㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩ─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋";
var GBhz = "啊阿埃挨哎唉哀皑癌蔼矮艾碍爱隘鞍氨安俺按暗岸胺案肮昂盎凹敖熬翱袄傲奥懊澳芭捌扒叭吧笆八疤巴拔跋靶把耙坝霸罢爸白柏百摆佰败拜稗斑班搬扳般颁板版扮拌伴瓣半办绊邦帮梆榜膀绑棒磅蚌镑傍谤苞胞包褒剥薄雹保堡饱宝抱报暴豹鲍爆杯碑悲卑北辈背贝钡倍狈备惫焙被奔苯本笨崩绷甭泵蹦迸逼鼻比鄙笔彼碧蓖蔽毕毙毖币庇痹闭敝弊必辟壁臂避陛鞭边编贬扁便变卞辨辩辫遍标彪膘表鳖憋别瘪彬斌濒滨宾摈兵冰柄丙秉饼炳病并玻菠播拨钵波博勃搏铂箔伯帛舶脖膊渤泊驳捕卜哺补埠不布步簿部怖擦猜裁材才财睬踩采彩菜蔡餐参蚕残惭惨灿苍舱仓沧藏操糙槽曹草厕策侧册测层蹭插叉茬茶查碴搽察岔差诧拆柴豺搀掺蝉馋谗缠铲产阐颤昌猖场尝常长偿肠厂敞畅唱倡超抄钞朝嘲潮巢吵炒车扯撤掣彻澈郴臣辰尘晨忱沉陈趁衬撑称城橙成呈乘程惩澄诚承逞骋秤吃痴持匙池迟弛驰耻齿侈尺赤翅斥炽充冲虫崇宠抽酬畴踌稠愁筹仇绸瞅丑臭初出橱厨躇锄雏滁除楚础储矗搐触处揣川穿椽传船喘串疮窗幢床闯创吹炊捶锤垂春椿醇唇淳纯蠢戳绰疵茨磁雌辞慈瓷词此刺赐次聪葱囱匆从丛凑粗醋簇促蹿篡窜摧崔催脆瘁粹淬翠村存寸磋撮搓措挫错搭达答瘩打大呆歹傣戴带殆代贷袋待逮怠耽担丹单郸掸胆旦氮但惮淡诞弹蛋当挡党荡档刀捣蹈倒岛祷导到稻悼道盗德得的蹬灯登等瞪凳邓堤低滴迪敌笛狄涤翟嫡抵底地蒂第帝弟递缔颠掂滇碘点典靛垫电佃甸店惦奠淀殿碉叼雕凋刁掉吊钓调跌爹碟蝶迭谍叠丁盯叮钉顶鼎锭定订丢东冬董懂动栋侗恫冻洞兜抖斗陡豆逗痘都督毒犊独读堵睹赌杜镀肚度渡妒端短锻段断缎堆兑队对墩吨蹲敦顿囤钝盾遁掇哆多夺垛躲朵跺舵剁惰堕蛾峨鹅俄额讹娥恶厄扼遏鄂饿恩而儿耳尔饵洱二贰发罚筏伐乏阀法珐藩帆番翻樊矾钒繁凡烦反返范贩犯饭泛坊芳方肪房防妨仿访纺放菲非啡飞肥匪诽吠肺废沸费芬酚吩氛分纷坟焚汾粉奋份忿愤粪丰封枫蜂峰锋风疯烽逢冯缝讽奉凤佛否夫敷肤孵扶拂辐幅氟符伏俘服浮涪福袱弗甫抚辅俯釜斧脯腑府腐赴副覆赋复傅付阜父腹负富讣附妇缚咐噶嘎该改概钙盖溉干甘杆柑竿肝赶感秆敢赣冈刚钢缸肛纲岗港杠篙皋高膏羔糕搞镐稿告哥歌搁戈鸽胳疙割革葛格蛤阁隔铬个各给根跟耕更庚羹埂耿梗工攻功恭龚供躬公宫弓巩汞拱贡共钩勾沟苟狗垢构购够辜菇咕箍估沽孤姑鼓古蛊骨谷股故顾固雇刮瓜剐寡挂褂乖拐怪棺关官冠观管馆罐惯灌贯光广逛瑰规圭硅归龟闺轨鬼诡癸桂柜跪贵刽辊滚棍锅郭国果裹过哈骸孩海氦亥害骇酣憨邯韩含涵寒函喊罕翰撼捍旱憾悍焊汗汉夯杭航壕嚎豪毫郝好耗号浩呵喝荷菏核禾和何合盒貉阂河涸赫褐鹤贺嘿黑痕很狠恨哼亨横衡恒轰哄烘虹鸿洪宏弘红喉侯猴吼厚候后呼乎忽瑚壶葫胡蝴狐糊湖弧虎唬护互沪户花哗华猾滑画划化话槐徊怀淮坏欢环桓还缓换患唤痪豢焕涣宦幻荒慌黄磺蝗簧皇凰惶煌晃幌恍谎灰挥辉徽恢蛔回毁悔慧卉惠晦贿秽会烩汇讳诲绘荤昏婚魂浑混豁活伙火获或惑霍货祸击圾基机畸稽积箕肌饥迹激讥鸡姬绩缉吉极棘辑籍集及急疾汲即嫉级挤几脊己蓟技冀季伎祭剂悸济寄寂计记既忌际妓继纪嘉枷夹佳家加荚颊贾甲钾假稼价架驾嫁歼监坚尖笺间煎兼肩艰奸缄茧检柬碱硷拣捡简俭剪减荐槛鉴践贱见键箭件健舰剑饯渐溅涧建僵姜将浆江疆蒋桨奖讲匠酱降蕉椒礁焦胶交郊浇骄娇嚼搅铰矫侥脚狡角饺缴绞剿教酵轿较叫窖揭接皆秸街阶截劫节桔杰捷睫竭洁结解姐戒藉芥界借介疥诫届巾筋斤金今津襟紧锦仅谨进靳晋禁近烬浸尽劲荆兢茎睛晶鲸京惊精粳经井警景颈静境敬镜径痉靖竟竞净炯窘揪究纠玖韭久灸九酒厩救旧臼舅咎就疚鞠拘狙疽居驹菊局咀矩举沮聚拒据巨具距踞锯俱句惧炬剧捐鹃娟倦眷卷绢撅攫抉掘倔爵觉决诀绝均菌钧军君峻俊竣浚郡骏喀咖卡咯开揩楷凯慨刊堪勘坎砍看康慷糠扛抗亢炕考拷烤靠坷苛柯棵磕颗科壳咳可渴克刻客课肯啃垦恳坑吭空恐孔控抠口扣寇枯哭窟苦酷库裤夸垮挎跨胯块筷侩快宽款匡筐狂框矿眶旷况亏盔岿窥葵奎魁傀馈愧溃坤昆捆困括扩廓阔垃拉喇蜡腊辣啦莱来赖蓝婪栏拦篮阑兰澜谰揽览懒缆烂滥琅榔狼廊郎朗浪捞劳牢老佬姥酪烙涝勒乐雷镭蕾磊累儡垒擂肋类泪棱楞冷厘梨犁黎篱狸离漓理李里鲤礼莉荔吏栗丽厉励砾历利傈例俐痢立粒沥隶力璃哩俩联莲连镰廉怜涟帘敛脸链恋炼练粮凉梁粱良两辆量晾亮谅撩聊僚疗燎寥辽潦了撂镣廖料列裂烈劣猎琳林磷霖临邻鳞淋凛赁吝拎玲菱零龄铃伶羚凌灵陵岭领另令溜琉榴硫馏留刘瘤流柳六龙聋咙笼窿隆垄拢陇楼娄搂篓漏陋芦卢颅庐炉掳卤虏鲁麓碌露路赂鹿潞禄录陆戮驴吕铝侣旅履屡缕虑氯律率滤绿峦挛孪滦卵乱掠略抡轮伦仑沦纶论萝螺罗逻锣箩骡裸落洛骆络妈麻玛码蚂马骂嘛吗埋买麦卖迈脉瞒馒蛮满蔓曼慢漫谩芒茫盲氓忙莽猫茅锚毛矛铆卯茂冒帽貌贸么玫枚梅酶霉煤没眉媒镁每美昧寐妹媚门闷们萌蒙檬盟锰猛梦孟眯醚靡糜迷谜弥米秘觅泌蜜密幂棉眠绵冕免勉娩缅面苗描瞄藐秒渺庙妙蔑灭民抿皿敏悯闽明螟鸣铭名命谬摸摹蘑模膜磨摩魔抹末莫墨默沫漠寞陌谋牟某拇牡亩姆母墓暮幕募慕木目睦牧穆拿哪呐钠那娜纳氖乃奶耐奈南男难囊挠脑恼闹淖呢馁内嫩能妮霓倪泥尼拟你匿腻逆溺蔫拈年碾撵捻念娘酿鸟尿捏聂孽啮镊镍涅您柠狞凝宁拧泞牛扭钮纽脓浓农弄奴努怒女暖虐疟挪懦糯诺哦欧鸥殴藕呕偶沤啪趴爬帕怕琶拍排牌徘湃派攀潘盘磐盼畔判叛乓庞旁耪胖抛咆刨炮袍跑泡呸胚培裴赔陪配佩沛喷盆砰抨烹澎彭蓬棚硼篷膨朋鹏捧碰坯砒霹批披劈琵毗啤脾疲皮匹痞僻屁譬篇偏片骗飘漂瓢票撇瞥拼频贫品聘乒坪苹萍平凭瓶评屏坡泼颇婆破魄迫粕剖扑铺仆莆葡菩蒲埔朴圃普浦谱曝瀑期欺栖戚妻七凄漆柒沏其棋奇歧畦崎脐齐旗祈祁骑起岂乞企启契砌器气迄弃汽泣讫掐恰洽牵扦钎铅千迁签仟谦乾黔钱钳前潜遣浅谴堑嵌欠歉枪呛腔羌墙蔷强抢橇锹敲悄桥瞧乔侨巧鞘撬翘峭俏窍切茄且怯窃钦侵亲秦琴勤芹擒禽寝沁青轻氢倾卿清擎晴氰情顷请庆琼穷秋丘邱球求囚酋泅趋区蛆曲躯屈驱渠取娶龋趣去圈颧权醛泉全痊拳犬券劝缺炔瘸却鹊榷确雀裙群然燃冉染瓤壤攘嚷让饶扰绕惹热壬仁人忍韧任认刃妊纫扔仍日戎茸蓉荣融熔溶容绒冗揉柔肉茹蠕儒孺如辱乳汝入褥软阮蕊瑞锐闰润若弱撒洒萨腮鳃塞赛三叁伞散桑嗓丧搔骚扫嫂瑟色涩森僧莎砂杀刹沙纱傻啥煞筛晒珊苫杉山删煽衫闪陕擅赡膳善汕扇缮墒伤商赏晌上尚裳梢捎稍烧芍勺韶少哨邵绍奢赊蛇舌舍赦摄射慑涉社设砷申呻伸身深娠绅神沈审婶甚肾慎渗声生甥牲升绳省盛剩胜圣师失狮施湿诗尸虱十石拾时什食蚀实识史矢使屎驶始式示士世柿事拭誓逝势是嗜噬适仕侍释饰氏市恃室视试收手首守寿授售受瘦兽蔬枢梳殊抒输叔舒淑疏书赎孰熟薯暑曙署蜀黍鼠属术述树束戍竖墅庶数漱恕刷耍摔衰甩帅栓拴霜双爽谁水睡税吮瞬顺舜说硕朔烁斯撕嘶思私司丝死肆寺嗣四伺似饲巳松耸怂颂送宋讼诵搜艘擞嗽苏酥俗素速粟僳塑溯宿诉肃酸蒜算虽隋随绥髓碎岁穗遂隧祟孙损笋蓑梭唆缩琐索锁所塌他它她塔獭挞蹋踏胎苔抬台泰酞太态汰坍摊贪瘫滩坛檀痰潭谭谈坦毯袒碳探叹炭汤塘搪堂棠膛唐糖倘躺淌趟烫掏涛滔绦萄桃逃淘陶讨套特藤腾疼誊梯剔踢锑提题蹄啼体替嚏惕涕剃屉天添填田甜恬舔腆挑条迢眺跳贴铁帖厅听烃汀廷停亭庭挺艇通桐酮瞳同铜彤童桶捅筒统痛偷投头透凸秃突图徒途涂屠土吐兔湍团推颓腿蜕褪退吞屯臀拖托脱鸵陀驮驼椭妥拓唾挖哇蛙洼娃瓦袜歪外豌弯湾玩顽丸烷完碗挽晚皖惋宛婉万腕汪王亡枉网往旺望忘妄威巍微危韦违桅围唯惟为潍维苇萎委伟伪尾纬未蔚味畏胃喂魏位渭谓尉慰卫瘟温蚊文闻纹吻稳紊问嗡翁瓮挝蜗涡窝我斡卧握沃巫呜钨乌污诬屋无芜梧吾吴毋武五捂午舞伍侮坞戊雾晤物勿务悟误昔熙析西硒矽晰嘻吸锡牺稀息希悉膝夕惜熄烯溪汐犀檄袭席习媳喜铣洗系隙戏细瞎虾匣霞辖暇峡侠狭下厦夏吓掀锨先仙鲜纤咸贤衔舷闲涎弦嫌显险现献县腺馅羡宪陷限线相厢镶香箱襄湘乡翔祥详想响享项巷橡像向象萧硝霄削哮嚣销消宵淆晓小孝校肖啸笑效楔些歇蝎鞋协挟携邪斜胁谐写械卸蟹懈泄泻谢屑薪芯锌欣辛新忻心信衅星腥猩惺兴刑型形邢行醒幸杏性姓兄凶胸匈汹雄熊休修羞朽嗅锈秀袖绣墟戌需虚嘘须徐许蓄酗叙旭序畜恤絮婿绪续轩喧宣悬旋玄选癣眩绚靴薛学穴雪血勋熏循旬询寻驯巡殉汛训讯逊迅压押鸦鸭呀丫芽牙蚜崖衙涯雅哑亚讶焉咽阉烟淹盐严研蜒岩延言颜阎炎沿奄掩眼衍演艳堰燕厌砚雁唁彦焰宴谚验殃央鸯秧杨扬佯疡羊洋阳氧仰痒养样漾邀腰妖瑶摇尧遥窑谣姚咬舀药要耀椰噎耶爷野冶也页掖业叶曳腋夜液一壹医揖铱依伊衣颐夷遗移仪胰疑沂宜姨彝椅蚁倚已乙矣以艺抑易邑屹亿役臆逸肄疫亦裔意毅忆义益溢诣议谊译异翼翌绎茵荫因殷音阴姻吟银淫寅饮尹引隐印英樱婴鹰应缨莹萤营荧蝇迎赢盈影颖硬映哟拥佣臃痈庸雍踊蛹咏泳涌永恿勇用幽优悠忧尤由邮铀犹油游酉有友右佑釉诱又幼迂淤于盂榆虞愚舆余俞逾鱼愉渝渔隅予娱雨与屿禹宇语羽玉域芋郁吁遇喻峪御愈欲狱育誉浴寓裕预豫驭鸳渊冤元垣袁原援辕园员圆猿源缘远苑愿怨院曰约越跃钥岳粤月悦阅耘云郧匀陨允运蕴酝晕韵孕匝砸杂栽哉灾宰载再在咱攒暂赞赃脏葬遭糟凿藻枣早澡蚤躁噪造皂灶燥责择则泽贼怎增憎曾赠扎喳渣札轧铡闸眨栅榨咋乍炸诈摘斋宅窄债寨瞻毡詹粘沾盏斩辗崭展蘸栈占战站湛绽樟章彰漳张掌涨杖丈帐账仗胀瘴障招昭找沼赵照罩兆肇召遮折哲蛰辙者锗蔗这浙珍斟真甄砧臻贞针侦枕疹诊震振镇阵蒸挣睁征狰争怔整拯正政帧症郑证芝枝支吱蜘知肢脂汁之织职直植殖执值侄址指止趾只旨纸志挚掷至致置帜峙制智秩稚质炙痔滞治窒中盅忠钟衷终种肿重仲众舟周州洲诌粥轴肘帚咒皱宙昼骤珠株蛛朱猪诸诛逐竹烛煮拄瞩嘱主著柱助蛀贮铸筑住注祝驻抓爪拽专砖转撰赚篆桩庄装妆撞壮状椎锥追赘坠缀谆准捉拙卓桌琢茁酌啄着灼浊兹咨资姿滋淄孜紫仔籽滓子自渍字鬃棕踪宗综总纵邹走奏揍租足卒族祖诅阻组钻纂嘴醉最罪尊遵昨左佐柞做作坐座亍丌兀丐廿卅丕亘丞鬲孬噩丨禺丿匕乇夭爻卮氐囟胤馗毓睾鼗丶亟鼐乜乩亓芈孛啬嘏仄厍厝厣厥厮靥赝匚叵匦匮匾赜卦卣刂刈刎刭刳刿剀剌剞剡剜蒯剽劂劁劐劓冂罔亻仃仉仂仨仡仫仞伛仳伢佤仵伥伧伉伫佞佧攸佚佝佟佗伲伽佶佴侑侉侃侏佾佻侪佼侬侔俦俨俪俅俚俣俜俑俟俸倩偌俳倬倏倮倭俾倜倌倥倨偾偃偕偈偎偬偻傥傧傩傺僖儆僭僬僦僮儇儋仝氽佘佥俎龠汆籴兮巽黉馘冁夔勹匍訇匐凫夙兕亠兖亳衮袤亵脔裒禀嬴蠃羸冫冱冽冼凇冖冢冥讠讦讧讪讴讵讷诂诃诋诏诎诒诓诔诖诘诙诜诟诠诤诨诩诮诰诳诶诹诼诿谀谂谄谇谌谏谑谒谔谕谖谙谛谘谝谟谠谡谥谧谪谫谮谯谲谳谵谶卩卺阝阢阡阱阪阽阼陂陉陔陟陧陬陲陴隈隍隗隰邗邛邝邙邬邡邴邳邶邺邸邰郏郅邾郐郄郇郓郦郢郜郗郛郫郯郾鄄鄢鄞鄣鄱鄯鄹酃酆刍奂劢劬劭劾哿勐勖勰叟燮矍廴凵凼鬯厶弁畚巯坌垩垡塾墼壅壑圩圬圪圳圹圮圯坜圻坂坩垅坫垆坼坻坨坭坶坳垭垤垌垲埏垧垴垓垠埕埘埚埙埒垸埴埯埸埤埝堋堍埽埭堀堞堙塄堠塥塬墁墉墚墀馨鼙懿艹艽艿芏芊芨芄芎芑芗芙芫芸芾芰苈苊苣芘芷芮苋苌苁芩芴芡芪芟苄苎芤苡茉苷苤茏茇苜苴苒苘茌苻苓茑茚茆茔茕苠苕茜荑荛荜茈莒茼茴茱莛荞茯荏荇荃荟荀茗荠茭茺茳荦荥荨茛荩荬荪荭荮莰荸莳莴莠莪莓莜莅荼莶莩荽莸荻莘莞莨莺莼菁萁菥菘堇萘萋菝菽菖萜萸萑萆菔菟萏萃菸菹菪菅菀萦菰菡葜葑葚葙葳蒇蒈葺蒉葸萼葆葩葶蒌蒎萱葭蓁蓍蓐蓦蒽蓓蓊蒿蒺蓠蒡蒹蒴蒗蓥蓣蔌甍蔸蓰蔹蔟蔺蕖蔻蓿蓼蕙蕈蕨蕤蕞蕺瞢蕃蕲蕻薤薨薇薏蕹薮薜薅薹薷薰藓藁藜藿蘧蘅蘩蘖蘼廾弈夼奁耷奕奚奘匏尢尥尬尴扌扪抟抻拊拚拗拮挢拶挹捋捃掭揶捱捺掎掴捭掬掊捩掮掼揲揸揠揿揄揞揎摒揆掾摅摁搋搛搠搌搦搡摞撄摭撖摺撷撸撙撺擀擐擗擤擢攉攥攮弋忒甙弑卟叱叽叩叨叻吒吖吆呋呒呓呔呖呃吡呗呙吣吲咂咔呷呱呤咚咛咄呶呦咝哐咭哂咴哒咧咦哓哔呲咣哕咻咿哌哙哚哜咩咪咤哝哏哞唛哧唠哽唔哳唢唣唏唑唧唪啧喏喵啉啭啁啕唿啐唼唷啖啵啶啷唳唰啜喋嗒喃喱喹喈喁喟啾嗖喑啻嗟喽喾喔喙嗪嗷嗉嘟嗑嗫嗬嗔嗦嗝嗄嗯嗥嗲嗳嗌嗍嗨嗵嗤辔嘞嘈嘌嘁嘤嘣嗾嘀嘧嘭噘嘹噗嘬噍噢噙噜噌噔嚆噤噱噫噻噼嚅嚓嚯囔囗囝囡囵囫囹囿圄圊圉圜帏帙帔帑帱帻帼帷幄幔幛幞幡岌屺岍岐岖岈岘岙岑岚岜岵岢岽岬岫岱岣峁岷峄峒峤峋峥崂崃崧崦崮崤崞崆崛嵘崾崴崽嵬嵛嵯嵝嵫嵋嵊嵩嵴嶂嶙嶝豳嶷巅彳彷徂徇徉後徕徙徜徨徭徵徼衢彡犭犰犴犷犸狃狁狎狍狒狨狯狩狲狴狷猁狳猃狺狻猗猓猡猊猞猝猕猢猹猥猬猸猱獐獍獗獠獬獯獾舛夥飧夤夂饣饧饨饩饪饫饬饴饷饽馀馄馇馊馍馐馑馓馔馕庀庑庋庖庥庠庹庵庾庳赓廒廑廛廨廪膺忄忉忖忏怃忮怄忡忤忾怅怆忪忭忸怙怵怦怛怏怍怩怫怊怿怡恸恹恻恺恂恪恽悖悚悭悝悃悒悌悛惬悻悱惝惘惆惚悴愠愦愕愣惴愀愎愫慊慵憬憔憧憷懔懵忝隳闩闫闱闳闵闶闼闾阃阄阆阈阊阋阌阍阏阒阕阖阗阙阚丬爿戕氵汔汜汊沣沅沐沔沌汨汩汴汶沆沩泐泔沭泷泸泱泗沲泠泖泺泫泮沱泓泯泾洹洧洌浃浈洇洄洙洎洫浍洮洵洚浏浒浔洳涑浯涞涠浞涓涔浜浠浼浣渚淇淅淞渎涿淠渑淦淝淙渖涫渌涮渫湮湎湫溲湟溆湓湔渲渥湄滟溱溘滠漭滢溥溧溽溻溷滗溴滏溏滂溟潢潆潇漤漕滹漯漶潋潴漪漉漩澉澍澌潸潲潼潺濑濉澧澹澶濂濡濮濞濠濯瀚瀣瀛瀹瀵灏灞宀宄宕宓宥宸甯骞搴寤寮褰寰蹇謇辶迓迕迥迮迤迩迦迳迨逅逄逋逦逑逍逖逡逵逶逭逯遄遑遒遐遨遘遢遛暹遴遽邂邈邃邋彐彗彖彘尻咫屐屙孱屣屦羼弪弩弭艴弼鬻屮妁妃妍妩妪妣妗姊妫妞妤姒妲妯姗妾娅娆姝娈姣姘姹娌娉娲娴娑娣娓婀婧婊婕娼婢婵胬媪媛婷婺媾嫫媲嫒嫔媸嫠嫣嫱嫖嫦嫘嫜嬉嬗嬖嬲嬷孀尕尜孚孥孳孑孓孢驵驷驸驺驿驽骀骁骅骈骊骐骒骓骖骘骛骜骝骟骠骢骣骥骧纟纡纣纥纨纩纭纰纾绀绁绂绉绋绌绐绔绗绛绠绡绨绫绮绯绱绲缍绶绺绻绾缁缂缃缇缈缋缌缏缑缒缗缙缜缛缟缡缢缣缤缥缦缧缪缫缬缭缯缰缱缲缳缵幺畿巛甾邕玎玑玮玢玟珏珂珑玷玳珀珉珈珥珙顼琊珩珧珞玺珲琏琪瑛琦琥琨琰琮琬琛琚瑁瑜瑗瑕瑙瑷瑭瑾璜璎璀璁璇璋璞璨璩璐璧瓒璺韪韫韬杌杓杞杈杩枥枇杪杳枘枧杵枨枞枭枋杷杼柰栉柘栊柩枰栌柙枵柚枳柝栀柃枸柢栎柁柽栲栳桠桡桎桢桄桤梃栝桕桦桁桧桀栾桊桉栩梵梏桴桷梓桫棂楮棼椟椠棹椤棰椋椁楗棣椐楱椹楠楂楝榄楫榀榘楸椴槌榇榈槎榉楦楣楹榛榧榻榫榭槔榱槁槊槟榕槠榍槿樯槭樗樘橥槲橄樾檠橐橛樵檎橹樽樨橘橼檑檐檩檗檫猷獒殁殂殇殄殒殓殍殚殛殡殪轫轭轱轲轳轵轶轸轷轹轺轼轾辁辂辄辇辋辍辎辏辘辚軎戋戗戛戟戢戡戥戤戬臧瓯瓴瓿甏甑甓攴旮旯旰昊昙杲昃昕昀炅曷昝昴昱昶昵耆晟晔晁晏晖晡晗晷暄暌暧暝暾曛曜曦曩贲贳贶贻贽赀赅赆赈赉赇赍赕赙觇觊觋觌觎觏觐觑牮犟牝牦牯牾牿犄犋犍犏犒挈挲掰搿擘耄毪毳毽毵毹氅氇氆氍氕氘氙氚氡氩氤氪氲攵敕敫牍牒牖爰虢刖肟肜肓肼朊肽肱肫肭肴肷胧胨胩胪胛胂胄胙胍胗朐胝胫胱胴胭脍脎胲胼朕脒豚脶脞脬脘脲腈腌腓腴腙腚腱腠腩腼腽腭腧塍媵膈膂膑滕膣膪臌朦臊膻臁膦欤欷欹歃歆歙飑飒飓飕飙飚殳彀毂觳斐齑斓於旆旄旃旌旎旒旖炀炜炖炝炻烀炷炫炱烨烊焐焓焖焯焱煳煜煨煅煲煊煸煺熘熳熵熨熠燠燔燧燹爝爨灬焘煦熹戾戽扃扈扉礻祀祆祉祛祜祓祚祢祗祠祯祧祺禅禊禚禧禳忑忐怼恝恚恧恁恙恣悫愆愍慝憩憝懋懑戆肀聿沓泶淼矶矸砀砉砗砘砑斫砭砜砝砹砺砻砟砼砥砬砣砩硎硭硖硗砦硐硇硌硪碛碓碚碇碜碡碣碲碹碥磔磙磉磬磲礅磴礓礤礞礴龛黹黻黼盱眄眍盹眇眈眚眢眙眭眦眵眸睐睑睇睃睚睨睢睥睿瞍睽瞀瞌瞑瞟瞠瞰瞵瞽町畀畎畋畈畛畲畹疃罘罡罟詈罨罴罱罹羁罾盍盥蠲钅钆钇钋钊钌钍钏钐钔钗钕钚钛钜钣钤钫钪钭钬钯钰钲钴钶钷钸钹钺钼钽钿铄铈铉铊铋铌铍铎铐铑铒铕铖铗铙铘铛铞铟铠铢铤铥铧铨铪铩铫铮铯铳铴铵铷铹铼铽铿锃锂锆锇锉锊锍锎锏锒锓锔锕锖锘锛锝锞锟锢锪锫锩锬锱锲锴锶锷锸锼锾锿镂锵镄镅镆镉镌镎镏镒镓镔镖镗镘镙镛镞镟镝镡镢镤镥镦镧镨镩镪镫镬镯镱镲镳锺矧矬雉秕秭秣秫稆嵇稃稂稞稔稹稷穑黏馥穰皈皎皓皙皤瓞瓠甬鸠鸢鸨鸩鸪鸫鸬鸲鸱鸶鸸鸷鸹鸺鸾鹁鹂鹄鹆鹇鹈鹉鹋鹌鹎鹑鹕鹗鹚鹛鹜鹞鹣鹦鹧鹨鹩鹪鹫鹬鹱鹭鹳疒疔疖疠疝疬疣疳疴疸痄疱疰痃痂痖痍痣痨痦痤痫痧瘃痱痼痿瘐瘀瘅瘌瘗瘊瘥瘘瘕瘙瘛瘼瘢瘠癀瘭瘰瘿瘵癃瘾瘳癍癞癔癜癖癫癯翊竦穸穹窀窆窈窕窦窠窬窨窭窳衤衩衲衽衿袂袢裆袷袼裉裢裎裣裥裱褚裼裨裾裰褡褙褓褛褊褴褫褶襁襦襻疋胥皲皴矜耒耔耖耜耠耢耥耦耧耩耨耱耋耵聃聆聍聒聩聱覃顸颀颃颉颌颍颏颔颚颛颞颟颡颢颥颦虍虔虬虮虿虺虼虻蚨蚍蚋蚬蚝蚧蚣蚪蚓蚩蚶蛄蚵蛎蚰蚺蚱蚯蛉蛏蚴蛩蛱蛲蛭蛳蛐蜓蛞蛴蛟蛘蛑蜃蜇蛸蜈蜊蜍蜉蜣蜻蜞蜥蜮蜚蜾蝈蜴蜱蜩蜷蜿螂蜢蝽蝾蝻蝠蝰蝌蝮螋蝓蝣蝼蝤蝙蝥螓螯螨蟒蟆螈螅螭螗螃螫蟥螬螵螳蟋蟓螽蟑蟀蟊蟛蟪蟠蟮蠖蠓蟾蠊蠛蠡蠹蠼缶罂罄罅舐竺竽笈笃笄笕笊笫笏筇笸笪笙笮笱笠笥笤笳笾笞筘筚筅筵筌筝筠筮筻筢筲筱箐箦箧箸箬箝箨箅箪箜箢箫箴篑篁篌篝篚篥篦篪簌篾篼簏簖簋簟簪簦簸籁籀臾舁舂舄臬衄舡舢舣舭舯舨舫舸舻舳舴舾艄艉艋艏艚艟艨衾袅袈裘裟襞羝羟羧羯羰羲籼敉粑粝粜粞粢粲粼粽糁糇糌糍糈糅糗糨艮暨羿翎翕翥翡翦翩翮翳糸絷綦綮繇纛麸麴赳趄趔趑趱赧赭豇豉酊酐酎酏酤酢酡酰酩酯酽酾酲酴酹醌醅醐醍醑醢醣醪醭醮醯醵醴醺豕鹾趸跫踅蹙蹩趵趿趼趺跄跖跗跚跞跎跏跛跆跬跷跸跣跹跻跤踉跽踔踝踟踬踮踣踯踺蹀踹踵踽踱蹉蹁蹂蹑蹒蹊蹰蹶蹼蹯蹴躅躏躔躐躜躞豸貂貊貅貘貔斛觖觞觚觜觥觫觯訾謦靓雩雳雯霆霁霈霏霎霪霭霰霾龀龃龅龆龇龈龉龊龌黾鼋鼍隹隼隽雎雒瞿雠銎銮鋈錾鍪鏊鎏鐾鑫鱿鲂鲅鲆鲇鲈稣鲋鲎鲐鲑鲒鲔鲕鲚鲛鲞鲟鲠鲡鲢鲣鲥鲦鲧鲨鲩鲫鲭鲮鲰鲱鲲鲳鲴鲵鲶鲷鲺鲻鲼鲽鳄鳅鳆鳇鳊鳋鳌鳍鳎鳏鳐鳓鳔鳕鳗鳘鳙鳜鳝鳟鳢靼鞅鞑鞒鞔鞯鞫鞣鞲鞴骱骰骷鹘骶骺骼髁髀髅髂髋髌髑魅魃魇魉魈魍魑飨餍餮饕饔髟髡髦髯髫髻髭髹鬈鬏鬓鬟鬣麽麾縻麂麇麈麋麒鏖麝麟黛黜黝黠黟黢黩黧黥黪黯鼢鼬鼯鼹鼷鼽鼾齄";
var GBK_A940 = "〡〢〣〤〥〦〧〨〩㊣㎎㎏㎜㎝㎞㎡"


//提取十六进制
function parseHex(data) {
  var hexRet = {}
  hexRet.data = ""
  hexRet.code = true

  for (var i = 0; i < data.length; i++) {
    try {
      var c = data.substring(i, i + 1);
      if (c == " " || c == "\n" || c == "0") {
        //空格、回车不用屏蔽
        hexRet.data += c;
        continue;
      }
      var n = parseInt("0x" + c);
      if (!n) {
        // isHex = false;
        hexRet.code = false;
        break;
      }
      else {
        hexRet.data += c;
      }
    } catch (e) {
      // isHex = false;
      hexRet.code = false;
      break;
    }
  }
  return hexRet;
}

//剔除空格回车
function stringTrim(data) {
  var resultStr = data.replace(/[ ]/g, "");    //去掉空格
  return resultStr.replace(/[\r\n]/g, "");//去掉回车换行
}

//将非中文字符串转16进制字符串,每个前面加0x,回车加0a0d
function strToHexCharCode(str) {
  if (str === "")
    return "";
  var hexCharCode = [];
  //   hexCharCode.push("0x");
  for (var i = 0; i < str.length; i++) {
    var c = str.substring(i, i + 1);
    if (c == "\n") {
      //换行
      hexCharCode.push("0a".toString(16));
      continue;
    }
    else if (c == "\r") {
      //回车
      hexCharCode.push("0d".toString(16));
      continue;
    }

    hexCharCode.push((str.charCodeAt(i)).toString(16));
  }
  return hexCharCode.join("");
}

//asii码字符串转十六进制字符串  用于图片打印
function asiiStrToHex(str) {
  var hex = "";
  for (var i = 0; i < str.length; i++) {
    var c1 = str.charAt(i)
    var c2 = str.substring(i, i + 1)
    var c3 = str.substring(i, i + 2)
    var c4 = str.substr(i, i + 1)
    var c5 = str.substr(i, i + 2)
    var c = str.charCodeAt(i).toString(16)
    var c6 = str.charCodeAt(i)
    if (c.length == 1) {
      c = "0" + c;
    }
    hex += c;
  }
  return hex;
}
function toUTF8Array(str) {
  var utf8 = [];
  for (var i = 0; i < str.length; i++) {
    var charcode = str.charCodeAt(i);
    if (charcode < 0x80) utf8.push(charcode);
    else if (charcode < 0x800) {
      utf8.push(0xc0 | (charcode >> 6),
        0x80 | (charcode & 0x3f));
    }
    else if (charcode < 0xd800 || charcode >= 0xe000) {
      utf8.push(0xe0 | (charcode >> 12),
        0x80 | ((charcode >> 6) & 0x3f),
        0x80 | (charcode & 0x3f));
    }
    // surrogate pair
    else {
      i++;
      // UTF-16 encodes 0x10000-0x10FFFF by
      // subtracting 0x10000 and splitting the
      // 20 bits of 0x0-0xFFFFF into two halves
      charcode = 0x10000 + (((charcode & 0x3ff) << 10)
        | (str.charCodeAt(i) & 0x3ff));
      utf8.push(0xf0 | (charcode >> 18),
        0x80 | ((charcode >> 12) & 0x3f),
        0x80 | ((charcode >> 6) & 0x3f),
        0x80 | (charcode & 0x3f));
    }
  }
  return utf8;
}

//字符串转GBK十六进制内码
function strToGBKHex(str) {
  var ch, pos, val, ret = "", strSpecial = "!\"#$%&'()*+,/:;<=>?@[\]^`{|}~%";
  console.log('GBK123');
  for (var i = 0; i < str.length; i++) {
    ch = str.charAt(i);
    val = str.charCodeAt(i);
    if (val >= 0x4e00 && val < 0x9FA5){
      if ((pos = GBhz.indexOf(ch)) != -1)
        ret += ("%" + (0xB0 + parseInt(pos / 94)).toString(16) + "%" + (0xA1 + pos % 94).toString(16)).toUpperCase();
    } 
    else if ((pos = GBfh.indexOf(ch)) != -1){
      console.log('GBfh'+ch)
      ret += ("%" + (0xA1 + parseInt(pos / 94)).toString(16) + "%" + (0xA1 + pos % 94).toString(16)).toUpperCase();
    }
    else if ((pos = GBK_A940.indexOf(ch)) != -1){
      console.log(pos)
      ret += ("%" + (0xA9).toString(16) + "%" + (0x40 + pos).toString(16)).toUpperCase();
    }
    else if (strSpecial.indexOf(ch) != -1) {
      // ret += "%" + val.toString(16);      
      ret += val.toString(16);
    }
    else if (ch == " ") {
      // ret += "+";
      ret += "20";
    }
    else {
      //
      ret += strToHexCharCode(ch);
    }

  }
  return ret;
}

function stringToByte(str) {
  var bytes = new Array();
  var len, c;
  len = str.length;
  for (var i = 0; i < len; i++) {
    c = str.charCodeAt(i);
    console.log('c', c)
    if (c >= 0x010000 && c <= 0x10FFFF) {
      bytes.push(((c >> 18) & 0x07) | 0xF0);
      bytes.push(((c >> 12) & 0x3F) | 0x80);
      bytes.push(((c >> 6) & 0x3F) | 0x80);
      bytes.push((c & 0x3F) | 0x80);
    } else if (c >= 0x000800 && c <= 0x00FFFF) {
      bytes.push(((c >> 12) & 0x0F) | 0xE0);
      bytes.push(((c >> 6) & 0x3F) | 0x80);
      bytes.push((c & 0x3F) | 0x80);
    } else if (c >= 0x000080 && c <= 0x0007FF) {
      bytes.push(((c >> 6) & 0x1F) | 0xC0);
      bytes.push((c & 0x3F) | 0x80);
    } else {
      bytes.push(c & 0xFF);
    }
  }
  return bytes;
}

function strToGBKByte(str) {
  var bytes = new Array();
  /*********改自<a href="http://blog.csdn.net/qiushuiwuhen/article/details/14112">qiushuiwuhen(2002-9-16)</a>********/
  var ch, pos, val, strSpecial = "!\"#$%&'()*+,/:;<=>?@[\]^`{|}~%";
  for (var i = 0; i < str.length; i++) {
    ch = str.charAt(i);
    val = str.charCodeAt(i);
    //console.log(ch, val)
    if (val >= 0x4e00 && val < 0x9FA5) {      
      if ((pos = GBhz.indexOf(ch)) != -1){ bytes.push(0xB0 + parseInt(pos / 94)); bytes.push(0xA1 + pos % 94);}        
    }
    else if ((pos = GBfh.indexOf(ch)) != -1){      
      bytes.push(0xA1 + parseInt(pos / 94)); bytes.push(0xA1 + pos % 94);
    }
    else if((pos = GBK_A940.indexOf(ch)) != -1){
      bytes.push(0xA9); bytes.push(0x40+pos);
    }    
    else if (strSpecial.indexOf(ch) != -1) {      
      bytes.push(val);
    }
    else if (ch == " ") {   
      bytes.push(0x20);
    }
    else {      
      bytes.push(val);
    }
  }

  const buffer = new Uint8Array(bytes).buffer;
  return buffer;
}

/**
 * utf8 byte to unicode string
 * @param utf8Bytes
 * @returns {string}
 */
function utf8ByteToUnicodeStr(utf8Bytes) {
  var unicodeStr = "";
  for (var pos = 0; pos < utf8Bytes.length;) {
    // var flag = utf8Bytes[pos];
    var flag = utf8Bytes.charCodeAt(pos);
    var unicode = 0;
    if ((flag >>> 7) === 0) {
      unicodeStr += String.fromCharCode(utf8Bytes[pos]);
      pos += 1;

    } else if ((flag & 0xFC) === 0xFC) {
      unicode = (utf8Bytes[pos] & 0x3) << 30;
      unicode |= (utf8Bytes[pos + 1] & 0x3F) << 24;
      unicode |= (utf8Bytes[pos + 2] & 0x3F) << 18;
      unicode |= (utf8Bytes[pos + 3] & 0x3F) << 12;
      unicode |= (utf8Bytes[pos + 4] & 0x3F) << 6;
      unicode |= (utf8Bytes[pos + 5] & 0x3F);
      unicodeStr += String.fromCharCode(unicode);
      pos += 6;

    } else if ((flag & 0xF8) === 0xF8) {
      unicode = (utf8Bytes[pos] & 0x7) << 24;
      unicode |= (utf8Bytes[pos + 1] & 0x3F) << 18;
      unicode |= (utf8Bytes[pos + 2] & 0x3F) << 12;
      unicode |= (utf8Bytes[pos + 3] & 0x3F) << 6;
      unicode |= (utf8Bytes[pos + 4] & 0x3F);
      unicodeStr += String.fromCharCode(unicode);
      pos += 5;

    } else if ((flag & 0xF0) === 0xF0) {
      unicode = (utf8Bytes[pos] & 0xF) << 18;
      unicode |= (utf8Bytes[pos + 1] & 0x3F) << 12;
      unicode |= (utf8Bytes[pos + 2] & 0x3F) << 6;
      unicode |= (utf8Bytes[pos + 3] & 0x3F);
      unicodeStr += String.fromCharCode(unicode);
      pos += 4;

    } else if ((flag & 0xE0) === 0xE0) {
      unicode = (utf8Bytes[pos] & 0x1F) << 12;;
      unicode |= (utf8Bytes[pos + 1] & 0x3F) << 6;
      unicode |= (utf8Bytes[pos + 2] & 0x3F);
      unicodeStr += String.fromCharCode(unicode);
      pos += 3;

    } else if ((flag & 0xC0) === 0xC0) { //110
      unicode = (utf8Bytes[pos] & 0x3F) << 6;
      unicode |= (utf8Bytes[pos + 1] & 0x3F);
      unicodeStr += String.fromCharCode(unicode);
      pos += 2;

    } else {
      unicodeStr += String.fromCharCode(utf8Bytes[pos]);
      pos += 1;
    }
  }
  return unicodeStr;
}

function stringToArrayBuffer(str) {
	var bytes = new Array(); 
	var len,c;
	len = str.length;
	for(var i = 0; i < len; i++){
		c = str.charCodeAt(i);
		if(c >= 0x010000 && c <= 0x10FFFF){
			bytes.push(((c >> 18) & 0x07) | 0xF0);
			bytes.push(((c >> 12) & 0x3F) | 0x80);
			bytes.push(((c >> 6) & 0x3F) | 0x80);
			bytes.push((c & 0x3F) | 0x80);
		}else if(c >= 0x000800 && c <= 0x00FFFF){
			bytes.push(((c >> 12) & 0x0F) | 0xE0);
			bytes.push(((c >> 6) & 0x3F) | 0x80);
			bytes.push((c & 0x3F) | 0x80);
		}else if(c >= 0x000080 && c <= 0x0007FF){
			bytes.push(((c >> 6) & 0x1F) | 0xC0);
			bytes.push((c & 0x3F) | 0x80);
		}else{
			bytes.push(c & 0xFF);
		}
  }
  var array = new Int8Array(bytes.length+1);
  for(var i in bytes){
    array[i] =bytes[i];
  }
  array[bytes.length]=0;
	return array.buffer;
}

function arrayBufferToString(arr){
  if(typeof arr === 'string') {  
      return arr;  
  }  
  var dataview=new DataView(arr.data);
  var ints=new Uint8Array(arr.data.byteLength);
  for(var i=0;i<ints.length;i++){
    ints[i]=dataview.getUint8(i);
  }
  arr=ints;
  var str = '',  
      _arr = arr;  
  for(var i = 0; i < _arr.length; i++) {  
      var one = _arr[i].toString(2),  
          v = one.match(/^1+?(?=0)/);  
      if(v && one.length == 8) {  
          var bytesLength = v[0].length;  
          var store = _arr[i].toString(2).slice(7 - bytesLength);  
          for(var st = 1; st < bytesLength; st++) {  
              store += _arr[st + i].toString(2).slice(2);  
          }  
          str += String.fromCharCode(parseInt(store, 2));  
          i += bytesLength - 1;  
      } else {  
          str += String.fromCharCode(_arr[i]);  
      }  
  }  
  return str; 
}

print.js

class Bluetooth {

	constructor() {
		this.isOpenBle = false;
		this.deviceId = "";
		this.serviceId = "";
		this.writeId = "";
		this.notifyId = "";
		this.BluetoothConnectStatus = false;
		this.printStatus = false;
		// this.init()
	}
	init() {
		return new Promise((resolve, reject) => {
			this.closeBluetoothAdapter().then(() => {
				console.log("init初始关闭蓝牙模块")
				this.openBluetoothAdapter().then(() => {
					console.log("init初始化蓝牙模块")
					// this.reconnect() //自动连接蓝牙设备
					resolve()
				})
			})
		});

	}
	showToast(title) {
		uni.showToast({
			title: title,
			icon: 'none',
			'duration': 2000
		});
	}

	openBluetoothAdapter() {
		return new Promise((resolve, reject) => {
			uni.openBluetoothAdapter({
				success: res => {
					this.isOpenBle = true;
					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
		let deviceId = this.deviceId;
		let self = this;

		// uni.showLoading({
		// 	mask: true,
		// 	title: '设别连接中,请稍候...'
		// })
		console.log(this.deviceId, 'prinjs');
		return new Promise((resolve, reject) => {
			uni.createBLEConnection({
				deviceId,
				success: (res) => {
					console.log("res:createBLEConnection " + JSON.stringify(res));
					resolve(res)
				},
				fail: err => {
					uni.hideLoading();
					self.showToast(`搜索蓝牙设备失败` + JSON.stringify(err));
					reject(err);
				}
			})
		});
	}

	//获取蓝牙设备所有服务(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();
							console.log("_serviceList: " + JSON.stringify(_serviceList));
							resolve(_serviceList)
						},
						fail: err => {
							uni.hideLoading();
							self.showToast(`获取设备服务失败` + JSON.stringify(err));
							reject(err);
						},
					})
				},
				500);
		});
	}

	//获取蓝牙设备某个服务中所有特征值(characteristic)
	getBLEDeviceCharacteristics() {
		// console.log("getBLEDeviceCharacteristics")
		let deviceId = this.deviceId;
		let serviceId = this.serviceId;

		let self = this;
		return new Promise((resolve, reject) => {
			uni.getBLEDeviceCharacteristics({
				deviceId,
				serviceId,
				success: 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("res:getBLEDeviceCharacteristics " + JSON.stringify(res));
					let result = {
						'notifyId': self.notifyId,
						'writeId': self.writeId
					};
					// self.showToast(`获取服务中所有特征值OK,${JSON.stringify(result)}`);
					this.BluetoothStatus = true
					resolve(result)
				},
				fail: err => {
					self.showToast(`getBLEDeviceCharacteristics` + JSON.stringify(err));
					reject(err);
				}
			})
		});
	}

	//断开联链接
	closeBLEConnection() {
		let deviceId = this.deviceId;
		uni.closeBLEConnection({
			deviceId,
			success(res) {
				console.log("closeBLEConnection" + res)
			}
		})
	}

	notifyBLECharacteristicValue() {
		let deviceId = this.deviceId;
		let serviceId = this.serviceId;
		let characteristicId = this.notifyId;

		uni.notifyBLECharacteristicValueChange({
			state: true,
			// 启用 notify 功能
			deviceId,
			serviceId,
			characteristicId,
			success(res) {
				uni.onBLECharacteristicValueChange(function(res) {
					console.log('onBLECharacteristicValueChange', 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(deviceId);
		// console.log(serviceId);
		// console.log(characteristicId);
		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() {
		return new Promise((resolve, reject) => {
			uni.closeBluetoothAdapter({
				success: res => {
					resolve()
				},
				fail: (err) => {
					console.log(err, 'mysad');
					resolve()
				}
			});
		})

	}

	//若APP在之前已有搜索过某个蓝牙设备,并成功建立连接,可直接传入之前搜索获取的 deviceId 直接尝试连接该设备,无需进行搜索操作。
	reconnect() {
		(async () => {
			try {
				this.deviceId = this.deviceId || uni.getStorageSync("deviceId");
				this.serviceId = this.serviceId || uni.getStorageSync("serviceId");
				console.log("this.deviceId", this.deviceId)
				console.log("this.serviceId", this.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));
				this.BluetoothConnectStatus = true
				this.showToast("蓝牙打印设备连接成功")
				// this.writeId = uni.getStorageSync("writeId");
				// this.notifyId = uni.getStorageSync("notifyId");
			} catch (err) {
				console.log("err: " + err);
				this.showToast("蓝牙打印设备连接失败")
			}

		})();
	}
}

export
default Bluetooth;

页面相关操作代码:


import Bluetooth from '@/utils/print.js';
const gbk = require('../../utils/gbk.js');
import * as zksdk from '../../utils/printerjobs.js';

...

data() {
	return {
		hasSignPix: false, // 是否有签名图片
		tempDeviceList: [],
		serviceList: [],
		bluetooth: new Bluetooth(),
		...
	};
}

methods:{

	// 初始化蓝牙,并搜索蓝牙设备,显示弹窗列表
		async printOrder() {
			await this.bluetooth.init();
			let self = this;
			self.tempDeviceList = [];
			uni.startBluetoothDevicesDiscovery({
				services: ['xxx'], // 打印设备的服务号,不填写的话就搜索附近所有蓝牙设备
				success: res => {
					uni.onBluetoothDeviceFound(devices => {
						console.log('发现设备: ' + JSON.stringify(devices));
						if (self.tempDeviceList.length && devices.devices[0].name && !self.tempDeviceList.some(item => item.name == devices.devices[0].name)) {
							self.tempDeviceList.push(devices.devices[0]);
						} else if (!self.tempDeviceList.length) {
							self.tempDeviceList.push(devices.devices[0]);
						}
					});
					this.$refs.popupPrint.open();
				},
				fail: err => {
					console.log('搜索设备失败' + JSON.stringify(err));
					uni.showToast({
						title: '搜索设备失败' + JSON.stringify(err),
						icon: 'none'
					});
				}
			});
		},
		// 选中设备 并获取该蓝牙的服务,
		async select_deviceId(item) {
			uni.showLoading({
				title: '连接中...',
				mask: true
			});
			this.bluetooth.deviceId = item.deviceId;
			uni.setStorageSync('deviceId', this.bluetooth.deviceId);
			this.serviceList = [];
			this.$refs.popupPrint.close();
			try {
				//1.链接设备
				let result = await this.bluetooth.createBLEConnection();
				//2.寻找服务
				let result2 = null;
				setTimeout(async () => {
					result2 = await this.bluetooth.getBLEDeviceServices();
					console.log('获取服务: ' + JSON.stringify(result2));
					this.serviceList = result2;

					console.log('serviceList', this.serviceList.length);

					if (this.serviceList[0].uuid) {
						this.select_service(this.serviceList[0].uuid);
					} else {
						uni.showToast({
							title: '不是打印设备',
							icon: 'none'
						});
					}
				}, 1000);
			} catch (e) {
				console.log('e: ' + JSON.stringify(e));
			}
		},
		// 从该蓝牙服务中 过滤特性服务 notifyId 和 writeId
		async select_service(res) {
			this.bluetooth.serviceId = res;
			// console.log('this.bluetooth.serviceId', this.bluetooth.serviceId);
			uni.setStorageSync('serviceId', res);

			try {
				let result = await this.bluetooth.getBLEDeviceCharacteristics();

				this.writeBLECharacteristicValueShenqindan();
			} catch (e) {
				console.log('e: ' + JSON.stringify(e));
			}
		},

		// 准备打印内容
		async writeBLECharacteristicValueShenqindan() {
			const str = this.orderInfo.orderItemDisplay;
			const remarkStr = this.orderInfo.remark;
			// 此处是将字符串做打印换行处理,每行24个字符,备注每行18个字符
			const orderItemDisplayResult = str.replace(/(.{24})/g, '$1\r\n') + '\r\n';
			const remarkResult = remarkStr.replace(/(.{18})/g, '$1\r\n') + '\r\n';
			
			uni.canvasGetImageData({  // 获取签名图片,并用canvas获取图片数据
				canvasId: 'handWriting3',
				x: 0,
				y: 0,
				width: 304,
				height: 128,
				success: res => {
					let pixData = {
						width: 304, // 宽和高 最好是8的倍数,不然打印出来是个黑色块块
						height: 128, // 宽和高 最好是8的倍数,不然打印出来是个黑色块块
						imageData: res.data,
						threshold: 190
					};
					let result = zksdk.overwriteImageData(pixData);
					let pix = {
						width: result.width,
						height: result.height,
						imageData: result.array
					};

					let strCmd = zksdk.CreatCPCLPage(570, 1700, 1, 0);
					strCmd += zksdk.addCPCLLocation(2);
					strCmd += zksdk.addCPCLText(0, 30, '8', '4', 0, this.orderInfo.labName);
					strCmd += zksdk.addCPCLText(0, 70, '8', '2', 0, '检验申请单');
					strCmd += zksdk.addCPCLLine(0, 120, 560, 120, 3);
					strCmd += zksdk.addCPCLLocation(2);
					strCmd += zksdk.addCPCLBarCode(0, 150, '128', 80, 0, 1, 1, this.orderInfo.orderCode);
					strCmd += zksdk.addCPCLLocation(0);
					strCmd += zksdk.addCPCLText(10, 280, '3', '0', 0, '医院名称');
					strCmd += zksdk.addCPCLLocation(1);
					strCmd += zksdk.addCPCLText(10, 280, '3', '0', 0, this.orderInfo.hospitalName);
					strCmd += zksdk.addCPCLLocation(0);
					strCmd += zksdk.addCPCLText(10, 320, '3', '0', 0, '科室');
					strCmd += zksdk.addCPCLLocation(1);
					strCmd += zksdk.addCPCLText(10, 320, '3', '0', 0, this.orderInfo.hospitalDepName);
					strCmd += zksdk.addCPCLLocation(0);
					strCmd += zksdk.addCPCLText(10, 360, '3', '0', 0, '申请人');
					strCmd += zksdk.addCPCLLocation(1);
					strCmd += zksdk.addCPCLText(10, 360, '3', '0', 0, this.orderInfo.createdName);
					strCmd += zksdk.addCPCLLocation(0);
					strCmd += zksdk.addCPCLText(10, 400, '3', '0', 0, '申请时间');
					strCmd += zksdk.addCPCLLocation(1);
					strCmd += zksdk.addCPCLText(10, 400, '3', '0', 0, this.orderInfo.createdTime);
					strCmd += zksdk.addCPCLLocation(0);
					strCmd += zksdk.addCPCLText(10, 440, '3', '0', 0, '订单号');
					strCmd += zksdk.addCPCLLocation(1);
					strCmd += zksdk.addCPCLText(10, 440, '3', '0', 0, this.orderInfo.orderCode);
					strCmd += zksdk.addCPCLLocation(0);
					strCmd += zksdk.addCPCLText(10, 480, '3', '0', 0, '患者姓名');
					strCmd += zksdk.addCPCLLocation(1);
					strCmd += zksdk.addCPCLText(10, 480, '3', '0', 0, this.orderInfo.patient.name);
					strCmd += zksdk.addCPCLLocation(0);
					strCmd += zksdk.addCPCLText(10, 520, '3', '0', 0, '患者性别');
					strCmd += zksdk.addCPCLLocation(1);
					strCmd += zksdk.addCPCLText(10, 520, '3', '0', 0, this.orderInfo.patient.sex == 1 ? '男' : '女');
					strCmd += zksdk.addCPCLLocation(0);
					strCmd += zksdk.addCPCLText(10, 560, '3', '0', 0, '患者年龄');
					strCmd += zksdk.addCPCLLocation(1);
					strCmd += zksdk.addCPCLText(10, 560, '3', '0', 0, this.orderInfo.patient.ageDisplay);
					strCmd += zksdk.addCPCLLine(0, 590, 560, 590, 3);
					strCmd += zksdk.addCPCLLocation(0);
					strCmd += zksdk.addCPCLText(10, 620, '3', '0', 0, '检测项目');
					strCmd += zksdk.addCPCLMLText(10, 660, '0', '24', '30', orderItemDisplayResult);
					strCmd += zksdk.addCPCLText(10, 920, '3', '0', 0, '总计金额');
					strCmd += zksdk.addCPCLLocation(1);
					strCmd += zksdk.addCPCLText(10, 920, '3', '0', 0, `${this.orderInfo.totalAmount} 元`);
					strCmd += zksdk.addCPCLLocation(0);
					strCmd += zksdk.addCPCLText(10, 960, '3', '0', 0, '备注信息');
					strCmd += zksdk.addCPCLLocation(1);
					strCmd += zksdk.addCPCLText(10, 960, '3', '0', 0, remarkResult);
					strCmd += zksdk.addCPCLLocation(0);
					strCmd += zksdk.addCPCLLine(0, 1060, 560, 1060, 3);
					strCmd += zksdk.addCPCLLocation(2);
					strCmd += zksdk.addCPCLSETMAG(2, 2);
					strCmd += zksdk.addCPCLQRCode(0, 1090, 'M', 2, 6, this.orderInfo.orderCode);
					strCmd += zksdk.addCPCLLine(0, 1290, 560, 1290, 3);
					strCmd += zksdk.addCPCLSETMAG(0, 0);
					strCmd += zksdk.addCPCLLocation(0);
					strCmd += zksdk.addCPCLText(10, 1330, '3', '0', 0, '签名');
					if (this.hasSignPix) {
						strCmd += zksdk.addCPCLLocation(0);
						strCmd += zksdk.addCPCLImageCmd(10, 1370, { imageData: pix.imageData, width: pix.width, height: pix.height, threshold: 190 });
					}

					strCmd += zksdk.addCPCLPrint();
					let buffer = gbk.strToGBKByte(strCmd);
					console.log(buffer, 'befor');
					buffer = zksdk.myGzip(buffer);
					// let hexStr = Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join(' ');
					// console.log(hexStr);
					console.log(buffer, 'after');
					this.printbuffs(buffer);
				},
				fail: err => {
					console.log(err);
					uni.showToast({
						title: '获取签名失败,请重试',
						icon: 'none'
					});
				}
			});
		},
		// 转译传输内容,并截取20字节一次
		cutCommand(data) {
			var _this = this;
			var sendData64 = [];
			var packageLength = 20;
			// var byData = wx.base64ToArrayBuffer(ToBase64.encode64gb2312(data));
			var byData = data;
			for (let i = 0; i < Math.ceil(byData.byteLength / packageLength); i++) {
				var ble_end = packageLength * (i + 1);
				var ble_begin = i * packageLength;
				if (ble_end > byData.byteLength) {
					//从begin(包括),到end(不包括)。
					const newBuffer = byData.slice(ble_begin); // 从哪个开始到那个结束
					sendData64[i] = newBuffer;
				} else {
					const newBuffer = byData.slice(ble_begin, ble_end); // 从哪个开始到那个结束
					sendData64[i] = newBuffer;
				}
			}
			return sendData64;
		},

		// 传输内容
		printbuffs(buffer, fun) {
			let _t = this;
			let p = new Promise((resolve, reject) => {
				resolve(_t.cutCommand(buffer));
			});
			p.then(buffer => {
				this.printbuff(buffer, 1);
			});
		},
		// 打印
		async printbuff(buffer, times) {
			uni.showLoading({
				title: '打印中...',
				mask: true
			});
			let deviceId = this.bluetooth.deviceId;
			let serviceId = this.bluetooth.serviceId;
			let characteristicId = this.bluetooth.writeId;
			var _t = this;
			var sendData64 = buffer;
			if (sendData64.length >= times) {
				wx.writeBLECharacteristicValue({
					deviceId: deviceId,
					serviceId: serviceId,
					characteristicId: characteristicId,
					value: sendData64[times - 1],
					success: function(res) {
						_t.printbuff(buffer, ++times);
					},
					fail: function(res) {
						uni.showToast({
							title: "提示, '传输失败'"
						});
					}
				});
			} else {
				wx.hideLoading();
			}
		}


}

  • 开始使用的是汉印的 蓝牙打印机,用了一个星期机器出了点故障,就换了芝柯的打印机,所以代码里面有一些注释了。
  • 签名的的组件,在插件市场可以找到。稍微改造一下就行,需要注意的是,横图转角度,需要新建一个canvas 。
  • 打印图片时,需先下载图片,创建canvas填充图片,获取canvas内容,转16进制再打印。一般图片内容会比较大,所以可以先 转成 黑白位图,基本会缩小4倍左右。 然后再使用 pako 压缩。主要是因为微信小程序的使用低功耗蓝牙,小程序不会对写入数据包大小做限制,但系统与蓝牙设备会限制蓝牙 4.0 单次传输的数据大小,超过最大字节数后会发生写入错误,建议每次写入不超过 20 字节。 而一张图片的内容,转译之后基本都是上万
  • 关于图片宽和高 使用8的倍数,会方便一些。因为转黑白位图及转译时,会将8个单位压缩成1个

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/463654.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Undefined symbol解决方法

1.初级错误 (1)C中未定义 (2)H中未引用 (3)未包含含有该类型的.H文件 (4)在keil中未添加.C或.H文件到工程 2.C和C代码混合调用引起的未定义错误 1.一般情况下&#xff0c;Error: L6218E: Undefined symbol 若是由于未定义引起的错误&#xff0c;可以根据错误提示定位到相应的…

大模型时代,RPA的冰与火之歌|产业特稿

从市场趋势来看&#xff0c;RPA属性正在逐渐淡化&#xff0c;一些厂商都已瞄准更高阶的智能机器人。可能未来5&#xff5e;10年&#xff0c;随着AI语言模型的发展&#xff0c;RPA的产品逻辑会彻底改变&#xff0c;RPA厂商也会进化到更智能的阶段。 作者|思杭 编辑|皮爷 出…

C#开发的OpenRA的游戏侧边界面

C#开发的OpenRA的游戏侧边界面 OpenRA游戏开始之后,会在右边提供一个游戏侧边界面, 通过这个游戏界面,可以查看游戏状态、执行一些特殊的命令,以及雷达显示, 还有创建各种需要的建筑物,以及生产各种兵种,飞机等等。 这个游戏界面,就是给玩家提供一个操作平台,因此它…

年轻不乏野心,想做年薪40万+的软件测试工程师?写给长途漫漫中的你...

本人从事自动化测试10年多&#xff0c;之前在猪场工作&#xff0c;年薪突破40W&#xff0c;算是一个生活过得去的码农。&#xff08;仅代表本人&#xff09; 目前从事自动化测试的薪资待遇还是很不错的&#xff0c;所以如果朋友们真的对自动化感兴趣的话可以坚持学下去&#xf…

开放式蓝牙耳机排行,列举几款值得推荐的开放式蓝牙耳机

开放式耳机是通过人的颅骨振动将声音转换成声波&#xff0c;不通过耳膜&#xff0c;可以听到外界的声音&#xff0c;可以保护耳朵&#xff0c;也可以保护听力。并且大部分的开放式耳机都是采用挂耳式的佩戴设计&#xff0c;即使是长时间佩戴也不会让耳朵感到疲劳&#xff0c;下…

线性回归模型(7大模型)

线性回归模型&#xff08;7大模型&#xff09; 线性回归是人工智能领域中最常用的统计学方法之一。在许多不同的应用领域中&#xff0c;线性回归都是非常有用的&#xff0c;例如金融、医疗、社交网络、推荐系统等等。 在机器学习中&#xff0c;线性回归是最基本的模型之一&am…

Cortex-A7中断详解(一)

STM32中断系统回顾 中断向量表NVIC&#xff08;内嵌向量中断控制器&#xff09;中断使能中断服务函数 中断向量表 中断向量表是一个表&#xff0c;表里面存放的是中断向量。 中断服务程序的入口地址或存放中断服务程序的首地址成为中断向量&#xff0c;因此中断向量表是一系…

电脑开机memory management错误蓝屏了怎么办?

电脑开机memory management错误蓝屏了怎么办&#xff1f;windows系统出现不兼容问题之后&#xff0c;很容易出现电脑蓝屏的情况。最近有用户遇到了上述的蓝屏错误情况&#xff0c;不知道怎么去进行解决。今天我们就一起来看看以下的解决方法分享吧。 准备工作&#xff1a; 1、U…

yolov5半自动打标签(opencv版本),识别目标画框并将坐标信息保存在xml中

文章目录 1.yolov5预训练模型推理2. opencv边缘检测结果展示 yolov5训练数据集时&#xff0c;需要对数据进行打标签&#xff0c;可以通过两种方法进行半自动化打标签。 1.yolov5预训练模型推理 yolov5预训练模型&#xff1a;将待打标签的图片输入预训练模型中进行推理&#xf…

实现PXE批量网络装机及kickstrat无人值守安装(富士山终究留不住欲落的樱花)

一、PXE概述和部署PXE批量装机 1.PXE简介 PXE&#xff08;预启动执行环境&#xff0c;在操作系统之前运行&#xff09;是由Intel公司开发的网络引导技术&#xff0c;c/s架构&#xff0c;允许客户机通过网络从远程服务器下载引导镜像&#xff0c;并加载安装文件或者整个操作系统…

2023_8.0.33版windows版MySql安装_配置远程连接_修改设置初始密码---MySql工作笔记0001

MySQL :: Download MySQL Community Server https://dev.mysql.com/downloads/mysql/ 首先去下载mysql 可以看到这里下载第一个就可以了,最新版的8.0.33 这里点击仅仅下载 just start my download 然后解压到一个文件夹,然后配置一下环境变量 然后新建一个my.ini文件 然后把…

ubuntu22.04下挂载第二块硬盘

文章目录 一、查看硬盘情况二、找到nvme1n1三、挂载四、修改分区文件 一、查看硬盘情况 首先要查看一下系统识别出来的设备。也就是说&#xff0c;我希望知道&#xff0c;ubuntu到底发现了几块硬盘。用命令&#xff1a;lsblk 显示结果如下&#xff1a; 有两块硬盘&#xff1a…

Win11打开移动热点后电脑无法上网怎么办?

Win11打开移动热点后电脑无法上网怎么办&#xff1f;有用户将自己的电脑开启移动热点来使用的时候&#xff0c;发现自己的电脑出现了无法上网的情况。那么为什么开启热点之后&#xff0c;就会无法进行上网呢&#xff1f;来看看以下的解决方法分享吧。 Win11打开移动热点无法上网…

virtual kubelet 简单使用例子

virtual kubelet 简单使用例子 实现过程制作virtual kubelet节点证书下载virtual kubelet代码并编译virtual kubelet virtual kubelet 顾名思义就是虚拟的kubelet节点 效果如下&#xff1a; 实现过程 制作virtual kubelet节点证书 openssl genrsa -out client.key 2048 opens…

EPICS aSub记录使用实例

本实例描述了在数据库中如何使用aSub记录 本实验中使用了三个k型热电偶&#xff0c;一个3路k型热电偶变送器以及一个串口服务器&#xff1a; 温度变送器参数&#xff1a; 串口服务器&#xff1a; 1) 用makeBaseApp.pl构建IOC应用程序的目录结构&#xff1a; [blctrllocalhost…

OpenGL入门教程之 摄像机

引言 前面的教程中我们讨论了观察矩阵以及如何使用观察矩阵移动场景。OpenGL本身没有摄像机的概念&#xff0c;但我们可以通过把场景中的所有物体往相反方向移动的方式来模拟出摄像机&#xff0c;这样感觉就像我们在移动&#xff0c;而不是场景在移动。  本节我们将会讨论如何…

从零开始学架构——高可用存储架构

双机架构 存储高可用方案的本质都是通过将数据复制到多个存储设备&#xff0c;通过数据冗余的方式来实现高可用&#xff0c;其复杂性主要体现在如何应对复制延迟和中断导致的数据不一致问题。因此&#xff0c;对任何一个高可用存储方案&#xff0c;我们需要从以下几个方面去进…

【MySQL】一个脚本启动MySQL 8.0并初始化数据库

引 很多情况下需要在客户端发布时发布 MySQL 数据库&#xff0c;这种发布方式虽然存在文件资源较大、易出错等缺点&#xff0c;但是却可以让桌面产品的发布更加完整。 本文将阐述如何使用一个脚本启动并初始化 MySQL 8.0 的方法&#xff0c;涵盖数据库下载、脚本源码、测试及…

PFSK162 3BSE015088R1通常都要做空载全电压合闸冲击试验

​ PFSK162 3BSE015088R1通常都要做空载全电压合闸冲击试验 变压器励磁涌流影响的保护整定 摘要&#xff1a;在大型变压器空栽冲击过程中&#xff0c;由于励磁涌流和负序电压的存在&#xff0c;如果定值整定不得当&#xff0c;会导致差动保护&#xff0c;复压过流保护等误动作&…

设计模式——组件协作模式之观察者模式

文章目录 前言一、“组件协作” 模式二、Observer 观察者模式1、动机2、模式定义3、伪代码示例①、第一种方案&#xff0c;最朴素的方式②、第二种方案&#xff0c;重构使得遵循DIP原则&#xff1a;③、进一步的小优化&#xff1a;④、修改使得支持多个观察者&#xff1a; 4、结…