render logs into images

This commit is contained in:
seb
2026-07-11 05:41:17 +02:00
parent 9466d295a4
commit a46e2705a4
12 changed files with 1366 additions and 249 deletions

View File

@@ -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.