How to print raw ESC/POS commands from Blazor
Product JSPrintManager for Blazor Published 07/07/2021 Updated 11/28/2024 Author Neodynamic
Overview
Many kind of printers like dot-matrix, impact, kiosk, thermal, inkjet, etc; do internally handle ESC/POS (a.k.a. ESC/P) commands which are processed to produce the output printing. ESC/POS was designed by EPSON and is widely used by many other printer brands mainly on POS (Point Of Sales or Point of Services) scenarios like retail, banking, hospitality, and healthcare.
ESC/POS commands are very simple and the main character you'll find in each command is ESC i.e. ASCII hex 1B. Almost any ESC/POS command will start with the ESC (hex 1B) character although it's not the only one as you'll see in the next sample later. The main advantage of using raw ESC/POS commands for printing instead of using the built-in browser javascript printing (window.print();) is that the printing performance will be way faster; a factor that is key in the aforementioned scenarios. You'll be able to use raw printing feature with the help of our JSPrintManager for Blazor solution that was specially designed for this kind of printing needs.
In this walkthrough, you'll learn how to print raw ESC/POS commands from Blazor directly to the client printer without displaying a print dialog at all. You'll be able to print ESC/POS commands to the Default client printer as well as to any other installed printer at the client machine. This solution works with any popular browser like Chrome, Firefox, IE/Edge & Safari on Windows, Linux, Raspberry Pi and Mac systems!
The ESC/POS commands that we'll use in this article will print out a simple retail receipt that will look like this:
A Sample Receipt printed from Blazor and created by using ESC/POS commands
How to specify ESC/POS commands in Blazor
ESC/POS commands are composed of a set of simple bytes (from 00 up to FF in hex notation) and most of them always starts with ESC which is byte 1B.
Some commands require additional parameters which have to be expressed in bytes too. For example, the following shows how the ESC/POS command for "emphasized text " is found in the reference manual and how it should be specified in bytes.
- ESC/POS command for: "Emphasized mode selected."
-
From the ESC/POS Reference Manual:
ESC ! 8
-
It must be specified in bytes (HEX notation) as:
0x1B!0x08Notice that ESC needs to be specified as 0x1B and the integer parameter value is NOT digit 8 char (hex 38) BUT byte hex 08!!! Be aware of the way you must specify commands & params values as a misunderstanding on this subject might carry unexpected printing results or no printing output at all.
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 <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> <h1>Print ESP/POS commands from Blazor</h1> <hr /> <EditForm Model="@MyPrinter"> <div class="form-check"> <InputCheckbox class="form-check-input" @bind-Value="UseDefaultPrinter" />Print to <strong>Default Printer?</strong><br /> </div> <p>or...</p> <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> <br /><br /> <input type="button" value="Print Now..." @onclick="DoPrint" /> </div> } } @code { // An Installed Printer instance private InstalledPrinter MyPrinter { get; set; } = new(); // Use default printer? private bool UseDefaultPrinter = false; // Printing... private void DoPrint() { // Status = Open means that JSPM Client App is up and running! if (JSPrintManager.Status == JSPMWSStatus.Open) { // Create a ClientPrintJob var cpj = new ClientPrintJob(); // Set target Printer cpj.ClientPrinter = UseDefaultPrinter ? new DefaultPrinter() : MyPrinter; // Create ESC/POS commands for sample label var esc = (char)0x1B; //ESC byte in hex notation var newLine = (char)0x0A; //LF byte in hex notation var cmds = esc + "@"; //Initializes the printer (ESC @) cmds += esc + "!" + (char)0x38; //Emphasized + Double-height + Double-width mode selected (ESC ! (8 + 16 + 32)) 56 dec => 38 hex cmds += "BEST DEAL STORES"; //text to print cmds += newLine + newLine; cmds += esc + "!" + (char)0x00; //Character font A selected (ESC ! 0) cmds += "COOKIES 5.00"; cmds += newLine; cmds += "MILK 65 Fl oz 3.78"; cmds += newLine + newLine; cmds += "SUBTOTAL 8.78"; cmds += newLine; cmds += "TAX 5% 0.44"; cmds += newLine; cmds += "TOTAL 9.22"; cmds += newLine; cmds += "CASH TEND 10.00"; cmds += newLine; cmds += "CASH DUE 0.78"; cmds += newLine + newLine; cmds += esc + "!" + (char)0x18; //Emphasized + Double-height mode selected (ESC ! (16 + 8)) 24 dec => 18 hex cmds += "# ITEMS SOLD 2"; cmds += esc + "!" + (char)0x00; //Character font A selected (ESC ! 0) cmds += newLine + newLine; cmds += "11/03/13 19:53:17"; // Set the RAW commands to send to the printer... cpj.PrinterCommands = cmds; // PRINT IT!!! JSPrintManager.SendClientPrintJob(cpj); } } 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); } }
- That's it! Run your website and test it. Click on Print Now... to print the ESP/POS Commands 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.
NOTE You can also print directly to any LPT Parallel Port, RS232 Serial Port or IP/Ethernet Printer although these scenarios have not been considered in this article for simplicity. For further details on those scenarios, please contact our tech support.