在前段時間做了一下列印,因為需要支持的格式比較多,所以wpf能列印的有限分享一下幾種格式的列印(.xls .xlsx .doc .docx .png .jpg .bmp .pdf) 首先為了保證excel和word的格式問題,excel和word是調用的office進行列印的。 獲取所有印表機的方法 ...
在前段時間做了一下列印,因為需要支持的格式比較多,所以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群。