How to silently print multiple images with duplex setting from Blazor
Product JSPrintManager for Blazor Published 07/09/2021 Updated 11/28/2024 Author Neodynamic
Overview
In this walkthrough, you'll learn how to silently print multiple images like JPG & PNG with duplex settings from any Razor page directly to the client printer without displaying any print dialog and by writing pure Blazor code. This is useful in scenarios that require CARD ID printing where you need to print one image on the front and another image on the back of a card from websites. The PrintFileGroup class will allow you to perform this task very easily.
Follow up these steps
- Be sure you install in your dev machine JSPrintManager (JSPM) (Available for Windows, Linux, Raspberry Pi & Mac)
This small app must be installed on each client that will print from your website! - In your Blazor project...
- Add a NuGet reference to the JSPrintManager Razor Component
- Add the JSPrintManager service...
- Add the following statement at the top of your
Startup
file
using Neodynamic.Blazor;
- For Blazor Server
Add the following line in theStartup's ConfigureServices
method
services.AddJSPrintManager();
For .NET 8+ you must use Interactive Server components and render mode, so add these settings:
builder.Services.AddRazorComponents() .AddInteractiveServerComponents();
app.MapRazorComponents<App>() .AddInteractiveServerRenderMode()
- For Blazor WebAssembly
Add the following line in theProgram's Main
method
builder.Services.AddJSPrintManager();
- For Blazor Server
- Add the following statement at the top of your
- Add the following statement in the
_Imports.razor
file
@using Neodynamic.Blazor
- Add a new Razor Page and copy/paste the following code. Please read the source code comments to understand the printing logic!
For .NET 8+ Blazor Server you must use Interactive Server render mode, so add these settings:
@page "/" @rendermode InteractiveServer @inject JSPrintManager JSPrintManager
@page "/" @inject JSPrintManager JSPrintManager @using System @using System.IO <div> <strong>JSPM </strong><span>WebSocket Status </span> @if (JSPrintManager.Status == JSPMWSStatus.Open) { <span class="badge badge-success"> <i class="fa fa-check" /> Open </span> } else if (JSPrintManager.Status == JSPMWSStatus.Closed) { <span class="badge badge-danger"> <i class="fa fa-exclamation-circle" /> Closed! </span> <div> <strong>JSPrintManager (JSPM) App</strong> is not installed or not running! <a href="https://neodynamic.com/downloads/jspm" target="_blank">Download JSPM Client App...</a> </div> } else if (JSPrintManager.Status == JSPMWSStatus.Blocked) { <span class="badge badge-warning"> <i class="fa fa-times-circle" /> This Website is Blocked! </span> } else if (JSPrintManager.Status == JSPMWSStatus.WaitingForUserResponse) { <span class="badge badge-warning"> <i class="fa fa-user-circle" /> Waiting for user response... </span> } </div> @if (JSPrintManager.Status == JSPMWSStatus.Open) { @if (JSPrintManager.Printers == null) { <hr /> <div class="spinner-border text-info" role="status"> <span class="sr-only">Please wait...</span> </div> <strong><em>Getting local printers...</em></strong> } else { <div class="row"> <div class="col-md-12"> <h2 class="text-center"> <i class="fa fa-files-o" /> Multiple Image Printing with Duplex from Blazor </h2> <hr /> </div> </div> <EditForm Model="@MyCPJ"> <div class="row"> <div class="col-md-12"> <div class="bg-light"> <strong>Select the Image Files to print <em>(max 10 files)</em></strong> <br /> <InputFile OnChange="@LoadFiles" class="form-control-file" accept=".jpg,.png" multiple/> <br /> @if (isLoading) { <p><em><small>Loading files...</small></em></p> <div class="progress"> <div class="progress-bar bg-info" role="progressbar" style="width: @(loadingStep)%;" aria-valuenow="@(loadingStep)" aria-valuemin="0" aria-valuemax="100">@(loadingStep)%</div> </div> } </div> </div> </div> </EditForm> <div class="row"> <div class="col-md-12"> <EditForm Model="@MyPrinter"> <p>Select an <strong>Installed Printer</strong>:</p> <InputSelect @bind-Value="MyPrinter.PrinterName" class="form-control form-control-sm"> @foreach (var p in JSPrintManager.Printers) { <option value="@p">@p</option> } </InputSelect> </EditForm> </div> </div> <div class="row"> <div class="col-md-12"> <br /> <div class="text-center"> <button class="btn btn-success btn-lg" @onclick="DoPrinting"> <i class="fa fa-print" /> Print Now... </button> </div> </div> </div> } } @code { protected override void OnAfterRender(bool firstRender) { if (firstRender) { // Handle OnGetPrinters event... JSPrintManager.OnGetPrinters += () => { if (JSPrintManager.Printers != null && JSPrintManager.Printers.Length > 0) { // Display installed printers... StateHasChanged(); } else { Console.WriteLine("No printers found..."); } }; // Handle OnStatusChanged event to detect any WSS status change JSPrintManager.OnStatusChanged += () => { StateHasChanged(); // Status = Open means that JSPM Client App is up and running! if (JSPrintManager.Status == JSPMWSStatus.Open) { //Try getting local printers... JSPrintManager.TryGetPrinters(); } }; // Start WebSocket comm JSPrintManager.Start(); } base.OnAfterRender(firstRender); } private ClientPrintJob MyCPJ { get; set; } = new(); private InstalledPrinter MyPrinter { get; set; } = new(); private void DoPrinting() { // Set built-in duplex printing MyPrinter.Duplex = Duplex.DuplexLongEdge; // set target printer MyCPJ.ClientPrinter = MyPrinter; // set files source... var myFileGroup = new PrintFileGroup() { FileName = "MyFileGroup" }; foreach (var fileEntry in loadedFiles) { var myFile = new PrintFile() { FileContentType = FileSourceType.Base64, FileContent = fileEntry.Value, FileName = fileEntry.Key }; myFileGroup.FileContent.Add(myFile); } // Add the file group to the print job MyCPJ.Files.Clear(); MyCPJ.Files.Add(myFileGroup); // Send job to the client! JSPrintManager.SendClientPrintJob(MyCPJ); } #region File Source Handling private Dictionary<string, byte[]> loadedFiles = new(); private int maxAllowedFiles = 10; private int maxSizeFile = 5000000; //5MB private bool isLoading = false; private int loadingStep = 0; private async Task LoadFiles(InputFileChangeEventArgs e) { isLoading = true; loadedFiles.Clear(); loadingStep = 0; var numOfFiles = Math.Min(e.FileCount, maxAllowedFiles); var i = 1; foreach (var file in e.GetMultipleFiles(maxAllowedFiles)) { try { await using MemoryStream ms = new(); await file.OpenReadStream(maxSizeFile).CopyToAsync(ms); loadedFiles.Add(file.Name, ms.ToArray()); loadingStep = (int)(((float)i / (float)numOfFiles) * 100f); StateHasChanged(); } catch (Exception ex) { } i++; } isLoading = false; } #endregion }
- That's it! Run your website and test it. Click on Print Now... to print the files without print dialog. You can print it to the Default client printer or you can get a list of the installed printers available at the client machine.