EPSON热敏打印机通过POSDLL调用POS_PreDownloadBmpToRAM、POS_S_PrintBmpInRAM函数实现电影票等单色位图的二维码打印,而在转换单色位图后,需将图像信息头中的位图点阵图使用的调色板颜色数(10)及指定重要的颜色数(11)设置为0;同时,点阵图资料大小为(7)为(2)。
- size:4 bytes,0x28 = 40 bytes,表示Info Header的大长度总共 40 bytes
- width:4 bytes,0x10 = 16,图像宽度为16 pixel
- height:4 bytes,0x10 = 16,图像高度为16 pixel
- planes:2 bytes,0x01 = 1,位元面数为1
- bits:2 bytes,0x20 = 32,每個pixel需要32bits
- compression:4 bytes,0代表不压缩
- imagesize:4 bytes,0x400 = 1024 bytes,点阵图资料大小为1024 bytes
- xresolution:4 bytes,水平解析度
- yresolution:4 bytes,垂直解析度
- ncolours:4 bytes,点阵图使用的调色板颜色数
- importantcolours:4 bytes,重要的颜色数
图片引用自《http://blog.csdn.net/o_sun_o/article/details/8351037》。
具体操作方法为:
/// <summary>
/// 生成二维码代码
/// </summary>
/// <param name="txt_qr">需要生成二维码的信息</param>
/// <param name="txt_size">值越大生成的二维码图片像素越高</param>
/// <returns>二维码图片的信息</returns>
private static string generateQRCode(string txt_qr, string txt_size)
{
//生成二维码
string filepath = string.Empty;
string qrEncoding = "Byte";
string Level = "M";
string txt_ver = "0";
QRCodeEncoder qrCodeEncoder = new QRCodeEncoder();
String encoding = qrEncoding;
if (encoding == "Byte")
{
qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;
}
else if (encoding == "AlphaNumeric")
{
qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.ALPHA_NUMERIC;
}
else if (encoding == "Numeric")
{
qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.NUMERIC;
}
string errorCorrect = Level;
if (errorCorrect == "L")
qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.L;
else if (errorCorrect == "M")
qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M;
else if (errorCorrect == "Q")
qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.Q;
else if (errorCorrect == "H")
qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.H;
try
{
int scale = Convert.ToInt16(txt_size);
qrCodeEncoder.QRCodeScale = scale;///大小(值越大生成的二维码图片像素越高)
int version = Convert.ToInt16(txt_ver);
qrCodeEncoder.QRCodeVersion = version;
String data = txt_qr;
Bitmap image = qrCodeEncoder.Encode(data);
int image_Width = image.Width;
int image_Height = image.Height;
Bitmap resizedBmp = new Bitmap(image_Width + 4, image_Height + 4);
Graphics g = Graphics.FromImage(resizedBmp);
g.Clear(Color.White);//用背景色刷新
// Create rectangle for displaying image.
Rectangle destRect = new Rectangle(2, 2, image_Width, image_Height);
// Create rectangle for source image.
Rectangle srcRect = new Rectangle(0, 0, image_Width, image_Height);
// Draw image to screen.
g.DrawImage((Image)image, destRect, srcRect, GraphicsUnit.Pixel); g.Dispose();
filepath = ConvertToBpp(resizedBmp);
resizedBmp.Dispose();
image.Dispose();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "信息提示");
}
return filepath;
}
/// <summary>
/// 转换单色位图的方法
/// </summary>
/// <param name="img"></param>
private static Bitmap xxx(Bitmap img)
{
int w = img.Width;
int h = img.Height;
Bitmap bmp = new Bitmap(w, h, PixelFormat.Format1bppIndexed);
BitmapData data = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);
for (int y = 0; y < h; y++)
{
byte[] scan = new byte[(w + 7) / 8];
for (int x = 0; x < w; x++)
{
Color c = img.GetPixel(x, y);
if (c.GetBrightness() >= 0.5) scan[x / 8] |= (byte)(0x80 >> (x % 8));
}
Marshal.Copy(scan, 0, (IntPtr)((int)data.Scan0 + data.Stride * y), scan.Length);
}
bmp.Palette = CreateGrayscalePalette();
return bmp;
}
/// 创建图像格式对应的调色板
/// </summary>
/// <param name="pixelFormat">图像格式,只能是Format1bppIndexed,Format1bppIndexed,Format1bppIndexed</param>
/// <returns>返回调色板;如果创建失败或者图像格式不支持,返回null。</returns>
private static ColorPalette CreateColorPalette(PixelFormat pixelFormat)
{
ColorPalette palette = null;
if (pixelFormat == PixelFormat.Format1bppIndexed || pixelFormat == PixelFormat.Format4bppIndexed || pixelFormat == PixelFormat.Format8bppIndexed)
{
//因为ColorPalette类没有构造函数,所以这里创建一个1x1的位图,然后抓取该位图的调色板
Bitmap temp = new Bitmap(1, 1, pixelFormat);
palette = temp.Palette;
temp.Dispose();
}
return palette;
}
/// <summary>
/// 根据颜色深度,创建对应的调色板
/// </summary>
/// <param name="depth">颜色深度,即表示颜色所用的位数</param>
/// <returns>返回调色板</returns>
private static ColorPalette CreateColorPalette(int depth)
{
//根据颜色数,决定使用什么样的调色板
PixelFormat pixelFormat = PixelFormat.Format1bppIndexed;
if (depth > 2)
pixelFormat = PixelFormat.Format4bppIndexed;
if (depth > 16)
pixelFormat = PixelFormat.Format8bppIndexed;
return CreateColorPalette(pixelFormat);
}
/// <summary>
/// 创建单色灰度调色板
/// </summary>
/// <returns>返回调色板</returns>
private static ColorPalette CreateGrayscalePalette()
{
ColorPalette palette = CreateColorPalette(PixelFormat.Format1bppIndexed);
palette.Entries[0] = Color.FromArgb(0, 0, 0, 0);
palette.Entries[1] = Color.FromArgb(0, 255, 255, 255);
return palette;
}
/**
* byte数组中取int数值,本方法适用于(低位在前,高位在后)的顺序。
*
* @param ary
* byte数组
* @param offset
* 从数组的第offset位开始
* @return int数值
*/
private static int bytesToInt(byte[] ary, int offset)
{
int value;
value = (int)((ary[offset] & 0xFF)
| ((ary[offset + 1] << 8) & 0xFF00)
| ((ary[offset + 2] << 16) & 0xFF0000)
| ((ary[offset + 3] << 24) & 0xFF000000));
return value;
}
/// <summary>
/// 转换为单色位图后,图像信息头中的位图使用的颜色数及指定重要的颜色数设置为0
/// </summary>
/// <param name="img"></param>
/// <returns></returns>
private static string ConvertToBpp(Bitmap bitMap)
{
//打开任一索引色的或者非索引色的图像
Bitmap bm = xxx(bitMap);
MemoryStream ms = new MemoryStream();
bm.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
byte[] buffer = new byte[ms.Length];
//Image.Save()会改变MemoryStream的Position,需要重新Seek到Begin
ms.Seek(0, SeekOrigin.Begin);
ms.Read(buffer, 0, buffer.Length);
byte[] bitLenght = new byte[4];
Array.Copy(buffer, 2, bitLenght, 0, 4);
int ibitlen = bytesToInt(bitLenght, 0);
//byte[] bitBuffer = new byte[2];
//bitBuffer[0] = 0x2C;
//bitBuffer[1] = 0x04;
//Array.Copy(bitBuffer, 0, buffer, 34, 2);
Array.Copy(bitLenght, 0, buffer, 34, 4);
byte[] bitmapBuffer = new byte[1];
bitmapBuffer[0] = 0;
Array.Copy(bitmapBuffer, 0, buffer, 46, 1);
Array.Copy(bitmapBuffer, 0, buffer, 50, 1);
FileStream fs = null;
string file = Guid.NewGuid().ToString().Replace("-","").ToString() + ".bmp";
//将待写的入数据从字符串转换为字节数组
fs = File.OpenWrite(file);
//设定书写的开始位置为文件的末尾
fs.Position = 0;//fs.Length
//将待写入内容追加到文件末尾
fs.Write(buffer, 0, ibitlen);
fs.Close();
bm.Dispose();
return file;
}