该页面可以包含自动翻译的文本。

在 C# 和 VB.NET 中渲染并打印 PDF 文档

提到读取 PDF 文档,大家通常会想到 Adobe Reader。但如果你是软件开发者,并且想在应用程序中显示 PDF 文档,该怎么办?你不希望让用户去安装 Adobe Reader,然后在那里打开文档。

你可能还需要实现其他与 PDF 相关的需求。例如,打印 PDF 文档。或者为上传的 PDF 文档生成缩略图。或者在桌面或 Web 应用程序中支持 PDF 编辑。

你只需要一个能够渲染和打印 PDF 文档的 PDF 库。

在 C# 中打印 PDF

用于查看、编辑或打印 PDF 文档的 .NET 库

Docotic.Pdf 库允许你在 C# 和 VB.NET 中显示、编辑和打印 PDF 文档。你可以使用三个核心功能实现任何复杂的 PDF 渲染流程。

第一个功能是将 PDF 转换为图像的能力。基于这个功能,你几乎可以实现一切。从 PDF 打印,到在 HoloLens 上显示 PDF,或在 Instagram 上发布 PDF。之所以可行,是因为图像几乎在任何地方都受支持。

第二个关键功能是在 System.Drawing.Graphics 的绘图表面上绘制 PDF 页面。它允许你在 Windows Forms 或 WPF 应用程序中渲染和打印 PDF。要使用此功能,请将 BitMiracle.Docotic.Pdf.Gdi 扩展 DLL 添加到你的项目中。

最后但同样重要的是提取 PDF 页面对象的能力。此功能允许你在 C# 或 VB.NET 应用程序中构建 PDF 查看器或 PDF 编辑器。

请在 下载 C# .NET PDF 库 页面获取该库和一个免费的限时许可证密钥。

.NET 默认不支持打印 PDF 文档。你需要先将 PDF 文档转换为图像、XPS 文件,或者将其绘制到 System.Drawing.Graphics 表面上。然后,你可以使用 .NET 类从 Windows Forms 或 WPF 应用程序中打印输出。

在 Windows Forms 应用程序中,你可以使用 System.Drawing.Printing 命名空间中的类。还有便捷的 PrintDialogPrintPreviewDialog 类可用于构建打印 UI。

请注意,不建议在 macOS 和 Linux 环境中使用 System.Drawing 命名空间中的任何内容。System.Drawing 在 macOS 和 Linux 上的实现不完整,并且与 Windows 实现不同。如果在 macOS 和 Linux 环境中使用 System.Drawing 命名空间,可能会得到错误和/或不一致的结果。

WPF 提供了另一个 PrintDialog 类,但不提供打印预览类。幸运的是,WPF 允许你使用 System.Windows.Forms.dll 中的 PrintPreviewDialog 类。因此,在 WPF 应用程序中使用 System.Windows.FormsSystem.Drawing.Printing 命名空间中的打印类更容易。

请查看 在 .NET 中打印 PDF 演示应用的 C# 和 VB.NET 版本,适用于 WinForms 和 WPF。该应用演示如何:

  • 显示 PDF 文档的打印预览
  • 将 PDF 文档打印到选定的打印机
  • 设置纸张大小、缩放模式和其他打印设置

该应用使用 Docotic.Pdf 库、BitMiracle.Docotic.Pdf.Gdi 扩展 DLL,以及来自 System.Windows.FormsSystem.Drawing.Printing 命名空间的打印类。你可以在 WPF 或 Windows Forms 项目中使用其 PdfPrintDocumentPdfPrintHelper 类。

PdfPrintDocument 类描述了主要的打印逻辑。该类将 Docotic.Pdf 与 System.Drawing.Printing.PrintDocument 类连接起来。关键方法是 printDocument_PrintPage 事件处理程序:

private void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
    Graphics gr = e.Graphics ?? throw new InvalidOperationException("No Graphics!");

    // 使用 point 单位,以便在所有上下文中保持一致的单位:
    // 1. 打印机
    // 2. 打印预览
    // 3. PDF
    gr.PageUnit = GraphicsUnit.Point;

    if (m_printAction == PrintAction.PrintToPreview)
    {
        gr.Clear(Color.LightGray);
        gr.FillRectangle(Brushes.White, m_printableAreaInPoints);
        gr.IntersectClip(m_printableAreaInPoints);

        gr.TranslateTransform(m_printableAreaInPoints.X, m_printableAreaInPoints.Y);
    }

    PdfPage page = m_pdf.Pages[m_pageIndex];
    PdfSize pageSizeInPoints = getPageSizeInPoints(page);

    if (m_printSize == PrintSize.FitPage)
    {
        float sx = (float)(m_printableAreaInPoints.Width / pageSizeInPoints.Width);
        float sy = (float)(m_printableAreaInPoints.Height / pageSizeInPoints.Height);
        float scaleFactor = Math.Min(sx, sy);

        centerContentInPrintableArea(gr, pageSizeInPoints, scaleFactor);
        gr.ScaleTransform(scaleFactor, scaleFactor);
    }
    else if (m_printSize == PrintSize.ActualSize)
    {
        centerContentInPrintableArea(gr, pageSizeInPoints, 1);
    }

    page.Draw(gr);

    ++m_pageIndex;
    e.HasMorePages = (m_pageIndex <= m_lastPageIndex);
}

首先,我们为打印页的 Graphics 对象设置变换。需要正确处理“适合页面”和“实际大小”设置。我们还会在打印预览对话框中显示打印机的硬边距。然后,我们使用 PdfPage.Draw 扩展方法将当前 PDF 页面绘制到 Graphics 对象上。

PdfPrintHelper 类允许你将 PdfPrintDocument 与用于打印的 UI 类一起使用。例如,你可以像这样为 PDF 文档显示打印对话框:

using (var pdf = new PdfDocument("your_document.pdf"))
    action(pdf, getPrintSize());

public static DialogResult ShowPrintDialog(PdfDocument pdf, PrintSize printSize)
{
    using (var printDialog = new PrintDialog())
    {
        printDialog.AllowSomePages = true;
        printDialog.AllowCurrentPage = true;
        printDialog.AllowSelection = true;

        printDialog.PrinterSettings.MinimumPage = 1;
        printDialog.PrinterSettings.MaximumPage = pdf.PageCount;
        printDialog.PrinterSettings.FromPage = printDialog.PrinterSettings.MinimumPage;
        printDialog.PrinterSettings.ToPage = printDialog.PrinterSettings.MaximumPage;

        var result = printDialog.ShowDialog();
        if (result == DialogResult.OK)
        {
            using (var printDocument = new PdfPrintDocument(pdf, printSize))
                printDocument.Print(printDialog.PrinterSettings);
        }

        return result;
    }
}

就是这样。在你的 Windows Forms 或 WPF 应用程序中实现 PDF 打印,只需:

  • 示例中添加 PdfPrintDocumentPdfPrintHelperPrintSize 文件
  • 添加对 Docotic.Pdf 库的引用
  • 添加对 BitMiracle.Docotic.Pdf.Gdi 扩展 DLL 的引用
  • (仅 WPF)添加对 System.Windows.Forms 和 System.Drawing 程序集的引用

System.Drawing.Printing 命名空间中的类在 Windows Forms 和 WPF 应用程序中表现良好。但是,在某些情况下,你不能或不应该使用 System.Drawing.Printing

例如,不应在 Windows 服务或 ASP.NET 应用程序中使用 System.Drawing.Printing。在 Linux 或 macOS 上打印时,System.Drawing.Printing 可能会产生不一致的结果。并且你不能在 Eto.Forms 或 Avalonia 应用程序中使用 System.Drawing.Printing

在这种情况下,你需要先将 PDF 文档转换为图像。下面这个 C# 示例展示了如何将 PDF 页面保存为 PNG 图像,或将整个 PDF 文档转换为多页 TIFF:

using var pdf = new PdfDocument(@"your_document.pdf");

PdfDrawOptions options = PdfDrawOptions.Create();
options.HorizontalResolution = printerDpi;
options.VerticalResolution = printerDpi;

// 保存一页
pdf.Pages[0].Save("page0.png", options);

// 将整个文档保存为多页二值 TIFF
options.Compression = ImageCompressionOptions.CreateTiff().SetBitonal();
pdf.SaveAsTiff("your_document.tiff", options);

然后,使用替代的打印框架或工具打印图像。请查看 在 Eto.Forms 中打印 PDF 演示应用,了解如何在不使用 System.Drawing.Printing 的情况下打印 PDF 文档。

在 C# 和 VB.NET 中渲染 PDF

在应用程序中显示 PDF 与打印类似。在 ASP.NET、WPF、Eto.Forms、Avalonia 或任何其他类型的应用程序中,先将 PDF 转换为图像,然后显示该图像。

在 Windows Forms 应用中,你可以从任何控件向 System.Drawing.Graphics 上下文绘制 PDF 页面。或者,你可以将 PDF 页面转换为 System.Drawing.Bitmap,然后在 PictureBox 中显示该位图。

下面的示例展示了如何在 C# 中将 PDF 页面转换为 Bitmap

using var pdf = new PdfDocument("render.pdf");
const float TargetResolution = 300;

PdfPage page = pdf.Pages[0];
double scaleFactor = TargetResolution / page.Resolution;

using var bitmap = new Bitmap((int)(page.Width * scaleFactor), (int)(page.Height * scaleFactor));
bitmap.SetResolution(TargetResolution, TargetResolution);

using (Graphics gr = Graphics.FromImage(bitmap))
    page.Draw(gr);

bitmap.Save("result.png");

以上代码要求你将 BitMiracle.Docotic.Pdf.Gdi 扩展 DLL 添加到项目中。

在 .NET 应用程序中创建 PDF 查看器或 PDF 编辑器

Docotic.Pdf 允许你获取 PDF 页面上每个对象的详细信息。你可以从 PDF 页面中提取文本块、图像、矢量路径、表单控件和注释。

然后,在你的应用程序中,你可以渲染所有提取出的对象。你也可以实现选择和编辑渲染对象的能力。

请查看从 PDF 中提取文本、图像和路径示例。它展示了如何将页面对象提取并绘制到 System.Drawing.Graphics 上下文。

你还可以将文本对象提取为矢量路径。为此请使用 PdfPage.GetObjects(PdfObjectExtractionOptions) 的重载。

结论

使用 Docotic.Pdf 库在你的 .NET 项目中显示和打印 PDF 文档。请查看相关的 C# 和 VB.NET 示例:

如果你对 PDF 打印或渲染有任何问题,请联系我们