C# 关于PrintDocument打印及预览实现【基于调研结果展开的应用】

//补充一些对于pdf组件的调研结果和心路历程
在这里插入图片描述

心得:
原生的能实现的就尽量用原生的,调研任务是针对于达到目的,而不是针对于如何使用。
首先不得不承认spire.pdf的强大,但是其收费限制也是挺恶心的。pdf页面转图片功能也是效率特别低的。恰好pdfiumViewer补足了这部分短板。spir.pdf打印也只能打印前三页。pdfiumViewer对于打印支持的内容太少了。恰好原生的pdfDocument补足了这块短板。其它也有调研,但大都发现需要代码做到开源。具体功能也都有部分限制。
一:spire.pdf组件的使用
这里使用spir.pdf处理了一些各类格式的文件转为pdf亦或是pdf合并等小功能点的实现。正因为如此。利用递归繁琐的处理也是可以跳过十页,三页的限制的。但是打印时会有断层。
二:pdfiumViewer组件的使用
注意pdfiumViewer是将pdf页面转为图片,值得注意的是:【转换后的图片有很大程度的失真效果】。
1、Method下面是通过调整分辨率,解决的失真方式。

public static List<string> PdfToJpg(string filePath, string saveDir, float dpiWidth = 1600, float dpiHeight = 900, bool isMax = true)
{
    if (string.IsNullOrWhiteSpace(filePath) || !File.Exists(filePath))
    {
        throw new ArgumentException("文件有误或不存在,请检查文件是否正确。");
    }

    List<string> imageLst = new List<string>();
    using (var document = PdfDocument.Load(filePath))
    {
        for (int i = 0; i < document.PageCount; i++)
        {
            var page = document.PageSizes[i];
            SizeF standardSize = new SizeF(dpiWidth, dpiHeight);
            float height = page.Height;

            //等比处理分辨率
            float scale = isMax ? Math.Max(standardSize.Width / page.Width, standardSize.Height / height) : Math.Min(standardSize.Width / page.Width, standardSize.Height / height);
            SizeF scaledSize = new SizeF(page.Width * scale, page.Height * scale);

            using (Image img = document.Render(i, (int)scaledSize.Width, (int)scaledSize.Height, (int)scaledSize.Width, (int)scaledSize.Height, true))
            {
                string jpgPath = Path.Combine(saveDir, $"{i + 1}.jpg");
                img.Save(jpgPath, ImageFormat.Jpeg);
                imageLst.Add(jpgPath);
            }
        }
    }
    return imageLst;
}

2、Method下面是一个主要的方法,可以实现对于pdf文件页面进行等分,转换为照片。

public List<string> cutPdfByPdfiumView(string fileStream, int copies, string outPdfPath)
{
    List<string> files = new List<string>();

    // 删除文件夹及其所有内容
    if (Directory.Exists(outPdfPath))
    {
        Directory.Delete(outPdfPath, true);
    }
    // 创建空文件夹
    Directory.CreateDirectory(outPdfPath);

    using (var document = PdfDocument.Load(fileStream))
    {
        for (int i = 0; i < document.PageCount; i++)
        {
            var page = document.PageSizes[i];
            SizeF standardSize = new SizeF(1600, 900);

            float top = 0, height = page.Height / copies;

            float scale = Math.Max(standardSize.Width / page.Width, standardSize.Height / height);
            SizeF scaledSize = new SizeF(page.Width * scale, page.Height * scale);

            using (var pageImage = document.Render(i, (int)scaledSize.Width, (int)scaledSize.Height, (int)scaledSize.Width, (int)scaledSize.Height, true))
            {
                height = scaledSize.Height / copies;
                for (int n = 0; n < copies; n++)
                {
                    using (Bitmap img = new Bitmap(pageImage.Width, (int)height))
                    {
                        using (Graphics graphics = Graphics.FromImage(img))
                        {
                            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                            graphics.SmoothingMode = SmoothingMode.HighQuality;
                            graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
                            graphics.DrawImage(pageImage
                                , new RectangleF(0, 0, img.Width, img.Height)
                                , new RectangleF(0, top, img.Width, img.Height), GraphicsUnit.Pixel);
                            top += img.Height;
                            if (IsImageBlank(img))
                            {
                                continue;
                            }
                            string filePath = Path.Combine(outPdfPath, $"{i + 1}-{n + 1}.png");
                            img.Save(filePath, ImageFormat.Png);

                            files.Add(filePath);
                        }
                    }
                }
            }
        }
    }
    return files;
}

下面是一个拓展的例子,对于页面进行随意切割

new BankReceiptCutDto("民生银行",false,0, new List<float>{ 715,60,715,60,715},@"\s交易流水号:\s*\d+[A-Z0-9]+\s*",new List<string>{ "交易流水号",":",":"},new char[]{':',':'}),

//流水号匹配数据
private readonly string regularTradeno = @"\s交易流水号:\s*\d+[A-Z0-9]+\s*";
private readonly List<string> strTradeno = new List<string>() { "交易流水号", ":", ":" };
private readonly char[] chrTradeno = new char[] { ':', ':' };

public List<BankBillFile> CutBankReceipt(string bankType, string fileStream)
{
    try
    {
        //先获取银行类型内置的处理逻辑
        BankReceiptCutDto match = ReceiptCutHelper.GetReceiptCutDto(bankType);

        if (match == null)
        {
            throw new ArgumentException("未获取到该银行类型的处理逻辑,必要时您可以联系客服寻求帮助。");
        }

        //处理后的回单文件
        List<BankBillFile> billFiles = new List<BankBillFile>();


        using (var document = PdfDocument.Load(fileStream))
        {
            for (int i = 0; i < document.PageCount; i++)
            {
                var page = document.PageSizes[i];
                SizeF standardSize = new SizeF(1600, 900);
                float top = 0, height = page.Height;

                //获取是等分还是按照长度分割
                int copies = match.isBisection ? match.copies : match.cutDistance.Count;

                height = page.Height / copies;

                //等比处理分辨率
                float scale = Math.Min(standardSize.Width / page.Width, standardSize.Height / height);
                SizeF scaledSize = new SizeF(page.Width * scale, page.Height * scale);

                #region "处理获取匹配信息"
                string txt = document.GetPdfText(i);
                //处理从里面获取需要的文字信息
                List<string> matchTradeNos = new List<string>();

                MatchCollection tradenoLst = Regex.Matches(txt, regularTradeno);
                if (tradenoLst == null || tradenoLst.Count <= 0)
                {
                    throw new ArgumentException("未获取到匹配数据,请确认导入文件是否正确,必要时您可以联系客服寻求帮助。");
                }
                for (int no = 0; no < tradenoLst.Count; no++)
                {
                    string TradenoStr = PdfiumViewerHelper.DealMatchText(tradenoLst[no].ToString(), strTradeno, chrTradeno);

                    matchTradeNos.Add(TradenoStr.Substring(0, 23));
                }
                #endregion

                using (var pageImage = document.Render(i, (int)scaledSize.Width, (int)scaledSize.Height, (int)scaledSize.Width, (int)scaledSize.Height, true))
                {
                    int noName = 0;
                    for (int n = 0; n < copies; n++)
                    {
                        float imgHeight = match.isBisection ? scaledSize.Height / copies : match.cutDistance[n];
                        using (Bitmap img = new Bitmap(pageImage.Width, (int)imgHeight))
                        {
                            using (Graphics graphics = Graphics.FromImage(img))
                            {
                                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                                graphics.SmoothingMode = SmoothingMode.HighQuality;
                                graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
                                graphics.DrawImage(pageImage
                                    , new RectangleF(0, 0, img.Width, img.Height)
                                    , new RectangleF(0, top, img.Width, img.Height), GraphicsUnit.Pixel);
                                top += imgHeight;

                                //去掉非回单页 虚线行等
                                if (!match.isBisection && img.Height != (int)match.cutDistance.Max())
                                {
                                    continue;
                                }
                                //去掉空白页
                                if (PdfiumViewerHelper.IsImageBlank(img))
                                {
                                    continue;
                                }

                                //以防万一 文件命名没名字
                                string pngName = $"{ i + 1 }-{ n + 1}";
                                if (matchTradeNos != null && matchTradeNos.Count >= noName + 1)
                                {
                                    //需要做一个受限 不然textLst越界
                                    pngName = matchTradeNos[noName];
                                    noName++;
                                }

                                byte[] ImgBt = PdfiumViewerHelper.ImageToByteArray(img, ImageFormat.Png);

                                BankBillFile bankBill = new BankBillFile()
                                {
                                    AccountId = GlobalParameter.AccountId,
                                    TradeNo = pngName,
                                    FileContent = ImgBt,
                                };
                                billFiles.Add(bankBill);

                            }
                        }
                    }
                }
            }
        }

        return billFiles;

    }
    catch (ArgumentException aex)
    {
        throw aex;
    }
    catch (Exception ex)
    {
        Logger.Error(ex.Message);
        throw new ArgumentException("民生银行回单处理有误请重试,必要时您可以联系客服寻求帮助。");
    }
}

三、对于图片或者pdf进行打印操作。
具体想打印什么,都可以通用,比较繁琐罢了,避过去了任何收费和开源限制。任何文件都可以递归都可以利用spire.pdf转为pdf,利用pdfiumViewer转换为照片,这些处理操作过程中的失真效果也可以处理,最后利用不会导致失真的pdfDocument进行缩放打印处理。下面具体的处理代码,可以稍作调整,直接使用。

private void printFile()
{
    try
    {
        if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
        {
            throw new ArgumentException("请检查打印文件是否存在");
        }
        //string fileName = Path.GetFileName(filePath).ToLower();
        string fileExtension = Path.GetExtension(filePath).ToLower();
        if (fileExtension == ".jpg"
            || fileExtension == ".jpeg"
            || fileExtension == ".png"
            || fileExtension == ".bmp")
        {
            Image image = new Bitmap(filePath);
            fileList.Add(image);
        }
        else if (fileExtension == ".pdf")
        {
            var imgLst = PdfiumViewerHelper.PdfToImage(filePath);
            if (imgLst != null && imgLst.Count > 0)
            {
                imgLst.ForEach(s => fileList.Add(s));
            }
        }

        PrintDocument printDocument = new PrintDocument();

        printDocument.PrintPage += printdocument_PrintPage;
        //设置打印机
        printDocument.PrinterSettings.PrinterName = this.Report.printer;
        //设置打印纸
        printDocument.DefaultPageSettings.PaperSize = this.Report.paperSize;
        //设置页边距
        printDocument.DefaultPageSettings.Margins = new Margins((int)(this.Report.papermargintop * 100 / 2.54m), (int)(this.Report.papermarginbottom * 100 / 2.54m), (int)(this.Report.papermarginleft * 100 / 2.54m), (int)(this.Report.papermarginright * 100 / 2.54m));
        //设置页方向
        printDocument.DefaultPageSettings.Landscape = this.Report.direction == Paperdirection.horizontal;

        printDocument.PrintController = new StandardPrintController();

        //printDocument.
        //ConfigHelper.PREVIEW_BEFROE_PRINT
        string chkPreview = ConfigHelper.GetValue(ConfigHelper.PREVIEW_BEFROE_PRINT);
        if (chkPreview =="True")
        {
            PrintPreviewDialog previewDialog = new PrintPreviewDialog();
            previewDialog.Document = printDocument;
            previewDialog.ShowIcon = false;
            previewDialog.WindowState = FormWindowState.Maximized;
            previewDialog.ShowDialog(this);
        }
        else
        {
            printDocument.Print();
        }

    }
    catch (ArgumentException ex)
    {
        throw ex;
    }
    catch (Exception ex)
    {
        Logger.Error(ex.Message);
        throw new ArgumentException("打印失败,请稍后重试或联系工程师查阅打印日志");
    }
}

正在使用的代码是按照图片居左自适应处理,注释掉的代码是对于打印内容进行按照打印内容进行调整,具体看个人要求来处理。

private void printdocument_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
    //图片抗锯齿
    e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

    //Stream fs = new FileStream(fileList[printNum].ToString().Trim(), FileMode.Open, FileAccess.Read);
    System.Drawing.Image image = fileList[printNum];
    int x = e.MarginBounds.X;
    int y = e.MarginBounds.Y;
    int width = image.Width;
    int height = image.Height;
    if (((double)width / e.MarginBounds.Width) > ((double)height / e.MarginBounds.Height))
    {
        width = e.MarginBounds.Width;
        height = image.Height * e.MarginBounds.Width / image.Width;
    }
    else
    {
        height = e.MarginBounds.Height;
        width = image.Width * e.MarginBounds.Height / image.Height;
    }

    //DrawImage参数根据打印机和图片大小自行调整

    System.Drawing.Rectangle destRect = new System.Drawing.Rectangle(x, y, width, height);

    if (image.Height < e.MarginBounds.Height)
    {
        //e.Graphics.DrawImage(image, 0, 30, image.Width + 20, image.Height);
        e.Graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, System.Drawing.GraphicsUnit.Pixel);
    }
    else
    {
        //e.Graphics.DrawImage(image, 0, 0, image.Width + 20, image.Height);
        e.Graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, System.Drawing.GraphicsUnit.Pixel);
    }

    //if (image.Height < e.MarginBounds.Height)
    //{
    //    if (image.Width < e.MarginBounds.Width)
    //    {
    //        e.Graphics.DrawImage(image, (int)this.Report.papermargintop, (int)this.Report.papermarginleft, image.Width - widthMargin, image.Height - heightMargin);
    //    }
    //    else
    //    {
    //        e.Graphics.DrawImage(image, (int)this.Report.papermargintop, (int)this.Report.papermarginleft, e.MarginBounds.Width - widthMargin, image.Height - heightMargin);
    //    }
    //}
    //else
    //{
    //    if (image.Width < e.MarginBounds.Width)
    //    {
    //        e.Graphics.DrawImage(image, (int)this.Report.papermargintop, (int)this.Report.papermarginleft, image.Width - widthMargin, e.MarginBounds.Height - heightMargin);
    //    }
    //    else
    //    {
    //        e.Graphics.DrawImage(image, (int)this.Report.papermargintop, (int)this.Report.papermarginleft, e.MarginBounds.Width - widthMargin, e.MarginBounds.Height - heightMargin);
    //    }
    //}

    if (printNum < fileList.Count - 1)
    {
        printNum++;
        e.HasMorePages = true;
        return;
    }
    e.HasMorePages = false;
}

需要注意的点:
1、 if ((width / e.MarginBounds.Width) > (height / e.MarginBounds.Height))
这句代码进行调整,因为前后求出结果会取整。
调整后内容:
if (((double)width / e.MarginBounds.Width) > ((double)height / e.MarginBounds.Height))

行文至此,后续再补充,莫愁莫愁,个人调研路,前路漫漫

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值