using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
namespace libEShangPB
{
///
/// CLR版本 :4.0.30319.42000
/// 命名空间 :TouchCashier.WorkUtils.Print
/// 文件名称 :PrintDeviceHelper.cs
/// 小票打印机处理类
/// 创 建 者 :liben
/// 创建日期 :2021/12/16 21:26:12
/// 最后修改者 :liben
/// 最后修改日期:2021/12/16 21:26:12
///
[ComVisible(false)]
internal class PrintDeviceHelper
{
#region 打印机参数
const uint GENERIC_READ = 0x80000000;
const uint GENERIC_WRITE = 0x40000000;
const uint FILE_ATTRIBUTE_NORMAL = 0x80;
const int OPEN_EXISTING = 3;
static string prnPort = "LPT1";
[StructLayout(LayoutKind.Sequential)]
private struct OVERLAPPED
{
int Internal;
int InternalHigh;
int Offset;
int OffSetHigh;
int hEvent;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode,
int lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile);
[DllImport("kernel32.dll ")]
private static extern bool WriteFile(int hFile, byte[] lpBuffer, int nNumberOfBytesToWrite,
ref int lpNumberOfBytesWritten, ref OVERLAPPED lpOverlapped);
[DllImport("kernel32.dll ")]
private static extern bool DefineDosDevice(int dwFlags, string lpDeviceName, string lpTargetPath);
[DllImport("kernel32.dll ")]
private static extern bool CloseHandle(int hObject);
[DllImport("kernel32.dll ")]
private static extern bool ReadFile(int hFile, byte[] lpBuffer, int nNumberOfBytesToRead,
ref int lpNumberOfBytesRead, int lpOverlapped);
#endregion
#region 方法 -> LPT打印票据信息
///
/// LPT打印票据信息
///
/// 待打印内容列表
/// 打印份数
/// 票尾走纸行数
/// 是否开钱箱
///
public static bool PrintList(List PrintList, int PrintCount = 1, int PaperLine = 6, bool IsOpenBox = true)
{
if (PrintList.Count == 0)
{
return false;
}
try
{
IntPtr iHandle = CreateFile(prnPort, 0x40000000, 0, 0, OPEN_EXISTING, 0, 0);
using (SafeFileHandle _SafeFileHandle = new SafeFileHandle(iHandle, true))
{
if (iHandle.ToInt32() == -1)
{
return false;
}
else
{
FileStream fs_Print = new FileStream(_SafeFileHandle, FileAccess.ReadWrite);
if (IsOpenBox)
{
//发送开钱箱指令
char[] _open = { (char)27, (char)112, (char)0, (char)32, (char)160 };
byte[] _byte = Encoding.Default.GetBytes(_open);
fs_Print.Write(_byte, 0, _byte.Length);
}
string str_Print = $"{(char)27}{(char)64}{(char)27}{(char)33}{(char)0}";
for (int i = 0; i < PrintCount; i++)
{
foreach (string str_Temp in PrintList)
{
str_Print += str_Temp + "\n";
}
str_Print += $"{(char)27}{(char)64}{(char)27}{(char)33}{(char)0}";
for (int p = 0; p < PaperLine; p++)
{
str_Print += "\n";
}
}
byte[] byte_Print = Encoding.Default.GetBytes(str_Print);
fs_Print.Write(byte_Print, 0, byte_Print.Length);
fs_Print.Close();
}
return true;
}
}
catch
{
return false;
}
}
#endregion
#region 方法 -> LPT打印机开钱箱
///
/// LPT打印机开钱箱
///
///
public static bool LptOpenBox()
{
try
{
IntPtr iHandle = CreateFile(prnPort, 0x40000000, 0, 0, OPEN_EXISTING, 0, 0);
using (SafeFileHandle _SafeFileHandle = new SafeFileHandle(iHandle, true))
{
if (iHandle.ToInt32() == -1)
{
return false;
}
else
{
FileStream fs = new FileStream(_SafeFileHandle, FileAccess.ReadWrite);
char[] _open = { (char)27, (char)112, (char)0, (char)32, (char)160 };
byte[] _byte = Encoding.Default.GetBytes(_open);
fs.Write(_byte, 0, _byte.Length);
fs.Close();
}
return true;
}
}
catch
{
return false;
}
}
#endregion
#region 方法 -> LPT打印图片
///
/// 打印图片方法
///
///
public static bool PrintQRCode(Bitmap bmpQRcode)
{
IntPtr iHandle = CreateFile(prnPort, 0x40000000, 0, 0, OPEN_EXISTING, 0, 0);
using (SafeFileHandle _SafeFileHandle = new SafeFileHandle(iHandle, true))
{
if (iHandle.ToInt32() == -1)
{
return false;
//throw new Exception("没有连接打印机或者打印机端口不是LPT1");
}
else
{
OVERLAPPED x = new OVERLAPPED();
int y = 0;
//设置字符行间距为n点行
//byte[] data = new byte[] { 0x1B, 0x33, 0x00 };
string send = "" + (char)(27) + (char)(51) + (char)(0);
byte[] data = new byte[send.Length];
for (int i = 0; i < send.Length; i++)
{
data[i] = (byte)send[i];
}
WriteFile(iHandle.ToInt32(), data, data.Length, ref y, ref x);
//Write(data);
data[0] = (byte)'\x00';
data[1] = (byte)'\x00';
data[2] = (byte)'\x00'; // Clear to Zero.
Color pixelColor;
//ESC * m nL nH d1…dk 选择位图模式
// ESC * m nL nH
byte[] escBmp = new byte[] { 0x1B, 0x2A, 0x00, 0x00, 0x00 };
escBmp[2] = (byte)'\x21';
//nL, nH
escBmp[3] = (byte)(bmpQRcode.Width % 256);
escBmp[4] = (byte)(bmpQRcode.Width / 256);
//循环图片像素打印图片
//循环高
for (int i = 0; i < (bmpQRcode.Height / 24 + 1); i++)
{
//设置模式为位图模式
WriteFile(iHandle.ToInt32(), escBmp, escBmp.Length, ref y, ref x);
//循环宽
for (int j = 0; j < bmpQRcode.Width; j++)
{
for (int k = 0; k < 24; k++)
{
if (((i * 24) + k) < bmpQRcode.Height) // if within the BMP size
{
pixelColor = bmpQRcode.GetPixel(j, (i * 24) + k);
if (pixelColor.R == 0)
{
data[k / 8] += (byte)(128 >> (k % 8));
}
}
}
//一次写入一个data,24个像素
WriteFile(iHandle.ToInt32(), data, data.Length, ref y, ref x);
data[0] = (byte)'\x00';
data[1] = (byte)'\x00';
data[2] = (byte)'\x00'; // Clear to Zero.
}
//换行,打印第二行
byte[] data2 = { 0xA };
WriteFile(iHandle.ToInt32(), data2, data2.Length, ref y, ref x);
} // data
byte[] data3 = new byte[] { 0x1B, 0X32, 0xA, 0xA, 0xA, 0xA };
WriteFile(iHandle.ToInt32(), data3, data3.Length, ref y, ref x);
CloseHandle(iHandle.ToInt32());
}
return true;
}
}
#endregion
#region 方法 -> 设置打印字体大小
///
/// 设置打印字体大小
///
/// 字体放大倍数,0为默认大小
/// 字体是否加粗
///
public static string SetPrintFontSize(int multiple, bool bold = false)
{
if (multiple < 0)
{
multiple = 0;
}
int int_FontSize = multiple * 16;
string str_FontSize = $"{(char)27}{(char)33}{(char)int_FontSize}";
if (bold)
{
str_FontSize += $"{(char)27}{(char)69}{(char)15}";
}
else
{
str_FontSize += $"{(char)27}{(char)69}{(char)0}";
}
return str_FontSize;
}
#endregion
#region 方法 -> 选择/取消下划线模式
///
/// 选择/取消下划线模式
///
/// 下划线宽度,可选:
/// 0:取消下划线模式
/// 1:选择下划线模式(1 点宽)
/// 2:选择下划线模式(2 点宽)
///
public static string SetPrintCharacter(int multiple)
{
if (multiple < 0)
{
multiple = 0;
}
return $"{(char)27}{(char)45}{(char)multiple}";
}
#endregion
#region 方法 -> 生成两侧对齐行
///
/// 生成两侧对齐行
///
/// 左侧字符字符串
/// 右侧字符串
/// 填充的字符
/// 行长度
///
public static string CreateSideLine(string leftString, string rightString, char paddingChar = ' ', int lineLength = 32)
{
try
{
int i_Len = lineLength - StringLength(leftString) - StringLength(rightString);
return leftString + rightString.PadLeft(i_Len + rightString.Length, paddingChar);
}
catch
{
return leftString + rightString;
}
}
#endregion
#region 方法 -> 生成居中行
///
/// 生成居中对齐行
///
/// 居中字符串
/// 填充的字符
/// 行长度
///
public static string CreateCenterLine(string centerString, char paddingChar = ' ', int lineLength = 32)
{
try
{
int i_Len = (lineLength - StringLength(centerString)) / 2;
return centerString.PadLeft(i_Len + centerString.Length, paddingChar);
}
catch
{
return centerString;
}
}
#endregion
#region 方法 -> 生成左对齐行
///
/// 生成左对齐行
///
/// 需要左对齐的文本
/// 填充的字符
/// 单行字符字节长度
///
public static string CreateLeftLine(string leftString, char paddingChar = ' ', int lineLength = 32)
{
try
{
int i_Len = lineLength - StringLength(leftString);
return leftString.PadRight(i_Len + leftString.Length, paddingChar);
}
catch
{
return leftString;
}
}
#endregion
#region 方法 -> 生成右对齐行
///
/// 生成右对齐行
///
/// 需要右对齐的文本
/// 填充的字符
/// 单行字符字节长度
///
public static string CreateRightLine(string rightString, char paddingChar = ' ', int lineLength = 32)
{
try
{
int i_Len = lineLength - StringLength(rightString);
return rightString.PadLeft(i_Len + rightString.Length, paddingChar);
}
catch
{
return rightString;
}
}
#endregion
#region 方法 -> 计算字符串字节长度
///
/// 计算字符串字节长度
///
/// 待计算字符串
///
private static int StringLength(string calculateString)
{
if (string.IsNullOrEmpty(calculateString))
{
return 0;
}
//计算得到该字符串对应单字节字符串的长度
return Regex.Replace(calculateString, @"[^\x00-\xff]", "aa").Length;
}
#endregion
}
}