打印文档概述 (WPF .NET)

借助 Microsoft .NET,使用 Windows Presentation Foundation (WPF) 的应用程序开发人员拥有一套丰富的打印和打印系统管理 API。 此功能的核心是 XML 纸张规范 (XPS) 文件格式和 XPS 打印路径。

关于 XPS

XPS 是一种电子文档格式、后台打印文件格式和页面描述语言。 它是一种开放文档格式,它使用 XML、开放打包约定和其他行业标准来创建跨平台文档。 XPS 简化了创建、共享、打印、查看和存档数字文档的过程。 有关 XPS 的详细信息,请参阅 XPS 文档

XPS 打印路径

XPS 打印路径 是一项 Windows 功能,用于重新定义 Windows 应用程序中的打印处理方式。 XPS 打印路径可以替换:

  • 文档表示语言,如富文本格式或可移植文档格式。
  • 打印后台处理程序格式,例如 Windows 图元文件或增强型图元文件 (EMF)。
  • 页面说明语言,如打印机命令语言或 PostScript。

因此,XPS 打印路径从应用程序发布到打印机驱动程序或设备的最终处理过程中一直保持 XPS 格式。

XPS 文档的打印后台处理程序支持 XPS 打印路径和 GDI 打印路径。 XPS 打印路径本身使用 XPS 后台打印文件并需要 XPS 打印机驱动程序。 XPS 打印路径基于 XPS 打印机驱动程序 (XPSDrv) 模型构建。

XPS 打印路径的优点包括:

  • 所见即所得的打印支持。
  • 对高级颜色配置文件的本机支持,例如每通道 32 位、CMYK 颜色模型、已命名的颜色、n 墨迹以及透明度和渐变。
  • 改进了打印性能 - XPS 功能和增强功能仅适用于面向 XPS 打印路径的应用程序。
  • 行业标准 XPS 格式。

对于基本打印场景,有一个带有标准 UI 的简单直观 API 可用于打印配置和作业提交。 对于高级方案,API 支持 UI 自定义或根本不支持 UI、同步或异步打印以及批处理打印功能。 简单选项和高级选项在完全或部分信任模式下都提供打印支持。

XPS 的设计具有可扩展性,因此可以采用模块化方式将特性和功能添加到 XPS。 扩展性功能包括:

  • 支持快速扩展设备功能的打印架构。 架构的公共部分会定期更新,以添加所需的设备功能。 有关详细信息,请参阅 可扩展体系结构
  • XPSDrv 驱动程序使用一种可扩展的过滤管道,以支持 XPS 文档的直接打印和可缩放打印。 有关详细信息,请参阅 XPSDrv 打印机驱动程序

WPF 应用程序原生支持 XPS 打印路径,并且可以使用 XPS 打印 API 直接打印到 XPSDrv 驱动程序。 如果写入操作的目标打印队列没有 XPSDrv 驱动程序,则 XpsDocumentWriter 类的 WriteWriteAsync 方法将自动将内容从 XPS 转换为 GDI 格式(对于 GDI 打印路径)。

下图显示了打印子系统,并定义了Microsoft和独立软件和硬件供应商提供的部分。

显示 XPS 打印系统的 屏幕截图。

基本 XPS 打印

WPF 具有支持基本和高级打印功能的打印 API。 对于不需要大量打印自定义或访问完整 XPS 功能集的应用程序,基本打印支持可能已足够。 基本打印支持是通过 PrintDialog 控件提供的,该控件需要最少的配置、具有熟悉的 UI 并支持许多 XPS 功能。

打印对话框

System.Windows.Controls.PrintDialog 控件为 UI、配置和 XPS 作业提交提供单个入口点。 若要了解如何实例化和使用控件,请参阅 如何显示打印对话框

高级 XPS 打印

若要访问完整的 XPS 功能集,请使用高级打印 API。 本节介绍了几个相关的 API,包括 PrintTicketPrintCapabilitiesPrintServerPrintQueue,以及 XpsDocumentWriter。 有关 XPS 打印路径 API 的完整列表,请参阅 System.Windows.XpsSystem.Printing 命名空间。

PrintTicket 和 PrintCapabilities

PrintTicketPrintCapabilities 类是高级 XPS 功能的基础。 这两个对象都包含由打印架构定义的面向打印的功能的 XML 格式结构。 这些功能包括双面打印、自动分页和装订。 PrintTicket 指令指示打印机如何处理打印作业。 PrintCapabilities 类定义打印机的功能。 通过查询打印机的功能,可以创建充分利用打印机的受支持功能的 PrintTicket。 同样,可以避免不支持的功能。

以下示例查询打印机的 PrintCapabilities,并使用代码创建 PrintTicket

/// <summary>
/// Returns a print ticket, which is a set of instructions telling a printer how
/// to set its various features, such as duplexing, collating, and stapling.
/// </summary>
/// <param name="printQueue">The print queue to print to.</param>
/// <returns>A print ticket.</returns>
public static PrintTicket GetPrintTicket(PrintQueue printQueue)
{
    PrintCapabilities printCapabilites = printQueue.GetPrintCapabilities();

    // Get a default print ticket from printer.
    PrintTicket printTicket = printQueue.DefaultPrintTicket;

    // Modify the print ticket.
    if (printCapabilites.CollationCapability.Contains(Collation.Collated))
        printTicket.Collation = Collation.Collated;
    if (printCapabilites.DuplexingCapability.Contains(Duplexing.TwoSidedLongEdge))
        printTicket.Duplexing = Duplexing.TwoSidedLongEdge;
    if (printCapabilites.StaplingCapability.Contains(Stapling.StapleDualLeft))
        printTicket.Stapling = Stapling.StapleDualLeft;

    // Returns a print ticket, which is a set of instructions telling a printer how
    // to set its various features, such as duplexing, collating, and stapling.
    return printTicket;
}
''' <summary>
''' Returns a print ticket, which is a set of instructions telling a printer how
''' to set its various features, such as duplexing, collating, and stapling.
''' </summary>
''' <param name="printQueue">The print queue to print to.</param>
''' <returns>A print ticket.</returns>
Public Shared Function GetPrintTicket(printQueue As PrintQueue) As PrintTicket

    Dim printCapabilites As PrintCapabilities = printQueue.GetPrintCapabilities()

    ' Get a default print ticket from printer.
    Dim printTicket As PrintTicket = printQueue.DefaultPrintTicket

    ' Modify the print ticket.
    If printCapabilites.CollationCapability.Contains(Collation.Collated) Then
        printTicket.Collation = Collation.Collated
    End If
    If printCapabilites.DuplexingCapability.Contains(Duplexing.TwoSidedLongEdge) Then
        printTicket.Duplexing = Duplexing.TwoSidedLongEdge
    End If
    If printCapabilites.StaplingCapability.Contains(Stapling.StapleDualLeft) Then
        printTicket.Stapling = Stapling.StapleDualLeft
    End If

    ' Returns a print ticket, which is a set of instructions telling a printer how
    ' to set its various features, such as duplexing, collating, and stapling.
    Return printTicket

End Function

PrintServer 和 PrintQueue

PrintServer 类表示网络打印服务器,PrintQueue 类表示打印机及其关联的输出作业队列。 这些 API 共同支持对服务器的打印作业进行高级管理。 PrintServer 或其派生类之一用于管理 PrintQueue

以下示例创建一个 LocalPrintServer 并使用代码访问本地计算机的 PrintQueueCollection

/// <summary>
/// Return a collection of print queues, which individually hold the features or states
/// of a printer as well as common properties for all print queues.
/// </summary>
/// <returns>A collection of print queues.</returns>
public static PrintQueueCollection GetPrintQueues()
{
    // Create a LocalPrintServer instance, which represents 
    // the print server for the local computer.
    LocalPrintServer localPrintServer = new();

    // Get the default print queue on the local computer.
    //PrintQueue printQueue = localPrintServer.DefaultPrintQueue;

    // Get all print queues on the local computer.
    PrintQueueCollection printQueueCollection = localPrintServer.GetPrintQueues();

    // Return a collection of print queues, which individually hold the features or states
    // of a printer as well as common properties for all print queues.
    return printQueueCollection;
}
''' <summary>
''' Return a collection of print queues, which individually hold the features or states
''' of a printer as well as common properties for all print queues.
''' </summary>
''' <returns>A collection of print queues.</returns>
Public Shared Function GetPrintQueues() As PrintQueueCollection

    ' Create a LocalPrintServer instance, which represents 
    ' the print server for the local computer.
    Dim localPrintServer As LocalPrintServer = New LocalPrintServer()

    ' Get the default print queue on the local computer.
    'Dim  printQueue As PrintQueue = localPrintServer.DefaultPrintQueue

    ' Get all print queues on the local computer.
    Dim printQueueCollection As PrintQueueCollection = localPrintServer.GetPrintQueues()

    ' Return a collection of print queues, which individually hold the features or states
    ' of a printer as well as common properties for all print queues.
    Return printQueueCollection

End Function

XpsDocumentWriter

XpsDocumentWriter具有多种 WriteWriteAsync 方法,用于将 XPS 文档添加到 PrintQueue。 例如,Write(FixedDocumentSequence, PrintTicket) 方法用于同步向队列添加带有打印票证的 XPS 文档。 WriteAsync(FixedDocumentSequence, PrintTicket) 方法用于将带有打印票证的 XPS 文档异步添加到队列。

以下示例创建一个 XpsDocumentWriter,并使用代码同步和异步将 XPS 文档添加到 PrintQueue

/// <summary>
/// Asynchronously, add the XPS document together with a print ticket to the print queue.
/// </summary>
/// <param name="xpsFilePath">Path to source XPS file.</param>
/// <param name="printQueue">The print queue to print to.</param>
/// <param name="printTicket">The print ticket for the selected print queue.</param>
public static void PrintXpsDocumentAsync(string xpsFilePath, PrintQueue printQueue, PrintTicket printTicket)
{
    // Create an XpsDocumentWriter object for the print queue.
    XpsDocumentWriter xpsDocumentWriter = PrintQueue.CreateXpsDocumentWriter(printQueue);

    // Open the selected document.
    XpsDocument xpsDocument = new(xpsFilePath, FileAccess.Read);

    // Get a fixed document sequence for the selected document.
    FixedDocumentSequence fixedDocSeq = xpsDocument.GetFixedDocumentSequence();

    // Asynchronously, add the XPS document together with a print ticket to the print queue.
    xpsDocumentWriter.WriteAsync(fixedDocSeq, printTicket);
}

/// <summary>
/// Synchronously, add the XPS document together with a print ticket to the print queue.
/// </summary>
/// <param name="xpsFilePath">Path to source XPS file.</param>
/// <param name="printQueue">The print queue to print to.</param>
/// <param name="printTicket">The print ticket for the selected print queue.</param>
public static void PrintXpsDocument(string xpsFilePath, PrintQueue printQueue, PrintTicket printTicket)
{
    // Create an XpsDocumentWriter object for the print queue.
    XpsDocumentWriter xpsDocumentWriter = PrintQueue.CreateXpsDocumentWriter(printQueue);

    // Open the selected document.
    XpsDocument xpsDocument = new(xpsFilePath, FileAccess.Read);

    // Get a fixed document sequence for the selected document.
    FixedDocumentSequence fixedDocSeq = xpsDocument.GetFixedDocumentSequence();

    // Synchronously, add the XPS document together with a print ticket to the print queue.
    xpsDocumentWriter.Write(fixedDocSeq, printTicket);
}
''' <summary>
''' Asynchronously, add the XPS document together with a print ticket to the print queue.
''' </summary>
''' <param name="xpsFilePath">Path to source XPS file.</param>
''' <param name="printQueue">The print queue to print to.</param>
''' <param name="printTicket">The print ticket for the selected print queue.</param>
Public Shared Sub PrintXpsDocumentAsync(xpsFilePath As String, printQueue As PrintQueue, printTicket As PrintTicket)

    ' Create an XpsDocumentWriter object for the print queue.
    Dim xpsDocumentWriter As XpsDocumentWriter = PrintQueue.CreateXpsDocumentWriter(printQueue)

    ' Open the selected document.
    Dim xpsDocument As XpsDocument = New XpsDocument(xpsFilePath, FileAccess.Read)

    ' Get a fixed document sequence for the selected document.
    Dim fixedDocSeq As FixedDocumentSequence = xpsDocument.GetFixedDocumentSequence()

    ' Asynchronously, add the XPS document together with a print ticket to the print queue.
    xpsDocumentWriter.WriteAsync(fixedDocSeq, printTicket)

End Sub

''' <summary>
''' Synchronously, add the XPS document together with a print ticket to the print queue.
''' </summary>
''' <param name="xpsFilePath">Path to source XPS file.</param>
''' <param name="printQueue">The print queue to print to.</param>
''' <param name="printTicket">The print ticket for the selected print queue.</param>
Public Shared Sub PrintXpsDocument(xpsFilePath As String, printQueue As PrintQueue, printTicket As PrintTicket)

    ' Create an XpsDocumentWriter object for the print queue.
    Dim xpsDocumentWriter As XpsDocumentWriter = PrintQueue.CreateXpsDocumentWriter(printQueue)

    ' Open the selected document.
    Dim xpsDocument As XpsDocument = New XpsDocument(xpsFilePath, FileAccess.Read)

    ' Get a fixed document sequence for the selected document.
    Dim fixedDocSeq As FixedDocumentSequence = xpsDocument.GetFixedDocumentSequence()

    ' Synchronously, add the XPS document together with a print ticket to the print queue.
    xpsDocumentWriter.Write(fixedDocSeq, printTicket)

End Sub

GDI 打印路径

尽管 WPF 应用程序本机支持 XPS 打印路径,但它们也可以通过以下方式输出到 GDI 打印路径:调用 XpsDocumentWriter 类的 WriteWriteAsync 方法之一,并为非 XpsDrv 打印机选择打印队列。

对于不需要 XPS 功能或支持的应用程序,当前 GDI 打印路径保持不变。 有关 GDI 打印路径和各种 XPS 转换选项的详细信息,请参阅 Microsoft XPS 文档转换器(MXDC)XPSDrv 打印机驱动程序

XPSDrv 驱动程序模型

在打印到支持 XPS 的打印机或驱动程序时,XPS 打印路径将 XPS 用作本机后台打印格式,从而提高后台处理程序的效率。 与 EMF(将应用程序输出表示为对呈现服务的 GDI 进行的一系列调用)不同,XPS 后台打印格式表示文档。 因此,当 XPS 后台打印文件输出到基于 XPS 的打印机驱动程序时,它们不需要进一步解释,因为驱动程序会直接对采用该格式的数据进行操作。 此功能消除了 EMF 文件和基于 GDI 的打印驱动程序所需的数据和颜色空间转换。

简化的后台打印过程不需要在后台打印文档之前生成中间后台打印文件(例如 EMF 数据文件)。 通过减小后台打印文件的大小,XPS 打印路径可以减少网络流量并提高打印性能。 与其 EMF 等效项相比,使用 XPS 打印路径时,XPS 后台打印文件通常会变小。 可通过几种机制来缩小后台打印文件:

  • 字体子集,它只在 XPS 文件中存储文档内使用的字符。
  • 高级图形支持,本机支持透明度和渐变基元以避免 XPS 内容光栅化
  • 识别常见资源,例如文档中多次使用的公司徽标的图像。 公共资源被视为共享资源,并且仅加载一次。
  • ZIP 压缩,适用于所有 XPS 文档。

如果矢量图形高度复杂、多层或编写效率低下,XPS 缓存文件的大小可能不会减小。 与 GDI 后台打印文件不同,XPS 文件嵌入设备字体和基于计算机的字体以用于屏幕显示,不过这两种字体都划分了子集,并且打印机驱动程序可以在将文件传输到打印机之前删除设备字体。

提示

还可以使用 PrintQueue.AddJob 方法打印 XPS 文件。 有关详细信息,请参阅 如何打印 XPS 文件

另请参阅