Skip to main content

datamax-dpl

CI CodeQL License: MIT Open in Codespaces PyPI PyPI - Downloads Code Style: Ruff codecov security: bandit

datamax-dpl turns a label described in JSON into a print job in DPL, the Datamax Programming Language, and sends it to the printer. You describe text, lines, boxes, circles, polygons, barcodes (PDF417, MaxiCode and DataMatrix included) and images in millimetres; datamax-dpl writes the DPL records for the printer model you name.

Datamax models differ a lot. A Prodigy has no circles, an Allegro no metric formats, scalable fonts arrived on the DMX 600 with firmware 2.01. datamax-dpl knows the 18 models of the 1998 DPL manual and checks every label against the one you print on. Where a model lacks a feature it either applies a documented fallback and tells you (a circle becomes a downloaded bitmap) or, if you prefer, refuses the label.

It is a Python library and a command line tool. Every command can answer with a JSON envelope and meaningful exit codes, so scripts and LLM agents can drive it. With a camera configured, verify prints a label, photographs it and puts the photo next to the expected preview.

Status: no real printer or camera has been attached yet. Everything is built from the manual and tested against simulated printers. Treat the output as unverified on hardware until this notice goes away.

Install

Python 3.10 or newer. Run it without installing, with uv:

uvx datamax-dpl --help

or install it:

uv tool install datamax-dpl
# or
pip install datamax-dpl

datamax-dpl preview draws text as grey cells by default. With the preview extra (Pillow, Python 3.11 or newer) it writes the actual text into the picture:

uvx --from "datamax-dpl[preview]" datamax-dpl --help
# or
pip install "datamax-dpl[preview]"

More ways to install are in INSTALL.md.

Quick start

The examples/ folder holds a product label, a shipping label with placeholders, and data records for it.

Check a label against a model without printing:

datamax-dpl validate examples/product-label.json --model dmx-600
OK: model dmx-600, 1 label(s), 5 field(s), 149 bytes
INFO    check_digit_added [element 3]: the printer adds check digit 1
INFO    cutter_assumed: cut commands assume the printer's cutter is installed and enabled

Show the DPL it produces (control characters written as <STX>, <CR>):

datamax-dpl render examples/product-label.json --model dmx-600

Write the raw job to a file instead, or draw it as a PNG at the printer's resolution:

datamax-dpl render examples/product-label.json --model dmx-600 -o label.dpl
datamax-dpl preview examples/product-label.json --model dmx-600 -o label.png

Print it. Datamax network cards listen for raw jobs on port 9100:

datamax-dpl print examples/product-label.json --model dmx-600 --printer tcp://192.0.2.60:9100

Fill placeholders from data records, one label per record:

datamax-dpl render examples/shipping-label.json --data examples/shipping-records.json --model pe42

The same from Python:

from datamax_dpl import Barcode, Label, RenderOptions, Symbology, Text, render

label = Label(
    width=60,
    height=30,
    elements=[
        Text(x=3, y=20, text="ART. 4711", font=3),
        Barcode(x=3, y=3, symbology=Symbology.EAN13, data="400638133393", height=12),
    ],
)
result = render(label, RenderOptions(model="dmx-600"))
print(result.data)  # b'\x02L\rm\r131100002000030ART. 4711\r1F0012000300030400638133393\rQ0001\rE\r'
for finding in result.findings:
    print(finding.severity.value, finding.code, finding.message)

render raises LabelRejectedError when a finding is an error; build_job returns the same result without raising. For data records use render_batch(label, records, options), and to send bytes open a transport with open_printer(uri, timeout=10) and call send(data) on it. All of these are imported from datamax_dpl.

The label format

A label is a JSON document with job settings (unit, size, quantity, cutting, speeds, heat, media) and a list of elements:

{
  "unit": "mm",
  "width": 60,
  "height": 30,
  "elements": [
    {"type": "text", "x": 3, "y": 20, "text": "ART. 4711", "font": 3},
    {"type": "barcode", "x": 3, "y": 3, "symbology": "ean13", "data": "400638133393", "height": 12}
  ]
}

Element types are text, scalable_text, line, box, circle, polygon, barcode and image. Text and barcode data may contain {name} placeholders. Every field is described in docs/label-spec.md; datamax-dpl schema prints the JSON Schema.

Coordinates

Coordinates follow DPL, which is not how screens do it:

  • x is measured from the left edge of the label.
  • y is measured from the BOTTOM edge. A larger y is higher up.
  • An element is placed by its lower-left corner before rotation; a circle by its centre.
  • Lengths are millimetres unless the label sets "unit": "in" or "unit": "dots".

datamax-dpl preview draws the label with these rules, so you can check the placement before wasting labels.

Printer models and fallbacks

datamax-dpl models lists the profiles; datamax-dpl capabilities <model> shows one in full. Besides the 18 models there are generic (the default: only what every model can do) and permissive (no model checks). Tell datamax-dpl the firmware (--firmware 2.01) and installed options (--option datamatrix) where a feature depends on them.

The policy decides what happens when a label asks for something the model lacks:

  • --policy degrade (default) applies the documented fallback and reports a warning.
  • --policy strict turns the same finding into an error, and nothing is printed.

The model matrix, the limits and the full fallback table are in docs/capabilities.md.

Printer URIs

--printer (or [printer] uri in the configuration) says where the job goes:

URI Channel
tcp://HOST:PORT Raw socket; the port defaults to 9100. Can read answers.
serial:///dev/ttyS0?baud=9600&parity=N&bytesize=8&stopbits=1&rtscts=0&xonxoff=0 Serial port (serial://COM3?... on Windows); every parameter is optional. Can read answers.
device:///dev/usb/lp0 A device file, write only.
file:PATH or file:///abs/path Appends the job to a file.
- Writes the job to standard output.

status and detect need a channel that can read the printer's answer (tcp or serial). reset, cancel, pause, feed and cut send single printer commands.

JSON output for scripts and LLMs

Put --json (indented) or --json-bare (one line) before the command. The answer on stdout is an envelope:

datamax-dpl --json validate examples/product-label.json --model allegro --policy strict
{
  "ok": false,
  "command": "validate",
  "data": {
    "model": "allegro",
    "dpl_unit": "inch",
    "records": 1,
    "fields": 5,
    "bytes": 1568,
    "downloads": ["DPLR0001"],
    "findings": [
      {"code": "circle_rasterized", "severity": "error", "message": "circle cannot be drawn natively: circles: Allegro does not have it", "element": 4, "fallback": "drawn as downloaded image DPLR0001 (81x81 dots)", "record": null}
    ]
  },
  "skipped": []
}

(Shortened: the real answer also lists the info findings and a few empty fields.) When the command cannot run at all, the envelope carries error (the exception type) and message instead of data.

Exit code Meaning
0 Done.
1 Refused: at least one finding is an error. Nothing was printed or written.
2 Could not run: unreadable or invalid label, unknown model, bad configuration, printer or camera not reachable.

Finding codes are stable, so a script can react to circle_rasterized without parsing the message.

Camera verification

The [camera] configuration section names a camera; see CONFIG.md. Four kinds exist: none (default), command (run a capture program such as fswebcam), http (fetch a snapshot URL) and file (take the newest image a camera drops into a folder).

datamax-dpl capture --output-dir photos
datamax-dpl verify examples/product-label.json --model dmx-600 --printer tcp://192.0.2.60:9100 --output-dir photos

verify sends the job, polls the printer status until it is idle (on a one-way channel it waits five seconds instead), waits settle_seconds, takes one photo, and writes expected-<time>.png next to it. It does not judge the photo; a person, or an LLM given both pictures, compares them. This loop has only run against a simulated printer and camera so far.

Claude Code skill

The repository is also a Claude Code plugin with a skill that teaches an agent to use datamax-dpl. Inside Claude Code:

/plugin marketplace add bitranox/datamax-dpl
/plugin install datamax-dpl

Status and limits

  • Built from the Datamax DPL Programmer's Manual 88-2051-01 Rev D2 (1998) only. Models and commands that came later, QR codes among them, are not supported.
  • Nothing has been checked on a real printer or camera yet.
  • The manual contradicts itself in places; docs/dpl-reference.md lists each case and the reading taken.
  • The manual is copyrighted and not included or redistributed here. Get it from the vendor.

Configuration

Defaults for the printer (model, firmware, URI, policy, timeout, cutter, options) and the camera live in a layered configuration: bundled defaults, system, host and user files, .env, environment variables and --set. CONFIG.md explains every key.

Development

DEVELOPMENT.md covers the make targets and the test setup, CONTRIBUTING.md the workflow, docs/systemdesign/module_reference.md the module layout, and CHANGELOG.md the releases. How AI tools were used is described in ai-transparency.md.

License

MIT, see LICENSE.

Metadata

Release files for datamax-dpl 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for datamax-dpl 0.1.1
File Size Uploaded Provenance
datamax_dpl-0.1.1.tar.gz 289.4 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for datamax-dpl 0.1.1
File Interpreter ABI Platform
datamax_dpl-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 490.3 kB

Release files / datamax_dpl-0.1.1.tar.gz

Download URL datamax_dpl-0.1.1.tar.gz
Size 289.4 kB
Tags Source
SHA-256 checksum
How to use checksums
5ea44181363cc1c1ec1d5d32b04861424222d525f2671d77bd1713095fba1061
BLAKE2b-256 checksum
How to use checksums
b4afed2c84dc99ade7b7a133a529f6ac185c32e3f697a9a1cb81a2040fd0b23f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / datamax_dpl-0.1.1-py3-none-any.whl

Download URL datamax_dpl-0.1.1-py3-none-any.whl
Size 200.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6ad726090287550dd171a33c27530476a01b6e04041258d13e1fe3e0a995a272
BLAKE2b-256 checksum
How to use checksums
c5225bc04f8883d11368ab92731bde5ffc1ee4d8ed9028bf16e1bbdc5212dda4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Security for datamax-dpl 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for datamax_dpl-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page