当前位置: 首页 > news >正文

网站开发报价表格百度指数官方下载

网站开发报价表格,百度指数官方下载,怎样做网站性能优化,旅游门户网站建设方案模板一:实践前的理论部分 蓝牙/热敏打印机如何打印图片。 票据打印机的指令和条码打印机的指令对于打印图片的格式要求基本都相似 看看ESC/POS指令的文档 是的看不懂。。。干脆直接试试好了,从如何打印一个像素的小黑点开始。 注意到x的最小单位是字节数…

一:实践前的理论部分

蓝牙/热敏打印机如何打印图片。

票据打印机的指令和条码打印机的指令对于打印图片的格式要求基本都相似

看看ESC/POS指令的文档

在这里插入图片描述
是的看不懂。。。干脆直接试试好了,从如何打印一个像素的小黑点开始。

注意到x的最小单位是字节数,而一个字节等于8个比特也就是说如果其实我能一次性控制8个点的打印
所以打印一个小黑点的指令就得出是:1D 76 30 00 01 00 01 00 80
如果想要八个点全黑,对应的指令是:1D 76 30 00 01 00 01 00 FF

我们能改变的最小单位也就是 80 和 FF

在这里插入图片描述

所以按这个公式理论上可以在一张小票纸上的任意位置打出黑点。

二、理论后的实践部分

实践:
从打印一个黑点开始,用到 get-pixels这个库可以获取到图片的宽高以及每个像素点的 rgba

仓库地址:https://github.com/scijs/get-pixels.git

1、打印一个黑点

getPixels('test/576.jpg',(err, { data, shape }) => {data = [0, 0, 0, 255]//这里直接赋值了一个黑点像素点的 rgba 信息shape = [1, 1, 4]//const imgData = rgba2hex(data, shape);const width = shape[0];const height = shape[1];const xL = Math.ceil((width / 8) % 256);  // 1const xH = Math.floor((width / 8) / 256); // 0const yL = height % 256; // 1const yH = Math.floor(height / 256); // 0const buffer = Buffer.from([0x1d, 0x76, 0x30, 0, xL, xH, yL, yH, ...imgData]);console.log("🚀 ~ getPixel ~ buffer:", buffer)//<Buffer 1d 76 30 00 01 00 01 00 80>const tenBuffer = blutoothEncode(buffer)console.log("🚀 ~ getPixels ~ tenBuffer:", tenBuffer.toString())
})

2、打印一排24个黑点

getPixels('test/576.jpg',(err, { data, shape }) => {data = [0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,]shape = [24, 1, 4]const imgData = rgba2hex(data, shape);const width = shape[0];const height = shape[1];const xL = Math.ceil((width / 8) % 256);  // 1const xH = Math.floor((width / 8) / 256); // 0const yL = height % 256; // 1const yH = Math.floor(height / 256); // 0const buffer = Buffer.from([0x1d, 0x76, 0x30, 0, xL, xH, yL, yH, ...imgData]);console.log("🚀 ~ getPixel ~ buffer:", buffer)//<Buffer 1d 76 30 00 01 00 01 00 80>const tenBuffer = blutoothEncode(buffer)console.log("🚀 ~ getPixels ~ tenBuffer:", tenBuffer.toString())
})

3、打印宽24,高8的黑点图

getPixels('test/576.jpg',(err, { data, shape }) => {data = [0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,0, 0, 0, 255,]shape = [24, 8, 4]const imgData = rgba2hex(data, shape);const width = shape[0];const height = shape[1];const xL = Math.ceil((width / 8) % 256);  // 1const xH = Math.floor((width / 8) / 256); // 0const yL = height % 256; // 1const yH = Math.floor(height / 256); // 0const buffer = Buffer.from([0x1d, 0x76, 0x30, 0, xL, xH, yL, yH, ...imgData]);console.log("🚀 ~ getPixel ~ buffer:", buffer)const tenBuffer = blutoothEncode(buffer)console.log("🚀 ~ getPixels ~ tenBuffer:", tenBuffer.toString())
})const rgba2hex = (data, shape) => {const bitArr = [];for (let i = 0; i < data.length; i = i + 4) {if (i[3] === 0) {bitArr.push(0);continue;}// 计算平均值判断const bit = (data[i] + data[i + 1] + data[i + 2]) / 3 > 160 ? 0 : 1;bitArr.push(bit);}// bitArr: [1]// 对bitArr做补0的动作let newBitArr = [];const width = shape[0];const isNeed = width % 8 !== 0;const height = shape[1];if (isNeed) {for (let i = 0; i < height; i++) {newBitArr.push(...bitArr.slice(i * width, (i + 1) * width));for (let j = 0; j < 8 - (width % 8); j++) {newBitArr.push(0);}}} else {newBitArr = bitArr;}// newBitArr: [1, 0, 0, 0, 0, 0, 0, 0]const byteArr = [];for (let i = 0; i < newBitArr.length; i = i + 8) {const byte =(newBitArr[i] << 7) +(newBitArr[i + 1] << 6) +(newBitArr[i + 2] << 5) +(newBitArr[i + 3] << 4) +(newBitArr[i + 4] << 3) +(newBitArr[i + 5] << 2) +(newBitArr[i + 6] << 1) +(newBitArr[i + 7]);byteArr.push(byte);}// byteArr: [128] = [0x80];return new Uint8Array(byteArr);
}/** 蓝牙十六进制指令 转换start */
const blutoothEncode = (buffer) => {let length = 0;buffer.forEach(item => {if (typeof item === "number") {length += 1;} else {length += item.length;}});const result = new Uint8Array(length);let index = 0;buffer.forEach(item => {if (typeof item === "number") {result[index] = item;index += 1;} else {result.set(item, index);index += item.length;}});// 取反码return handlePrintData(result);
}
// 处理打印机数据
function handlePrintData(arr) {let result = new Array(arr.length);for (let i = 0; i < arr.length; i++) {if (arr[i] < 128) {result[i] = arr[i];} else {// 减一let item = arr[i] - 1;// 反码let item2 = tenToTwo(item);let item3 = getReverseCode(item2);let item4 = twoToTen(item3);// 加上符号位result[i] = -item4;}}return result;
}
// 取反码
function getReverseCode(arr) {let result = [];for (let i = 0; i < arr.length; i++) {let item = arr[i];if (item === 1) {result.push(0);} else {result.push(1);}}return result;
}// 十进制转二进制
function tenToTwo(num) {let result = [];while (num > 0) {result.unshift(num % 2);num = Math.floor(num / 2);}return result;
}// 二进制转十进制
function twoToTen(arr) {let result = 0;for (let i = 0; i < arr.length; i++) {let item = arr[i];result += item * Math.pow(2, arr.length - i - 1);}return result;
}
/** 蓝牙十六进制指令 转换end */

十六进制的打印指令
getPixel ~ buffer: <Buffer 1d 76 30 00 03 00 08 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff>
十进制的打印指令
getPixels ~ tenBuffer: 29,118,48,0,3,0,8,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1

打印结果:

在这里插入图片描述

再测试打印一张图片:

在这里插入图片描述

三、实践结束理解图片打印指令

位图的基本概念?

位图: 是由许多像素点组成的图像表示方法。每个像素点都有其特定的颜色值或灰度值。
像素点: 是位图中的最小单位,每个像素点都有其特定的属性(如颜色、亮度等)。
字节存储:在打印指令中,位图数据通常以字节为单位进行存储和传输。

例如,在图中的xL、xH、yL、yH参数就是用于确定水平和垂直方向上的位图字节数和点数。

当打印机接收到包含位图数据的打印指令时,它会根据指令中的参数(如位图的大小、位置等)将位图数据转换为实际的打印输出。例如,指令中的xLxH确定了水平方向上的位图字节数,yLyH确定了垂直方向上的位图点数。打印机根据这些参数来安排位图在打印纸上的布局。

位图的分辨率(如纵向分辨率和横向分辨率)会影响打印输出的质量。在图中的指令格式中,不同的m值会选择不同的纵向和横向分辨率模式,从而影响位图在打印时的清晰度和大小。总之,位图在打印领域是一种重要的数据表示方式。

位图中像素点与字节、比特的关系?

在一般的位图表示中,一个像素点所占用的存储大小取决于位图的颜色深度。

黑白位图(1 - bit 位图)
如果是黑白位图,每个像素点只有两种状态:黑或白。这种情况下,一个像素点只需要 1 比特(1 bit)来表示。例如,0 可以表示白色,1 可以表示黑色。

灰度位图
对于灰度位图,如果有 256 级灰度,那么每个像素点需要 8 比特(1 字节,因为 1 字节 = 8 比特)来表示。这是因为 256 级灰度需要用 8 位二进制数(00000000 - 11111111)来区分不同的灰度级别。

彩色位图
在彩色位图中,情况更为复杂。例如,常见的 24 - bit 真彩色位图,每个像素点由红、绿、蓝(RGB)三个颜色通道组成,每个通道用 8 比特表示,所以一个像素点总共需要 24 比特(3 字节)来表示。

为什么 m 的取值范围有 2 个?

这个区间内的m值用于选择正常模式、倍宽模式、倍高模式和倍宽倍高模式。这些模式主要用于调整字符的宽度和高度。这个区间内的m值实际上是重复了 0 - 3 区间内的功能。这样设计可能是为了方便编程和指令的兼容性。这种设计使得在不同的编程环境或设备中,可以灵活地选择m值来实现相同的打印效果,提高了指令的通用性和易用性。

关于xL、xH、yL、yH的定义?

xL和xH:
xLxH表示水平方向位图字节数(xL + xH×256)。这里的xL是低字节xH是高字节。它们共同确定了水平方向上的位图字节数量。

例如,当xL + xH×256 = 64时,表示水平方向上有 64 个字节用于存储位图数据。

yL和yH:
yLyH表示垂直方向位图点数(yL + yH×256)。yL是低字节yH是高字节。它们共同确定了垂直方向上的位图点数。

例如,在图中的示例里,yL + yH×256表示垂直方向上的点数。

以水平方向为例,
如果xL = 1且xH = 0,那么水平方向位图字节数为1+0×256 = 1字节。
如果xL = 0且xH = 1,那么水平方向位图字节数为0 + 1×256=256字节。
在实际打印光栅位图时,通过这些参数可以准确地确定位图在纸张上的大小和位置,从而实现精确的打印输出。

字节顺序的概念?

在计算机中,数据常常以多个字节来存储。当一个数据需要用多个字节表示时,就存在字节顺序的问题。例如,一个 16 位的数据(在这个例子中类似xL + xH×256这样的数据)需要用两个字节来存储。
低字节(xL):指的是数据的低位部分。在数值表示中,它占的权重较小。
高字节(xH):指的是数据的高位部分。在数值表示中,它占的权重较大。

以xL + xH×256为例:

假设我们有一个水平方向位图字节数为 1000(十进制)。将 1000 转换为十六进制是03E8

在这种情况下:
低字节(xL):十六进制的E8(十进制的 232),这是低位部分。
高字节(xH):十六进制的03(十进制的 3),这是高位部分。

在 ESC/POS 指令中,当你看到xLxH这两个参数时,要知道它们组合起来表示一个较大的数值。xL总是代表低位部分,xH总是代表高位部分。在计算水平方向位图字节数时,就是按照xL + xH×256这样的公式来计算的。

到这里应该就比较清楚了类似 xL + xH×256 的式子就是在计算字节数的公式而已。

为什么 xL 等参数的取值范围是0 到 255?

在计算机中,一个字节(8 位)可以表示的数据范围是 0 - 255(十进制)。这是因为 8 位二进制数可以表示 个不同的值,从 00000000(十进制 0)到 11111111(十进制 255)。
xL、xH、yL、yH这些参数通常是用一个字节来存储的,所以它们的取值范围自然就限制在 0 - 255

对于大多数实际的打印应用场景,用一个字节来表示位图的大小或位置信息已经足够。常见的小票打印机或简单的标签打印机中,打印区域通常较小,不需要超过 255 个单位(字节数或点数)来表示位图的相关尺寸。如果超出这个范围,可能需要使用多个字节来表示更大的数值,但这会增加指令的复杂性和数据传输量。

总结

通过这个打印方式可以控制这张纸上能被热敏头接触到的任意地方都能打印出自己想要的信息,所以可以说是最好的打印方式。

缺点:从下发打印指令到打印机开始打印这个过程根据数据量的大小,会有不同程度的延迟,其次打印过程中并不能一次性的打完所有指令,会存在打一段停一段的情况,所以不适合大数据量的图片打印。

tip:某些打印机厂商的打印机没有好好实现规范于是按上述的图片指令打印方案图片高度超过一定程度就会出现乱码,需要把这张图片拆分成多张小图片才能正常打。

getPixels('test/576.jpg',(err, { data, shape }) => {const imgData = rgba2hex(data, shape);const width = shape[0];const height = shape[1];const xL = Math.ceil((width / 8) % 256);  // 1const xH = Math.floor((width / 8) / 256); // 0const yL = height % 256; // 1const yH = Math.floor(height / 256); // 0//const buffer = Buffer.from([0x1d, 0x76, 0x30, 0, xL, xH, yL, yH, ...imgData]);//const tenBuffer = blutoothEncode(buffer)//拆成小图const buffer = [];for(let i=0;i<height;i++) {let tempBuffer = [0x1d, 0x76, 0x30, 0, xL, xH, 1, 0, imgData.slice(i*(xL + 256*xH), (i+1)*(xL + 256*xH))]buffer[i] = tempBuffer;}
})

参考链接:
https://juejin.cn/post/7362537451170185252
https://juejin.cn/post/7297529039312158730
https://tech.youzan.com/retail-printer-picture

http://www.yayakq.cn/news/539926/

相关文章:

  • 新建网站后域名跳转到别的网站了顺德区网站设计建设企业
  • 网站正在建设中色天使广州酒店网站制作
  • 网站建设一定要买数据盘吗鞍山最新消息
  • 软件推广平台有哪些怎么在网站里做关键词优化
  • 微信上的小说网站是怎么做的网站有版权吗
  • 外贸网站建设不可缺少的灵活性广州建设网站是什么关系
  • 深圳网站建设相关推荐中国机械设备采购网
  • 三灶网站建设网站建立的步骤
  • 网站速度慢wordpress免费ppt生成器
  • 山东网站推广公司建设工程合同协议书
  • 网站娱乐app网站开发网络传媒有限公司
  • 公众号网站大连市城乡建设档案馆网站
  • 怎么建设回收网站佛山网络推广培训
  • 网站建设放什么会计科目教做网站视频
  • 浙江建设招生网站沈阳正规的男科医院排名
  • 天水营销型网站建设宁波网站建设电话咨询
  • 做宣传类网站需要什么资质网上自己建网站
  • 北京微网站建设网站后端建设
  • 网站搭建哪里找最好云南网络推广公司
  • 领导交给你一个网站你该怎么做浙江温州乐清新闻
  • 手机网站建设app网站建设服务商怎么收费
  • 网站建设顺序合肥网站建设zgkr
  • wordpress主题的网站做招商加盟网站怎么样
  • 网业制作与网站建设企业年金怎么缴纳
  • 中国建筑公司网站大全企业管理系统平台新一代数字化办公平台
  • 西安网站开发公司怎么选本周热点新闻事件
  • 是阿里巴巴好还是自己做网站好?做外卖网站的模板
  • 张家界企业网站制作建设银行大冶支行网站
  • 网站模板代理什么软件可以制作图片
  • 大数据网站怎么做物流公司名称起名大全