打印概述

借助 Microsoft .NET Framework,使用 Windows Presentation Foundation 的应用程序开发人员 (WPF) 具有一组丰富的新打印和打印系统管理 API。 对于 Windows Vista,其中一些打印系统增强功能也可供创建 Windows 窗体应用程序的开发人员和使用非托管代码的开发人员使用。 此新功能的核心是新的 XML 纸张规范 (XPS) 文件格式和 XPS 打印路径。

本主题包含以下各节:

关于 XPS

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

以编程方式打印 XPS 文件中演示了几种使用 WPF 打印基于 XPS 的内容的技术。 在查看本主题中的内容时,参考这些示例会很有帮助。 (非托管代码开发人员应参阅 MXDC_ESCAPE 函数的文档。Windows 窗体开发人员必须使用 System.Drawing.Printing 命名空间中的 API,该命名空间不支持完整的 XPS 打印路径,但支持混合 GDI 到 XPS 打印路径。请参阅下面的“打印路径体系结构”。)

XPS 打印路径

XML 纸张规范 (XPS) 打印路径是一项新的 Windows 功能,它重新定义了在 Windows 应用程序中处理打印的方式。 因为 XPS 可以替代文档表示语言(如 RTF)、后台打印程序格式(如 WMF)和页面描述语言(如 PCL 或 Postscript);新的打印路径保持从应用程序发布到打印驱动程序或设备中的最终处理的 XPS 格式。

XPS 打印路径基于 XPS 打印机驱动程序模型 (XPSDrv) 构建,它为开发人员提供了多项优势,例如“所见即所得”(WYSIWYG) 打印、改进的颜色支持以及显着改进的打印性能。 (有关 XPSDrv 的详细信息,请参阅 Windows 驱动程序开发工具包。)

XPS 文档的后台打印程序的操作与以前版本的 Windows 基本相同。 但是,除了现有的 GDI 打印路径之外,它已得到增强以支持 XPS 打印路径。 新的打印路径本机使用 XPS 后台打印文件。 虽然为以前版本的 Windows 编写的用户模式打印机驱动程序将继续工作,但需要 XPS 打印机驱动程序 (XPSDrv) 才能使用 XPS 打印路径。

XPS 打印路径具有巨大优势,其中包括:

  • WYSIWYG 打印支持

  • 对高级颜色配置文件的本机支持(包括 32 位/通道 (bpc)、CMYK、已命名的颜色、n 墨迹)以及对透明和渐变的本机支持。

  • 改进了 .NET Framework 和基于 Win32 的应用程序的打印性能。

  • 行业标准 XPS 格式。

对于基本的打印场景,可以使用简单直观的 API 以及用于用户界面、配置和作业提交的单一入口点。 对于高级场景,完全添加了对 UI 的额外支持)、同步或异步打印以及批量打印功能。 这两个选项在完全或部分信任模式下都提供打印支持。

XPS 的设计考虑了可扩展性。 通过使用可扩展性框架,可以以模块化方式将特性和功能添加到 XPS。 扩展性功能包括:

  • 打印架构。 公共架构将定期进行更新,并可以实现设备功能的迅速扩展。 (请参阅下面的 PrintTicket 和 PrintCapabilities。)

  • 可扩展筛选器管道。 XPS 打印机驱动程序 (XPSDrv) 过滤器管道旨在实现 XPS 文档的直接和可扩展打印。 有关详细信息,请参阅 XPSDrv 打印机驱动程序

虽然 Win32 和 .NET Framework 应用程序都支持 XPS,但 Win32 和 Windows 窗体应用程序使用 GDI 到 XPS 的转换,以便为 XPS 打印机驱动程序 (XPSDrv) 创建 XPS 格式的内容。 这些应用程序不需要使用 XPS 打印路径,并且可以继续使用基于增强型元文件 (EMF) 的打印。 但是,大多数 XPS 功能和增强功能仅适用于以 XPS 打印路径为目标的应用程序。

为了使 Win32 和 Windows 窗体应用程序能够使用基于 XPSDrv 的打印机,XPS 打印机驱动程序 (XPSDrv) 支持将 GDI 转换为 XPS 格式。 XPSDrv 模型还提供了 XPS 到 GDI 格式的转换器,以便 Win32 应用程序可以打印 XPS 文档。 对于 WPF 应用程序,只要写入操作的目标打印队列没有 XPSDrv 驱动程序,就会由 XpsDocumentWriter 类的 WriteWriteAsync 方法自动完成 XPS 到 GDI 格式的转换。 (Windows 窗体应用程序无法打印 XPS 文档)

下图描述了打印子系统并定义了 Microsoft 提供的部分,以及软件和硬件供应商定义的部分:

Screenshot shows the XPS print system.

基本 XPS 打印

WPF 定义了基本 API 和高级 API。 对于那些不需要大量打印定制或访问完整 XPS 功能集的应用程序,可以使用基本打印支持。 基本打印支持通过打印对话框控件公开,该控件需要最少的配置并具有熟悉的 UI。 使用这种简化的打印模型时可以使用许多 XPS 功能。

PrintDialog

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

高级 XPS 打印

要访问完整的 XPS 功能集,必须使用高级打印 API。 下面更详细地描述了几个相关的 API。 有关 XPS 打印路径 API 的完整列表,请参阅 System.Windows.XpsSystem.Printing 命名空间参考。

PrintTicket 和 PrintCapabilities

PrintTicketPrintCapabilities 类是高级 XPS 功能的基础。 这两种类型的对象都是面向打印的功能(如排序规则、双面打印、装订等)的 XML 格式结构。这些结构由打印架构定义。 PrintTicket 指示打印机如何处理打印作业。 PrintCapabilities 类定义打印机的各种功能。 通过查询打印机的功能,可以创建充分利用打印机的受支持功能的 PrintTicket。 同样,可以避免不受支持的功能。

下面的示例演示如何使用代码查询打印机的 PrintCapabilities 和创建 PrintTicket

// ---------------------- GetPrintTicketFromPrinter -----------------------
/// <summary>
///   Returns a PrintTicket based on the current default printer.</summary>
/// <returns>
///   A PrintTicket for the current local default printer.</returns>
PrintTicket^ GetPrintTicketFromPrinter () 
{
   PrintQueue^ printQueue = nullptr;

   LocalPrintServer^ localPrintServer = gcnew LocalPrintServer();

   // Retrieving collection of local printer on user machine
   PrintQueueCollection^ localPrinterCollection = localPrintServer->GetPrintQueues();

   System::Collections::IEnumerator^ localPrinterEnumerator = localPrinterCollection->GetEnumerator();

   if (localPrinterEnumerator->MoveNext())
   {
      // Get PrintQueue from first available printer
      printQueue = ((PrintQueue^)localPrinterEnumerator->Current);
   } else
   {
      return nullptr;
   }
   // Get default PrintTicket from printer
   PrintTicket^ printTicket = printQueue->DefaultPrintTicket;

   PrintCapabilities^ printCapabilites = printQueue->GetPrintCapabilities();

   // Modify PrintTicket
   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;
   }
   return printTicket;
};// end:GetPrintTicketFromPrinter()
// ---------------------- GetPrintTicketFromPrinter -----------------------
/// <summary>
///   Returns a PrintTicket based on the current default printer.</summary>
/// <returns>
///   A PrintTicket for the current local default printer.</returns>
private PrintTicket GetPrintTicketFromPrinter()
{
    PrintQueue printQueue = null;

    LocalPrintServer localPrintServer = new LocalPrintServer();

    // Retrieving collection of local printer on user machine
    PrintQueueCollection localPrinterCollection =
        localPrintServer.GetPrintQueues();

    System.Collections.IEnumerator localPrinterEnumerator =
        localPrinterCollection.GetEnumerator();

    if (localPrinterEnumerator.MoveNext())
    {
        // Get PrintQueue from first available printer
        printQueue = (PrintQueue)localPrinterEnumerator.Current;
    }
    else
    {
        // No printer exist, return null PrintTicket
        return null;
    }

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

    PrintCapabilities printCapabilites = printQueue.GetPrintCapabilities();

    // Modify PrintTicket
    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;
    }

    return printTicket;
}// end:GetPrintTicketFromPrinter()
' ---------------------- GetPrintTicketFromPrinter -----------------------
''' <summary>
'''   Returns a PrintTicket based on the current default printer.</summary>
''' <returns>
'''   A PrintTicket for the current local default printer.</returns>
Private Function GetPrintTicketFromPrinter() As PrintTicket
    Dim printQueue As PrintQueue = Nothing

    Dim localPrintServer As New LocalPrintServer()

    ' Retrieving collection of local printer on user machine
    Dim localPrinterCollection As PrintQueueCollection = localPrintServer.GetPrintQueues()

    Dim localPrinterEnumerator As System.Collections.IEnumerator = localPrinterCollection.GetEnumerator()

    If localPrinterEnumerator.MoveNext() Then
        ' Get PrintQueue from first available printer
        printQueue = CType(localPrinterEnumerator.Current, PrintQueue)
    Else
        ' No printer exist, return null PrintTicket
        Return Nothing
    End If

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

    Dim printCapabilites As PrintCapabilities = printQueue.GetPrintCapabilities()

    ' Modify PrintTicket
    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

    Return printTicket
End Function ' end:GetPrintTicketFromPrinter()

PrintServer 和 PrintQueue

PrintServer 类表示一个网络打印服务器,而 PrintQueue 类则表示一台打印机以及与其关联的输出作业队列。 结合使用这些 ,可以对服务器的打印作业进行高级管理。 PrintServer 或其派生类之一用于管理 PrintQueueAddJob 方法用于将新的打印作业插入队列。

下面的示例演示如何使用代码创建 LocalPrintServer 和访问其默认的 PrintQueue

// -------------------- GetPrintXpsDocumentWriter() -------------------
/// <summary>
///   Returns an XpsDocumentWriter for the default print queue.</summary>
/// <returns>
///   An XpsDocumentWriter for the default print queue.</returns>
private XpsDocumentWriter GetPrintXpsDocumentWriter()
{
    // Create a local print server
    LocalPrintServer ps = new LocalPrintServer();

    // Get the default print queue
    PrintQueue pq = ps.DefaultPrintQueue;

    // Get an XpsDocumentWriter for the default print queue
    XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(pq);
    return xpsdw;
}// end:GetPrintXpsDocumentWriter()
' -------------------- GetPrintXpsDocumentWriter() -------------------
''' <summary>
'''   Returns an XpsDocumentWriter for the default print queue.</summary>
''' <returns>
'''   An XpsDocumentWriter for the default print queue.</returns>
Private Function GetPrintXpsDocumentWriter() As XpsDocumentWriter
    ' Create a local print server
    Dim ps As New LocalPrintServer()

    ' Get the default print queue
    Dim pq As PrintQueue = ps.DefaultPrintQueue

    ' Get an XpsDocumentWriter for the default print queue
    Dim xpsdw As XpsDocumentWriter = PrintQueue.CreateXpsDocumentWriter(pq)
    Return xpsdw
End Function ' end:GetPrintXpsDocumentWriter()

XpsDocumentWriter

XpsDocumentWriter 及其许多 WriteWriteAsync 方法用于将 XPS 文档写入 PrintQueue。 例如,Write(FixedPage, PrintTicket) 方法用于同步输出 XPS 文档和 PrintTicketWriteAsync(FixedDocument, PrintTicket) 方法用于异步输出 XPS 文档和 PrintTicket

下面的示例演示如何使用代码创建 XpsDocumentWriter

// -------------------- GetPrintXpsDocumentWriter() -------------------
/// <summary>
///   Returns an XpsDocumentWriter for the default print queue.</summary>
/// <returns>
///   An XpsDocumentWriter for the default print queue.</returns>
private XpsDocumentWriter GetPrintXpsDocumentWriter()
{
    // Create a local print server
    LocalPrintServer ps = new LocalPrintServer();

    // Get the default print queue
    PrintQueue pq = ps.DefaultPrintQueue;

    // Get an XpsDocumentWriter for the default print queue
    XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(pq);
    return xpsdw;
}// end:GetPrintXpsDocumentWriter()
' -------------------- GetPrintXpsDocumentWriter() -------------------
''' <summary>
'''   Returns an XpsDocumentWriter for the default print queue.</summary>
''' <returns>
'''   An XpsDocumentWriter for the default print queue.</returns>
Private Function GetPrintXpsDocumentWriter() As XpsDocumentWriter
    ' Create a local print server
    Dim ps As New LocalPrintServer()

    ' Get the default print queue
    Dim pq As PrintQueue = ps.DefaultPrintQueue

    ' Get an XpsDocumentWriter for the default print queue
    Dim xpsdw As XpsDocumentWriter = PrintQueue.CreateXpsDocumentWriter(pq)
    Return xpsdw
End Function ' end:GetPrintXpsDocumentWriter()

AddJob 方法还提供打印方法。 请参阅以编程方式打印 XPS 文件。 了解详细信息。

GDI 打印路径

虽然 WPF 应用程序本身支持 XPS 打印路径,但 Win32 和 Windows 窗体应用程序也可以利用一些 XPS 功能。 XPS 打印机驱动程序 (XPSDrv) 可以将基于 GDI 的输出转换为 XPS 格式。 对于高级方案,使用 Microsoft XPS 文档转换器 (MXDC) 时支持自定义内容转换。 同样,WPF 应用程序也可以通过调用 XpsDocumentWriter 类的 WriteWriteAsync 方法之一并将非 XpsDrv 打印机指定为目标打印队列来输出到 GDI 打印路径。

对于不需要 XPS 功能或支持的应用程序,当前的 GDI 打印路径保持不变。

XPSDrv 驱动程序模型

在打印到支持 XPS 的打印机或驱动程序时,XPS 打印路径将 XPS 用作本机打印后台处理格式,从而提高打印后台处理程序的效率。 简化的后台打印过程不需要在后台打印文档之前生成中间后台打印文件(例如 EMF 数据文件)。 通过减小后台打印文件的大小,XPS 打印路径可以减少网络流量并提高打印性能。

EMF 是一种封闭格式,它将应用程序输出表示为对呈现服务的 GDI 进行的一系列调用。 与 EMF 不同的是,XPS 后台打印格式呈现实际的文档,而无需在输出到基于 XPS 的打印机驱动程序 (XPSDrv) 时进行进一步的转译。 这些驱动程序可以用这种格式直接对数据进行操作。 此功能消除了在使用 EMF 文件和基于 GDI 的打印驱动程序时所需的数据和颜色空间转换。

使用以 XPS 打印机驱动程序 (XPSDrv) 为目标的 XPS 文档时,后台打印文件的大小通常会比它们的 EMF 等效文件小;但也有例外:

  • 相当复杂、分为多层或者编写效率低下的向量图形可能比同一图形的位图图形更大。

  • 出于屏幕显示的目的,XPS 文件中嵌入了设备字体以及基于计算机的字体,而 GDI 打印后台文件未嵌入设备字体。 这两种字体都划分了子集(请参见下面的内容),而且打印机驱动程序可以在将文件传输给打印机之前删除这些设备字体。

可通过几种机制来减小后台打印文件的大小:

  • 字体子集划分。 只有在实际文档中使用的字符才会存储在 XPS 文件中。

  • 高级图形支持。 对透明度和渐变基元的本机支持避免了 XPS 文档中内容的光栅化。

  • 公共资源的识别。 将多次使用的资源(如表示公司徽标的图像)视为共享资源,并且只加载一次。

  • ZIP 压缩。 所有 XPS 文档都使用 ZIP 压缩。

另请参阅