Panduan desain aplikasi dukungan cetak
Artikel ini memberikan panduan dan contoh bagi OEM printer dan IHV untuk mengembangkan aplikasi dukungan cetak (PSA) yang dapat meningkatkan pengalaman cetak pengguna Windows dengan beberapa cara.
Penting
Dimulai dengan rilis Windows 11 SDK (22000.1), Print Support Apps (PSA) adalah metode yang direkomendasikan untuk mengembangkan aplikasi UWP untuk printer. Untuk mengembangkan Aplikasi Dukungan Cetak untuk perangkat cetak Anda, unduh dan instal Windows 11 SDK untuk versi Windows yang Anda targetkan.
Penting
Topik ini berisi bagian yang menjelaskan fungsionalitas PSA yang tersedia mulai Dari Windows 11, versi 22H2. Bagian tersebut berisi catatan yang menunjukkan bahwa itu berlaku untuk versi tersebut.
Beberapa fitur printer tidak disajikan dalam dialog cetak yang ditunjukkan oleh Windows karena fitur tersebut adalah fitur khusus yang memerlukan bantuan dari aplikasi produsen untuk dikonfigurasi dengan benar. Mereka mungkin juga fitur yang tidak disediakan dalam kemampuan default printer.
Fitur spesifik printer dapat dikelompokkan dengan cara yang memudahkan pengguna untuk memilih opsi dan mempercayai bahwa semua fitur yang terlibat dalam skenario tersebut secara otomatis diatur ke nilai yang benar. Contohnya bisa menjadi pilihan antara penghemat tinta, penghemat kertas, dan mode kualitas tertinggi yang dapat memanipulasi berbagai fitur cetak secara otomatis berdasarkan satu pilihan dari pengguna. Windows tidak dapat mengelompokkannya secara otomatis karena memerlukan pemahaman semua fitur kustom dari setiap model printer.
Kebutuhan untuk menampilkan preferensi cetak kustom ditangani oleh API ini dengan kontrak ekstensi UWP opsional yang dapat diaktifkan oleh pengguna dari semua dialog cetak Windows dan dialog cetak kustom yang menggunakan API yang disediakan oleh Windows. Produsen dapat menyesuaikan UI mereka untuk memberikan pengalaman cetak terbaik untuk printer tertentu yang dimiliki pengguna.
Area lain di mana produsen printer dapat meningkatkan dan membedakan adalah kualitas cetak. Produsen dapat meningkatkan kualitas cetak setelah penyajian dengan mengoptimalkan isi untuk printer tertentu. Mereka juga dapat menyajikan pratinjau keakuratan tinggi yang lebih mewakili output akhir karena dapat mempertimbangkan fitur spesifik printer.
Terminologi
Term | Definisi |
---|---|
PSA | Cetak Aplikasi Dukungan. Aplikasi UWP yang menggunakan API yang dijelaskan dalam artikel ini. |
MPD | Dialog Cetak Modern. Ini ditampilkan kepada pengguna saat aplikasi mencetak menggunakan Windows.Graphics.Printing API. |
CPD | Dialog Cetak Umum. Ini ditampilkan kepada pengguna saat aplikasi mencetak menggunakan API Win32. Aplikasi yang perlu menampilkan pratinjau cetak tidak memicu dialog ini dan menerapkan versi dialog itu sendiri. aplikasi Office adalah contoh utama dari ini. |
IPP | Protokol Pencetakan Internet. Digunakan dari perangkat klien untuk berinteraksi dengan printer untuk mengambil dan mengatur preferensi pencetakan dan mengirim dokumen yang akan dicetak. |
Cetak Dukungan Printer Terkait | Printer yang ditautkan ke PSA. |
IPP Printer | Printer yang mendukung protokol IPP. |
Pengaturan Lainnya | Tautan yang membuka UI aplikasi yang disediakan mitra di MPD. Default untuk membuka UI preferensi cetak bawaan saat tidak ada PSA yang diinstal. |
Antarmuka Pengguna Preferensi Printer | Dialog yang digunakan untuk mengatur opsi printer default yang diterapkan pada waktu cetak. Misalnya: orientasi, ukuran kertas, warna, cetak di kedua sisi, dan sebagainya. |
PDL | Bahasa Deskripsi Halaman. Format di mana dokumen dikirim ke pencetak. |
Printer PSA Terkait | Printer IPP fisik yang terkait dengan aplikasi PSA. |
PrintDeviceCapabilities | Format dokumen XML untuk menentukan kemampuan printer. Untuk informasi selengkapnya, lihat Cetak Tiket dan Teknologi Kemampuan Cetak. |
PrintTicket | Kumpulan berbagai fitur terkait cetak dan nilainya yang digunakan untuk menangkap niat pengguna untuk pekerjaan cetak tertentu. |
PrintSupportExtension | Tugas latar belakang PSA yang bertanggung jawab untuk menyediakan kemampuan ekstensi batasan printer. |
Mencetak namespace dukungan
Sampel ini mereferensikan namespace layanan printsupport , yang didefinisikan sebagai:
xmlns:printsupport="http://schemas.microsoft.com/appx/manifest/printsupport/windows10"
Mencetak antarmuka pengguna pengaturan dukungan
Ketika pengguna akan mencetak dokumen, mereka sering ingin mengatur beberapa preferensi untuk mencetaknya. Misalnya, mereka dapat memilih untuk mencetak dokumen dalam orientasi lanskap. Mereka juga dapat memanfaatkan fitur kustom yang didukung printer mereka. Windows menyediakan antarmuka pengguna default untuk menampilkan preferensi kustom, tetapi pengguna mungkin tidak memahaminya karena tidak ada ikon atau deskripsi yang sesuai. Windows mungkin juga menggunakan kontrol UI yang salah untuk menyajikannya. Fitur kustom seperti itu paling baik disajikan oleh aplikasi yang memahami fitur sepenuhnya. Ini adalah motivasi di balik penawaran API yang memungkinkan produsen printer membuat aplikasi yang disesuaikan dengan berbagai model printer yang mereka buat.
Kontrak ekstensi UAP baru dibuat dengan kategori baru bernama windows.printSupport Pengaturan UI. Aplikasi yang diaktifkan dengan kontrak ini menerima ActivationKind baru yang disebut PrintSupport Pengaturan UI. Kontrak ini tidak memerlukan kemampuan baru.
<Extensions>
<printsupport:Extension Category="windows.printSupportSettingsUI"
EntryPoint="PsaSample.PsaSettingsUISample"/>
</Extensions>
Kontrak ini dipanggil ketika pengguna memilih Lebih banyak Pengaturan di MPD atau Preferensi di CPD. Kontrak ini juga dapat dipanggil dari Preferensi Pencetakan di aplikasi Pengaturan. Ketika kontrak diaktifkan, aplikasi menerima objek PrintSupport Pengaturan UISession yang dapat digunakan untuk mendapatkan objek PrintTicket dan PrintDevice saat ini. Objek PrintDevice dapat digunakan untuk berkomunikasi dengan printer untuk menerima atribut printer dan pekerjaan. Aplikasi kemudian dapat menampilkan UI dengan opsi printer yang sesuai kepada pengguna. Ketika pengguna membuat pilihan dan memilih OK, aplikasi kemudian dapat mengubah tiket cetak, memvalidasinya, lalu mengirimkan kembali menggunakan objek PrintSupportPrintTicketTarget . Jika pengguna memilih untuk membatalkan jendela preferensi, perubahan harus dibuang, dan aplikasi harus keluar dengan menyelesaikan deferral yang diambil dari objek PrintSupport Pengaturan UISession.
Aplikasi Dukungan Cetak diharapkan menangani beberapa aktivasi simultan untuk pekerjaan cetak yang berbeda, sehingga aplikasi tersebut harus mendukung beberapa instans menggunakan elemen SupportsMultipleInstances dalam file package.appxmanifest. Kegagalan untuk melakukannya dapat mengakibatkan situasi di mana mengonfirmasi preferensi dari satu pekerjaan cetak mungkin menutup jendela preferensi lain yang mungkin terbuka. Pengguna diharuskan untuk membuka jendela preferensi tersebut lagi.
Diagram urutan berikut mewakili konsep manipulasi tiket cetak UI Pengaturan:
Mengubah PrintTicket di antarmuka pengguna pengaturan
Kode sampel C# untuk aktivasi UI Pengaturan saat diluncurkan dari dialog cetak apa pun (MPD/CPD atau dialog cetak kustom) atau dari pengaturan sistem:
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 untuk kelas Default Pengaturan View:
<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>
Kode sampel C# untuk menampilkan UI dan mengubah PrintTicket:
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();
}
}
}
Mendapatkan atribut printer dari perangkat printer
Respons WireShark dari printer IPP ke kueri get-printer-attributes:
Kode sampel C# untuk mendapatkan nama tinta dan tingkat tinta dari printer:
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));
}
}
}
}
Menyetel atribut printer pada pencetak
Kode sampel C# untuk mengatur atribut printer:
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;
}
}
}
}
Memperluas batasan printer
Aplikasi Dukungan Cetak mendukung validasi PrintTicket kustom dan menentukan PrintTicket default. Bagian ini menjelaskan cara kami mendukung fitur-fitur ini.
Untuk mendukung batasan ekstensi printer, jenis tugas latar belakang baru, PrintSupportExtension, telah diimplementasikan. Package.appxmanifest memiliki entri ekstensibilitas untuk Ekstensi Dukungan Cetak seperti yang ditunjukkan di sini:
<Extensions>
<printsupport:Extension Category="windows.printSupportExtension"
EntryPoint="PsaBackgroundTasks.PrintSupportExtension"/>
</Extensions>
Layanan ini dapat berjalan kapan saja dalam pekerjaan cetak untuk printer IPP terkait. Karena Ekstensi Dukungan Cetak diaktifkan melalui fungsi Run(IBackgroundTaskInstance taskInstance), instans IBackgroundTaskInstance diberikan kepada PrintSupportExtension untuk menyediakan akses ke kelas runtime PrintSupportExtensionTriggerDetails, yang secara internal menyediakan PrintSupportExtensionSession sebagai properti. Kelas latar belakang PrintSupportExtension kemudian dapat menggunakan objek sesi untuk mendaftar peristiwa yang ingin menyediakan fungsionalitas kustom.
event Windows.Foundation.TypedEventHandler<PrintSupportExtensionSession, PrintSupportPrintTicketValidationRequestedEventArgs>; PrintTicketValidationRequested;
Jika Ekstensi Dukungan Cetak menyediakan mekanisme validasi PrintTicket sendiri, ekstensi ini dapat mendaftar untuk kejadian ini. Setiap kali PrintTicket perlu divalidasi, sistem cetak akan menaikkan kejadian ini. PrintSupportExtension kemudian akan mendapatkan PrintTicket saat ini yang perlu divalidasi dalam EventArgs. Kelas latar belakang PrintSupportExtension kemudian dapat memeriksa PrintTicket untuk validitas dan memodifikasinya untuk mengatasi konflik apa pun. Kelas latar belakang PrintSupportExtension kemudian harus mengatur hasil untuk validasi menggunakan fungsi SetPrintTicketResult untuk menunjukkan apakah PrintTicket telah diselesaikan, memiliki konflik, atau tidak valid. Kejadian ini dapat dinaikkan kapan saja selama masa pakai pekerjaan cetak. Jika kelas PrintSupportExtension tidak mendaftar untuk kejadian ini, sistem cetak melakukan validasi PrintTicket sendiri.
event Windows.Foundation.TypedEventHandler<PrintSupportExtensionSession, PrintSupportPrintDeviceCapabilitiesChangedEventArgs>; PrintDeviceCapabilitiesChanged;
Peristiwa dinaikkan setelah sistem cetak memperbarui PrintDeviceCapabilities yang di-cache dari printer IPP terkait. Ketika peristiwa ini dinaikkan, kelas latar belakang PrintSupportExtension dapat memeriksa PrintDeviceCapabilities yang diubah dan memodifikasinya.
Validasi kustom tiket cetak
Kode sampel C# untuk menyediakan layanan validasi PrintTicket:
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);
}
}
Memperbarui PrintDeviceCapabilities
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);
}
}
Peningkatan kualitas cetak
Setelah pengguna berkomitmen untuk mencetak dengan menekan tombol cetak pada dialog cetak, dokumen yang akan dicetak dikirim ke tumpukan cetak dari aplikasi yang sedang mencetak. Dokumen ini kemudian mengalami transformasi (penyajian ke PDL) agar cocok untuk printer target. Windows akan menentukan transformasi apa yang akan dipilih berdasarkan atribut yang dikueri dari printer. Dokumen yang diubah kemudian dikirim ke printer. Meskipun ini berfungsi dengan baik untuk sebagian besar printer, ada kasus di mana kualitas cetak dapat ditingkatkan dengan memungkinkan aplikasi mitra untuk berpartisipasi dalam transformasi. Untuk memfasilitasi hal ini, API Alur Kerja pencetakan saat ini diperluas untuk menyertakan panggilan ke aplikasi di titik tambahan dari tumpukan cetak. API ini mendukung dua peristiwa baru yang dapat didaftarkan oleh aplikasi PSA. Ini adalah satu-satunya titik masuk ke permukaan API PSA:
JobStarting
- Kejadian ini dimunculkan ketika pekerjaan cetak dimulai oleh aplikasi apa pun. Saat peristiwa dinaikkan, Aplikasi Dukungan Cetak dapat memilih untuk melewati penyajian sistem dengan memanggil SetSkipSystemRendering di PrintWorkflowJobStartingEventArgs. Jika melewati penyajian sistem dipilih, sistem cetak tidak akan mengonversi dokumen XPS ke dalam format PDL yang diperlukan oleh printer. Sebaliknya, XPS yang dihasilkan oleh aplikasi pencetakan akan langsung diberikan kepada PSA yang kemudian bertanggung jawab untuk mengonversi XPS ke format PDL.
PdlModificationRequested
- Kejadian ini dimunculkan ketika Windows memulai konversi aliran XPS ke format PDL yang ditunjukkan oleh printer. Kelas runtime PrintWorkflowPdlModificationRequestedEventArgs disediakan sebagai argumen untuk peristiwa ini. Kelas kejadian ini menyediakan objek sumber dan target PDL untuk membaca dan menulis konten pekerjaan cetak. Jika Aplikasi menentukan bahwa aplikasi memerlukan input pengguna, aplikasi dapat meluncurkan UI menggunakan PrintWorkflowUILauncher dari EventArgs. API ini menggunakan pola Tester-Doer. PrintWorkflowUILauncher tidak akan dapat memanggil UI jika fungsi IsUILaunchEnabled mengembalikan false. Fungsi ini mengembalikan false jika sesi PSA berjalan dalam mode senyap (mode headless atau kios). Aplikasi Dukungan Cetak tidak boleh mencoba meluncurkan UI jika fungsi mengembalikan false.
OutputStream tersedia sebagai bagian dari PrintWorkflowPdlTargetStream yang dikembalikan oleh fungsi GetStreamTargetAsync. Konten yang ditulis ke target OutputStream diteruskan bersama ke printer sebagai konten dokumen.
Diagram urutan untuk peristiwa modifikasi PDL:
Aplikasi latar depan PSA diluncurkan ketika tugas latar belakang PSA meminta peluncuran UI. PSA dapat menggunakan kontrak latar depan untuk mendapatkan input pengguna dan/atau untuk menampilkan pratinjau pratinjau cetak kepada pengguna.
Mencetak tugas latar belakang alur kerja dukungan
Tipe tugas latar belakang printSupportWorkflow baru telah ditentukan. Package.appxmanifest memiliki entri ekstensibilitas berikut untuk kontrak PrintSupportWorkflow :
<Extensions>
<printsupport:Extension Category="windows.printSupportWorkflow"
EntryPoint="PsaBackgroundTasks.PrintSupportWorkflowSample"/>
</Extensions>
Pada aktivasi kontrak, PrintWorkflowJobTriggerDetails diberikan sebagai IBackgroundTaskInstance-TriggerDetails>. PrintWorkflowJobTriggerDetails secara internal menyediakan PrintWorkflowJobBackgroundSession sebagai bagian dari propertinya. Aplikasi ini dapat menggunakan PrintWorkflowJobBackgroundSession untuk mendaftar peristiwa yang terkait dengan berbagai titik injeksi dalam alur kerja pekerjaan cetak. Setelah pendaftaran peristiwa selesai, aplikasi harus memanggil PrintWorkflowJobBackgroundSession::Start untuk sistem cetak untuk mulai menembakkan peristiwa yang terkait dengan berbagai titik injeksi.
Mencetak UI pekerjaan alur kerja
ActivationKind baru yang disebut PrintSupportJobUI ditentukan. Ini tidak memerlukan kemampuan baru.
<Extensions>
<printsupport:Extension Category="windows.printSupportJobUI"
EntryPoint="PsaSample.PrintSupportJobUISample"/>
</Extensions>
Ini adalah kontrak UI yang dapat diluncurkan dari kontrak latar belakang Alur Kerja Dukungan Cetak, atau ketika pengguna memilih roti panggang kesalahan pekerjaan cetak. Pada aktivasi, PrintWorkflowJobActivatedEventArgs disediakan, yang memiliki objek PrintWorkflowJobUISession. Menggunakan PrintWorkflowJobUISession, aplikasi latar depan harus mendaftar untuk peristiwa PdlDataAvailable jika ingin mengakses data PDL. Jika aplikasi latar depan ingin menampilkan pesan kesalahan kustom untuk kesalahan apa pun yang dapat terjadi selama pekerjaan, aplikasi tersebut harus mendaftar untuk peristiwa JobNotification . Setelah peristiwa terdaftar, aplikasi harus memanggil fungsi PrintWorkflowJobUISession::Start agar sistem cetak mulai menembakkan peristiwa.
Melompati penyajian sistem
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();
}
}
}
}
Peristiwa modifikasi PDL
Diagram urutan untuk peristiwa modifikasi PDL:
Kode sampel C# untuk Print Support Job Monitor membaca dan menulis konten pekerjaan cetak:
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();
}
}
}
Meluncurkan UI dari latar belakang alur kerja
Kode sampel C# untuk meluncurkan UI Pekerjaan Dukungan Cetak dari kontrak peristiwa yang diminta modifikasi PSA PDL:
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();
}
}
Aktivasi UI pekerjaan alur kerja untuk peristiwa PDLDataAvailable
Diagram urutan untuk aktivasi UI pekerjaan cetak untuk peristiwa PdlDataAvailable :
Kode sampel C# untuk kontrak aktivasi UI pekerjaan 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);
}
}
}
}
Mendapatkan atribut pekerjaan printer
Kode sampel C# untuk mendapatkan atribut pekerjaan untuk pekerjaan cetak:
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();
}
}
}
Mengatur atribut pekerjaan printer
Kode sampel C#, berlanjut dari bagian Dapatkan atribut pekerjaan printer di atas, menunjukkan pengaturan atribut pekerjaan:
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);
}
}
Beberapa printer IPP tidak mendukung atribut pekerjaan mendapatkan/mengatur setelah pekerjaan dibuat. Untuk printer tersebut, PrintJob memiliki properti JobId yang diatur ke "0" dan GetJobAttributes/SetJobAttributes akan segera gagal dengan pengecualian.
Menyediakan akses file penyimpanan ke konten PDL
Beberapa format PDL seperti PDF memerlukan aliran lengkap agar tersedia untuk mulai diproses. Untuk alasan itu, metode baru bernama GetContentFileAsync disediakan pada kelas PrintWorkflowPdlSourceContent yang mengembalikan StorageFile dari konten sumber.
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);
}
}
}
}
}
Konversi PDL XPS ke PDF
Kode sampel C# memperlihatkan konversi PDL XPS ke 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();
}
Peristiwa pemberitahuan pekerjaan
Diagram urutan untuk peristiwa pemberitahuan pekerjaan:
Kode sampel C#, berlanjut dari aktivasi UI pekerjaan alur kerja untuk bagian peristiwa PDLDataAvailable di atas, untuk menampilkan kesalahan pada pemberitahuan pekerjaan:
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;
}
}
}
}
Membuat pekerjaan dengan atribut pekerjaan awal
Saat ini, beberapa printer IPP tidak mendukung operasi set-attribute. Fungsi CreateJobOnPrinterWithAttributes dan fungsi CreateJobOnPrinterWithAttributesBuffer pada PrintWorkflowPdlDataAvailableEventArgs disediakan untuk mengurangi masalah ini. Dengan menggunakan API ini, pengembang PSA dapat menyediakan atribut pekerjaan yang diteruskan ke printer saat pekerjaan dibuat pada printer.
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
}
}
Pemrosesan XPS berurutan
Kode sampel C++/Winrt untuk memproses XPS secara berurutan sebelum penampungan selesai.
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()));
}
}
}
Menampilkan pelokalan nama dan integrasi API Passthrough PDL
Penting
Bagian ini menjelaskan fungsionalitas PSA yang tersedia mulai dari Windows 11, versi 22H2.
Dalam skenario ini, PSA menyesuaikan Kemampuan Perangkat Cetak (PDC) dan menyediakan Sumber Daya Perangkat Cetak (PDR) untuk pelokalan string.
PSA juga mengatur jenis konten API Passthrough PDL yang didukung (format PDL). Jika PSA tidak berlangganan peristiwa atau tidak memanggil SetSupportedPdlPassthroughContentTypes secara eksplisit, Passthrough PDL dinonaktifkan untuk printer yang terkait dengan aplikasi PSA ini.
// 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);
}
}
Dukungan fitur tingkat halaman dan atribut operasi
Penting
Bagian ini menjelaskan fungsionalitas PSA yang tersedia mulai dari Windows 11, versi 22H2.
Skenario dukungan fitur tingkat halaman dan atribut operasi dikelompokkan karena ditangani dengan membuat perubahan di tempat yang sama dalam kode sampel.
Dukungan fitur tingkat halaman: Dalam skenario ini, aplikasi PSA menentukan atribut tingkat halaman, yang seharusnya tidak ditimpa oleh atribut IPP yang diurai dari PrintTicket.
Koleksi terpisah untuk dukungan atribut operasi (pencetakan PIN): Dalam skenario ini, aplikasi PSA menentukan atribut operasi IPP kustom (misalnya, PIN).
Kode sampel C# berikut menunjukkan perubahan yang diperlukan untuk dukungan fitur Tingkat Halaman dan Koleksi terpisah untuk skenario atribut operasi.
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();
}
}
Meningkatkan dialog cetak dengan PSA
Penting
Bagian ini menjelaskan fungsionalitas PSA yang tersedia mulai dari Windows 11, versi 22H2.
Dalam skenario ini, menggunakan dialog cetak dengan integrasi PSA memungkinkan tindakan berikut:
Dapatkan panggilan balik ketika pilihan diubah dalam MPD ke printer yang terkait dengan PSA
Perlihatkan satu AdaptiveCard dengan dukungan tindakan openUrl
Perlihatkan fitur dan parameter kustom pada dialog cetak
Ubah PrintTicket, sehingga mengubah pilihan untuk opsi fitur yang diperlihatkan dalam dialog cetak
Dapatkan Windows.ApplicationModel.AppInfo dari aplikasi pencetakan, membuka dialog cetak
Sampel C# berikut mengilustrasikan penyempurnaan dialog cetak ini:
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""
}}");
}
Konversi PDL dengan bendera pemrosesan berbasis host
Penting
Bagian ini menjelaskan fungsionalitas PSA yang tersedia mulai dari Windows 11, versi 22H2.
API konversi PDL saat ini, PrintWorkflowPdlConverter.ConvertPdlAsync, melakukan pemrosesan berbasis host secara default. Ini berarti bahwa komputer host/pencetakan melakukan rotasi, urutan halaman, dan sebagainya, sehingga printer tidak perlu melakukan operasi ini. Namun, IHV printer mungkin menginginkan konversi PDL tanpa pemrosesan berbasis host karena printer mereka dapat melakukan ini dengan lebih baik. Fungsi ConvertPdlAsync mengambil bendera pemrosesan berbasis host untuk mengatasi persyaratan ini. PSA dapat melewati semua pemrosesan berbasis host atau operasi pemrosesan berbasis host tertentu menggunakan bendera ini.
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
}
Mengatur kebijakan pembaruan Kemampuan Perangkat Cetak (PDC)
Penting
Bagian ini menjelaskan fungsionalitas PSA yang tersedia mulai dari Windows 11, versi 22H2.
IHV Printer mungkin memiliki persyaratan yang berbeda ketika Kemampuan Perangkat Cetak (PDC) perlu diperbarui. Untuk memenuhi persyaratan ini, PrintSupportPrintDeviceCapabilitiesUpdatePolicy dapat mengatur kebijakan pembaruan untuk PDC. PSA dapat mengatur kebijakan pembaruan PDC berdasarkan waktu atau jumlah pekerjaan cetak menggunakan API ini.
Mengatur kebijakan pembaruan PDC berdasarkan jumlah pekerjaan
// 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);
}
}
Mengatur kebijakan pembaruan PDC berdasarkan TimeOut
// 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);
}
}
Panduan desain aplikasi dukungan cetak umum (PSA)
Saat merancang aplikasi dukungan cetak, penting untuk menyertakan aspek-aspek ini dalam desain:
Kontrak latar depan dan latar belakang harus ditandai sebagai mendukung beberapa instans, misalnya, SupportsMultipleInstance harus ada dalam manifes paket. Ini untuk memastikan bahwa masa pakai kontrak dapat dikelola dengan andal untuk beberapa pekerjaan simultan.
Perlakukan antarmuka pengguna peluncuran untuk modifikasi PDL sebagai langkah opsional. Lakukan upaya terbaik untuk menyelesaikan pekerjaan cetak dengan sukses meskipun peluncuran UI tidak diizinkan. Tugas cetak hanya boleh dibatalkan jika tidak ada cara untuk menyelesaikannya dengan sukses tanpa input pengguna selama modifikasi PDL. Pertimbangkan untuk mengirim PDL yang tidak dimodifikasi dalam kasus seperti itu.
Saat meluncurkan UI untuk modifikasi PDL, panggil IsUILaunchEnabled sebelum memanggil LaunchAndCompleteUIAsync. Ini untuk memastikan bahwa skenario yang tidak dapat menampilkan UI pada saat ini terus mencetak dengan benar. Skenario ini dapat berada di perangkat tanpa kepala atau perangkat yang saat ini dalam mode kios atau tidak mengganggu mode.
Artikel terkait
Mencetak asosiasi aplikasi dukungan
Windows.Graphics.Printing.PrintSupport