为了在小票上打印二维码,折腾了好多天,终于搞定了,现将关键点做个记录。
- 二维码的打印,首先是根据内容生成二维码bmp图片,这个我是通过网上找的一个叫qrencode的lib实现的,生成的bmp为24位的图片,我花费好多天没有成功的原因首先就是没搞清ESC/POS指令中关于位图打印的命令需要的是单色位图数据,还有对于命令中的宽度高度等参数没有搞清什么nL,nH的含义,原来是用两个自己来表示的一个数值(低8位和高8位,所以一般传的值就是x%256和x/256),搞清了这两点就是成功的关键。所以需要在qrencode生成的bmp基础上对位图进行调整后才能满足打印命令的需要。
- 第一步就是对生成的24位二维码bmp进行尺寸修正,这个要视小票宽度来定,比如58mm的纸一般384点/行,两边预留一点的话,基本上最大就是344(此值一般定义为8的倍数,否则打印时补的位会是黑块),所以在调整时对于原始的bmp超过此值的话需要进行缩放至此值(bmp缩放可自行搜索,这个简单),调整好宽度后,再将24位图转换为单色图(1位,这个也不难)。
- 经过第一步的调整后就可以读取并打印bmp了。我使用的是GS v 0 m xL xH yLyH d1...dk 这个命令来打印的,直接上代码了。此打印函数支持58mm和80mm,_nPaperType=0表示58mm,1表示80mm。其中的Write函数是向打印机写数据的。Feed是调用Write打印空行的。如下:
void printBmp(LPCSTR _file, BOOL _bCenter, int _nPaperType)
{
long lWidth, lHeight;
BITMAPFILEHEADER bf;
BITMAPINFOHEADER bi;
FILE *fileR;
fopen_s(&fileR, _file, "rb");
if (fileR)
{
fread(&bf, sizeof(BITMAPFILEHEADER), 1, fileR);
fread(&bi, sizeof(BITMAPINFOHEADER), 1, fileR);
RGBQUAD rgb[2];
fread(rgb, 2 * sizeof(RGBQUAD), 1, fileR); // 读颜色表信息
lWidth = bi.biWidth;
lWidth = (lWidth % 8 == 0) ? (lWidth / 8) : (lWidth / 8 + 1); // 宽度由点数调整为字节数
long lWidthBmp = (lWidth % 4 == 0) ? lWidth : (lWidth + 4 - (lWidth % 4)); // 如果字节数不是4的倍数,要调整为4的倍数个
lHeight = bi.biHeight;
if (lHeight < 0)
{
lHeight *= -1; // 高度值为负数时需要转为正的
}
long lImageSize = lWidthBmp*lHeight; // 要读取的图像数据长度
BYTE *pData = new BYTE[lImageSize];
fread(pData, lImageSize, 1, fileR);
fclose(fileR);
Write((BYTE*)"\x1B\x33\x15", 3L); // 调整行间距,以便图片和上下的内容保持合适的间距
Feed(1); // 空一行
if (_bCenter)
{
Write((BYTE*)"\x1B\x61\x01", 3L); // 居中
}
BYTE buf[] = { 0x1d, 0x76, 0x30, 0x00, BYTE(lWidth % 256), BYTE(lWidth / 256), BYTE(lHeight % 256), BYTE(lHeight / 256) };
Write(buf, 8L);
// bi.biHeight 为负时,从上到下逐行遍历,反之从下到上
for (int y = (bi.biHeight < 0)? 0 : (lHeight - 1); (bi.biHeight < 0) ? (y < lHeight) : (y >= 0); y += (bi.biHeight < 0) ? 1 : -1)
{
for (int x = 0; x < lWidthBmp; ++x)
{
if (x < lWidth) // 有效数据范围内
{
if (x == lWidth - 1) // 最后一个有效字节
{
int n = bi.biWidth % 8; // 余数,大于0说明有补位
if (n > 0) // 如果最后一位有补位,将补位置为 1,翻转后就不打印
{
pData[y*lWidthBmp + x] |= (0xff >> n);
}
}
pData[y*lWidthBmp + x] = ~pData[y*lWidthBmp + x]; // 黑白翻转
Write(pData + y*lWidthBmp + x, 1L);
}
}
}
delete pData;
if (_bCenter)
{
Write((BYTE*)"\x1B\x61\x00", 3L); // 恢复左对齐
}
Feed(1); // 空行
Write((BYTE*)"\x1B\x32", 2L); // 恢复默认行间距
}
}