GhostLabel prints shipping label PDFs to a KNAON Y813BT Bluetooth thermal label printer from Linux, without the Android app.
The KNAON Y813BT is a cheap 4-inch Bluetooth thermal label printer sold under a dozen different brand names on Amazon and AliExpress. The manufacturer only provides a proprietary Android app called "Flash Label Pro" -- there's no Linux client, SDK, or protocol documentation of any kind. If you want to print from a desktop you have to email the PDF to your phone, open it, share it to the app, and print. Every single time.
I reverse-engineered the printer from scratch so you can drag a PDF onto a window and it prints. That's it.
Most cheap thermal printers in this price range speak ESC/POS over Bluetooth SPP (UUID 00001101-0000-1000-8000-00805F9B34FB, RFCOMM channel 1). I tried GS v 0 (raster bit-image, 0x1D 0x76 0x30) first and it printed -- blurry, but it printed. That confirmed the transport and command set.
I decompiled the Android app with jadx to see if the manufacturer was doing anything beyond standard ESC/POS:
adb connect <device-ip>:<port>
adb pull /data/app/~~.../com.flashlabel.flashlabelpro-1/base.apk flash_label.apk
adb pull /data/app/~~.../com.flashlabel.flashlabelpro-1/split_config.arm64_v8a.apk
jadx -d flash_label_src flash_label.apkThe app is a Flutter shell. The printing logic lives in libdnInkPrinter.so extracted from the arm64 split APK. After strings-analysis I realised libdnInkPrinter is an inkjet library -- wrong product line entirely. The Y813BT ignores every command it doesn't understand and the Flutter layer was just calling straight ESC/POS the whole time.
Raw ESC/POS at 203 DPI produced readable but poor-quality prints. There were three issues:
| Problem | Root cause | Fix |
|---|---|---|
| Washed-out / light print | No contrast stretching | autocontrast: stretch histogram 1st to 99th percentile to 0-255 |
| Horizontal banding (white stripes in solid areas) | 2x oversample then LANCZOS downsample: ringing artifacts became evenly-spaced white lines after threshold | Render direct at 203 DPI, no downsample |
| Garbled output after failed jobs | Printer still waiting for bytes from previous command | Flush: 200 x 0x00 + ESC @ before every job |
| Bytes | Command | Purpose |
|---|---|---|
1B 40 |
ESC @ | Initialize / hard reset |
1B 32 |
ESC 2 | Set default line spacing |
1D 76 30 m xL xH yL yH [data] |
GS v 0 | Raster bit-image (1-bit, MSB = leftmost) |
1B 64 04 |
ESC d 4 | Feed 4 lines |
1D 56 41 03 |
GS V A 3 | Partial cut with feed |
One command that doesn't work: ESC * (column raster, mode 33). The printer ignores the data bytes and jams waiting for more input. If you accidentally send it, you need to power-cycle the printer or flush with 200+ null bytes followed by ESC @.
The Rust implementation connects over a raw libc::socket(31, SOCK_STREAM, 3) with a manually-constructed sockaddr_rc, which means no rfcomm bind and no system-level CUPS involvement. BlueZ stores bdaddr_t in reversed byte order, so AA:BB:CC:DD:EE:FF goes into the struct as [FF, EE, DD, CC, BB, AA].
Download the latest release from the Releases page.
| Package | Format | Distro |
|---|---|---|
GhostLabel_x.x.x_amd64.deb |
Debian package | Ubuntu, Debian, Mint, Pop!_OS |
GhostLabel_x.x.x_amd64.AppImage |
Portable executable | Any Linux distro |
GhostLabel-x.x.x-1.x86_64.rpm |
RPM package | Fedora, RHEL, openSUSE |
You'll also need poppler-utils on your machine -- GhostLabel shells out to pdftoppm to render PDFs:
# Ubuntu / Debian / Mint
sudo apt install poppler-utils
# Fedora
sudo dnf install poppler-utils
# Arch
sudo pacman -S popplerDebian / Ubuntu:
sudo dpkg -i GhostLabel_*.debAppImage (any distro):
chmod +x GhostLabel_*.AppImage
./GhostLabel_*.AppImagePair your printer in System Settings -> Bluetooth before first launch.
Requires Rust 1.75+, Node.js 18+, and poppler-utils.
npm install
npm run buildPackages are written to src-tauri/target/release/bundle/.
Releases are signed with minisign (Ed25519). The public key is at signing/ghostlabel.pub in this repo.
Public key fingerprint:
RWQLa9Chpu4iKdunJ/qhaiOisIb+tVYsHDb6xKkjdeHXJePY9oMYGeY0
Verify a downloaded binary:
# With the public key file
minisign -Vm ghostlabel -p signing/ghostlabel.pub
# Or inline
minisign -Vm ghostlabel -P RWQLa9Chpu4iKdunJ/qhaiOisIb+tVYsHDb6xKkjdeHXJePY9oMYGeY0The private key is gitignored and never published, so only the original author can produce valid signatures.
- Launch GhostLabel
- Drag-and-drop one or more PDF files onto the drop zone (or click to browse)
- Click Print All
First-run: click the gear icon to set your printer's MAC address. Config is saved to ~/.config/ghostlabel/config.json.
Basic
| Setting | Default | Notes |
|---|---|---|
| Bluetooth MAC | Your printer's MAC. Use SCAN to find it. | |
| RFCOMM Channel | 1 |
Don't change unless connection fails |
| DPI | 203 |
Match your printer's thermal head resolution (203 or 300) |
| Width (px) | 832 |
Max printable pixels at native DPI. KNAON Y813BT = 832 |
| Threshold | 160 |
Darkness cutoff. Higher = more dots printed = darker output |
| Dithering | off | Floyd-Steinberg for photos. Leave off for barcodes/text |
Quick presets: one-click starting points, tunable from there:
| Preset | Use case |
|---|---|
| HIGH QUALITY | Sharpest barcodes, slowest transfer. Best for archival or problem labels. |
| BALANCED | Default. Good for most shipping labels. |
| FAST | Minimal processing, quickest print. Fine for bulk jobs. |
Advanced (expand in sidebar)
| Setting | Default | Notes |
|---|---|---|
| Render Scale | 2 |
PDF rendered at DPI x scale then downsampled. 2 = 2x supersampling |
| Sharpen | 0.7 |
Unsharp mask before threshold. 0 = off. >1.2 causes halos |
| Slice Lines | 48 |
Lines per BT packet. Lower if printer pauses mid-label |
| Slice Delay | 80ms |
Pause between packets. Increase if thermal head overheats |
| Heat Time | 255 |
ESC 7 heating duration. Higher = darker. 0 = skip command |
| Heat Dots | 15 |
ESC 7 heating dots. Typically 7-15 for narrow printers |
Tested on the KNAON Y813BT (4-inch thermal, 203 DPI, Bluetooth SPP). These printers are sold under dozens of brand names -- HPRT, Xprinter, Munbyn, Polono, and plenty with no recognizable brand at all -- but most share the same internal hardware and firmware. If your printer accepts ESC/POS GS v 0 over Bluetooth RFCOMM, this will probably work.
GPL-3.0
