CrossEscPos.Controls 1.2.0

dotnet add package CrossEscPos.Controls --version 1.2.0
                    
NuGet\Install-Package CrossEscPos.Controls -Version 1.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CrossEscPos.Controls" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CrossEscPos.Controls" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="CrossEscPos.Controls" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CrossEscPos.Controls --version 1.2.0
                    
#r "nuget: CrossEscPos.Controls, 1.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CrossEscPos.Controls@1.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CrossEscPos.Controls&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=CrossEscPos.Controls&version=1.2.0
                    
Install as a Cake Tool

ESC/POS Receipt Printer Emulator

πŸ–¨οΈ This app emulates a networked receipt printer to test your ESC/POS commands against.

Emulator

About

  • Cross-platform application (Avalonia 12 + SkiaSharp + .NET 10), runs on Windows, macOS and Linux
  • Listens for ESC/POS commands over TCP/IP and (optionally) a serial port
  • Logs commands and visually represents the resulting receipt(s)
  • Renders 1D barcodes and 2D codes (QR, PDF417, DataMatrix, Aztec), bit images, and page mode
  • Answers status queries (DLE EOT, GS r, Automatic Status Back) β€” simulate paper-out, cover, drawer, offline and error states from the Printer state panel
  • Signals buzzer / cash-drawer events with a sound and on-screen toast
  • Configure the TCP listen address/port and serial port live from the UI
  • Export rendered tickets to PNG β€” all in one image, or one file per cut
  • It support different text formattings in the same line, although a few combinations were tested.

Cross-platform fork. This project began as a cross-platform port of roydejong/EscPosEmulator (originally a Windows/WPF app). It has been migrated to Avalonia + SkiaSharp + .NET 10 so it runs on Windows, macOS and Linux, and extended with barcode/QR rendering and a serial transport. All credit for the original emulator goes to the upstream author.

πŸ‘· This is an unfinished experiment. Use at your own risk and keep your expectations low. πŸ˜ƒ

Download

Pre-built, self-contained apps (no .NET install required) are published on the Releases page:

Platform Artifact
Windows (x64) CrossEscPos-win-x64.zip
Linux (x64) CrossEscPos-linux-x64.tar.gz
macOS (Intel) CrossEscPos-osx-x64.zip (.app bundle)
macOS (Apple Silicon) CrossEscPos-osx-arm64.zip (.app bundle)

Releases are produced by the Release GitHub Actions workflow on each v* tag.

macOS first launch. The .app is ad-hoc signed but not notarized (no paid Apple Developer ID). macOS quarantines anything downloaded from the internet, so on first launch you may see "CrossEscPos is damaged and can't be opened" (especially on Apple Silicon). Clear the quarantine flag once, then open it:

xattr -dr com.apple.quarantine /path/to/CrossEscPos.app
open /path/to/CrossEscPos.app

(Right-click β†’ Open also works once the quarantine is cleared.)

Built with

Supported commands

⚠️ Support is currently limited to only a subset of ESC/POS. Even the commands listed here may only be partially implemented.

  • Raw Text
  • LF: Line feed
  • CR: Carriage return
  • ESC Commands:
    • Initialize printer (ESC @)
    • Toggle italic (ESC 4 / ESC 5) [possibly deprecated?]
    • Select font (ESC M)
    • Select charset (ESC R)
    • Select character table (ESC t)
    • Select justification (ESC a)
    • Select line spacing (ESC 2 / ESC 3)
    • Toggle emphasis (ESC E)
    • Toggle underline (ESC -)
    • Set print text mode (ESC !)
    • Full cut (ESC m)
    • Partial cut (ESC i)
    • Print and feed n lines (ESC d)
    • Print and feed paper (ESC J)
    • Generate pulse / kick cash drawer (ESC p m t1 t2)
    • Select character code table (ESC t) β€” PC437/850/852/858/860/863/865/866/1252 remapped to Unicode
    • Beeper (ESC ( A)
    • Bit image (ESC *) β€” 8-dot and 24-dot inline raster
    • Page mode: select page / standard mode (ESC L / ESC S), print area (ESC W), direction (ESC T), absolute position (ESC $)
    • User-defined characters (ESC & / ESC % / ESC ?) β€” parsed & stored
  • Control characters:
    • Buzzer / beeper (BEL, 0x07)
    • Form feed (FF) β€” prints the page in page mode
    • Cancel (CAN) β€” cancels page data
  • DLE (real-time) Commands:
    • Real-time status (DLE EOT n, n=1-4)
    • Real-time request / recover (DLE ENQ)
    • Real-time cash-drawer pulse (DLE DC4 1 m t)
  • FS Commands:
    • Print stored logo (FS p n m)
    • Auto cut (FS } 0x60 n)
  • GS Commands:
    • Select character size
    • Select cut mode and cut paper
    • Paper eject (GS e n [m t])
    • Print raster image (GS v 0 [m xL xH yL yH ...pixels])
    • Print 1D barcode (GS k) β€” UPC-A/E, EAN-13/8, CODE39, CODE93, CODE128, ITF, CODABAR (both function A & B forms)
    • Set barcode height / module width (GS h / GS w)
    • Select HRI text position / font (GS H / GS f)
    • Print 2D symbols (GS ( k) β€” QR Code (cn=49), PDF417 (cn=48), DataMatrix (cn=54), Aztec (cn=55)
    • Status / transmit-back: paper & drawer status (GS r), printer ID (GS I), Automatic Status Back (GS a)
    • Download bit image: define (GS *) and print (GS /)
    • Set motion units (GS P), absolute/relative vertical position (GS $ / GS \)
    • Config (accepted/ignored): user setup (GS ( E), print control (GS ( K), response request (GS ( H)

The emulator is bidirectional: status commands (DLE EOT, GS r, GS I) and Automatic Status Back reply to the host over the same TCP/serial connection, driven by the Printer state panel (right side) where you can simulate paper-out/near-end, cover open, cash-drawer open/closed, offline, and error conditions. Like a real device, the emulator refuses to print while it isn't ready (out of paper, cover open, offline, or in an error state) and shows a notification instead.

Barcodes and QR codes render inline on the receipt, with optional HRI text:

Barcode and QR example

Not yet implemented

A few things remain partial or unimplemented:

  • Page-mode coordinate system β€” page mode buffers output and rasterizes it on FF, but absolute/relative positioning (ESC $, GS $, GS \) and print direction (ESC T) are accepted as no-ops rather than fully positioned.
  • User-defined glyph substitution β€” ESC & glyphs are parsed and stored, but the inline text renderer still draws the font glyph rather than the custom bitmap.
  • MaxiCode / GS1 DataBar / Composite 2D symbologies (GS ( k cn=50/51/52).
  • Graphics commands GS ( L / GS 8 L (NV/raster graphics store-and-print) and other ESC *-family densities.
  • Real-time DLE DC4 functions other than the cash-drawer pulse (power-off, recover-and-cancel, buzzer).
  • Katakana / CJK code pages render as missing glyphs since the bundled Latin font has no such glyphs.

Contributions welcome β€” new commands follow the simple BaseCommand pattern in EscPos/Commands and are registered in EscPosInterpreter.RegisterCommands.

Connecting

The emulator accepts ESC/POS data over two transports. Both can be changed live from the UI (left panel): pick a TCP listen address and port and Start/Stop the listener, or select a serial port + baud and Open/Close it (⟳ refreshes the port list). The environment variables below set the initial values at startup:

Variable Default Meaning
ESCPOS_LISTEN_ADDRESS 0.0.0.0 Initial TCP bind address (0.0.0.0 = all interfaces, 127.0.0.1 = localhost).
ESCPOS_TCP_PORT 9100 Initial TCP listen port. Set to off / 0 to start with TCP stopped.
ESCPOS_SERIAL_PORT (unset) Serial device to auto-open (e.g. /dev/ttys004, COM3). Unset = serial closed.
ESCPOS_SERIAL_BAUD 9600 Serial baud rate.
ESCPOS_DEBUG_DUMP (off) Set to 1 to dump every received payload to last_* files.
ESCPOS_RENDER_BACKEND skia Render backend: skia (default) or imagesharp (managed). The --backend arg overrides it.

Examples:

# (run is shorthand for: dotnet run --project src/CrossEscPos.App.Desktop)
dotnet run --project src/CrossEscPos.App.Desktop                  # TCP only, port 9100
ESCPOS_TCP_PORT=9200 dotnet run --project src/CrossEscPos.App.Desktop   # TCP on 9200
ESCPOS_SERIAL_PORT=/dev/ttys004 dotnet run --project src/CrossEscPos.App.Desktop  # TCP 9100 + serial
ESCPOS_TCP_PORT=off ESCPOS_SERIAL_PORT=COM3 dotnet run --project src/CrossEscPos.App.Desktop  # serial only

Pick the render backend (for A/B testing the two rendering libraries) with --backend skia (default) or --backend imagesharp (the managed, no-native backend). The active backend is shown in the window title bar.

dotnet run --project src/CrossEscPos.App.Desktop -- --backend imagesharp   # managed ImageSharp backend
dotnet run --project src/CrossEscPos.App.Desktop -- --backend skia         # default SkiaSharp backend

The status panel shows the active TCP endpoint and serial port.

Testing serial without hardware (app-to-app on one machine)

You don't need a USB serial adapter. Create a virtual serial bridge β€” a pair of linked ports β€” then point the emulator at one end and your POS application (or a shell) at the other. Bytes written to one end appear on the other.

macOS / Linux β€” using socat (brew install socat / apt install socat). A helper script is included:

./scripts/serial-bridge.sh
# It prints a linked pair, e.g.:
#   PORT A (emulator): /dev/ttys004
#   PORT B (your app): /dev/ttys005
# Leave it running.

Then, in two more terminals:

# Terminal 2 β€” run the emulator on port A
ESCPOS_SERIAL_PORT=/dev/ttys004 dotnet run --project src/CrossEscPos.App.Desktop

# Terminal 3 β€” send a receipt from "another app" on port B
cat test_receipt.txt > /dev/ttys005
#   …or from your own program, just open /dev/ttys005 like a normal serial port
#   (9600 8N1) and write ESC/POS bytes to it.

The receipt appears in the emulator window. Because the interpreter is stateful across reads, fragmented serial writes (commands split across packets) are handled correctly.

Windows β€” install com0com and create a linked pair (e.g. COM3 ↔ COM4). Run the emulator with ESCPOS_SERIAL_PORT=COM3 and have your application write to COM4.

Monitor (built-in test client)

Sending test jobs is the monitor's job β€” the emulator is the device, the monitor is the POS-side client that drives it over the wire (just like a real application would). Click Open monitor… to launch a second window (built on ESC-POS-.NET) and pick a transport:

  • TCP/IP β€” connect to the emulator's listener (or any networked printer).
  • Serial β€” pick a port + baud; pairs with the emulator's serial transport via a virtual port bridge.
  • USB β€” print directly to a real USB printer selected from the connected-device list (by VID:PID), via libusb. This is send-only (no status), and needs native libusb installed (macOS brew install libusb, Debian/Ubuntu apt install libusb-1.0-0; bundled on Windows) and the OS not already holding the device.

It then lets you exercise the target without writing any code:

  • Print a sample receipt, all 1D barcodes, or QR / PDF417 / DataMatrix / Aztec.
  • Send the full feature test receipt, open the cash drawer, buzz, or cut.
  • Watch the printer status the emulator reports back: toggle paper-out / cover / drawer / offline in the Printer state panel and the monitor's status display updates live (via Automatic Status Back), confirming the emulator's status responses are wire-correct. When the printer isn't ready, the emulator drops the job and shows a notification, just like real hardware.

Monitor

Toggling the emulator's Printer state panel pushes status to the monitor in real time β€” here the printer reports paper low and a recoverable error, so the monitor shows Not ready:

Monitor reflecting printer state

Exporting tickets

Each cut (ESC i / ESC m / GS V) starts a new receipt β€” a "page". The Export buttons in the left panel save the rendered tickets as PNG:

  • Export all (single image) β€” stacks every receipt into one tall PNG (a save dialog).
  • Export each cut (folder) β€” writes one receipt_NNN.png per cut into a chosen folder.

Architecture & packages

The emulator is split into layered, independently-publishable packages so the rendering backend is swappable and the core runs headless (and in the browser). The namespace is unified under CrossEscPos.* (organized by feature/directory, not by package), so types resolve across assemblies.

Package Namespace(s) Role Depends on
CrossEscPos.Abstractions CrossEscPos, CrossEscPos.Graphics Backend-agnostic rendering + printer contracts (IReceiptCanvas, IReceiptImage, IReceiptImageFactory, ITypefaceProvider, IImageEncoder, IReceiptPrintable, IPrinterResponder) β€”
CrossEscPos.Core CrossEscPos.Emulator, CrossEscPos.EscPos, … Headless ESC/POS interpreter, printer state machine, receipt document model, barcode/QR generation. ESC/POS code maps (2D families, code tables, barcode systems, status requests) are behaviour-carrying SmartEnums, not magic-number switches Abstractions, QRCoder, ZXing.Net, Ardalis.SmartEnum
CrossEscPos.Rendering.Skia CrossEscPos.Rendering.Skia The default render backend (SkiaSharp). Swap it for another IReceiptImageFactory/ITypefaceProvider/IImageEncoder Abstractions, SkiaSharp
CrossEscPos.Rendering.ImageSharp CrossEscPos.Rendering.ImageSharp A 100% managed render backend (ImageSharp) β€” no native dependency, so it runs in Blazor WASM without a native relink. Same output as the Skia backend Abstractions, SixLabors.ImageSharp.Drawing
CrossEscPos.Transports CrossEscPos.Transports TCP / serial / USB transports (desktop only) Core, System.IO.Ports, LibUsbDotNet, ESC-POS-.NET
CrossEscPos.Controls CrossEscPos.Controls Reusable Avalonia controls (ReceiptView, PrinterStatePanel) β€” host apps consume these. Backend-agnostic (no SkiaSharp dependency) Core, Avalonia

Core carries no UI and no graphics-backend dependency, so the library works headless or in WASM. The host (desktop, browser, or your own app) is the composition root: it picks a backend and injects it.

var imageFactory = new SkiaImageFactory();
var typefaces    = new SkiaTypefaceProvider();
var printer      = new ReceiptPrinter(PaperConfiguration.Default, imageFactory, typefaces);
printer.FeedEscPos(escPosBytes);                         // byte[] β€” ESC/POS is binary
using var image  = printer.CurrentReceipt.Render();      // IReceiptImage
new SkiaImageEncoder().EncodePng(image, outputStream);

πŸ“¦ Package usage guides: docs/packages/ β€” getting started, the core emulator, rendering & custom backends, the Avalonia controls, the transports, and a WASM JavaScript interop for rendering ESC/POS to PNG from any web project (no .NET on the caller's side).

Building & running

Requires the .NET 10 SDK (and the wasm-tools workload for the browser head: dotnet workload install wasm-tools).

# Desktop app (Windows / macOS / Linux)
dotnet run --project src/CrossEscPos.App.Desktop

# Headless: ESC/POS bytes -> PNG, no UI, no Avalonia
dotnet run --project samples/CrossEscPos.Headless -- test_receipt.txt out.png

# Browser (Avalonia WASM head): launches a dev server and opens the app
dotnet run --project src/CrossEscPos.App.Browser

# Blazor web emulator: pick the render engine (managed ImageSharp by default), render ESC/POS
# in the browser, and drive the printer state β€” the managed-backend showcase
dotnet run --project samples/CrossEscPos.Web

# Tests (unit + headless UI)
dotnet test CrossEscPos.slnx

The Blazor web app (samples/CrossEscPos.Web) renders receipts entirely in the browser and lets you switch the render engine at runtime β€” ImageSharp (managed) by default (no native relink) or SkiaSharp (native). It mirrors the desktop ReceiptView / PrinterStatePanel as Razor components. Paste ESC/POS text, upload a file, or load the bundled sample.

  • Windows / macOS: no extra setup β€” native rendering libraries ship with the Avalonia packages.
  • Linux: install the usual font/render native deps if they are missing, e.g. sudo apt install libfontconfig1 libfreetype6 (Debian/Ubuntu).

Testing

Two test projects under tests/:

  • CrossEscPos.Core.Tests β€” emulation coverage. ESC/POS sequences are fed through the interpreter and the observable results (rendered draws, printer state, host responses, events) asserted: text and control characters, styling (emphasis/italic/size/justification), cutting and feeding, 1D/2D barcodes and bit images, status/transmit-back (DLE EOT, GS r, GS I, GS a), cash drawer and buzzer, real-time commands, code pages, page mode and not-ready handling β€” plus exact StatusByteBuilder bit layouts and the SmartEnum code maps. Rendering goes to a synthetic backend, so the suite runs with no SkiaSharp (proving the core is headless).
  • CrossEscPos.Controls.Tests β€” headless Avalonia UI tests for the controls (two-way state binding, receipt image rendering).
dotnet test CrossEscPos.slnx

Fonts & license

Receipt text is rendered with JetBrains Mono, embedded in the CrossEscPos.Rendering.Skia package (under src/CrossEscPos.Rendering.Skia/Assets/Fonts/) so output is identical across platforms and works in the browser sandbox (no file IO). JetBrains Mono is licensed under the SIL Open Font License 1.1; the full license text is included at src/CrossEscPos.Rendering.Skia/Assets/Fonts/OFL.txt. Per the OFL, the font is redistributed here under its original license and "JetBrains Mono" is a trademark of JetBrains s.r.o. To swap in a different monospace font, replace the receipt-mono*.ttf files (and keep its license alongside).

Emulated printer

This program emulates a printer with the following specifications:

  • 80mm paper width
  • 72mm printing width
  • 180x180dpi
  • ASCII Font A/B: 12x24 pixels
  • Automatic line feed
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 47 7/7/2026