Skip to content

feat: QR codes and barcodes from templates - #556

Open
switch87 wants to merge 25 commits into
barebaric:mainfrom
switch87:feat/barcodes
Open

switch87 wants to merge 25 commits into
barebaric:mainfrom
switch87:feat/barcodes

Conversation

@switch87

@switch87 switch87 commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR change?

Implements #529: QR codes and barcodes as workpieces whose content is a template.

  • Encoders.
    • Code 128 switches between code sets B and C on its own.
    • EAN-13 adds the check digit, or verifies it when 13 digits are given.
    • QR comes from segno (BSD-3, pure Python, no dependencies), with error correction L/M/Q/H.
  • Dependency. segno==1.6.6 is added to requirements.txt, pixi.toml, pixi.lock, debian/control (python3-segno) and the Windows setup list. pixi.lock is regenerated with pixi lock.
  • Barcode asset. A barcode asset implementing IGeometryProvider, so a barcode is an ordinary workpiece.
    • Modules are merged into closed outlines with holes, so both Engrave and Contour work.
    • Settings: module size, quiet zone, bar height, optional human-readable text, and invert for light codes on dark material.
  • Templates. The content resolves {...} like a text box, so {counter} from feat: job counter variable for text templates #554 and {csv[...]} from feat: CSV merge for text templates #555 work once those land.
  • UI and docs. Object → Add Barcode…, a Barcode properties group, and a docs page.
  • Sketcher guard. A small is_sketch_workpiece() check, because the sketcher assumed every geometry provider is a sketch. This is a separate commit.

Why did you choose this specific architectural approach?

A barcode is a geometry provider asset, the same contract a sketch uses, so selection, transform, steps, the pipeline and save/load need no new code. Content goes through the existing template machinery, and the asset reports its template sources like a text box does. Outlines are built with raygeo (get_polygons_union, normalize_winding_orders) instead of Python polygon code. Settings change through the core UpdateAssetCommand, so undo works like for other assets. Lengths use LengthSpinRow, so they follow the user's unit. Everything lives in its own addon, so the core only gains the generic guard.

Open points:

  • Template functions: {today()} and {uuid()} don't work in barcodes yet. Their registry lives in the sketcher addon, and addons can't import each other reliably; moving it into core would be a separate PR.
  • Renderer: the barcode reuses the sketcher's renderer through the registry, hence requires: sketcher. A small generic fill renderer in core is an alternative.

How did you manually test this locally?

  1. Object → Add Barcode…: a QR code "Rayforge" appears in the middle of the work area. Scan the screen with a phone: it reads "Rayforge".
  2. In the Barcode properties, switch to Code 128 with content SN-{counter:05d} and human-readable text on: the text under the bars matches the counter. Change the length unit to inch: the size rows follow it.
  3. Engrave and Contour both produce clean outlines in the preview, including the holes in QR modules. Invert gives a light code on dark material.
  4. Undo of a settings change and save + reopen both keep the barcode.

Checklist

  • I am not an AI. I have manually read the code and understand it.
  • I take full responsibility for the quality and architectural fit of
    this code.
  • I agree to publish this code under the MIT license.

@switch87
switch87 force-pushed the feat/barcodes branch 3 times, most recently from e19cbfa to 30a0a6c Compare October 12, 2026 18:12
@switch87 switch87 changed the title WIP: QR codes and barcodes from templates feat: QR codes and barcodes from templates Oct 12, 2026
@switch87
switch87 marked this pull request as ready for review October 13, 2026 18:16
@switch87

Copy link
Copy Markdown
Contributor Author

I went through this PR again against the existing architecture and pushed a few corrections as separate commits (cc61601..1b4002f), so you can review just those:

  • New barcodes are placed with MachinePanel.work_area_center() instead of my own math on machine.work_area, which was wrong for origins other than bottom-left.
  • The contour orientation now uses raygeo's normalize_winding_orders() instead of a Python copy.
  • Setting changes go through the existing UpdateAssetCommand, like the sketcher, instead of ChangePropertyCommand plus a custom descriptor and resize loop.
  • Module size and bar height use LengthSpinRow, so they follow the user's length unit.
  • The barcode icon moved into the addon's resources/icons, registered from its frontend like the other addons.
  • is_sketch_workpiece is a TypeGuard now, so the asserts in the sketcher are gone.

The open points from the description still stand (renderer reuse from the sketcher, template functions, the hand-edited pixi.lock).

The new barcodes addon starts with the encoders. Code 128 switches
between code sets B and C on its own, EAN-13 adds or verifies the check
digit, and QR codes come from segno, a pure-Python dependency (BSD-3).

Refs barebaric#529
Dark modules are merged into closed outlines with holes, in
millimetres. 1D codes get a bar height and optional human-readable
text (EAN-13 in its usual layout, with the guard bars reaching into the
text). Invert draws a dark quiet zone around a light code. Every loop is
oriented by its nesting depth, so non-zero and even-odd filling agree.

Refs barebaric#529
Other geometry providers also set a provider uid on their workpieces,
so the sketch property group, Edit Sketch and its context menu entry
now check that the provider really is a Sketch.

Refs barebaric#529
A barcode is a document asset that provides the geometry of a QR code,
Code 128 or EAN-13 symbol, so it becomes an ordinary workpiece. Its
content is a template resolved with the parameters the workpiece
passes in; the result is cached like text box templates. Content the
symbology cannot encode gives a placeholder square and an error.

Refs barebaric#529
Object > Add Barcode adds a QR code in the middle of the work area, as
one undo step. A Barcode group in the properties panel edits the
content, type, error correction, module size, bar height, quiet zone,
text and invert; every change is undoable and gives the workpiece the
symbol's true size. Content the type cannot encode is flagged.

Refs barebaric#529
pytest imports test modules by basename; test_commands.py clashed with
the image editing addon's tests and broke collection.
machine.work_area is a machine-space rect, so its center was wrong for
origins other than bottom-left. Use MachinePanel.work_area_center(),
like the image drop and layer column do.

Refs barebaric#529
Drop the Python orient_by_nesting in favour of raygeo's
Geometry.normalize_winding_orders(), and let the geometry module
return a Geometry instead of loose loops.

Refs barebaric#529
Barcode settings went through ChangePropertyCommand, a self-made
descriptor that sent updated, and a separate resize loop. The core
UpdateAssetCommand already updates a geometry provider asset, resizes
its workpieces and restores their matrices on undo, as the sketcher
does. Use it and make the settings plain attributes.

Refs barebaric#529
Use LengthSpinRow like the other length settings, so the values follow
the user's length unit instead of always showing mm. Drop the markup
escaping of a plain-text tooltip.

Refs barebaric#529
Addon icons live in the addon's resources/icons and are registered
from its frontend, as in the laser, CNC and automation addons.

Refs barebaric#529
Lets the type checker narrow to WorkPiece, so the asserts that only
served narrowing go away.

Refs barebaric#529
Module Size and Bar Height follow the chosen length unit, and Quiet
Zone can only be changed while Invert is on.

Refs barebaric#529
Add the Barcodes addon page to every translated docs directory.

Refs barebaric#529
pixi.lock taken from main and relocked with pixi lock, so the only
difference to main is segno.
barebaric#554 renamed the template variable to {counter} and the docs page to
features/job-counter. The content tooltip, the tests and the Barcodes
page in all languages follow.

Refs barebaric#529
After the merge with main it sat in the released 1.13.0-beta1 section.

Refs barebaric#529
Main's anchor modes ask every geometry provider for one; the fake from
the is_sketch_workpiece tests failed after the merge.

Refs barebaric#529
The properties panel creates its providers while the main window is
built. main_window_ready runs after that, so the Barcode group never
showed up in the app. Register on import, like the sketcher does.

Refs barebaric#529
pyflakes ignores noqa and flagged the side-effect import.

Refs barebaric#529
barebaric#554 adds get_template_sources() and variables_used() to the provider
protocol; with them the fake keeps passing pyright whichever PR lands
first.

Refs barebaric#529

This branch was previously deployed

1 inactive deployment
pypi — c4039760 Deployed Oct 21, 2026 by switch87 via Build and Publish Wheel #2432
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant