wordpress产品图片大小不一,惠州seo推广外包,wordpress 漏洞 利用,西安搬家公司哪家便宜一#xff1a;实践前的理论部分
蓝牙/热敏打印机如何打印图片。
票据打印机的指令和条码打印机的指令对于打印图片的格式要求基本都相似
看看ESC/POS指令的文档 是的看不懂。。。干脆直接试试好了#xff0c;从如何打印一个像素的小黑点开始。
注意到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 80const 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 80const 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参数就是用于确定水平和垂直方向上的位图字节数和点数。
当打印机接收到包含位图数据的打印指令时它会根据指令中的参数如位图的大小、位置等将位图数据转换为实际的打印输出。例如指令中的xL和xH确定了水平方向上的位图字节数yL和yH确定了垂直方向上的位图点数。打印机根据这些参数来安排位图在打印纸上的布局。
位图的分辨率如纵向分辨率和横向分辨率会影响打印输出的质量。在图中的指令格式中不同的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 xL和xH表示水平方向位图字节数xL xH×256。这里的xL是低字节xH是高字节。它们共同确定了水平方向上的位图字节数量。
例如当xL xH×256 64时表示水平方向上有 64 个字节用于存储位图数据。
yL和yH yL和yH表示垂直方向位图点数yL yH×256。yL是低字节yH是高字节。它们共同确定了垂直方向上的位图点数。
例如在图中的示例里yL yH×256表示垂直方向上的点数。
以水平方向为例 如果xL 1且xH 0那么水平方向位图字节数为10×256 1字节。 如果xL 0且xH 1那么水平方向位图字节数为0 1×256256字节。 在实际打印光栅位图时通过这些参数可以准确地确定位图在纸张上的大小和位置从而实现精确的打印输出。
字节顺序的概念
在计算机中数据常常以多个字节来存储。当一个数据需要用多个字节表示时就存在字节顺序的问题。例如一个 16 位的数据在这个例子中类似xL xH×256这样的数据需要用两个字节来存储。 低字节xL指的是数据的低位部分。在数值表示中它占的权重较小。 高字节xH指的是数据的高位部分。在数值表示中它占的权重较大。
以xL xH×256为例:
假设我们有一个水平方向位图字节数为 1000十进制。将 1000 转换为十六进制是03E8。
在这种情况下 低字节xL十六进制的E8十进制的 232这是低位部分。 高字节xH十六进制的03十进制的 3这是高位部分。
在 ESC/POS 指令中当你看到xL和xH这两个参数时要知道它们组合起来表示一个较大的数值。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 i0;iheight;i) {let tempBuffer [0x1d, 0x76, 0x30, 0, xL, xH, 1, 0, imgData.slice(i*(xL 256*xH), (i1)*(xL 256*xH))]buffer[i] tempBuffer;}
})参考链接 https://juejin.cn/post/7362537451170185252 https://juejin.cn/post/7297529039312158730 https://tech.youzan.com/retail-printer-picture