欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

WPF实战案例-打印

程序员文章站 2022-07-26 10:43:32
在前段时间做了一下打印,因为需要支持的格式比较多,所以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群。