388 lines
15 KiB
C#
388 lines
15 KiB
C#
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
|
||
{
|
||
/// <summary>
|
||
/// CLR版本 :4.0.30319.42000
|
||
/// 命名空间 :TouchCashier.WorkUtils.Print
|
||
/// 文件名称 :PrintDeviceHelper.cs
|
||
/// <para>小票打印机处理类</para>
|
||
/// <para>创 建 者 :liben</para>
|
||
/// <para>创建日期 :2021/12/16 21:26:12 </para>
|
||
/// <para>最后修改者 :liben</para>
|
||
/// <para>最后修改日期:2021/12/16 21:26:12 </para>
|
||
/// </summary>
|
||
[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打印票据信息
|
||
/// <summary>
|
||
/// LPT打印票据信息
|
||
/// </summary>
|
||
/// <param name="PrintList">待打印内容列表</param>
|
||
/// <param name="PrintCount">打印份数</param>
|
||
/// <param name="PaperLine">票尾走纸行数</param>
|
||
/// <param name="IsOpenBox">是否开钱箱</param>
|
||
/// <returns></returns>
|
||
public static bool PrintList(List<string> 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打印机开钱箱
|
||
/// <summary>
|
||
/// LPT打印机开钱箱
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
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打印图片
|
||
/// <summary>
|
||
/// 打印图片方法
|
||
/// </summary>
|
||
/// <param name="bmpQRcode"></param>
|
||
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 方法 -> 设置打印字体大小
|
||
/// <summary>
|
||
/// 设置打印字体大小
|
||
/// </summary>
|
||
/// <param name="multiple">字体放大倍数,0为默认大小</param>
|
||
/// <param name="bold">字体是否加粗</param>
|
||
/// <returns></returns>
|
||
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 方法 -> 选择/取消下划线模式
|
||
/// <summary>
|
||
/// 选择/取消下划线模式
|
||
/// </summary>
|
||
/// <param name="multiple">下划线宽度,可选:
|
||
/// <para>0:取消下划线模式</para>
|
||
/// <para>1:选择下划线模式(1 点宽)</para>
|
||
/// <para>2:选择下划线模式(2 点宽)</para></param>
|
||
/// <returns></returns>
|
||
public static string SetPrintCharacter(int multiple)
|
||
{
|
||
if (multiple < 0)
|
||
{
|
||
multiple = 0;
|
||
}
|
||
return $"{(char)27}{(char)45}{(char)multiple}";
|
||
}
|
||
#endregion
|
||
|
||
#region 方法 -> 生成两侧对齐行
|
||
/// <summary>
|
||
/// 生成两侧对齐行
|
||
/// </summary>
|
||
/// <param name="leftString">左侧字符字符串</param>
|
||
/// <param name="rightString">右侧字符串</param>
|
||
/// <param name="paddingChar">填充的字符</param>
|
||
/// <param name="lineLength">行长度</param>
|
||
/// <returns></returns>
|
||
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 方法 -> 生成居中行
|
||
/// <summary>
|
||
/// 生成居中对齐行
|
||
/// </summary>
|
||
/// <param name="centerString">居中字符串</param>
|
||
/// <param name="paddingChar">填充的字符</param>
|
||
/// <param name="lineLength">行长度</param>
|
||
/// <returns></returns>
|
||
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 方法 -> 生成左对齐行
|
||
/// <summary>
|
||
/// 生成左对齐行
|
||
/// </summary>
|
||
/// <param name="leftString">需要左对齐的文本</param>
|
||
/// <param name="paddingChar">填充的字符</param>
|
||
/// <param name="lineLength">单行字符字节长度</param>
|
||
/// <returns></returns>
|
||
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 方法 -> 生成右对齐行
|
||
/// <summary>
|
||
/// 生成右对齐行
|
||
/// </summary>
|
||
/// <param name="rightString">需要右对齐的文本</param>
|
||
/// <param name="paddingChar">填充的字符</param>
|
||
/// <param name="lineLength">单行字符字节长度</param>
|
||
/// <returns></returns>
|
||
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 方法 -> 计算字符串字节长度
|
||
/// <summary>
|
||
/// 计算字符串字节长度
|
||
/// </summary>
|
||
/// <param name="calculateString">待计算字符串</param>
|
||
/// <returns></returns>
|
||
private static int StringLength(string calculateString)
|
||
{
|
||
if (string.IsNullOrEmpty(calculateString))
|
||
{
|
||
return 0;
|
||
}
|
||
//计算得到该字符串对应单字节字符串的长度
|
||
return Regex.Replace(calculateString, @"[^\x00-\xff]", "aa").Length;
|
||
}
|
||
#endregion
|
||
}
|
||
}
|