Skip to content

AmigoUK/BarcodeLabelGen

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

173 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

BarcodeLabelGen

Web-based label editor and PDF batch generator for non-technical office users. Self-hosted, multilingual (PL + EN), runs on a single Docker host behind Tailscale.

Editor with a real label template

The editor open on a Zebra 2Γ—1β€³ template β€” text, dynamic {{placeholders}}, an EAN-128 barcode, all positioned in millimetres. Right panel shows the per-object inspector with Lock + Print-in-PDF toggles, font, size, alignment.


What it does

  • Online label editor β€” Konva-powered drag-and-drop canvas (text, text blocks with auto-fit, rectangles, lines, images, barcodes, dynamic {{column}} fields).
  • Lockable + non-printable objects β€” pin a logo so it can't be moved; drop a scan of a pre-printed sheet as a layout reference that stays out of the final PDF.
  • Layer order + alignment + distribute β€” z-stack controls (front/back/forward/backward), 6 page-relative + 6 selection-relative align operations, equal distribution.
  • Duplicate fast β€” Alt+drag a selected object to clone it under the cursor; Ctrl/Cmd+D to duplicate in place. Multi-select supported.
  • Barcodes β€” EAN-13, EAN-14, GTIN, Code 128, GS1-128, QR (with checksum validation).
  • Series generation β€” upload a CSV, Excel, or SQLite file, map placeholders to columns (or write a custom SELECT), optionally filter rows, get a single PDF with one label per row. Up to 1,000 labels per batch.
  • ZPL / ZPL II round-trip β€” paste an existing ZPL label, adjust element positions on the canvas, and export native ZPL back out (copy to clipboard or download .zpl) for use in external software. Single-brace {VARIABLES}, ^PQ{NoLabel} quantity, resident fonts (E:ARIxxx.TTF) and native QR are preserved 1:1; a batch mode fills {{column}} values from a dataset. DPI is auto-detected from ^PW/^LL.
  • TSPL export (TSC / desktop Toshiba) β€” export the same canvas as TSPL/TSPL2 (SIZE/GAP/DIRECTION/CLS … PRINT) for TSC and desktop-Toshiba printers: text, barcodes (Code 128, GS1-128, EAN-13, QR), rectangles, lines and tables. Copy to clipboard or download a .txt; warnings flag anything approximated (bitmap fonts) or skipped (images).
  • Print preview β€” hit πŸ‘ Preview to render the single-label PDF and see it embedded in the app (with any text-overflow warnings) before committing to a download β€” the same generation is reused, so preview + download is one action.
  • Editable label size β€” resize a template (width Γ— height in mm, with presets) at any time from the editor; undoable and persisted, so a label never has to be recreated just to change its dimensions.
  • Date placeholders β€” {{date+14d}}, {{date+3m:YYYY-MM-DD}} compute best-before / production dates at generation time (PDF and ZPL alike), with a live preview chip in the editor and month-end-safe arithmetic.
  • Direct printing via the local connector β€” a single-binary Go agent (connector/) polls the server's print queue with a per-device Bearer token and forwards ZPL to label printers over RAW TCP 9100 (Zebra / JetDirect compatible). Register devices on the Devices page, then hit πŸ–¨ Print in the editor; job status (queued β†’ printing β†’ done/error) reports back live. Pure Go, zero cgo β€” prebuilt binaries ship for Windows, macOS (Intel + Apple Silicon) and Linux (amd64/arm64/arm, incl. Raspberry Pi) with launchd / systemd / service setup in the connector README. An Android connector core (connector/mobilecore/) is in progress.
  • Virtual printer capture β€” the same agent can pose as a network printer (JetDirect listener): anything another application prints to it lands in the web app's Inbox, one click away from becoming an editable template β€” the escape hatch from legacy label software. On Windows via the ZDesigner driver + a Standard TCP/IP port; on macOS / Linux via a CUPS raw queue (one-command connector/install-capture-cups.sh).
  • Template import / export β€” every template is a single self-contained .blg-template.json (size, objects, embedded images). Cross-instance portable; partial import lets you skip objects + override the size.
  • Multilingual UI + in-app docs β€” Polish + English from day one, with HELP + FAQ rendered inside the app.
  • Roles β€” admin / editor / viewer; admin manages users + temporary password resets.
  • Label formats β€” A4, A5, A6, common Zebra sizes (4Γ—6", 4Γ—4", 3Γ—2", 2Γ—1"), plus arbitrary custom mm.

Tour

1 Β· Dashboard

Dashboard with two CTA cards

First screen after signing in. Two cards point straight at the user's job: open the template editor, or read the in-app guide. Sidebar exposes Dashboard / Templates / Help / Administration β†’ Users.

2 Β· Templates library

Templates grid

Every template you (or a shared admin) own. Search filters by name; each tile shows the size + version + last-modified date. Hover a tile to reveal Export (⬇) and Delete (βœ•). Top-right pair: Import (from a .blg-template.json file) and New template (pick a format).

3 Β· Bring your data

Sample data file in Numbers

The "left side" of the mail-merge flow. Any CSV / Excel / SQLite with column headers works. Here: 60 products with SKU, ProductName, Ingredients, BatchNo, BestBefore, EAN-128 β€” feeds straight into a template that uses {{SKU}}, {{ProductName}} etc.

4 Β· Generate Series β€” pick the source

Generate Series wizard β€” upload step

Step 1 of the 4-step wizard. Accept any of: .csv, .xls, .xlsx (max 10 MB / 1,000 rows) or .db / .sqlite / .sqlite3 (max 50 MB).

5 Β· SQLite source β€” table picker + custom SELECT

SQLite source picker

When the uploaded file is a SQLite database the wizard detects every user-visible table (sorted by row count β€” biggest first) and lets you either pick one or expand "Show advanced" to write a SELECT with WHERE/JOIN/UPPER(...) etc. Read-only connection; single-statement validator blocks INSERT / UPDATE / DELETE / DROP / ATTACH / PRAGMA; auto-LIMIT 1000.

6 Β· Map placeholders to columns

Mapping placeholders

Step 2 detects every {{name}} placeholder in the template and auto-maps it to a same-named column. Mismatched names are pickable from a dropdown β€” the wizard refuses to move on until every placeholder has a source.

Picking a column manually

The fallback dropdown showing every column the source carries. Works the same whether the source was CSV, Excel, or a SQLite query.

7 Β· Per-row PDF output

Generated label preview

One PDF, one page per row. Each {{placeholder}} is replaced by the row's value β€” here Victoria Sponge Cake is row 5 of 60, with its own ingredients, batch number, and GS1-128 barcode. Long ingredients lists wrap inside the text block; the renderer reports a warning if anything doesn't fit.

πŸ“„ Download a sample PDF β†’ (50 Zebra 2Γ—1β€³ labels, 668 KB) β€” generated from the products dataset above, ready to inspect or print.

8 Β· Import / export templates

Import template modal

Every template exports to a single .blg-template.json (size + objects + embedded images, all base64). The import modal lets you rename the new template, override the size, and uncheck specific objects to bring in β€” the {{…}} chip flags objects that carry dynamic placeholders. Duplicate images (detected by SHA-256) prompt a reuse-vs-copy choice.

9 Β· ZPL / ZPL II round-trip β€” paste, adjust, copy back

ZPL import dialog β€” paste, Auto-detect DPI, Analyze

Paste an existing ZPL label, leave DPI on Auto-detect (or force 203 / 300), and hit Analyze: the elements become editable canvas objects, the dialog reports the detected DPI + object count and warns when the content spills past the label (a wrong-DPI signal). Import keeps the label size you already set; single-brace {VARIABLES}, ^PQ{NoLabel}, resident fonts (E:ARIxxx.TTF) and native QR survive the round-trip.

ZPL export panel β€” live preview, Copy, Download .zpl

A live native-ZPL preview of the current label with Copy and Download .zpl. Template mode keeps the variables intact for your external system; batch mode substitutes {{column}} values from a dataset and emits one ^XA…^XZ block per row.

10 Β· Resize the label anytime

Label-size dialog β€” width Γ— height in mm with presets

The size button (πŸ“ WΓ—H) in the toolbar opens a dialog to change the label's width Γ— height in millimetres, with one-click presets (40Γ—100, 50Γ—30, 100Γ—150, 105Γ—148, 210Γ—297). The change is undoable and saved to the template β€” object positions stay put.

11 Β· Print preview before download

Editor Print-preview modal β€” the single-label PDF embedded in a dialog, with any text-overflow warnings above it and Download / Close buttons

The πŸ‘ Preview toolbar button renders the single-label PDF and embeds it right in the app β€” check the layout (and any wrapping warnings) before you download. The same generation is reused, so preview + download counts as one action in the history.

12 Β· TSPL export β€” TSC / desktop Toshiba

Editor Export-TSPL modal β€” density selector (203/300 dpi), a read-only TSPL text preview starting with SIZE/GAP/DIRECTION/CLS, Copy and Download .txt buttons

Export the current label as TSPL/TSPL2 for TSC and desktop-Toshiba printers: pick the density, preview the generated commands (SIZE/GAP/DIRECTION/CLS … PRINT), then Copy or Download .txt. Text, barcodes, QR, rectangles, lines and tables map across; a warnings list flags approximated bitmap fonts or skipped images.

13 Β· Cross-platform connector + CUPS capture

A macOS or Linux terminal running ./install-capture-cups.sh, showing the raw CUPS queue being created and pointed at the local connector on 127.0.0.1:9101

The connector ships as prebuilt binaries for Windows, macOS (Intel + Apple Silicon) and Linux (amd64/arm64/arm, incl. Raspberry Pi) β€” see connector/README.md. Virtual-printer capture works on macOS / Linux through a CUPS raw queue created by connector/install-capture-cups.sh, routing another app's ZPL into the web app's Inbox.


Tech stack

Layer Technology
Frontend React 18 + TypeScript + Vite + Konva + TailwindCSS + react-router 7 + react-i18next + react-markdown
Backend Python 3.12 + Flask 3 + uv + SQLAlchemy 2 + Alembic + ReportLab + python-barcode + qrcode + pandas + Pillow + pdfplumber
Database PostgreSQL 16 (production) Β· SQLite (test fixture)
Cache + sessions + job queue Redis 7
Infrastructure Docker + Docker Compose + nginx
Deployment Linux host fronted by Tailscale Serve
Tests pytest (backend) + tsc + eslint (frontend); Go go test for the connector

Quick start

# Clone
git clone https://github.com/AmigoUK/BarcodeLabelGen.git
cd BarcodeLabelGen

# Build + start (Postgres + Redis + Flask + nginx)
docker compose up -d

# First-time DB migration (auto-runs on web container start; explicit form below)
docker compose exec web alembic upgrade head

# Bootstrap an admin account (replace email + password)
docker compose exec web flask create-admin --email you@example.com --password 'change-me-now-please'

# Open in your browser
open http://127.0.0.1:18003

Behind Tailscale (recommended for production)

The service binds to 127.0.0.1:18003 only β€” to expose it to your tailnet (and get a free *.ts.net HTTPS cert):

tailscale serve --bg --https=18003 http://127.0.0.1:18003
# β†’ https://<your-machine>.<tailnet>.ts.net:18003

Development with hot reload

docker compose -f compose.dev.yml up
# Vite dev server + Flask debug, proxied through nginx.

Documentation


Project structure

BarcodeLabelGen/
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ models/        # SQLAlchemy models
β”‚   β”‚   β”œβ”€β”€ routes/        # Flask blueprints (REST endpoints)
β”‚   β”‚   β”œβ”€β”€ schemas/       # Pydantic request/response models
β”‚   β”‚   β”œβ”€β”€ services/      # Business logic (PDF render, batch, datasets, …)
β”‚   β”‚   └── factory.py     # Flask app factory
β”‚   β”œβ”€β”€ alembic/           # DB migrations (0001…0006)
β”‚   β”œβ”€β”€ tests/             # pytest β€” 203 tests
β”‚   └── pyproject.toml
β”œβ”€β”€ frontend/
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ components/    # Shared UI (Modal, Button, ImportTemplateModal, …)
β”‚   β”‚   β”œβ”€β”€ editor/        # Konva-based label editor (Canvas, panels, store)
β”‚   β”‚   β”œβ”€β”€ hooks/         # React-Query data hooks
β”‚   β”‚   β”œβ”€β”€ pages/         # Route components (Dashboard, Templates, Editor, Help, …)
β”‚   β”‚   β”œβ”€β”€ i18n/locales/  # PL + EN
β”‚   β”‚   └── lib/           # api client, csrf, download helper
β”‚   └── package.json
β”œβ”€β”€ docs/
β”‚   β”œβ”€β”€ HELP.{pl,en}.md    # User guide (rendered in-app)
β”‚   β”œβ”€β”€ FAQ.{pl,en}.md     # FAQ (rendered in-app)
β”‚   β”œβ”€β”€ PROJECT.md         # MVP specification
β”‚   └── screenshots/       # Images referenced from this README
β”œβ”€β”€ compose.yml            # Production docker-compose
└── README.md              # ← you are here

Status

βœ… Production on a Tailscale-only host.

  • Backend: 203 / 203 tests passing.
  • QA harness (PDF render geometry checks): all formats βœ….
  • Frontend: typecheck + lint + build clean; bundle 153 KB (gzipped 47 KB) main + lazy chunks for editor (Konva) and help (react-markdown).

Credits

dev@attv.uk Β· Project & Development: Tomasz 'Amigo' Lewandowski Β· www.attv.uk Β· GitHub

License

GPL-3.0 β€” see LICENSE.

About

Self-hosted web app for designing label templates and batch-generating PDFs (CSV / Excel / SQLite). Drag-and-drop editor with barcodes, dynamic placeholders, lockable references, partial-import. PL + EN. Docker + Tailscale.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors