在前段时间做了一下打印,因为需要支持的格式比较多,所以wpf能打印的有限分享一下几种格式的打印(.xls .xlsx .doc .docx .png .jpg .bmp .pdf)
首先为了保证excel和word的格式问题,excel和word是调用的office进行打印的。
获取所有打印机的方法:
LocalPrintServer print = new LocalPrintServer(); var printers = print.GetPrintQueues(); foreach (var item in printers) { //打印机名称 item.Name; }
Excel打印。三个参数 :1.打印机名称 2要打印的文件路径+名称 3要打印的sheet页名称(可以不写就打印全部sheet)
static Excel.Application Application { get; set; } public static void PrintExcel(string printName, string fileName, List<string> sheetNames = null) { if (Application == null) Application = new Excel.Application(); Application.Visible = false; //Application.Calculation = Excel.XlCalculation.xlCalculationManual; var book = Application.Workbooks.Open(fileName); if (sheetNames == null) { sheetNames = new List<string>(); Excel.Sheets sheets = book.Sheets; for (int i = 1; i <= sheets.Count; i++) { Excel.Worksheet workSheet = sheets.Item[i]; if (workSheet.Visible != Excel.XlSheetVisibility.xlSheetHidden) sheetNames.Add(workSheet.Name); } } foreach (var item in sheetNames) { Excel.Worksheet workSheet = (Excel.Worksheet)book.Worksheets[item]; //------------------------打印页面相关设置-------------------------------- workSheet.PageSetup.PaperSize = Excel.XlPaperSize.xlPaperA4;//纸张大小 //workSheet.PageSetup.Orientation = Excel.XlPageOrientation.xlLandscape;//页面横向 workSheet.PageSetup.Zoom = 75; //打印时页面设置,缩放比例百分之几 workSheet.PageSetup.Zoom = false; //打印时页面设置,必须设置为false,页高,页宽才有效 workSheet.PageSetup.FitToPagesWide = 1; //设置页面缩放的页宽为1页宽 workSheet.PageSetup.FitToPagesTall = false; //设置页面缩放的页高自动 //workSheet.PageSetup.LeftHeader = "Nigel";//页面左上边的标志 //workSheet.PageSetup.CenterFooter = "第 &P 页,共 &N 页";//页面下标 workSheet.PageSetup.FirstPageNumber = (int)Excel.Constants.xlAutomatic; workSheet.PageSetup.Order = Excel.XlOrder.xlDownThenOver; workSheet.PageSetup.PrintGridlines = true; //打印单元格网线 workSheet.PageSetup.TopMargin = 1.5 / 0.035; //上边距为2cm(转换为in) workSheet.PageSetup.BottomMargin = 1.5 / 0.035; //下边距为1.5cm workSheet.PageSetup.LeftMargin = 2 / 0.035; //左边距为2cm workSheet.PageSetup.RightMargin = 2 / 0.035; //右边距为2cm workSheet.PageSetup.CenterHorizontally = true; //文字水平居中 //------------------------打印页面设置结束-------------------------------- workSheet.PrintOutEx(Missing.Value, Missing.Value, Missing.Value, Missing.Value, printName); } //book.PrintOutEx(Missing.Value, Missing.Value, Missing.Value, Missing.Value, printName); //直接打印 book.Close(false); //关闭工作空间 }
excel有时候关不干净,贡献一个强制关闭的方法,可以在excel操作完成后调用:
[DllImport("User32.dll")] public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int Processid); public static void ExcelClose() { if (Application != null) { Application.Quit(); int iId = 0; IntPtr intptr = new IntPtr(Application.Hwnd); System.Diagnostics.Process p = null; try { GetWindowThreadProcessId(intptr, out iId); p = System.Diagnostics.Process.GetProcessById(iId); if (p != null) { p.Kill(); p.Dispose(); } Application = null; } catch (Exception e) { throw e; } } System.GC.Collect(); }
Word打印(打印机名称,要打印的文件路径+名称)
public static void PrintWord(string printName, string fileName) { Word.Application appword = new Word.Application(); appword.Visible = false; appword.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone; Word.Document doc = appword.Documents.Open(fileName); appword.ActivePrinter = printName; doc.PrintOut(true); doc.Close(false); appword.Quit(); }
图片打印WPF(支持格式 png jpg bmp)
public static string PrintImage(string printName, string fileName) { System.Windows.Controls.PrintDialog dialog = new System.Windows.Controls.PrintDialog();//开始打印 var printers = new LocalPrintServer().GetPrintQueues(); var selectedPrinter = printers.FirstOrDefault(d => d.Name == printName); if (selectedPrinter == null) { return "没有找到打印机"; } dialog.PrintQueue = selectedPrinter; dialog.PrintDocument(new TestDocumentPaginator(new BitmapImage(new Uri(fileName))), "Image"); return ""; }
public class TestDocumentPaginator : DocumentPaginator { #region 字段 private Size _pageSize; private ImageSource image; #endregion #region 构造 public TestDocumentPaginator(BitmapImage img) { image = img; //我们使用A3纸张大小 var pageMediaSize = LocalPrintServer.GetDefaultPrintQueue() .GetPrintCapabilities() .PageMediaSizeCapability .FirstOrDefault(x => x.PageMediaSizeName == PageMediaSizeName.ISOA4); if (pageMediaSize != null) { _pageSize = new Size((double)pageMediaSize.Width, (double)pageMediaSize.Height); } } #endregion #region 重写 /// <summary> /// /// </summary> /// <param name="pageNumber">打印页是从0开始的</param> /// <returns></returns> public override DocumentPage GetPage(int pageNumber) { var visual = new DrawingVisual(); using (DrawingContext dc = visual.RenderOpen()) { double imgWidth = 0; double imgHeight = 0; if (image.Height > _pageSize.Height) { double h = _pageSize.Height / image.Height; imgWidth = image.Width * h; imgHeight = image.Height * h; } if (image.Width > _pageSize.Width) { double w = _pageSize.Width / image.Width; imgWidth = image.Width * w; imgHeight = image.Height * w; } if (image.Width < _pageSize.Width && image.Height < _pageSize.Height) { double h = _pageSize.Height / image.Height; double w = _pageSize.Width / image.Width; if (h > w) { imgWidth = image.Width * w; imgHeight = image.Height * w; } else { imgWidth = image.Width * h; imgHeight = image.Height * h; } } double left = Math.Abs((_pageSize.Width - imgWidth) <= 0 ? 2 : (_pageSize.Width - imgWidth)) / 2; double top = Math.Abs((_pageSize.Height - imgHeight) <= 0 ? 2 : (_pageSize.Height - imgHeight)) / 2; dc.DrawImage(image, new Rect(left, top, imgWidth, imgHeight)); } return new DocumentPage(visual, _pageSize, new Rect(_pageSize), new Rect(_pageSize)); } public override bool IsPageCountValid { get { return true; } } public override Size PageSize { get { return _pageSize; } set { _pageSize = value; } } public override IDocumentPaginatorSource Source { get { return null; } } public override int PageCount { get { return 1; } } #endregion }
TestDocumentPaginator内部的重写方法是计算将图片全部居中显示。
关于图片打印多说一句:在之前我是使用image加载图片,然后通过PrintVisual打印控件的方式打印的,但是这种方式我发现在win7机器上打印出来的是空白纸张,还没明白是为什么,所以就用这种方式了。
PDF打印(这是调用windows api去打印,不需要乱起八糟的第三方):
// 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. public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount) { Int32 dwError = 0, dwWritten = 0; IntPtr hPrinter = new IntPtr(0); DOCINFOA di = new DOCINFOA(); bool bSuccess = false; // Assume failure unless you specifically succeed. di.pDocName = "My C#.NET RAW Document"; di.pDataType = "RAW"; // Open the printer. if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero)) { // Start a document. if (StartDocPrinter(hPrinter, 1, 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; } public 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(0); 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, 0, 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 SendStringToPrinter(string szPrinterName, string szString) { IntPtr pBytes; Int32 dwCount; // How many characters are in the string? dwCount = szString.Length; // Assume that the printer is expecting ANSI text, and then convert // the string to ANSI text. pBytes = Marshal.StringToCoTaskMemAnsi(szString); // Send the converted ANSI string to the printer. SendBytesToPrinter(szPrinterName, pBytes, dwCount); Marshal.FreeCoTaskMem(pBytes); return true; } public static void PrintPDF(string printName, string fileName) { SendFileToPrinter(printName, fileName); }
以上就是wpf常用的打印,目前看起来格式还是可以达到要求的,更多技术讨论请关注页面下方的qq群。