打印文档概述 (WPF .NET)

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

关于 XPS

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

XPS 打印路径

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

  • 文档呈现语言,例如 RTF 格式或可移植文档格式。
  • 打印后台处理程序格式,例如 Windows 图元文件或增强型图元文件 (EMF)。
  • 页面描述语言,例如打印机命令语言或 PostScript。

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

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

XPS 打印路径的优势包括:

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

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

XPS 在设计时考虑了扩展性,因此能够以模块化方式将特性和功能添加到 XPS。 扩展性功能包括:

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

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

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

Screenshot showing the XPS print system.

基本 XPS 打印

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

PrintDialog

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

高级 XPS 打印

若要访问完整的 XPS 功能集,请使用高级打印 API。 本部分介绍了几个相关的 API,包括 PrintTicketPrintCapabilitiesPrintServerPrintQueueXpsDocumentWriter。 有关 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 文件

另请参阅