c# 在进行小票打印时大致有三种方法。
1. 使用水晶报表进行打印。可以参考:https://www.cnblogs.com/aitong/p/10717786.html
2. 在 PrintDocument 对象上进行绘图,然后使用其打印方法直接打印。
using CrystalDecisions.CrystalReports.Engine;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Printing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms; namespace CrTest
{
public partial class Form1 : Form
{
string title = "标题标题标题标题标题标题标题标题标题标题标题";
public Form1()
{
InitializeComponent();
} private void button1_Click(object sender, EventArgs e)
{
//打印预览
PrintPreviewDialog ppd = new PrintPreviewDialog();
PrintDocument pd = new PrintDocument();
//设置边距
Margins margin = new Margins(, , , );
pd.DefaultPageSettings.Margins = margin;
int height = ;
if (title.Length > )
{
height = ;
}
//纸张设置默认
PaperSize pageSize = new PaperSize("First custom size", (int)( * / 25.4), height);//58mm 转绘图宽度
pd.DefaultPageSettings.PaperSize = pageSize;
//打印事件设置
pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);
ppd.Document = pd;
ppd.ShowDialog();
//try
//{
// pd.Print();
//}
//catch (Exception ex)
//{
// MessageBox.Show(ex.Message, "打印出错", MessageBoxButtons.OK, MessageBoxIcon.Error);
// pd.PrintController.OnEndPrint(pd, new PrintEventArgs());
//}
} private void pd_PrintPage(object sender, PrintPageEventArgs e)
{
Font font = new Font("Arial", , System.Drawing.FontStyle.Regular);
string text = title;
int yLocation = e.MarginBounds.Y;
int center = e.PageSettings.PaperSize.Width / ;
int heightStep = ;
while (text.Length > )
{
string printStr;
if (text.Length > )
{
printStr = text.Substring(, );
text = text.Substring();
}
else
{
printStr = text;
text = "";
}
SizeF size = e.Graphics.MeasureString(printStr, font);
heightStep =Convert.ToInt32( size.Height * 1.3);
e.Graphics.DrawString(printStr, font, System.Drawing.Brushes.Black, center - size.Width / , yLocation);
yLocation += heightStep;
}
}
}
}
3. 使用 ESC/POS 控制指令
注意 SendStringToPrinter 这个接口。
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
//https://www.cnblogs.com/QiuTianBaBa/p/6730829.html
//https://blog.csdn.net/andrewniu/article/details/80353655
namespace Evet2Basic.Model.Print.Report
{
public class RawPrint
{
// Structure and API declarions:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOCINFOA
{
[MarshalAs(UnmanagedType.LPStr)]
public string pDocName;
[MarshalAs(UnmanagedType.LPStr)]
public string pOutputFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pDataType;
}
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd); [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di); [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten); // SendBytesToPrinter()
// When the function is given a printer name and an unmanaged array
// of bytes, the function sends those bytes to the print queue.
// Returns true on success, false on failure.
private static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
{
Int32 dwError = , dwWritten = ;
IntPtr hPrinter = new IntPtr();
DOCINFOA di = new DOCINFOA();
bool bSuccess = false; // Assume failure unless you specifically succeed. di.pDocName = "XiaoPiao";
di.pDataType = "RAW"; // Open the printer.
if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
{
// Start a document.
if (StartDocPrinter(hPrinter, , di))
{
// Start a page.
if (StartPagePrinter(hPrinter))
{
// Write your bytes.
bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
EndPagePrinter(hPrinter);
}
EndDocPrinter(hPrinter);
}
ClosePrinter(hPrinter);
}
// If you did not succeed, GetLastError may give more information
// about why not.
if (bSuccess == false)
{
dwError = Marshal.GetLastWin32Error();
}
return bSuccess;
} private static bool SendFileToPrinter(string szPrinterName, string szFileName)
{
// Open the file.
FileStream fs = new FileStream(szFileName, FileMode.Open);
// Create a BinaryReader on the file.
BinaryReader br = new BinaryReader(fs);
// Dim an array of bytes big enough to hold the file's contents.
Byte[] bytes = new Byte[fs.Length];
bool bSuccess = false;
// Your unmanaged pointer.
IntPtr pUnmanagedBytes = new IntPtr();
int nLength; nLength = Convert.ToInt32(fs.Length);
// Read the contents of the file into the array.
bytes = br.ReadBytes(nLength);
// Allocate some unmanaged memory for those bytes.
pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
// Copy the managed byte array into the unmanaged array.
Marshal.Copy(bytes, , pUnmanagedBytes, nLength);
// Send the unmanaged bytes to the printer.
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
// Free the unmanaged memory that you allocated earlier.
Marshal.FreeCoTaskMem(pUnmanagedBytes);
return bSuccess;
} public static bool SendBytesToPrinter(string szPrinterName, byte[] buf)
{
bool bSuccess = false;
// Your unmanaged pointer.
IntPtr pUnmanagedBytes = new IntPtr();
// Allocate some unmanaged memory for those bytes.
pUnmanagedBytes = Marshal.AllocCoTaskMem(buf.Length);
// Copy the managed byte array into the unmanaged array.
Marshal.Copy(buf, , pUnmanagedBytes, buf.Length);
// Send the unmanaged bytes to the printer.
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, buf.Length);
// Free the unmanaged memory that you allocated earlier.
Marshal.FreeCoTaskMem(pUnmanagedBytes);
return bSuccess;
} /// <summary>
/// 切纸
/// </summary>
/// <param name="szPrinterName">打印机名</param>
/// <returns></returns>
public static bool Cut(string szPrinterName)
{
bool bSuccess = false; IntPtr pUnmanagedBytes = new IntPtr(); byte[] data = new byte[] { 0x1B, 0x69 };
pUnmanagedBytes = Marshal.AllocCoTaskMem(data.Length);
Marshal.Copy(data, , pUnmanagedBytes, data.Length);
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, data.Length);
Marshal.FreeCoTaskMem(pUnmanagedBytes);
return true;
} public static bool SendBytesToPrinterImg(string szPrinterName, Bitmap bmp, bool needWarning)
{
bool bSuccess = false; //Byte[] byte_send = Encoding.GetEncoding("GB2312").GetBytes("\x1b\x40");
IntPtr pUnmanagedBytes = new IntPtr();
//pUnmanagedBytes = Marshal.AllocCoTaskMem(byte_send.Length);
//Marshal.Copy(byte_send, 0, pUnmanagedBytes, byte_send.Length);
//bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, byte_send.Length);
//Marshal.FreeCoTaskMem(pUnmanagedBytes); byte[] data = new byte[] { 0x1B, 0x33, 0x00 };
//pUnmanagedBytes = new IntPtr(0);
pUnmanagedBytes = Marshal.AllocCoTaskMem(data.Length);
Marshal.Copy(data, , pUnmanagedBytes, data.Length);
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, data.Length);
Marshal.FreeCoTaskMem(pUnmanagedBytes);
data[] = (byte)'\x00';
data[] = (byte)'\x00';
data[] = (byte)'\x00'; Color pixelColor; // ESC * m nL nH 点阵图
byte[] escBmp = new byte[] { 0x1B, 0x2A, 0x00, 0x00, 0x00 };
escBmp[] = (byte)'\x21';
//nL, nH
escBmp[] = (byte)(bmp.Width % );
escBmp[] = (byte)(bmp.Width / ); // data
for (int i = ; i < (bmp.Height / ) + ; i++)
{
//pUnmanagedBytes = new IntPtr(0);
pUnmanagedBytes = Marshal.AllocCoTaskMem(escBmp.Length);
Marshal.Copy(escBmp, , pUnmanagedBytes, escBmp.Length);
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, escBmp.Length);
Marshal.FreeCoTaskMem(pUnmanagedBytes); byte[] temptype = new byte[bmp.Width * ];
int lengthNow = ;
for (int j = ; j < bmp.Width; j++)
{
for (int k = ; k < ; k++)
{
if (((i * ) + k) < bmp.Height) // if within the BMP size
{
pixelColor = bmp.GetPixel(j, (i * ) + k);
if (pixelColor.R == )
{
data[k / ] += (byte)( >> (k % ));
}
}
}
data.CopyTo(temptype, lengthNow);
lengthNow += ; data[] = (byte)'\x00';
data[] = (byte)'\x00';
data[] = (byte)'\x00';
} //pUnmanagedBytes = new IntPtr(0);
pUnmanagedBytes = Marshal.AllocCoTaskMem(temptype.Length);
Marshal.Copy(temptype, , pUnmanagedBytes, temptype.Length);
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, temptype.Length);
Marshal.FreeCoTaskMem(pUnmanagedBytes);
System.Threading.Thread.Sleep();
}
byte[] dataClear = new byte[] { 0x1B, 0x40 };
pUnmanagedBytes = Marshal.AllocCoTaskMem(dataClear.Length);
Marshal.Copy(dataClear, , pUnmanagedBytes, dataClear.Length);
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, dataClear.Length);
Marshal.FreeCoTaskMem(pUnmanagedBytes);
return bSuccess;
} public static bool SendStringToPrinter(string szPrinterName, string szString)
{
try
{
//指令见打印机官方文档 http://www.xprinter.net/index.php/Server/index/cid/3
byte[] smallArray = new byte[] { , , };
List<byte> list = new List<byte>(); list.AddRange(smallArray);
while (szString.Contains("<B>") || szString.Contains("<A>"))
{
if (!szString.Contains("<B>"))
{
ReplaceAB(ref szString, ref list, );
}
else if (!szString.Contains("<A>"))
{
ReplaceAB(ref szString, ref list, );
}
else
{
int indexA = szString.IndexOf("<A>");
int indexB = szString.IndexOf("<B>");
if (indexA < indexB)
{
ReplaceAB(ref szString, ref list, );
}
else
{
ReplaceAB(ref szString, ref list, );
}
}
}
Encoding enc = Encoding.GetEncoding("gb2312");
list.AddRange(enc.GetBytes(szString));
return RawPrint.SendBytesToPrinter(szPrinterName, list.ToArray());
}
catch (Exception)
{
return false;
}
} private static void ReplaceAB(ref string szString, ref List<byte> list, int mul)
{
//指令见打印机官方文档 http://www.xprinter.net/index.php/Server/index/cid/3
string replaceStr1 = "<B>";
string replaceStr2 = "</B>";
byte[] smallArray = new byte[] { , , };
byte[] bigArray = new byte[] { , , }; //放大三倍 //29, 33字体放大指令 34放大倍数 ( 0一倍 17两倍 34三倍 51四倍 68五倍 85六倍)
if (mul == )
{
replaceStr1 = "<A>";
replaceStr2 = "</A>";
bigArray = new byte[] { , , }; //放大两倍
}
Encoding enc = Encoding.GetEncoding("gb2312");
int index = szString.IndexOf(replaceStr1);
string first = szString.Substring(, index);
list.AddRange(enc.GetBytes(first));//第一段
list.AddRange(bigArray);//变成大写
szString = szString.Substring(index + );
int index2 = szString.IndexOf(replaceStr2);
string second = szString.Substring(, index2);
list.AddRange(enc.GetBytes(second));//大写段
list.AddRange(smallArray);//变小写
szString = szString.Substring(index2 + );
}
}
}