Guide de conception des applications de support d’impression
Cet article fournit des conseils et des exemples aux fabricants d’imprimantes et aux fournisseurs IHV pour développer une application de support d’impression (PSA) qui peut améliorer l’expérience d’impression d’un utilisateur Windows de plusieurs façons.
Important
À partir de la publication du SDK de Windows 11 (22000.1), les Applications de Support d’Impression (PSA) sont la méthode recommandée pour développer des applications UWP pour les imprimantes. Pour développer une application de support d’impression pour votre périphérique d’impression, téléchargez et installez le SDK Windows 11 pour la version Windows que vous ciblez.
Important
Ce sujet contient des sections qui décrivent les fonctionnalités PSA disponibles à partir de Windows 11, version 22H2. Ces sections contiennent une note indiquant qu’elle s’applique à cette version.
Certaines fonctionnalités d’imprimante ne sont pas présentées dans les boîtes de dialogue d’impression affichées par Windows car ce sont des fonctionnalités spéciales qui nécessitent l’aide d’une application du fabricant pour être configurées correctement. Elles peuvent également être des fonctionnalités qui ne sont pas fournies dans les capacités par défaut de l’imprimante.
Les fonctionnalités spécifiques à l’imprimante peuvent être regroupées de manière à ce que l’utilisateur puisse facilement choisir une option et faire confiance à ce que toutes les fonctionnalités impliquées dans ce scénario soient automatiquement définies sur les valeurs correctes. Un exemple de cela pourrait être un choix entre des modes d’économie d’encre, d’économie de papier et de qualité optimale qui pourraient manipuler diverses fonctionnalités d’impression automatiquement en fonction d’une sélection de l’utilisateur. Windows est incapable de les regrouper automatiquement car cela nécessite de comprendre toutes les fonctionnalités personnalisées de chaque modèle d’imprimante.
Ce besoin de montrer des préférences d’impression personnalisées est résolu par cette API avec un contrat d’extension UWP optionnel qui peut être activé par l’utilisateur à partir de toutes les boîtes de dialogue d’impression Windows et des boîtes de dialogue d’impression personnalisées qui utilisent l’API fournie par Windows. Les fabricants peuvent adapter leur interface utilisateur pour offrir la meilleure expérience d’impression pour l’imprimante spécifique que l’utilisateur possède.
Un autre domaine où les fabricants d’imprimantes peuvent améliorer et se différencier est la qualité d’impression. Ils peuvent améliorer la qualité d’impression après le rendu en optimisant le contenu pour l’imprimante spécifique. Ils peuvent également présenter un aperçu haute fidélité qui représente mieux la sortie finale car il peut prendre en compte des fonctionnalités spécifiques à l’imprimante.
Terminologie
Terme | Définition |
---|---|
Antigène prostatique spécifique (PSA) | Application de support d’impression. Une application UWP qui utilise l’API décrite dans cet article. |
MPD | Boîte de dialogue d’impression moderne. Cela est montré à l’utilisateur lorsqu’une application imprime en utilisant l’API Windows.Graphics.Printing. |
CPD | Boîte de dialogue d’impression commun. Cela est montré à l’utilisateur lorsqu’une application imprime en utilisant l’API Win32. Les applications qui doivent afficher un aperçu avant impression n’activent pas cette boîte de dialogue et implémentent une version de la boîte de dialogue elles-mêmes. Les applications Office en sont un exemple typique. |
IPP | Protocole d’impression Internet. Utilisé à partir d’un périphérique client pour interagir avec l’imprimante afin de récupérer et définir les préférences d’impression et pour envoyer le document à imprimer. |
Imprimante associée au support d’impression. | Imprimante liée à PSA. |
Imprimante IPP | Imprimante prenant en charge le protocole IPP. |
Plus de paramètres | Lien qui ouvre l’interface utilisateur fournie par le partenaire dans MPD. Par défaut, il ouvre l’interface utilisateur des préférences d’impression intégrées lorsqu’aucune PSA n’est installée. |
Interface utilisateur des préférences d’impression | Boîte de dialogue utilisée pour définir les options d’imprimante par défaut qui sont appliquées au moment de l’impression. Par exemple : orientation, format de papier, couleur, impression recto verso, etc. |
PDL | Langage de description de page. Le format dans lequel un document est envoyé à l’imprimante. |
Imprimante associée à PSA | Imprimante physique IPP associée à une application PSA. |
PrintDeviceCapabilities | Format de document XML pour définir les capacités de l’imprimante. Pour plus d’informations, veuillez consulter la section Technologies de ticket d’impression et de capacités d’impression. |
PrintTicket | Collection de diverses fonctionnalités liées à l’impression et à leurs valeurs utilisées pour capturer l’intention de l’utilisateur pour un travail d’impression donné. |
PrintSupportExtension | Tâche de fond PSA responsable de la fourniture des capacités d’extension de contrainte de l’imprimante. |
Espace de noms de support d’impression
Ces échantillons font référence à un espace de noms printsupport, qui est défini comme :
xmlns:printsupport="http://schemas.microsoft.com/appx/manifest/printsupport/windows10"
Interface utilisateur des paramètres de support d’impression
Lorsqu’un utilisateur s’apprête à imprimer un document, il souhaite souvent définir certaines préférences avec lesquelles l’imprimer. Par exemple, il peut choisir d’imprimer un document en orientation paysage. Il peut également profiter d’une fonction personnalisée que son imprimante prend en charge. Windows fournit une interface utilisateur par défaut pour afficher les préférences personnalisées, mais l’utilisateur peut ne pas les comprendre car il n’y a pas d’icônes ou de descriptions appropriées. Windows peut également utiliser le mauvais contrôle d’interface utilisateur pour les présenter. Une telle fonction personnalisée est mieux présentée par une application qui comprend entièrement la fonction. C’est la motivation derrière l’offre d’une API qui permet aux fabricants d’imprimantes de créer des applications adaptées aux différents modèles d’imprimantes qu’ils fabriquent.
Un nouveau contrat d’extension UAP est créé avec une nouvelle catégorie nommée windows.printSupportSettingsUI. Les applications activées avec ce contrat reçoivent un nouveau type d’activation appelé PrintSupportSettingsUI. Ce contrat ne nécessite aucune nouvelle capacité.
<Extensions>
<printsupport:Extension Category="windows.printSupportSettingsUI"
EntryPoint="PsaSample.PsaSettingsUISample"/>
</Extensions>
Ce contrat est invoqué lorsque l’utilisateur sélectionne Plus de paramètres dans MPD ou Préférences dans CPD. Ce contrat peut également être invoqué à partir de Préférences d’impression dans l’application Paramètres. Lorsque le contrat est activé, l’application reçoit un objet PrintSupportSettingsUISession qui peut être utilisé pour obtenir les objets PrintTicket et PrintDevice actuels. L’objet PrintDevice peut être utilisé pour communiquer avec l’imprimante afin de recevoir les attributs de l’imprimante et du travail. L’application peut ensuite afficher une interface utilisateur avec les options appropriées de l’imprimante à l’utilisateur. Lorsque l’utilisateur fait ses choix et sélectionne OK, l’application peut alors modifier le ticket d’impression, le valider, puis le soumettre à nouveau en utilisant l’objet PrintSupportPrintTicketTarget. Si l’utilisateur choisit d’annuler la fenêtre de préférences, les modifications doivent être abandonnées, et l’application doit se terminer en complétant le report pris à partir de l’objet PrintSupportSettingsUISession.
Il est attendu que l’application de support d’impression gère plusieurs activations simultanées pour différents travaux d’impression, donc une telle application doit prendre en charge plusieurs instances en utilisant l’élément SupportsMultipleInstances dans le fichier package.appxmanifest. Ne pas le faire pourrait entraîner des situations où la confirmation des préférences d’un travail d’impression pourrait fermer d’autres fenêtres de préférences qui pourraient être ouvertes. L’utilisateur est alors tenu d’ouvrir à nouveau ces fenêtres de préférences.
Le diagramme de séquence suivant représente le concept de manipulation du ticket d’impression de l’interface utilisateur des paramètres :
Changement du ticket d’impression dans l’interface utilisateur des paramètres.
Code source C# pour l’activation de l’interface utilisateur des paramètres lorsqu’elle est lancée à partir de n’importe quelle boîte de dialogue d’impression (MPD/CPD ou boîte de dialogue d’impression personnalisée) ou à partir des paramètres système :
namespace PsaSampleApp
{
sealed partial class App : Application
{
Deferral settingsDeferral;
protected override void OnActivated(IActivatedEventArgs args)
{
if (args.Kind == ActivationKind.PrintSupportSettingsUI)
{
// Get the activation arguments
var settingsEventArgs = args as PrintSupportSettingsActivatedEventArgs;
PrintSupportSettingsUISession settingsSession = settingsEventArgs.Session;
// Take deferral
this.settingsDeferral = settingsEventArgs.GetDeferral();
// Create root frame
var rootFrame = new Frame();
// Choose the page to be shown based upon where the application is being launched from
switch (settingsSession.LaunchKind)
{
case SettingsLaunchKind.UserDefaultPrintTicket:
{
// Show settings page when launched for default printer settings
rootFrame.Navigate(typeof(DefaultSettingsView), settingsSession);
}
break;
case SettingsLaunchKind.JobPrintTicket:
{
// Show settings page when launched from printing app
rootFrame.Navigate(typeof(JobSettingsView), settingsSession);
}
break;
}
Window.Current.Content = rootFrame;
}
}
internal void ExitSettings()
{
settingsDeferral.Complete();
}
}
}
XAML pour la classe DefaultSettingsView.
<Page
x:Class="PsaSampleApp.DefaultSettingsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PsaSampleApp"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Vertical" Margin="30,50,0,0">
<ComboBox x:Name="OrientationOptions" ItemsSource="{x:Bind OrientationFeatureOptions}" SelectedItem="{x:Bind SelectedOrientationOption, Mode=TwoWay}" DisplayMemberPath="DisplayName" HorizontalAlignment="Left" Height="Auto" Width="Auto" VerticalAlignment="Top"/>
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Button x:Name="Ok" Content="Ok" HorizontalAlignment="Left" Margin="50,0,0,0" VerticalAlignment="Top" Click="OkClicked"/>
<Button x:Name="Cancel" Content="Cancel" HorizontalAlignment="Left" Margin="20,0,0,0" VerticalAlignment="Top" Click="CancelClicked"/>
</StackPanel>
</Grid>
</Page>
Exemple de code C# pour afficher l’interface utilisateur et modifier le ticket d’impression.
namespace PsaSampleApp
{
/// <summary>
/// Class for showing print settings to the user and allow user to modify it
/// </summary>
public sealed partial class DefaultSettingsView: Page
{
private IppPrintDevice printer;
private PrintSupportSettingsUISession uiSession;
private WorkflowPrintTicket printTicket;
private App application;
// Bound to XAML combo box
public ObservableCollection<PrintTicketOption> OrientationFeatureOptions { get; } = new ObservableCollection<PrintTicketOption>();
public PrintTicketOption SelectedOrientationOption { get; set; }
public SettingsView()
{
this.InitializeComponent();
this.application = Application.Current as App;
this.orientationFeatureOptions = new ObservableCollection<PrintTicketOption>();
}
internal void OnNavigatedTo(NavigationEventArgs e)
{
this.uiSession = = e.Parameter as PrintSupportSettingsUISession;
this.printer = session.SessionInfo.Printer;
this.printTicket = session.SessionPrintTicket;
PrintTicketCapabilities printTicketCapabilities = this.printTicket.GetCapabilities();
// Read orientation feature from PrintTicket capabilities
PrintTicketFeature feature = printTicketCapabilities.PageOrientationFeature;
// Populate XAML combo box with orientation feature options
this.PopulateOrientationOptionComboBox(feature.Options);
PrintTicketOption printTicketOrientationOption = printTicket.PageOrientationFeature.GetSelectedOption();
// Update orientation option in XAML combo box
this.SelectedOrientationOption = this.orientationFeatureOptions.Single((option)=> (option.Name == printTicketOrientationOption.Name && option.XmlNamespace == printTicketOrientationOption.XmlNamespace));
}
private async void OkClicked(object sender, RoutedEventArgs e)
{
// Disable Ok button while the print ticket is being submitted
this.Ok.IsEnabled = false;
// Set selected orientation option in the PrintTicket and submit it
PrintTicketFeature orientationFeature = this.printTicket.PageOrientationFeature;
orientationFeature.SetSelectedOption(this.SelectedOrientationOption);
// Validate and submit PrintTicket
WorkflowPrintTicketValidationResult result = await printTicket.ValidateAsync();
if (result.Validated)
{
// PrintTicket validated successfully – submit and exit
this.uiSession.UpdatePrintTicket(printTicket);
this.application.ExitSettings();
}
else
{
this.Ok.IsEnabled = true;
// PrintTicket is not valid – show error
this.ShowInvalidPrintTicketError(result.ExtendedError);
}
}
private void CancelClicked(object sender, RoutedEventArgs e)
{
this.application.ExitSettings();
}
}
}
Obtenir les attributs d’imprimante à partir du périphérique d’imprimante
Réponse WireShark d’une imprimante IPP à une requête get-printer-attributes :
Exemple de code C# pour obtenir les noms et niveaux d’encre à partir de l’imprimante :
namespace PsaSampleApp
{
/// <summary>
/// Class for showing print settings to the user
/// </summary>
public sealed partial class SettingsView : Page
{
IList<string> inkNames;
IList<int> inkLevels;
private async void GetPrinterAttributes()
{
// Read ink names and levels, along with loaded media-sizes
var attributes = new List<string>();
attributes.Add("marker-names");
attributes.Add("marker-levels");
attributes.Add("media-col-ready");
IDictionary<string, IppAttributeValue> printerAttributes = this.printer.GetPrinterAttributes(attributes);
IppAttributeValue inkNamesValue = printerAttributes["marker-names"];
CheckValueType(inkNamesValue, IppAttributeValueKind.Keyword);
this.inkNames = inkNamesValue.GetKeywordArray();
IppAttributeValue inkLevelsValue = printerAttributes["marker-levels"];
CheckValueType(inkLevelsValue, IppAttributeValueKind.Integer);
this.inkLevels = inkLevelsValue.GetIntegerArray();
// Read loaded print media sizes
IppAttributeValue mediaReadyCollectionsValue = printerAttributes["media-col-ready"];
foreach (var mediaReadyCollection in mediaReadyCollectionsValue.GetCollectionArray())
{
IppAttributeValue mediaSizeCollection;
if (mediaReadyCollection.TryGetValue("media-size", out mediaSizeCollection))
{
var xDimensionValue = mediaSizeCollection.GetCollectionArray().First()["x-dimension"];
var yDimensionValue = mediaSizeCollection.GetCollectionArray().First()["y-dimension"];
CheckValueType(xDimensionValue, IppAttributeValueKind.Integer);
CheckValueType(yDimensionValue, IppAttributeValueKind.Integer);
int xDimension = xDimensionValue.GetIntegerArray().First();
int yDimension = yDimensionValue.GetIntegerArray().First();
this.AddMediaSize(xDimension, yDimension);
}
}
}
private void CheckValueType(IppAttributeValue value, IppAttributeValueKind expectedKind)
{
if (value.Kind != expectedKind)
{
throw new Exception(string.Format("Non conformant type found: {0}, expected: {1}", value.Kind, expectedKind));
}
}
}
}
Paramétrage des attributs de l’imprimante.
Exemple de code C# pour définir les attributs de l’imprimante :
int defaultResolutionX = 1200;
int defaultResolutionY = 1200;
string pdlFormat = "image/pwg-raster";
private async void SetPrinterAttributes()
{
var attributes = new Dictionary<string, IppAttributeValue>();
attributes.Add("document-format-default", IppAttributeValue.CreateKeyword(this.pdlFormat));
var resolution = new IppResolution(this.defaultResolutionX, this.defaultResolutionY, IppResolutionUnit.DotsPerInch);
attributes.Add("printer-resolution-default", IppAttributeValue.CreateResolution(resolution));
var result = this.printer.SetPrinterAttributes(attributes);
if (!result.Succeeded)
{
foreach (var attributeError in result.AttributeErrors)
{
var attributeName = attributeError.Key;
switch (attributeError.Value.Reason)
{
case IppAttributeErrorReason.AttributeValuesNotSupported:
var values = attributeError.Value.GetUnsupportedValues().First();
this.LogUnSupportedValues(attributeName, values);
break;
case IppAttributeErrorReason.AttributeNotSettable:
this.LogAttributeNotSettable(attributeName);
break;
case IppAttributeErrorReason.AttributeNotSupported:
this.LogAttributeNotSupported(attributeName);
break;
case IppAttributeErrorReason.RequestEntityTooLarge:
this.LogAttributeNotEntityTooLarge(attributeName);
break;
case IppAttributeErrorReason. ConflictingAttributes:
this.LogConflictingAttributes(attributeName);
break;
}
}
}
}
Extension des contraintes de l’imprimante
L’application de support d’impression prend en charge la validation personnalisée du ticket d’impression et la définition du ticket d’impression par défaut. Cette section décrit comment nous prenons en charge ces fonctionnalités.
Pour prendre en charge les contraintes d’extension de l’imprimante, un nouveau type de tâche en arrière-plan, PrintSupportExtension, a été implémenté. Le Package.appxmanifest comporte une entrée d’extensibilité pour l’extension Print Support, comme illustré ici :
<Extensions>
<printsupport:Extension Category="windows.printSupportExtension"
EntryPoint="PsaBackgroundTasks.PrintSupportExtension"/>
</Extensions>
Ce service peut s’exécuter à n’importe quel moment dans un travail d’impression pour l’imprimante IPP associée. Lorsque l’extension Print Support est activée via la fonction Run(IBackgroundTaskInstance taskInstance), une instance de IBackgroundTaskInstance est donnée à PrintSupportExtension pour permettre l’accès à la classe d’exécution PrintSupportExtensionTriggerDetails, qui fournit internement PrintSupportExtensionSession en tant que propriété. La classe d’arrière-plan PrintSupportExtension peut ensuite utiliser l’objet de session pour s’inscrire aux événements qu’elle souhaite fournir pour une fonctionnalité personnalisée.
event Windows.Foundation.TypedEventHandler<PrintSupportExtensionSession, PrintSupportPrintTicketValidationRequestedEventArgs>; PrintTicketValidationRequested;
Si l’extension Print Support fournit son propre mécanisme de validation du PrintTicket, elle peut s’inscrire à cet événement. Chaque fois qu’un PrintTicket doit être validé, le système d’impression déclenche cet événement. PrintSupportExtension obtiendra alors le PrintTicket actuel qui doit être validé dans les EventArgs. La classe d’arrière-plan PrintSupportExtension peut alors vérifier le PrintTicket pour sa validité et le modifier pour résoudre tout conflit. Ensuite, la classe d’arrière-plan PrintSupportExtension doit définir le résultat de validation en utilisant la fonction SetPrintTicketResult pour indiquer si le PrintTicket a été résolu, s’il présente des conflits ou s’il est invalide. Cet événement peut être déclenché à tout moment pendant la durée de vie d’un travail d’impression. Si la classe PrintSupportExtension ne s’inscrit pas à cet événement, le système d’impression effectue sa propre validation du PrintTicket.
event Windows.Foundation.TypedEventHandler<PrintSupportExtensionSession, PrintSupportPrintDeviceCapabilitiesChangedEventArgs>; PrintDeviceCapabilitiesChanged;
L’événement est déclenché après que le système d’impression met à jour les capacités d’imprimante mises en cache de l’imprimante IPP associée. Lorsque cet événement est déclenché, la classe d’arrière-plan PrintSupportExtension peut inspecter les capacités d’imprimante modifiées et les modifier.
Validation personnalisée du ticket d’impression
Exemple de code C# pour fournir un service de validation du ticket d’impression :
public void Run(IBackgroundTaskInstance taskInstance)
{
// Take task deferral
this.taskDeferral = taskInstance.GetDeferral();
// Associate a cancellation handler with the background task
taskInstance.Canceled += OnTaskCanceled;
var psaTriggerDetails = taskInstance.TriggerDetails as PrintSupportExtensionTriggerDetails;
var serviceSession = psaTriggerDetails.Session as PrintSupportExtensionSession;
this.ippPrintDevice = serviceSession.Printer;
serviceSession.PrintTicketValidationRequested += this.OnPrintTicketValidationRequested;
serviceSession.PrinterDeviceCapabilitiesChanged += this.OnPdcChanged;
serviceSession.Start();
}
private void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
// Complete the deferral
this.taskDeferral.Complete();
}
private void OnPrintTicketValidationRequested(PrintSupportExtensionSession session, PrintSupportPrintTicketValidationRequestedEventArgs args)
{
using (args.GetDeferral())
{
// Get PrintTicket that needs needs to be validated and resolved
var printTicket = args.PrintTicket;
// Validate and resolve PrintTicket
WorkflowPrintTicketValidationStatus validationStatus = this.ValidateAndResolvePrintTicket(printTicket);
args.SetPrintTicketValidationStatus(validationStatus);
}
}
Mise à jour des capacités de l’appareil d’impression
private void OnPdcChanged(PrintSupportExtensionSession session, PrintSupportPrintDeviceCapabilitiesChangedEventArgs args)
{
using (args.GetDeferral())
{
var pdc = args.GetCurrentPrintDeviceCapabilities();
// Check current PDC and make changes according to printer device capabilities
XmlDocument newPdc = this.CheckAndUpdatePrintDeviceCapabilities(pdc);
args.UpdatePrintDeviceCapabilities(newPdc);
}
}
Amélioration de la qualité d’impression
Une fois que l’utilisateur a confirmé l’impression en appuyant sur le bouton d’impression dans la boîte de dialogue d’impression, le document à imprimer est envoyé à la pile d’impression depuis l’application qui imprime. Ce document subit ensuite une transformation (rendu en PDL) pour le rendre adapté à l’imprimante cible. Windows déterminera quelle transformation choisir en fonction des attributs interrogés auprès de l’imprimante. Le document transformé est ensuite envoyé à l’imprimante. Bien que cela fonctionne bien pour la plupart des imprimantes, il existe des cas où la qualité d’impression pourrait être améliorée en permettant à une application partenaire de participer à la transformation. Pour faciliter cela, l’API de flux de travail d’impression actuelle est étendue pour inclure des appels à l’application à des points supplémentaires depuis la pile d’impression. Cette API prend en charge deux nouveaux événements auxquels l’application PSA peut s’inscrire. Ceux-ci sont les seuls points d’entrée dans la surface API de PSA :
JobStarting
- Cet événement est déclenché lorsqu’un travail d’impression est lancé par n’importe quelle application. Lorsque l’événement est déclenché, une application d’assistance à l’impression peut choisir de sauter le rendu système en appelant SetSkipSystemRendering sur PrintWorkflowJobStartingEventArgs. Si le saut du rendu système est choisi, le système d’impression ne convertira pas le document XPS en format PDL requis par l’imprimante. Au lieu de cela, le XPS généré par l’application d’impression sera directement transmis à l’application PSA, qui sera alors responsable de la conversion du XPS en format PDL.
PdlModificationRequested
- Cet événement est déclenché lorsque Windows commence la conversion du flux XPS vers le format PDL indiqué par l’imprimante. La classe d’exécution PrintWorkflowPdlModificationRequestedEventArgs est fournie en tant qu’argument pour cet événement. Cette classe d’événement fournit des objets source et cible PDL pour lire et écrire le contenu du travail d’impression. Si l’application détermine qu’elle a besoin de l’entrée de l’utilisateur, elle peut lancer une UI en utilisant PrintWorkflowUILauncher depuis EventArgs. Cette API utilise le modèle Tester-Doer. PrintWorkflowUILauncher ne pourra pas invoquer l’interface utilisateur si la fonction IsUILaunchEnabled retourne false. Cette fonction retourne false si la session PSA fonctionne en mode silencieux (mode autonome ou mode kiosque). L’application d’assistance à l’impression ne doit pas essayer de lancer une UI si la fonction retourne false.
Un OutputStream est disponible en tant que partie de PrintWorkflowPdlTargetStream qui est retourné par la fonction GetStreamTargetAsync. Le contenu écrit sur le OutputStream cible est transmis à l’imprimante en tant que contenu du document.
Diagramme de séquence pour l’événement de modification PDL :
L’application en premier plan de l’application PSA est lancée lorsque la tâche en arrière-plan de l’application PSA demande le lancement de l’interface utilisateur. L’application PSA peut utiliser le contrat en premier plan pour obtenir l’entrée de l’utilisateur et/ou pour afficher un aperçu de l’impression à l’utilisateur.
Tâche en arrière-plan du flux de travail d’assistance à l’impression
Un nouveau type de tâche en arrière-plan, printSupportWorkflow, a été défini. Le Package.appxmanifest a la nouvelle entrée d’extensibilité pour le contrat PrintSupportWorkflow :
<Extensions>
<printsupport:Extension Category="windows.printSupportWorkflow"
EntryPoint="PsaBackgroundTasks.PrintSupportWorkflowSample"/>
</Extensions>
Lors de l’activation du contrat, PrintWorkflowJobTriggerDetails est donné en tant que IBackgroundTaskInstance->TriggerDetails. PrintWorkflowJobTriggerDetails fournit internement PrintWorkflowJobBackgroundSession en tant que partie de ses propriétés. L’application peut utiliser PrintWorkflowJobBackgroundSession pour s’inscrire aux événements liés aux différents points d’injection dans le flux de travail du travail d’impression. Après l’inscription aux événements, l’application doit appeler la fonction PrintWorkflowJobBackgroundSession::Start pour que le système d’impression commence à déclencher des événements liés aux différents points d’injection.
Interface utilisateur du travail d’impression du flux de travail
Un nouveau ActivationKind appelé PrintSupportJobUI est défini. Cela ne nécessite pas une nouvelle capacité.
<Extensions>
<printsupport:Extension Category="windows.printSupportJobUI"
EntryPoint="PsaSample.PrintSupportJobUISample"/>
</Extensions>
C’est un contrat d’interface utilisateur qui peut être lancé à partir du contrat de fond de workflow d’assistance à l’impression, ou lorsque l’utilisateur sélectionne une notification d’erreur de travail d’impression. Lors de l’activation, PrintWorkflowJobActivatedEventArgs est fourni, qui a un objet PrintWorkflowJobUISession. En utilisant PrintWorkflowJobUISession, l’application en premier plan doit s’inscrire à l’événement PdlDataAvailable si elle souhaite accéder aux données PDL. Si l’application en premier plan souhaite afficher des messages d’erreur personnalisés pour toute erreur pouvant survenir pendant le travail, elle doit s’inscrire à l’événement JobNotification. Une fois les événements enregistrés, l’application doit appeler la fonction PrintWorkflowJobUISession::Start afin que le système d’impression commence à déclencher des événements.
Saut du rendu système
namespace PsaBackground
{
class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{
BackgroundTaskDeferral taskDeferral;
public void Run(IBackgroundTaskInstance taskInstance)
{
// Take Task Deferral
taskDeferral = taskInstance.GetDeferral();
var jobTriggerDetails = taskInstance.TriggerDetails as PrintWorkflowJobTriggerDetails;
var workflowBackgroundSession = jobTriggerDetails.PrintWorkflowJobSession as PrintWorkflowJobBackgroundSession;
// Register for events
workflowBackgroundSession.JobStarting += this.OnJobStarting;
workflowBackgroundSession.PdlModificationRequested += this.OnPdlModificationRequested;
// Start Firing events
workflowBackgroundSession.Start();
}
private void OnJobStarting(PrintWorkflowJobBackgroundSession session, PrintWorkflowJobStartingEventArgs args)
{
using (args.GetDeferral())
{
// Call SetSkipSystemRendering to skip conversion for XPS to PDL, so that PSA can directly manipulate the XPS file.
args.SetSkipSystemRendering();
}
}
}
}
Événement de modification PDL
Diagramme de séquence pour l’événement de modification PDL :
Exemple de code en C# pour la lecture et l’écriture du contenu du travail d’impression depuis le moniteur d’emploi d’assistance à l’impression :
private void OnPdlModificationRequested(PrintWorkflowJobBackgroundSession session, PrintWorkflowPdlModificationRequestedEventArgs args)
{
using (args.GetDeferral())
{
IInputStream pdlContent = args.SourceContent.GetInputStream();
// Specify the Content type of stream that will be written to target that is passed to printer accordingly.
PrintWorkflowPdlTargetStream streamTarget = args.CreateJobOnPrinter(args.SourceStream.ContentType);
IOutputStream outputStream = streamTarget.GetOutputStream();
using (var inputReader = new Windows.Storage.Streams.DataReader(pdlContent))
{
inputReader.InputStreamOptions = InputStreamOptions.Partial;
using (var outputWriter = new Windows.Storage.Streams.DataWriter(outputStream))
{
// Write the updated Print stream from input stream to the output stream
uint chunkSizeInBytes = 256 * 1024; // 256K chunks
uint lastAllocSize = 0;
byte[] contentData = new byte[chunkSize];
while(this.ReadChunk(inputReader, ref contentData))
{
// Make any changes required to the input data
// ...
// Write out the modified content
outputWriter.WriteBytes(contentData);
await outputWriter.StoreAsync();
}
}
}
streamTarget.CompleteStreamSubmission(PrintWorkflowSubmittedStatus.Succeeded);
this.taskDeferral.Complete();
}
}
}
Lancement de l’interface utilisateur depuis l’arrière-plan du flux de travail
Exemple de code en C# pour le lancement de l’interface utilisateur du travail d’impression depuis le contrat d’événement de modification PDL de l’application PSA :
private async void OnPdlModificationRequested(PrintWorkflowJobBackgroundSession session, PrintWorkflowPdlModificationRequestedEventArgs args)
{
IInputStream pdlContent = args.SourceContent.GetInputStream();
WorkflowPrintTicket printTicket = args.PrinterJob.GetJobPrintTicket();
bool uiRequired = this.IsUIRequired(pdlContent, printTicket);
if (!uiRequired)
{
// Specify the Content type of content that will be written to target that is passed to printer accordingly.
PrintWorkflowPdlTargetStream streamTarget = args.CreateJobOnPrinter (args.SourceStream.ContentType);
// Process content directly if UI is not required
this.ProcessContent(pdlContent, streamTarget);
}
else if (args.UILauncher.IsUILaunchEnabled())
{
// LaunchAndCompleteUIAsync will launch the UI and wait for it to complete before returning
PrintWorkflowUICompletionStatus status = await args.UILauncher.LaunchAndCompleteUIAsync();
if (status == PrintWorkflowUICompletionStatus.Completed)
{
PrintWorkflowPdlTargetStream streamTarget = args.CreateJobOnPrinter(args.SourceStream.ContentType);
this.ProcessContent(pdlContent, streamTarget);
}
else
{
if (status == PrintWorkflowUICompletionStatus.UserCanceled)
{
// Log user cancellation and cleanup here.
this.taskDeferral.Complete();
}
else
{
// UI launch failed, abort print job.
args.Configuration.AbortPrintFlow(PrintWorkflowAbortReason.JobFailed);
this.taskDeferral.Complete();
}
}
}
else
{
// PSA requires to show UI, but launching UI is not supported at this point because of user selection.
args.Configuration.AbortPrintFlow(PrintWorkflowAbortReason.JobFailed);
this.taskDeferral.Complete();
}
}
Activation de l’interface utilisateur du travail d’impression pour l’événement PDLDataAvailable
Diagramme de séquence pour l’activation de l’interface utilisateur du travail d’impression pour l’événement PdlDataAvailable :
Exemple de code en C# pour le contrat d’activation de l’interface utilisateur du travail d’impression de l’application PSA :
namespace PsaSampleApp
{
sealed partial class App : Application
{
protected override void OnActivated(IActivatedEventArgs args)
{
if (args.Kind == ActivationKind.PrintSupportJobUI)
{
var rootFrame = new Frame();
rootFrame.Navigate(typeof(JobUIPage));
Window.Current.Content = rootFrame;
var jobUI = rootFrame.Content as JobUIPage;
// Get the activation arguments
var workflowJobUIEventArgs = args as PrintWorkflowJobActivatedEventArgs;
PrintWorkflowJobUISession session = workflowJobUIEventArgs.Session;
session.PdlDataAvailable += jobUI.OnPdlDataAvailable;
session.JobNotification += jobUI.OnJobNotification;
// Start firing events
session.Start();
}
}
}
}
namespace PsaSampleApp
{
public sealed partial class JobUIPage : Page
{
public JobUIPage()
{
this.InitializeComponent();
}
public string WorkflowHeadingLabel;
public void OnPdlDataAvailable(PrintWorkflowJobUISession session, PrintWorkflowPdlDataAvailableEventArgs args)
{
using (args.GetDeferral())
{
string jobTitle = args.Configuration.JobTitle;
string sourceApplicationName = args.Configuration.SourceAppDisplayName;
string printerName = args.Printer.PrinterName;
this.WorkflowHeadingLabel = string.Format(this.formatHeading, jobTitle, sourceApplicationName, printerName);
// Get pdl stream and content type
IInputStream pdlContent = args.SourceContent.GetInputStream();
string contentType = args.SourceContent.ContentType;
this.ShowPrintPreview(pdlContent, contentType);
}
}
}
}
Obtenir les attributs de travail de l’imprimante
Exemple de code en C# pour obtenir les attributs de travail pour un travail d’impression :
namespace PsaBackground
{
class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{
private async void OnPdlModificationRequested(PrintWorkflowJobBackgroundSession session,
PrintWorkflowPdlModificationRequestedEventArgs args)
{
using (args.GetDeferral())
{
string colorMode = this.GetJobColorMode(args.PrinterJob);
if (colorMode != "monochrome")
{
this.SetJobColorModeToMonochrome(args.PrinterJob);
}
}
}
private string GetJobColorMode(PrintWorkflowPrinterJob printerJob)
{
var attributes = new List<string>();
attributes.Add("print-color-mode");
// Gets the IPP attributes from the current print job
IDictionary<string, IppAttributeValue> printerAttributes = printerJob.GetJobAttributes(attributes);
var colorModeValue = printerAttributes["print-color-mode"];
this.CheckValueType(colorModeValue, IppAttributeValueKind.Keyword);
return colorModeValue.GetKeywordArray().First();
}
}
}
Définir les attributs de travail de l’imprimante
Exemple de code en C#, en continuant à partir de la section Obtenir les attributs de travail de l’imprimante ci-dessus, démontrant le réglage des attributs de travail :
private async void SetJobColorModeToMonochrome(PrintWorkflowPrinterJob printerJob)
{
var attributes = new Dictionary<string, IppAttributeValue>();
attributes.Add("print-color-mode", IppAttributeValue.CreateKeyword("monochrome"));
var result = PrinterJob.SetJobAttributes(attributes);
if (!result.Succeeded)
{
this.LogSetAttributeError(result.AttributeErrors);
}
}
Certains imprimantes IPP ne prennent pas en charge l’obtention/définition des attributs de travail après la création du travail. Pour ces imprimantes, PrintJob a la propriété JobId définie sur « 0 » et GetJobAttributes/SetJobAttributes échouera immédiatement avec une exception.
Fournir l’accès à un fichier de stockage au contenu PDL
Certains formats PDL comme le PDF nécessitent un flux complet disponible pour commencer le traitement. Pour cette raison, une nouvelle méthode nommée GetContentFileAsync est fournie sur la classe PrintWorkflowPdlSourceContent qui retourne un StorageFile du contenu source.
public sealed partial class JobUIPage : Page
{
public async void OnPdlDataAvailable(PrintWorkflowJobUISession session, PrintWorkflowPdlDataAvailableEventArgs args)
{
using (args.GetDeferral())
{
if (String.Equals(args.SourceContent.ContentType, "application/pdf", StringComparison.OrdinalIgnoreCase))
{
// Wait for all PDL data to be available
StorageFile sourceFile == await args.SourceContent.GetContentFileAsync();
IRandomAccessStream sourceStream = await sourceFile.OpenReadAsync();
PdfDocument pdfDocument = await PdfDocument.LoadFromStreamAsync(sourceStream);
for (uint i = 0; i < pdfDocument.PageCount; i++)
{
PdfPage page = pdfDocument.GetPage(i);
var pageImage = new InMemoryRandomAccessStream();
await page.RenderToStreamAsync(pageImage);
this.AddImageToPreviewImageList(pageImage);
}
}
}
}
}
Conversion PDL de XPS en PDF
Exemple de code en C# montrant la conversion PDL de XPS en PDF :
private async void OnPdlModificationRequested(PrintWorkflowJobBackgroundSession session, PrintWorkflowPdlModificationRequestedEventArgs args)
{
using (args.GetDeferral())
{
if (String.Equals(args.SourceContent.ContentType, "application/oxps", StringComparison.OrdinalIgnoreCase))
{
var xpsContent = args.SourceContent.GetInputStream();
var printTicket = args.PrinterJob.GetJobPrintTicket();
PrintWorkflowPdlTargetStream streamTarget = args.CreateJobOnPrinter("application/pdf");
// Modify XPS stream here to make the needed changes
// for example adding a watermark
PrintWorkflowPdlConverter pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToPdf);
await pdlConverter.ConvertPdlAsync(printTicket, xpsContent, streamTarget.GetOutputStream());
streamTarget.CompleteStreamSubmission(PrintWorkflowSubmittedStatus.Succeeded);
}
else
{
// We except source content to be XPS in this case, abort the session if it is not XPS.
args.Configuration.AbortPrintFlow(PrintWorkflowAbortReason.JobFailed);
}
}
this.taskDeferral.Complete();
}
Événement de notification de travail
Diagramme de séquence pour l’événement de notification de travail :
Exemple de code en C#, en continuant à partir de la section d’activation de l’interface utilisateur du travail d’impression pour l’événement PDLDataAvailable ci-dessus, pour montrer une erreur de notification de travail :
public sealed partial class JobUIPage : Page
{
public void OnJobNotification(PrintWorkflowJobUISession session, PrintWorkflowJobNotificationEventArgs args)
{
using (args.GetDeferral())
{
PrintWorkflowPrinterJobStatus jobStatus = args.PrintJob.GetJobStatus();
switch (jobStatus)
{
case PrintWorkflowPrinterJobStatus::Error:
// Show print job error to the user
Frame->Navigate(JobErrorPage::typeid, this);
break;
case PrintWorkflowPrinterJobStatus::Abort:
// Show message that print job has been aborted.
Frame->Navigate(JobAbortPage::typeid, this);
break;
case PrintWorkflowPrinterJobStatus::Completed:
// Show job successfully completed message to the user.
Frame->Navigate(JobCompletedPage::typeid, this);
break;
}
}
}
}
Créer un travail avec des attributs de travail initiaux
Actuellement, certaines imprimantes IPP ne prennent pas en charge l’opération de définition d’attributs. La fonction CreateJobOnPrinterWithAttributes et la fonction CreateJobOnPrinterWithAttributesBuffer sur PrintWorkflowPdlDataAvailableEventArgs sont fournies pour atténuer ce problème. En utilisant ces API, un développeur PSA peut fournir des attributs de travail qui sont transmis à l’imprimante lorsque le travail est créé sur l’imprimante.
public sealed partial class JobUIPage : Page
{
public async void OnPdlDataAvailable(PrintWorkflowJobUISession session, PrintWorkflowPdlDataAvailableEventArgs args)
{
var attributes = new Dictionary<string, IppAttributeValue>();
attributes.Add("print-color-mode", IppAttributeValue.CreateKeyword("monochrome"));
// Create job on printer with initial job attributes
PrintWorkflowPdlTargetStream streamTarget = args.CreateJobOnPrinterWithAttributes(attributes, "application/pdf");
// Write data to target stream
}
}
Traitement séquentiel XPS
Exemple de code C++/Winrt pour traiter séquentiellement le XPS avant que l’impression ne soit terminée.
namespace winrt
{
struct WorkflowReceiver : public winrt::implements<WorkflowReceiver, IPrintWorkflowXpsReceiver2>
{
STDMETHODIMP SetDocumentSequencePrintTicket(_In_ IStream* documentSequencePrintTicket) noexcept override
{
// process document sequence print ticket
return S_OK;
}
STDMETHODIMP SetDocumentSequenceUri(PCWSTR documentSequenceUri) noexcept override
{
// process document sequence URI
}
STDMETHODIMP AddDocumentData(UINT32 documentId, _In_ IStream* documentPrintTicket,
PCWSTR documentUri) noexcept override
{
// process document URI and print ticket
return S_OK;
}
STDMETHODIMP AddPage(UINT32 documentId, UINT32 pageId,
_In_ IXpsOMPageReference* pageReference, PCWSTR pageUri) noexcept override
{
// process XPS page
return S_OK;
}
STDMETHODIMP Close() noexcept override
{
// XPS processing finished
return S_OK;
}
STDMETHODIMP Failed(HRESULT XpsError) noexcept override
{
// XPS processing failed, log error and exit
return S_OK;
}
};
void PsaBackgroundTask::OnPdlModificationRequested(PrintWorkflowJobBackgroundSession session,
PrintWorkflowPdlModificationRequestedEventArgs args)
{
auto contentType = args.SourceContent().ContentType();
if (contentType == L"application/oxps")
{
auto xpsContent = args.SourceContent().GetInputStream();
PrintWorkflowObjectModelSourceFileContent xpsContentObjectModel(xpsContent);
com_ptr<IPrintWorkflowObjectModelSourceFileContentNative> xpsContentObjectModelNative;
check_hresult(winrt::get_unknown(xpsContentObjectModel)->QueryInterface(
IID_PPV_ARGS(xpsContentObjectModelNative.put())));
auto xpsreceiver = make_self<WorkflowReceiver>();
check_hresult(xpsContentObjectModelNative->StartXpsOMGeneration(xpsreceiver.get()));
}
}
}
Localisation du nom d’affichage et intégration de l’API de transfert de PDL
Important
Cette section décrit les fonctionnalités de l’application d’assistance à l’impression (PSA) disponibles à partir de Windows 11, version 22H2.
Dans ce scénario, l’application PSA personnalise les Capacités de l’appareil d’impression (PDC) et fournit des Ressources de l’appareil d’impression (PDR) pour la localisation des chaînes.
L’application PSA définit également les types de contenu pris en charge par l’API de transfert de PDL (formats de PDL). Si l’application PSA ne s’abonne pas à l’événement ou n’appelle pas explicitement SetSupportedPdlPassthroughContentTypes, le transfert de PDL est désactivé pour les imprimantes associées à cette application PSA.
// Event handler called every time PrintSystem updates PDC or BindPrinter is called
private void OnPdcChanged(PrintSupportExtensionSession session, PrintSupportPrintDeviceCapabilitiesChangedEventArgs args)
{
using (args.GetDeferral())
{
XmlDocument pdc = args.GetCurrentPrintDeviceCapabilities();
XmlDocument pdr = args.GetCurrentPrintDeviceResources();
// Check current PDC and make changes according to printer device capabilities
XmlDocument newPdc = this.CheckAndUpdatePrintDeviceCapabilities(pdc);
// Get updated printer devices resources, corresponding to the new PDC
XmlDocument newPdr = this.GetPrintDeviceResourcesInfo(newPdc, pdr, args.ResourceLanguage);
// Update supported PDL formats
args.SetSupportedPdlPassthroughContentTypes(GetSupportedPdlContentTypes());
args.UpdatePrintDeviceCapabilities(newPdc);
args.UpdatePrintDeviceResources(newPdr);
}
}
Prise en charge des fonctionnalités au niveau de la page et des attributs d’opération
Important
Cette section décrit les fonctionnalités de l’application d’assistance à l’impression (PSA) disponibles à partir de Windows 11, version 22H2.
Le support des fonctionnalités au niveau de la page et des attributs d’opération sont regroupés car ils sont traités en apportant des modifications au même endroit dans le code source d’exemple.
Support des fonctionnalités au niveau de la page : Dans ce scénario, l’application PSA spécifie l’attribut au niveau de la page, qui ne doit pas être remplacé par un attribut IPP analysé à partir du PrintTicket.
Collection séparée pour le support des attributs d’opération (impression PIN) : Dans ce scénario, l’application PSA spécifie des attributs d’opération IPP personnalisés (par exemple, PIN).
Le code source d’exemple C# suivant montre les modifications nécessaires pour les scénarios Support des fonctionnalités au niveau de la page et Collection séparée pour les attributs d’opération.
private void OnPdlModificationRequested(PrintWorkflowJobBackgroundSession session, PrintWorkflowPdlModificationRequestedEventArgs args)
{
using (args.GetDeferral())
{
IInputStream pdlContent = args.SourceContent.GetInputStream();
// Custom job attributes to add to the printJob
IDictionary<string, IppAttributeValue> jobAttributes = LocalStorageUtil.GetCustomIppJobAttributes();
// Custom operation attributes to add to printJob
IDictionary<string, IppAttributeValue> operationAttributes = LocalStorageUtil.GetCustomIppOperationAttributes();
// PSA has an option to select preferred PDL format
string documentFormat = GetDocumentFormat(args.PrinterJob.Printer);
// Create PrintJob with specified PDL and custom attributes
PrintWorkflowPdlTargetStream targetStream = args.CreateJobOnPrinterWithAttributes(jobAttributes, documentFormat , operationAttributes,
PrintWorkflowAttributesMergePolicy .DoNotMergeWithPrintTicket /*jobAttributesMergePolicy*/, PrintWorkflowAttributesMergePolicy.MergePreferPsaOnConflict /*operationAttributesMergePolicy*/);
// Adding a watermark to the output(targetStream) if source payload type is XPS
this.ModifyPayloadIfNeeded(targetStream, args, documentFormat, deferral);
// Marking the stream submission as Succeeded.
targetStream.CompleteStreamSubmission(PrintWorkflowSubmittedStatus.Succeeded);
this.taskDeferral.Complete();
}
}
Amélioration de la boîte de dialogue d’impression avec PSA
Important
Cette section décrit les fonctionnalités de l’application d’assistance à l’impression (PSA) disponibles à partir de Windows 11, version 22H2.
Dans ce scénario, l’utilisation de la boîte de dialogue d’impression avec l’intégration PSA permet les actions suivantes :
Recevoir un rappel lorsque la sélection est modifiée dans le MPD vers l’imprimante associée à la PSA.
Afficher une AdaptiveCard avec une action de openUrl.
Afficher des fonctionnalités et des paramètres personnalisés sur la boîte de dialogue d’impression.
Modifier le PrintTicket, modifiant ainsi la sélection des options de fonctionnalités affichées dans la boîte de dialogue d’impression.
Obtenir les informations Windows.ApplicationModel.AppInfo de l’application d’impression, ouvrir la boîte de dialogue d’impression.
Le code source d’exemple C# suivant illustre ces améliorations de la boîte de dialogue d’impression :
public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
public void Run(IBackgroundTaskInstance taskInstance)
{
// Take task deferral
TaskInstanceDeferral = taskInstance.GetDeferral();
// Associate a cancellation handler with the background task
taskInstance.Canceled += OnTaskCanceled;
if (taskInstance.TriggerDetails is PrintSupportExtensionTriggerDetails extensionDetails)
{
PrintSupportExtensionSession session = extensionDetails.Session;
session.PrintTicketValidationRequested += OnSessionPrintTicketValidationRequested;
session.PrintDeviceCapabilitiesChanged += OnSessionPrintDeviceCapabilitiesChanged;
session.PrinterSelected += this.OnPrinterSelected;
}
}
private void OnTaskInstanceCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
TaskInstanceDeferral.Complete();
}
// Event handler called when the PSA Associated printer is selected in Print Dialog
private void OnPrinterSelected(PrintSupportExtensionSession session, PrintSupportPrinterSelectedEventArgs args)
{
using (args.GetDeferral())
{
// Show adaptive card in the Print Dialog (generated based on Printer and Printing App)
args.SetAdaptiveCard (GetCustomAdaptiveCard(session.Printer, args.SourceAppInfo));
// Request to show Features and Parameters in the Print Dialog if not shown already
const string xmlNamespace = "\"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords\"";
var additionalFeatures= new List<PrintSupportPrintTicketElement> { new PrintSupportPrintTicketElement { LocalName = "PageMediaType", NamespaceUri = xmlNamespace } };
var additionalParameters = new List<PrintSupportPrintTicketElement> { new PrintSupportPrintTicketElement { LocalName = "JobCopiesAllDocuments", NamespaceUri = xmlNamespace } };
if ((featuresToShow.Count + parametersToShow.Count) <= args.AllowedCustomFeaturesAndParametersCount)
{
args.SetAdditionalFeatures(additionalFeatures);
args.SetAdditionalParameter(additionalParameters);
}
else
{
// Cannot show that many additional features and parameters, consider reducing the number
// of additional features and parameters by selecting only the most important ones
}
}
}
// Create simple AdaptiveCard to show in MPD
public IAdaptiveCard GetCustomAdaptiveCard(IppPrintDevice ippPrinter, AppInfo appInfo)
{
return AdaptiveCardBuilder.CreateAdaptiveCardFromJson($@"
{{""body"": [
{{
""type"": ""TextBlock"",
""text"": ""Hello {appInfo.DisplayInfo.DisplayName} from {ippPrinter.PrinterName}!""
}}
],
""$schema"": ""http://adaptivecards.io/schemas/adaptive-card.json"",
""type"": ""AdaptiveCard"",
""version"": ""1.0""
}}");
}
Conversion PDL avec des indicateurs de traitement basé sur l’hôte
Important
Cette section décrit les fonctionnalités de l’application d’assistance à l’impression (PSA) disponibles à partir de Windows 11, version 22H2.
L’API actuelle de conversion PDL, PrintWorkflowPdlConverter.ConvertPdlAsync, effectue par défaut un traitement basé sur l’hôte. Cela signifie que l’ordinateur hôte/imprimante effectue la rotation, l’ordre des pages, etc., de sorte que l’imprimante n’ait pas besoin d’effectuer ces opérations. Cependant, les fournisseurs de périphériques d’impression (IHV) peuvent souhaiter une conversion PDL sans traitement basé sur l’hôte, car leur imprimante peut le faire mieux. La fonction ConvertPdlAsync prend en compte des indicateurs de traitement basé sur l’hôte pour répondre à cette exigence. La PSA peut ignorer tout traitement basé sur l’hôte ou une opération de traitement basé sur l’hôte particulière à l’aide de cet indicateur.
class HostBaseProcessingRequirements
{
public bool CopiesNeedsHostBasedProcessing = false;
public bool PageOrderingNeedsHostBasedProcessing = false;
public bool PageRotationNeedsHostBasedProcessing = false;
public bool BlankPageInsertionNeedsHostBasedProcessing = false;
}
private async void OnPdlModificationRequested(PrintWorkflowJobBackgroundSession sender, PrintWorkflowPdlModificationRequestedEventArgs args)
{
using (args.GetDeferral())
{
var targetStream = args.CreateJobOnPrinter("application/pdf");
var pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToPdf);
var hostBasedRequirements = this.ReadHostBasedProcessingRequirements(args.PrinterJob.Printer);
PdlConversionHostBasedProcessingOperations hostBasedProcessing = PdlConversionHostBasedProcessingOperations.None;
if (hostBasedRequirements.CopiesNeedsHostBasedProcessing)
{
hostBasedProcessing |= PdlConversionHostBasedProcessingOperations.Copies;
}
if (hostBasedRequirements.PageOrderingNeedsHostBasedProcessing)
{
hostBasedProcessing |= PdlConversionHostBasedProcessingOperations.PageOrdering;
}
if (hostBasedRequirements.PageRotationNeedsHostBasedProcessing)
{
hostBasedProcessing |= PdlConversionHostBasedProcessingOperations.PageRotation;
}
if (hostBasedRequirements.BlankPageInsertionNeedsHostBasedProcessing)
{
hostBasedProcessing |= PdlConversionHostBasedProcessingOperations.BlankPageInsertion;
}
await pdlConverter.ConvertPdlAsync(args.PrinterJob.GetJobPrintTicket(), args.SourceContent.GetInputStream(), targetStream.GetOutputStream(), hostBasedProcessing);
}
}
private HostBaseProcessingRequirements ReadHostBasedProcessingRequirements(IppPrintDevice printDevice)
{
// Read Host based processing requirements for the printer
}
Configurer la politique de mise à jour des capacités de l’appareil d’impression (PDC).
Important
Cette section décrit les fonctionnalités de l’application d’assistance à l’impression (PSA) disponibles à partir de Windows 11, version 22H2.
Les fournisseurs de périphériques d’impression (IHV) peuvent avoir des exigences différentes concernant le moment où les Capacités de Périphérique d’Impression (PDC) doivent être mises à jour. Pour répondre à ces exigences, PrintSupportPrintDeviceCapabilitiesUpdatePolicy peut définir une politique de mise à jour pour les PDC. La PSA peut définir la politique de mise à jour des PDC en fonction du temps ou du nombre de travaux d’impression à l’aide de cette API.
Définir la politique de mise à jour des PDC en fonction du nombre de travaux
// Event handler called every time PrintSystem updates PDC
private void OnPdcChanged(PrintSupportExtensionSession session, PrintSupportPrintDeviceCapabilitiesChangedEventArgs args)
{
using (args.GetDeferral())
{
// Set update policy to update the PDC on bind printer of every print job.
var updatePolicy = PrintSupportPrintDeviceCapabilitiesUpdatePolicy.CreatePrintJobRefresh(1);
args.SetPrintDeviceCapabilitiesUpdatePolicy(updatePolicy);
}
}
Définir la politique de mise à jour des PDC en fonction du délai d’attente
// Event handler called every time PrintSystem updates PDC
private void OnPdcChanged(PrintSupportExtensionSession session, PrintSupportPrintDeviceCapabilitiesChangedEventArgs args)
{
using (args.GetDeferral())
{
// Set update policy to update the PDC on bind printer of every print job.
var updatePolicy = PrintSupportPrintDeviceCapabilitiesUpdatePolicy.CreatePrintJobRefresh(1);
args.SetPrintDeviceCapabilitiesUpdatePolicy(updatePolicy);
}
}
Directives générales de conception de l’application de support d’impression (PSA)
Lors de la conception d’une application de support d’impression, il est important d’inclure ces aspects dans la conception :
Les contrats tant au premier plan qu’à l’arrière-plan doivent être marqués comme prenant en charge de multiples instances, par exemple, SupportsMultipleInstance devrait être présent dans le manifeste du package. Ceci est pour garantir que la durée de vie des contrats peut être gérée de manière fiable pour plusieurs travaux simultanés.
Traiter le lancement de l’interface utilisateur pour la modification de PDL comme une étape facultative. Faire de son mieux pour terminer le travail d’impression avec succès même si le lancement de l’interface utilisateur n’était pas autorisé. Les travaux d’impression ne devraient être interrompus que s’il n’y a aucun moyen de les terminer avec succès sans intervention de l’utilisateur pendant la modification de PDL. Envisagez d’envoyer le PDL sans modification dans de tels cas.
Lors du lancement de l’interface utilisateur pour la modification de PDL, appeler IsUILaunchEnabled avant d’appeler LaunchAndCompleteUIAsync. Ceci est pour garantir que les scénarios qui ne peuvent pas afficher d’interface utilisateur à l’heure actuelle continuent d’imprimer correctement. Ces scénarios pourraient être sur un appareil sans écran ou sur un appareil actuellement en mode kiosque ou ne pas déranger.
Articles connexes
Association de l’application de prise en charge d’impression
Windows.Graphics.Printing.PrintSupport