如何无打印对话框将WPF窗口直接导出为PDF?
解决方案
一、优化现有位图方案(解决占满页面+高分辨率问题)
如果暂时不想更换依赖库,可先调整现有代码解决前两个核心问题:
1. 提升渲染分辨率
将RenderTargetBitmap的DPI从默认96调高至300(或更高),同时按DPI比例放大渲染尺寸,确保生成的图片足够清晰:
// 目标打印DPI,设为300 double targetDpi = 300; // 计算相对于系统96DPI的缩放比例 double scale = targetDpi / 96; RenderTargetBitmap rendertargetbitmap = new RenderTargetBitmap( (int)(datagrid.ActualWidth * scale), (int)(datagrid.ActualHeight * scale), targetDpi, targetDpi, PixelFormats.Pbgra32); rendertargetbitmap.Render(datagrid);
2. 让图片填满PDF页面
放弃使用MarginBounds,改用PageBounds作为绘制范围,调整缩放逻辑让图片在保留比例的前提下最大化填充页面:
doc.PrintPage += (sender, args) => { System.Drawing.Rectangle pageBounds = args.PageBounds; double imageRatio = (double)i.Width / i.Height; double pageRatio = (double)pageBounds.Width / pageBounds.Height; int drawWidth, drawHeight; if (imageRatio > pageRatio) { drawWidth = pageBounds.Width; drawHeight = (int)(pageBounds.Width / imageRatio); } else { drawHeight = pageBounds.Height; drawWidth = (int)(pageBounds.Height * imageRatio); } // 如果不需要居中,直接将x、y设为0即可完全填充页面 int x = (pageBounds.Width - drawWidth) / 2; int y = (pageBounds.Height - drawHeight) / 2; args.Graphics.DrawImage(i, x, y, drawWidth, drawHeight); };
注:此方案仅优化位图质量和填充效果,无法解决文本不可选中的问题。
二、直接导出WPF Grid为矢量PDF(彻底解决所有问题)
采用无交互打印或专业PDF库,直接将WPF元素以矢量格式导出为PDF,从根源解决分辨率、文本可选、页面填充的问题。
方法1:使用WPF PrintQueue实现无交互打印
利用系统自带的"Microsoft Print to PDF"打印机,直接将Grid打印到指定文件,生成的PDF为矢量格式:
public void ExportGridToPdf(string outputPath) { Grid datagrid = pOTemplate.g; // 获取Microsoft Print to PDF打印队列 var printQueue = new PrintQueue(new PrintServer(), "Microsoft Print to PDF"); // 设置打印参数(横竖版、纸张尺寸按需调整) var printTicket = printQueue.DefaultPrintTicket; printTicket.PageOrientation = PageOrientation.Landscape; printTicket.PageMediaSize = new PageMediaSize(PageMediaSizeName.Letter); // 提交打印作业 var printJob = printQueue.AddJob("采购订单打印", datagrid, printTicket); // 等待打印完成,确保文件写入完成 while (!printJob.IsCompleted) { System.Threading.Thread.Sleep(100); } // 将系统临时生成的PDF移动到指定路径 var tempPdfPath = printJob.GetDocumentPath(); if (File.Exists(tempPdfPath)) { Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); File.Move(tempPdfPath, outputPath, overwrite: true); } }
调用时传入目标文件路径即可,全程无用户交互,生成的PDF文本可选中、布局与Grid完全一致。
方法2:使用新版PdfSharp/MigraDoc
放弃旧版1.31,使用最新版的PDF处理库,示例以.NET Core/.NET 5+的PdfSharpCore为例:
首先安装NuGet包:
Install-Package PdfSharpCore Install-Package MigraDocCore.DocumentObjectModel
示例代码(将Grid渲染为高清晰度PDF):
using PdfSharpCore.Drawing; using PdfSharpCore.Pdf; using System.Windows.Media; public void ExportGridToPdfWithPdfSharp(string outputPath) { Grid datagrid = pOTemplate.g; // 先测量并排列Grid,确保获取正确尺寸 datagrid.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); datagrid.Arrange(new Rect(0, 0, datagrid.DesiredSize.Width, datagrid.DesiredSize.Height)); // 高DPI渲染Grid double dpi = 300; var renderBitmap = new RenderTargetBitmap( (int)(datagrid.DesiredSize.Width * dpi / 96), (int)(datagrid.DesiredSize.Height * dpi / 96), dpi, dpi, PixelFormats.Pbgra32); renderBitmap.Render(datagrid); // 转换为PDF并保存 using (var stream = new MemoryStream()) { var encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(renderBitmap)); encoder.Save(stream); stream.Position = 0; var document = new PdfDocument(); var page = document.AddPage(); // 将WPF尺寸转换为PDF的毫米单位 page.Width = XUnit.FromMillimeters(datagrid.DesiredSize.Width * 25.4 / 96); page.Height = XUnit.FromMillimeters(datagrid.DesiredSize.Height * 25.4 / 96); using (var gfx = XGraphics.FromPdfPage(page)) { var xImage = XImage.FromStream(stream); gfx.DrawImage(xImage, 0, 0, page.Width, page.Height); } document.Save(outputPath); } }
若需要纯矢量PDF,可手动将Grid的XAML元素映射为MigraDoc的文档结构,适合复杂布局场景。
内容的提问来源于stack exchange,提问作者m4rs___
相关产品推荐
相关产品推荐

