Sdílet prostřednictvím


Průvodce návrhem rozhraní API pro podporu tisku v3

Tento článek obsahuje pokyny a příklady pro tiskárny OEM a IHV, které implementují aplikaci podpory tisku v3 (PSA) pro své zařízení.

Terminologie

Termín Definice
PSA Aplikace podpory tisku. UWP aplikace, která používá rozhraní API v tomto dokumentu.
IPP Protokol pro tisk přes internet. Používá se z klientského zařízení k interakci s tiskárnou k načtení a nastavení předvoleb tisku a k odeslání dokumentu, který se má vytisknout.
Podpora tisku přidružená tiskárna Fyzická tiskárna IPP, která je propojená s PSA.
Tiskárna IPP Tiskárna, která podporuje protokol IPP.
PDL Jazyk popisu stránky Formát, ve kterém je dokument odeslán do tiskárny.
Přidružená tiskárna PSA Fyzická tiskárna IPP přidružená k aplikaci PSA.
MožnostiTiskovéhoZařízení Formát dokumentu XML pro definování možností tiskárny
RozšířeníPodporyTisku Úloha na pozadí PSA zodpovědná za poskytování funkcí rozšíření omezení tiskárny.

Tento článek obsahuje rozšíření v3 pro stávající veřejné rozhraní API aplikace podpory tisku, jak je popsáno v průvodci návrhem aplikace podpory tisku a obor názvů Windows.Graphics.Printing.PrintSupport. Rozhraní PSA API umožňuje výrobcům tiskáren vyvíjet aplikace pro hardwarovou podporu, které mohou zlepšit uživatelský zážitek z tisku v systému Windows při používání předinstalovaného ovladače Microsoft IPP Class Driver, aniž by bylo nutné vyvíjet vlastní ovladač. Tiskové komponenty komunikují s aplikací PSA prostřednictvím procesu zprostředkovatele PSA.

Další informace najdete v následujících článcích:

Námět Popis
Průvodce návrhem aplikace podpory tisku Poskytuje pokyny a příklady pro tiskárny OEM a IHV, které implementují aplikaci podpory tisku (PSA) pro své zařízení.
Průvodce návrhem rozhraní API pro aplikaci podpory tisku v4 Poskytuje pokyny a příklady pro tiskárny OEM a IHV, které implementují aplikaci podpory tisku v4 (PSA) pro své zařízení.
specifikace manifestu MSIX pro virtuální tiskárnu s podporou tisku Poskytuje pokyny a příklady manifestu MSIX pro tiskárny OEM a IHV, které implementují virtuální tiskárnu s podporou tisku.
podpora přidružení aplikace pro tisk Obsahuje pokyny a příklady pro přidružení aplikace podpory tisku (PSA) k tiskárně.

Významná rozšíření rozhraní API jsou následující:

  • komprese IPP – rozhraní API PSA v3 přidává funkci pro vylepšení tisku protokolu IPP přidáním funkce komprese IPP do tiskové úlohy pro tiskárny IPP, které tuto funkci podporují. Některé PSA můžou mít vlastní kompresi, což znamená, že úloha v IPP má dvojitou kompresi, která ovlivňuje výkon. Aby se to zmírnilo, rozhraní API PSA v3 zavádí vlastnost IsIppCompressionEnabled a funkci DisableIppCompressionForJob (pokud je to potřeba pro zakázání komprese aktuální úlohy) ve třídě modulu runtime PrintWorkflowJobStartingEventArgs (PSA v1 API).

  • Zpracování chyb úloh IPP a informační zpráva k chybě – API PSA v3 zavádí událost JobIssueDetected ve třídě runtime PrintWorkflowJobBackgroundSession (PSA v1 API). Událost se vyvolá pokaždé, když PSA zjistí chybu nebo varování v tiskové úloze. PSA je pak zodpovědná za zobrazení chybového oznámení uživateli. Když PSA zaregistruje tuto událost a nastaví vlastnost SkipSystemErrorToast na true v PrintWorkflowJobIssueDetectedEventArgs, řekne tiskovému systému, aby nezobrazoval informační zprávu tiskového systému Windows. Rozhraní PSA v3 API také poskytuje mechanismus, který umožňuje PSA spustit uživatelské rozhraní, když uživatel interaguje s oznámením.

  • uživatelské časové limity komunikace IPP – rozhraní API ve verzi PSA v3 poskytuje prostředky, pomocí kterých může PSA nastavit časové limity IPP. Kromě toho je třída runtime PrintSupportIppCommunicationConfiguration přidána do PrintSupportPrintDeviceCapabilitiesChangedEventArgs pro manipulaci s IPP časovými limity komunikace. Kromě toho rozhraní API PSA v3 zavádí událost, která se vyvolá, když dojde k chybě při komunikaci protokolu IPP. Událost byla zavedena, aby IHV mohla prošetřit selhání a odpovídajícím způsobem upravit hodnoty časového limitu.

  • podpora IPPFaxOut – rozhraní API PSA v3 přidá do tiskového systému funkci pro podporu tiskáren IPPFaxOut. Aby byla poskytnuta podpora pro fax, PSA podporuje filtr vykreslování pro převod XPS na TIFF. Vzhledem k tomu, že PSA může manipulovat s obsahem XPS před převodem na TIFF, poskytuje výčtovou hodnotu XpsToTiff v PrintWorkflowPdlConversionType, aby měl PSA přístup ke konvertoru pro převod XPS na TIFF. Kromě toho poskytuje vlastnost IsIPPFaxOutPrinter pro runtime třídu IppPrintDevice, aby PSA mohl rozlišovat mezi standardní tiskárnou a tiskárnami IPPFaxOut.

Zakázání komprese protokolu IPP

Komprese IPP se zobrazuje v následující ukázce kódu.

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;
    } 
} 

Zpracování chyb úlohy IPP

Tato ukázka ukazuje, jak se aplikace PSA může registrovat k chybám úloh, zobrazit oznámení pro chyby úloh a spustit uživatelské rozhraní, když uživatel aktivuje oznámení.

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;
    }
}

Nastavení časového limitu komunikace protokolu IPP

Tato ukázka ukazuje, jak nastavit časový limit komunikace protokolu 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;
        }
    }
}

Zpracování chyb komunikace protokolu IPP

Tato ukázka ukazuje, jak zpracovávat chyby komunikace protokolu 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
            }
        }
    }  
}

Tisk na faxovou tiskárnu IPP v PSA

Tato ukázka ukazuje, jak tisknout na tiskárnu IPPFaxOut v aplikaci tiskové služby.

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;
    }
}

Zakázání uživatelského rozhraní faxu pro telefonní číslo z PSA

S podporou faxové tiskárny IPP se v této ukázce zobrazí uživatelské rozhraní pro vyžádání uživatele, aby při tisku na tiskárnu Fax zadal číslo faxu. Ale PSA může chtít zobrazit vlastní uživatelské rozhraní s více informacemi a možnostmi. Vzhledem k tomu, že je pro uživatele matoucí, pokud existují dvě uživatelská rozhraní faxu, ukazuje tato ukázka možnost pro PSA zakázat systémové uživatelské rozhraní, když chce zobrazit své uživatelské rozhraní faxu.

Následující ukázka ukazuje využití rozhraní 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;
    }  
}

Poznámky

Ukázky v tomto článku jsou založené na ukázkách rozhraní API PSA v1 a v2 v průvodci návrhem aplikace Print support s předpokladem, že vývojář je obeznámen s pracovním postupem rozhraní PSA API.

Tento článek obsahuje rozšíření pro stávající veřejné API aplikace podpory tisku popsané v průvodci návrhu aplikace pro podporu tisku a v oboru názvů Windows.Graphics.Printing.PrintSupport. Rozhraní PSA API umožňuje výrobcům tiskáren vyvíjet aplikace pro UWP, které mohou zlepšit zážitek z tisku pro uživatele Windows při použití integrovaného ovladače třídy Microsoft IPP, a to bez potřeby vývoje vlastního ovladače.

Tiskové komponenty komunikují s aplikací PSA prostřednictvím procesu zprostředkovatele PSA.

DisableIppCompressionForJob

Ukončení plánu údržby pro ovladače tiskáren třetích stran ve Windows

IsIppCompressionEnabled

IsIPPFaxOutPrinter

IppPrintDevice

problémSÚkolemZjištěn

KonfiguraceKomunikaceProPodporuTiskuIpp

PrintSupportPrintDeviceCapabilitiesChangedEventArgs

PrintWorkflowJobBackgroundSession

PrintWorkflowJobIssueDetectedEventArgs

PrintWorkflowJobStartingEventArgs

PrintWorkflowPdlConversionType

skipSystemErrorToast

Windows.Graphics.Printing.PrintSupport