2025-03-28 09:49:56 +08:00

388 lines
15 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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));
}
}
}
//一次写入一个data24个像素
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
}
}