打印Base64格式PDF文档时触发‘参数无效’错误求助
打印Base64 PDF时“参数无效”错误的排查与解决
问题场景
尝试使用以下C#代码打印Base64格式转换而来的PDF文档,触发打印任务时出现“参数无效”错误,怀疑是未配置RenderEvents导致,但不确定具体原因。
原代码:
try { using (var memoryStream = new MemoryStream(pdfBytes)) { // Load the PDF document PdfSharp.Pdf.PdfDocument pdfDocument = PdfReader.Open(memoryStream, PdfDocumentOpenMode.ReadOnly); // Print each page for (int i = 0; i < pdfDocument.PageCount; i++) { using (var printDocument = new PrintDocument()) { printDocument.PrinterSettings.PrinterName = printerName; // Handle the PrintPage event printDocument.PrintPage += (sender, e) => { PdfSharp.Events.RenderEvents renderEvents = new PdfSharp.Events.RenderEvents(); XGraphics graphics = XGraphics.FromGraphics(e.Graphics, new XSize(e.MarginBounds.Width, e.MarginBounds.Height), renderEvents); // Get the current page to print var page = pdfDocument.Pages[i]; var pageWidth = page.Width; var pageHeight = page.Height; // Calculate the scale to fit the page var scaleX = e.MarginBounds.Width / pageWidth; var scaleY = e.MarginBounds.Height / pageHeight; var scale = Math.Min(scaleX, scaleY); // Center the page on the printer var xPos = e.MarginBounds.Left + (e.MarginBounds.Width - (pageWidth * scale)) / 2; var yPos = e.MarginBounds.Top + (e.MarginBounds.Height - (pageHeight * scale)) / 2; // Draw the content of the PDF page XImage xImage = XImage.FromStream(memoryStream); graphics.DrawImage(xImage, xPos, yPos, pageWidth * scale, pageHeight * scale); // Draw rectangle for the page border graphics.DrawRectangle(XPens.Black, xPos, yPos, pageWidth * scale, pageHeight * scale); }; // Trigger the print job printDocument.Print(); } } } } catch (Exception ex) { // 异常捕获 }
排查与解决建议
1. 核心问题:MemoryStream 位置与使用错误
- 第一次用
memoryStream加载PDF后,流的指针已移动到末尾,后续调用XImage.FromStream(memoryStream)时,流中无可读数据,直接触发“参数无效”错误。 - 另外,
XImage.FromStream无法直接从整个PDF流中提取单页图像,属于用法错误。
2. 正确渲染方式:直接绘制PDF页面
无需将PDF转成XImage,直接使用PdfPage.Draw方法将页面渲染到XGraphics上,这是PdfSharp官方推荐的打印方式。
3. RenderEvents 不是问题根源
RenderEvents是可选参数,默认构造即可,不会引发“参数无效”错误,可保留或直接省略(XGraphics.FromGraphics有重载不需要该参数)。
修正后的代码
try { using (var memoryStream = new MemoryStream(pdfBytes)) { PdfSharp.Pdf.PdfDocument pdfDocument = PdfReader.Open(memoryStream, PdfDocumentOpenMode.ReadOnly); for (int i = 0; i < pdfDocument.PageCount; i++) { using (var printDocument = new PrintDocument()) { printDocument.PrinterSettings.PrinterName = printerName; int currentPage = i; // 捕获循环变量,避免闭包问题 printDocument.PrintPage += (sender, e) => { // 省略RenderEvents,使用重载方法 XGraphics graphics = XGraphics.FromGraphics(e.Graphics, new XSize(e.MarginBounds.Width, e.MarginBounds.Height)); var page = pdfDocument.Pages[currentPage]; var pageWidth = page.Width; var pageHeight = page.Height; // 计算缩放比例和位置 var scaleX = e.MarginBounds.Width / pageWidth; var scaleY = e.MarginBounds.Height / pageHeight; var scale = Math.Min(scaleX, scaleY); var xPos = e.MarginBounds.Left + (e.MarginBounds.Width - pageWidth * scale) / 2; var yPos = e.MarginBounds.Top + (e.MarginBounds.Height - pageHeight * scale) / 2; // 直接绘制PDF页面 graphics.ScaleTransform(scale); graphics.TranslateTransform(xPos / scale, yPos / scale); page.Draw(graphics); // 绘制页面边框(可选) graphics.DrawRectangle(XPens.Black, 0, 0, pageWidth, pageHeight); }; printDocument.Print(); } } } } catch (Exception ex) { // 处理异常 }
额外注意点
- 闭包问题:原代码直接在事件处理中使用循环变量
i,会导致所有打印任务都使用最后一次循环的i值,需将i赋值给局部变量currentPage再捕获。 - 流的复用:若需多次读取流,每次读取前要调用
memoryStream.Seek(0, SeekOrigin.Begin)重置指针,但本方案无需此操作,直接通过pdfDocument.Pages访问页面即可。
内容的提问来源于stack exchange,提问作者innom
相关产品推荐
相关产品推荐

