WPF实战案例-打印

在前段时间做了一下打印,因为需要支持的格式比较多,所以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群。
posted @ 2019-01-09 10:57 未雨先惆 阅读(...) 评论(...) 编辑 收藏
经典WPF源码共享,技术交流群总群:C#/WPF技术交流      经典WPF源码共享,技术交流群一群:C#/WPF技术交流     经典WPF源码共享,技术交流群二群:C#/WPF技术交流