HotPixels is a small command‑line tool that converts images into ESC/POS raster graphics and prints them on a thermal printer.
It runs on Windows and Linux and supports multiple dithering algorithms and optional gamma correction to fine‑tune brightness and contrast.
- Converts images to ESC/POS raster format (
GS v 0) - Multiple dithering modes (error‑diffusion + ordered dithers)
- Optional gamma correction
- Configurable print width in dots
- Optional automatic paper cut (requires a cutter, e.g. Epson TM‑T88III)
- Automatically rotates landscape images to portrait
- Prints to a print queue, a device node or a network printer, on Windows and Linux alike
HotPixels <target> <imagePath> [options]
-
target
Where to print. The transport follows from the shape of the value:Shape Transport Examples host:portTCP socket (network printers listen on port 9100) 192.168.1.50:9100An absolute path Written to directly /dev/usb/lp0,/dev/lp0,C:\out.binAnything else A print queue — the Windows spooler, or CUPS via lp -o rawEPSON TM-T88III,\\server\printerUse quotes if the value contains spaces.
Run the program without arguments to list the targets available on your machine.Writing to an absolute path is also the easiest way to inspect the generated ESC/POS bytes without using paper. IPv6 literals are not supported as network targets.
-
imagePath
Path to the image file.
Options may appear anywhere on the command line, and both --name=value and --name value are accepted.
| Option | Value | Default |
|---|---|---|
--dither=MODE |
Dithering algorithm, either by name (Jarvis, case-insensitive) or by its number. Run the program without arguments to list all modes |
2 (Jarvis) |
--gamma=F |
Gamma correction, a number greater than 0. Lower = brighter output | 0.75 |
--width=N |
Print width in dots, a positive multiple of 8. Must match the physical paper width your printer is configured for (e.g. 384 for 58 mm, 512 for 80 mm) | 384 |
--cut[=0|1] |
Send an automatic paper-cut command (ESC d 6 + GS V 0) after printing. Requires a printer with a built-in guillotine cutter (e.g. Epson TM‑T88III) |
off |
--help, -h, /? |
Show usage | — |
A bare --cut means on. To set it explicitly, use the inline form --cut=0 or --cut=1 — --cut never
consumes the following argument, because that would be ambiguous with the positional arguments.
An invalid value aborts with an error and exit code 1 without printing anything, so a typo cannot cost you a misprint.
HotPixels "EM5820" image.pngHotPixels "My Thermal Printer" photo.jpg --dither=StuckiHotPixels "ESC POS USB" logo.bmp --dither=Jarvis --gamma=0.6HotPixels "Epson TM-T88III" receipt.png --dither=Stucki --width=512 --cutHotPixels /dev/usb/lp0 photo.jpg --dither=AtkinsonHotPixels 192.168.1.50:9100 photo.jpg --width=512HotPixels /tmp/out.bin photo.jpg --width=512
xxd /tmp/out.bin | head- Windows or Linux
- .NET 10 or newer
- An ESC/POS‑compatible thermal printer
Before using HotPixels, your ESC/POS printer must be installed in Windows.
Most inexpensive 58 mm / 80 mm thermal printers identify as a USB serial device with a vendor-specific driver, but you can safely install them as a Generic / Text Only printer.
Follow these steps:
- Plug the printer into your Windows machine.
- Windows will usually show it as a USB printing device (often with names like USB Printing Support, GXMcu Micro-Printer, POS Printer, etc.).
- Open Control Panel
- Go to Devices and Printers
- Click Add Printer
- Choose The printer that I want isn’t listed
- Select Add a local printer or network printer with manual settings
- For the port, choose the automatically created USB00X port (e.g. USB001, USB002)
- In the manufacturer list, select Generic
- In the model list, choose Generic / Text Only
- Finish the installation
Give it a meaningful name like:
EM5820Thermal Receipt PrinterESC POS USB
You will use this exact name in the HotPixels command line:
HotPixels "ESC POS USB" image.pngESC/POS is a raw byte protocol, not a page-layout language.
Windows GDI drivers do not understand ESC/POS image commands, so you must use a raw-printing queue. The Generic / Text Only driver creates exactly that.
You have two options. The device node is the simpler one and needs no configuration at all.
A USB printer handled by the usblp kernel driver shows up as /dev/usb/lp0, and a parallel port as
/dev/lp0. Check what is there:
ls -l /dev/usb/lp* /dev/lp* 2>/dev/nullThose nodes usually belong to group lp, so add yourself to it and log in again:
sudo usermod -aG lp $USERThen print straight to it:
HotPixels /dev/usb/lp0 image.pngUse this for network printers, or when you want the printer shared. The queue must be raw so that CUPS passes the bytes through untouched — this is the exact counterpart of the Windows "Generic / Text Only" advice above:
# find the device URI
lpinfo -v
# create a raw queue (no driver, no filtering)
sudo lpadmin -p TM-T88III -E -v usb://EPSON/TM-T88III -m rawThen use the queue name as the target:
HotPixels TM-T88III image.pngHotPixels invokes lp -d <queue> -o raw for queue targets. The -o raw is what stops CUPS from
running the data through its filter chain and mangling the ESC/POS control codes.
dotnet testThe suite drives the built executable as a child process and covers the command line, the target resolution rules and the generated ESC/POS bytes. No printer is involved — everything goes to a temporary file or a deliberately unreachable target.
See tests/README.md for what each fixture covers and how to update a golden hash.
This project is provided under the MIT License. See LICENSE.md for details.