Руководство по проектированию API поддержки печати версии 3
В этой статье приведены рекомендации и примеры для изготовителей оборудования принтера и IHV, реализующих приложение поддержки печати версии 3 (PSA) для своего устройства.
Терминология
Срок | Определение |
---|---|
PSA | Приложение поддержки печати. Приложение UWP, использующее API в этом документе. |
IPP | Протокол интернет-печати. Используется с клиентского устройства для взаимодействия с принтером для получения и задания параметров печати и отправки документа для печати. |
Принтер, связанный со службой поддержки печати | Физический принтер IPP, связанный с PSA. |
Принтер IPP | Принтер, поддерживающий протокол IPP. |
PDL | Язык описания страницы. Формат, в котором документ отправляется на принтер. |
Связанный принтер PSA | Физический принтер IPP, связанный с приложением PSA. |
Возможности устройства печати | Формат XML-документа для определения возможностей принтера. |
Расширение Поддержки Печати | Фоновая задача PSA, отвечающая за предоставление возможностей расширения ограничений принтера. |
API поддержки печати версии 3
Эта статья содержит расширения версии 3 для существующего общедоступного API службы поддержки печати, описанного в проектном руководстве для приложений поддержки печати и в пространстве имен Windows.Graphics.Printing.PrintSupport. API PSA позволяет производителям принтеров разрабатывать приложения поддержки оборудования, которые могут улучшить возможности печати пользователя Windows при использовании драйвера класса Microsoft IPP без необходимости разработки пользовательского драйвера. Компоненты печати взаимодействуют с приложением PSA через процесс брокера PSA.
Дополнительные сведения см. в следующих статьях:
Тема | Описание |
---|---|
руководство по проектированию приложений для поддержки печати | Предоставляет рекомендации и примеры для изготовителей оборудования принтера и IHV, которые реализуют приложение поддержки печати (PSA) для своего устройства. |
Руководство по проектированию API приложения поддержки печати версии 4 | Предоставляет рекомендации и примеры для изготовителей оборудования принтера и IHV, которые реализуют приложение поддержки печати версии 4 (PSA) для своего устройства. |
спецификация манифеста MSIX для виртуального принтера поддержки печати | Предоставляет рекомендации по манифесту MSIX и примеры для изготовителей оборудования для принтера и независимых поставщиков оборудования, реализующих виртуальный принтер для поддержки печати. |
ассоциация приложения для поддержки печати | Предоставляет рекомендации и примеры для связывания приложения поддержки печати (PSA) с принтером. |
Ниже приведены значительные расширения API.
сжатие IPP — API PSA версии 3 добавляет функцию для улучшения печати IPP, добавив функцию сжатия IPP в задание печати для принтеров IPP, поддерживающих эту функцию. Некоторые PSA могут использовать пользовательское сжатие, что означает, что задание IPP подвержено двойному сжатию, что сказывается на производительности. Чтобы устранить эту проблему, API PSA версии 3 представляет свойство IsIppCompressionEnabled и функцию DisableIppCompressionForJob (чтобы отключить сжатие для текущего задания при необходимости) в классе среды выполнения PrintWorkflowJobStartingEventArgs (API PSA версии 1).
обработка ошибок задания IPP и API версии 3 PSA представляет событие JobIssueDetected в классе среды выполнения PrintWorkflowJobBackgroundSession (API версии 1 PSA). Событие возникает всякий раз, когда PSA обнаруживает ошибку или предупреждение в задании печати. Затем PSA отвечает за отображение всплывающего уведомления об ошибке пользователю. Если PSA регистрирует это событие и задает свойство skipSystemErrorToast значение true в PrintWorkflowJobIssueDetectedEventArgs, оно сообщает системе печати не показывать тост системы печати Windows. API PSA версии 3 также предоставляет механизм для запуска пользовательского интерфейса PSA, когда пользователь взаимодействует с всплывающим уведомлением.
Настраиваемые тайм-ауты связи IPP — API версии 3 предоставляет возможность PSA изменять тайм-ауты IPP. Кроме того, класс среды выполнения PrintSupportIppCommunicationConfiguration добавляется в PrintSupportPrintDeviceCapabilitiesChangedEventArgs для управления временем ожидания связи IPP. Кроме того, API PSA версии 3 представляет событие, которое возникает при возникновении ошибки связи IPP. Это событие было введено таким образом, чтобы IHV мог изучить сбой и соответствующим образом настроить значения времени ожидания.
Поддержка IPPFaxOut — API версии 3 PSA добавляет функцию в систему печати для поддержки принтеров IPPFaxOut. Для поддержки факса в PSA используется фильтр отрисовки для преобразования XPS в TIFF. Так как PSA может управлять содержимым XPS перед преобразованием в TIFF, она предоставляет значение перечисления XpsToTiff в PrintWorkflowPdlConversionType для доступа PSA к преобразователю XPS в TIFF. Кроме того, он предоставляет свойство IsIPPFaxOutPrinter для класса среды выполнения IppPrintDevice, чтобы PSA могли различать стандартный принтер и принтеры IPPFaxOut.
Отключение сжатия IPP
Сжатие IPP показано в следующем примере кода.
public sealed class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{
public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
private PrintWorkflowJobBackgroundSession session;
public void Run(IBackgroundTaskInstance taskInstance)
{
TaskInstanceDeferral = taskInstance.GetDeferral();
if (taskInstance.TriggerDetails is PrintWorkflowJobTriggerDetails jobDetails)
{
session = jobDetails.PrintWorkflowJobSession;
session.JobStarting += OnJobStarting;
session.PdlModificationRequested += OnPdlModificationRequested;
session.JobIssueDetected += OnJobIssueDetected;
// Make sure to register all the event handlers before PrintWorkflowJobBackgroundSession.Start is called.
session.Start();
}
}
private void OnJobStarting(PrintWorkflowJobBackgroundSession sender, PrintWorkflowJobStartingEventArgs args)
{
using (args.GetDeferral())
{
// Skip system rendering.
args.SetSkipSystemRendering();
// If Ipp compression is enabled by the system, check to see if PSA does custom compression for the printer
// and disable system compression if required.
if (args.IsIppCompressionEnabled)
{
if (this.HasCustomCompression(args.Printer))
{
args.DisableIppCompressionForJob();
}
}
}
}
bool HasCustomCompression(IppPrintDevice device)
{
bool hasCustomCompression = false;
// Check if the PSA does custom compression for the printer
return hasCustomCompression;
}
}
Обработка ошибок задания IPP
В этом примере показано, как приложение PSA может регистрировать ошибки заданий, показывать уведомления об ошибках заданий и открывать пользовательский интерфейс, когда пользователь активирует уведомления.
public sealed class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{
public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
private PrintWorkflowJobBackgroundSession session;
public void Run(IBackgroundTaskInstance taskInstance)
{
TaskInstanceDeferral = taskInstance.GetDeferral();
if (taskInstance.TriggerDetails is PrintWorkflowJobTriggerDetails jobDetails)
{
session = jobDetails.PrintWorkflowJobSession;
session.JobStarting += OnJobStarting;
session.PdlModificationRequested += OnPdlModificationRequested;
session.JobIssueDetected += OnJobIssueDetected;
// Make sure to register all the event handlers before PrintWorkflowJobBackgroundSession.Start is called.
session.Start();
}
}
private void OnJobIssueDetected (PrintWorkflowJobBackgroundSession sender, PrintWorkflowJobIssueDetectedEventArgs args)
{
// Using a deferral to exclude the background process from being suspended while PSA displays UI.
Deferral deferral = args.GetDeferral();
var toast = new ToastNotification(GetErrorToastXml(args.ExtendedError,
args.JobIssueKind, args.PrinterJob, args.Configuration));
toast.Activated += async (toastSender, e) =>
{
// PSA UI application
PrintWorkflowUICompletionStatus uiStatus = await args.UILauncher.LaunchAndCompleteUIAsync();
// Complete deferral
deferral.Complete();
};
toast.Dismissed += async (toastSender, e) => { deferral.Complete(); };
toast.Failed += async (toastSender, e) => { deferral.Complete(); };
ToastNotificationManager.CreateToastNotifier().Show(toast);
args.SkipSystemErrorToast = true;
}
private XmlDocument GetErrorToastXml(Exception jobError, PrintWorkflowJobIssueKind issueKind,
PrintWorkflowPrinterJob printerJob, PrintWorkflowConfiguration workflowConfig )
{
var errorToastXml = new XmlDocument();
// Generate Toast Xml based on error information from Exception and PrintWorkflowPrinterJob.
return errorToastXml;
}
}
Настройка времени ожидания связи IPP
В этом примере показано, как установить время ожидания соединения IPP.
public sealed class PrintSupportExtensionBackGroundTask : IBackgroundTask
{
public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
private PrintSupportExtensionSession session;
public void Run(IBackgroundTaskInstance taskInstance)
{
taskInstance.Canceled += OnTaskInstanceCanceled;
TaskInstanceDeferral = taskInstance.GetDeferral();
if (taskInstance.TriggerDetails is PrintSupportExtensionTriggerDetails extensionDetails)
{
session = extensionDetails.Session;
session.PrintTicketValidationRequested += OnSessionPrintTicketValidationRequested;
session.PrintDeviceCapabilitiesChanged += OnSessionPrintDeviceCapabilitiesChanged;
session.CommunicationErrorDetected += OnCommunicationErrorDetected;
// Make sure to register all the event handlers before PrintSupportExtensionSession.Start is called.
session.Start();
}
}
private void OnTaskInstanceCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
session = null;
TaskInstanceDeferral.Complete();
}
private void OnSessionPrintDeviceCapabilitiesChanged(PrintSupportExtensionSession sender, PrintSupportPrintDeviceCapabilitiesChangedEventArgs args)
{
// Using deferral to exclude the background process from being suspended while PSA updates the printer PDC and other configurations.
using (args.GetDeferral())
{
if (args.CommunicationConfiguration.CanModifyTimeouts)
{
this.UpdateAttributeTimeouts(args.CommunicationConfiguration, sender.Printer);
this.UpdateJobTimeouts(args.CommunicationConfiguration, sender.Printer);
}
// Do other operations, such as Updating PDC, PDR, and so on here.
}
}
void UpdateAttributeTimeouts(PrintSupportIppCommunicationConfiguration config, IppPrintDevice device)
{
IppPrinterCommunicationKind communicationKind = config.CommunicationKind;
PrintSupportIppCommunicationTimeouts currentTimeouts = config.IppAttributeTimeouts;
// Adjust attribute timeouts based on the printer
switch (communicationKind)
{
case IppPrinterCommunicationKind.Network:
currentTimeouts.ConnectTimeout = TimeSpan.FromSeconds(10);
currentTimeouts.SendTimeout = TimeSpan.FromSeconds(10);
currentTimeouts.ReceiveTimeout = TimeSpan.FromSeconds(10);
break;
case IppPrinterCommunicationKind.UniversalPrint:
// adjust timeout for universal printer
break;
}
}
void UpdateJobTimeouts(
PrintSupportIppCommunicationConfiguration config, IppPrintDevice device)
{
IppPrinterCommunicationKind communicationKind = config.CommunicationKind;
PrintSupportIppCommunicationTimeouts currentTimeouts = config.IppJobTimeouts;
// Adjust job timeouts based on the printer and communication type
switch (communicationKind)
{
case IppPrinterCommunicationKind.Network:
currentTimeouts.ConnectTimeout = TimeSpan.FromSeconds(30);
currentTimeouts.SendTimeout = TimeSpan.FromSeconds(30);
currentTimeouts.ReceiveTimeout = TimeSpan.FromSeconds(30);
break;
case IppPrinterCommunicationKind.UniversalPrint:
// adjust timeout for universal printer
break;
}
}
}
Обработка ошибок связи IPP
В этом примере показано, как обрабатывать ошибки связи IPP.
public sealed class PrintSupportExtensionBackGroundTask : IBackgroundTask
{
public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
private PrintSupportExtensionSession session;
public void Run(IBackgroundTaskInstance taskInstance)
{
taskInstance.Canceled += OnTaskInstanceCanceled;
TaskInstanceDeferral = taskInstance.GetDeferral();
if (taskInstance.TriggerDetails is PrintSupportExtensionTriggerDetails extensionDetails)
{
session = extensionDetails.Session;
session.PrintTicketValidationRequested += OnSessionPrintTicketValidationRequested;
session.PrintDeviceCapabilitiesChanged += OnSessionPrintDeviceCapabilitiesChanged;
session.CommunicationErrorDetected += OnCommunicationErrorDetected ;
// Make sure to register all the event handlers before PrintSupportExtensionSession.Start is called.
session.Start();
}
}
private void OnTaskInstanceCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
session = null;
TaskInstanceDeferral.Complete();
}
private void OnCommunicationErrorDetected(PrintSupportExtensionSession sender, PrintSupportCommunicationErrorDetectedEventArgs args)
{
// Using deferral to exclude the background process from being suspended while PSA updates the timeouts.
using (args.GetDeferral())
{
if (args.ErrorKind == IppCommunicationErrorKind.Timeout)
{
PrintSupportIppCommunicationConfiguration ippConfig = args.CommunicationConfiguration;
IppPrintDevice device = sender.Printer;
// Update timeout based on the communication error
}
}
}
}
Печать на IPP-совместимом принтере для исходящих факсов в PSA
В этом примере показано, как отправить задание на печать на принтер IPPFaxOut в PSA.
public sealed class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{
public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
private PrintWorkflowJobBackgroundSession session;
public void Run(IBackgroundTaskInstance taskInstance)
{
TaskInstanceDeferral = taskInstance.GetDeferral();
if (taskInstance.TriggerDetails is PrintWorkflowJobTriggerDetails jobDetails)
{
session = jobDetails.PrintWorkflowJobSession;
session.JobStarting += OnJobStarting;
session.PdlModificationRequested += OnPdlModificationRequested;
session.JobIssueDetected += OnJobIssueDetected;
// Make sure to register all the event handlers before PrintWorkflowJobBackgroundSession.Start is called.
session.Start();
}
}
private async void OnPdlModificationRequested(PrintWorkflowJobBackgroundSession sender, PrintWorkflowPdlModificationRequestedEventArgs args)
{
using (args.GetDeferral())
{
IppPrintDevice printer = args.PrinterJob.Printer;
IInputStream xpsContent = args.SourceContent.GetInputStream();
WorkflowPrintTicket printTicket = args.PrinterJob.GetJobPrintTicket();
string documentFormat = this.GetPrinterDocumentFormat(printer);
PrintWorkflowPdlTargetStream targetStream = args.CreateJobOnPrinter(documentFormat);
IInputStream xpsSourceContent = xpsContent;
if (printer.IsIPPFaxOutPrinter)
{
// Add cover page to XPS source document
xpsSourceContent = this.AddCoverPageToXpsContent(xpsContent);
}
PrintWorkflowPdlConverter pdlConverter;
switch (documentFormat.ToLowerInvariant())
{
case "image/pwg-raster":
pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToPwgr);
break;
case "application/pclm":
pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToPclm);
break;
case "application/pdf":
pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToPdf);
break;
case "image/tiff":
pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToTiff);
break;
default:
// This should not happen, aborting workflow if PSA does not identify the supported PDLs
args.Configuration.AbortPrintFlow(PrintWorkflowJobAbortReason.JobFailed);
return;
}
// Use pdlConverter to convert the source XPS stream to printer's document format and send it to the printer using targetStream.
await pdlConverter.ConvertPdlAsync(printTicket, xpsSourceContent, targetStream.GetOutputStream());
targetStream.CompleteStreamSubmission(PrintWorkflowSubmittedStatus.Succeeded);
}
}
private IInputStream AddCoverPageToXpsContent(IInputStream xpsStream)
{
var coverPageXps = new InMemoryRandomAccessStream();
// Add cover page to XPS content and write to coverPageXps stream
return coverPageXps;
}
}
Отключение пользовательского интерфейса факса для номера телефона из PSA
При поддержке принтера факса IPP в этом примере показан пользовательский интерфейс для запроса пользователя ввести номер факса при печати на принтер факса. Возможно, PSA захочет показать собственный пользовательский интерфейс с дополнительными сведениями и параметрами. Поскольку для пользователя сбивает с толку, если существует два интерфейса для факса, этот пример иллюстрирует вариант для PSA отключить системный пользовательский интерфейс, когда они хотят показать свой пользовательский интерфейс факса.
В следующем примере показано использование API.
public sealed class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{
private void OnJobStarting(PrintWorkflowJobBackgroundSession sender, PrintWorkflowJobStartingEventArgs args)
{
using (args.GetDeferral())
{
// If the job is printing to an Ipp fax printer,
// check whether PSA has a custom UI and disable system UI for getting the fax number.
if (args.IsIPPFaxOutPrinter)
{
if (this.HasCustomUIForFax(args.Printer))
{
args.SkipSystemFaxUI = true;
}
}
}
}
bool HasCustomUIForFax(IppPrintDevice device)
{
bool hasCustomUIForFax = false;
// Check if the PSA does custom UI for the given fax printer.
return hasCustomUIForFax;
}
}
Замечания
Примеры в этой статье основаны на примерах из API PSA версии 1 и версии 2 в руководстве по проектированию приложений для печати Print support app design guide с предположением, что разработчик обладает знанием рабочего процесса API PSA.
В этой статье содержатся расширения для существующего общедоступного API приложения поддержки печати, описанного в руководстве по проектированию приложений поддержки печати и Windows.Graphics.Printing.PrintSupport пространства имен. API PSA позволяет производителям принтеров разрабатывать приложения UWP, которые могут улучшить возможности печати пользователей Windows при использовании драйвера классов Microsoft IPP в папке "Входящие" без необходимости разработки пользовательского драйвера.
Компоненты печати взаимодействуют с приложением PSA через процесс брокера PSA.
Связанные статьи
Отключить Ipp сжатие для задания
Завершение плана обслуживания драйверов сторонних принтеров в Windows
PrintSupportIppCommunicationConfiguration
PrintSupportPrintDeviceCapabilitiesChangedEventArgs
PrintWorkflowJobBackgroundSession
PrintWorkflowJobIssueDetectedEventArgs
PrintWorkflowJobStartingEventArgs
PrintWorkflowPdlConversionType