render logs into images
This commit is contained in:
71
README.md
71
README.md
@@ -2,15 +2,18 @@
|
||||
|
||||
Minimal ESC/POS print proxy written as a Node.js ESM app.
|
||||
|
||||
It listens for incoming ESC/POS print jobs on a TCP port, **forwards the raw
|
||||
bytes straight to a target printer**, and **logs every job to disk** as both a
|
||||
raw `.bin` file and a decoded `.txt` sidecar.
|
||||
It listens for incoming ESC/POS print jobs on a TCP port, **forwards the raw bytes straight to a target printer**, and **automatically parses and renders every job** to disk as both a structured `.log` file and a high-fidelity `.png` receipt image.
|
||||
|
||||
A *job* is delimited by either:
|
||||
- a **cut command** ("bladecut") in the stream — ESC/POS `GS V` = `0x1D 0x56`, or
|
||||
- a **connection drop** (the client closes / resets the connection).
|
||||
|
||||
No database, websocket, or receipt re-rendering is involved.
|
||||
## Features
|
||||
|
||||
- **Transparent Proxying**: Forwards bytes losslessly to a physical ESC/POS printer.
|
||||
- **Advanced Parsing**: Decomposes the raw byte stream into ESC/POS commands, tracking formatting states (bold, underline, double-height, alignment).
|
||||
- **Native PNG Rendering**: Automatically generates a 1-bit style grayscale PNG image of the exact receipt that was printed.
|
||||
- **Embedded Graphics**: Supports rendering custom embedded `IMAGE` payloads and generates actual QR codes from `ESC Z` (2D symbol setup) commands.
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -18,6 +21,7 @@ Configuration lives in `.env` (copy `.env.example` to `.env` and edit). It is lo
|
||||
|
||||
```bash
|
||||
cp .env.example .env # first time only
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
@@ -35,18 +39,16 @@ npm start
|
||||
|
||||
Real environment variables always take precedence over `.env`.
|
||||
|
||||
## Logs
|
||||
## Logs and Output
|
||||
|
||||
For each completed job, two files are written into `LOG_DIR`:
|
||||
|
||||
- `job-<timestamp>-<seq>.bin` — the exact raw bytes (reprintable).
|
||||
- `job-<timestamp>-<seq>.txt` — the same bytes decoded as `latin1` (ASCII +
|
||||
control characters visible, ESC/POS faithful).
|
||||
- `job-<timestamp>-<seq>.log` — The parsed, human-readable token stream containing command opcodes, parameters, and decoded text.
|
||||
- `job-<timestamp>-<seq>.png` — A rendered visual receipt using the exact fonts (Font A / Font B) and layout applied by the software.
|
||||
|
||||
## Testing
|
||||
|
||||
`test-send.mjs` sends a sample ESC/POS receipt (with a `GS V` cut) to the
|
||||
listener so you can verify logging and forwarding:
|
||||
The `test-send.mjs` script sends a sample ESC/POS receipt (with a `GS V` cut) to the listener so you can verify logging, forwarding, and PNG generation:
|
||||
|
||||
```bash
|
||||
# terminal 1
|
||||
@@ -56,47 +58,10 @@ npm start
|
||||
npm run test:send
|
||||
```
|
||||
|
||||
## Parsing the logs
|
||||
## Architecture
|
||||
|
||||
`parser.js` is a **lossless** ESC/POS parser. It decomposes the raw byte stream
|
||||
into the ESC/POS command grammar: each control sequence is recognized by its
|
||||
opcode with its parsed parameters, and text is kept as raw byte spans (decoded
|
||||
via the selected code page). Nothing is *interpreted* into higher-level meaning
|
||||
(no "this is bold", no line/style inference) — it is a faithful tokenization.
|
||||
Every byte is preserved, and the original stream can be rebuilt via
|
||||
`serialize(parse(buf))`.
|
||||
|
||||
Token types:
|
||||
- `{ type: "text", bytes, text }` — raw bytes + code-page decode
|
||||
- `{ type: "command", bytes, group, name, params }` — control sequence + params
|
||||
- `{ type: "image", bytes, width, height, data }` — raster bit image (`GS v 0`)
|
||||
|
||||
`parse-log.mjs` is a CLI wrapper. By default it prints the parsed token stream
|
||||
(opcode + command name + parameters, text spans, images) and verifies the
|
||||
round-trip `serialize(parse(buf)) === buf` (no bytes lost).
|
||||
|
||||
```bash
|
||||
# parsed token stream (default) — a faithful decomposition
|
||||
npm run parse -- logs/job-2026-07-08T21-08-02-523Z-0003.bin
|
||||
|
||||
# parse every .bin in a directory
|
||||
node parse-log.mjs logs --all
|
||||
|
||||
# also show the raw bytes of each token
|
||||
node parse-log.mjs logs/job-...bin --hex
|
||||
|
||||
# convenience: decoded receipt text only (drops structure — not lossless)
|
||||
node parse-log.mjs logs/job-...bin --text
|
||||
|
||||
# also render raster bit images (e.g. QR codes) as ASCII art
|
||||
node parse-log.mjs logs/job-...bin --image --max-width 60
|
||||
```
|
||||
|
||||
As a module:
|
||||
|
||||
```js
|
||||
import { parse, serialize, renderText } from "./parser.js";
|
||||
const buf = fs.readFileSync("logs/job-xxx.bin");
|
||||
const events = parse(buf); // lossless token stream
|
||||
console.log(serialize(events).equals(buf)); // true — nothing lost
|
||||
```
|
||||
The source code resides in the `src/` directory:
|
||||
- `server.js` — The core TCP proxy server and chunk delimiter.
|
||||
- `parser.js` — The ESC/POS grammar parser.
|
||||
- `renderer.js` — The PNG generator leveraging the `sharp` and `qrcode` libraries to draw the parsed receipt instructions to an image buffer.
|
||||
- `font-12x24.js` / `font-9x16.js` — Exported native JS arrays containing the dot-matrix character maps used by the renderer.
|
||||
Reference in New Issue
Block a user