qr-cli -- A docker based QR Code generator
Two ways to generate QR codes - pick whichever fits your flow:
1. CLI tool -- generate QR codes by piping flags or JSON straight into the included dockerised qr-cli app, get a JSON
payload back with a base64 image and dataUri. No dependencies (node etc) are required on the host.
2. AI agent skill (/qr) -- generate QR codes, using plain English, which describes all the properties, look and
feel that you want in the QR Code image.
# skill example
/qr https://browserleaks.com/geo rounded, 'dead blue eyes' on 'creamed butter', low error correction WebP 450px with a border and margin of 30px
The skill translates your description into the right flags and hands the image back inline.
Built on qr-code-styling with a headless NodeJS runtime, node-canvas, Cairo, and Sharp.
Customise dot shapes, corner styles, colours, gradients, embedded logos, error correction levels, and output format (PNG, JPEG, WebP, SVG, dataUri).
Input accepts --key=value flags, a --json='{...}' blob, or piped JSON via stdin - and all three can be combined and merged at invocation time.
Output is always a consistent JSON object:
{ "success": true, "meta": { ...format, dimensions, colours, timing... }, "image": { ...base64, dataUri, filename... } }
Errors use the same schema ("success": false) so jq pipelines never need to branch on output shape or config selection.
Runs as a non-root user in a multi-stage Debian image. Works as a Docker sidecar, local dev tool, or CI step.
Quick start
Option A -- Docker Hub (no clone needed):
# turn off annoying spam
export DOCKER_CLI_HINTS=false
docker pull rondomondo/qr-cli:latest
docker run --rm rondomondo/qr-cli:latest \
--data="https://example.com" \
--format=webp \
--border=10 \
--margin=20 \
--dotsOptions.type=extra-rounded \
--dotsOptions.color="#185FA5" \
--backgroundOptions.color="#E6F1FB" 2> /dev/null \
| jq -r '.image.base64' | base64 -d > qr.webp
file qr.webp
|
Option B -- clone, build, and run the full example suite:
git clone https://github.com/rondomondo/qr-cli.git && cd qr-cli
make build
make examples
make skill-examples
Makefile targets
| Target | Description |
|---|---|
make build |
Build the Docker image ($(DOCKER_REPO)/qr-cli:latest) |
make build-clean |
Build with --no-cache |
make usage |
Show the generator's --help output as pretty-printed JSON |
make shell |
Open an interactive bash shell inside the container |
make gen-examples |
Parse EXAMPLES.md and regenerate scripts/run_examples.sh |
make examples |
Regenerate scripts/run_examples.sh then run all examples |
make skill-examples |
Print the /qr skill equivalent of every example in EXAMPLES.md |
make skill-install |
Install the /qr skill into ~/.claude/skills/qr/ |
make clean |
Remove the Docker image and build artefacts |
Usage
Basic -- URL to PNG
docker run --rm rondomondo/qr-cli:latest --project="daveco" \
--data="https://example.com"
JSON result
{
"success": true,
"meta": {
"format": "png",
"mimeType": "image/png",
"width": 300,
"height": 300,
"type": "canvas",
"data": "https://example.com",
"project": "daveco",
"sizeBytes": 1539,
"durationMs": 147,
"generatedAt": "2026-05-02T20:17:50.448Z",
"errorCorrectionLevel": "Q",
"dotsType": "square",
"dotsColor": "#000000",
"backgroundColor": "#ffffff",
"hasImage": false,
"margin": 0,
"border": 0
},
"image": {
"filename": "assets/images/daveco/300x300_000000_FFFFFF_daveco.png",
"generated": "2026-05-02T20:17:50.448Z",
"base64": "iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51AAAABmJLR0...",
"dataUri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEs..."
}
}
Specify image format
docker run --rm rondomondo/qr-cli:latest \
--data="https://example.com" \
--format=svg
Supported formats: png (default), jpeg, webp, svg
JSON result
{
"success": true,
"meta": {
"format": "svg",
"mimeType": "image/svg+xml",
"width": 300,
"height": 300,
"type": "svg",
"data": "https://example.com",
"sizeBytes": 23837,
"durationMs": 143,
"generatedAt": "2026-05-02T20:20:22.495Z",
"errorCorrectionLevel": "Q",
"dotsType": "square",
"dotsColor": "#000000",
"backgroundColor": "#ffffff",
"hasImage": false,
"margin": 0,
"border": 0
},
"image": {
"filename": "qr.svg",
"generated": "2026-05-02T20:20:22.495Z",
"base64": "PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg0KPH...",
"dataUri": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBz..."
}
}
Full styling via flags
docker run --rm rondomondo/qr-cli:latest \
--data="https://example.com" \
--width=400 \
--height=400 \
--format=png \
--border=20 \
--margin=10 \
--dotsOptions.type=rounded \
--dotsOptions.color="#185FA5" \
--backgroundOptions.color="#E6F1FB" \
--cornersSquareOptions.type=extra-rounded \
--cornersSquareOptions.color="#185FA5" \
--qrOptions.errorCorrectionLevel=H
JSON result
{
"success": true,
"meta": {
"format": "svg",
"mimeType": "image/svg+xml",
"width": 400,
"height": 400,
"type": "svg",
"data": "https://example.com",
"sizeBytes": 33606,
"durationMs": 156,
"generatedAt": "2026-05-02T20:21:20.076Z",
"errorCorrectionLevel": "H",
"dotsType": "rounded",
"dotsColor": "#185FA5",
"backgroundColor": "#E6F1FB",
"hasImage": false,
"margin": 10,
"border": 20
},
"image": {
"filename": "qr.svg",
"generated": "2026-05-02T20:21:20.076Z",
"base64": "PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg0KPH...",
"dataUri": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBz..."
}
}
Pass a full JSON config
docker run --rm rondomondo/qr-cli:latest \
--json='{
"data": "https://example.com",
"width": 600,
"height": 600,
"margin": 20,
"format": "png",
"project": "daveco",
"border": 10,
"dotsOptions": {
"type": "extra-rounded",
"color": "#185FA5"
},
"backgroundOptions": {
"color": "#E6F1FB"
},
"cornersDotOptions": {
"type": "dot",
"color": "#185FA5"
},
"qrOptions": {
"errorCorrectionLevel": "H"
}
}'
JSON result
{
"success": true,
"meta": {
"format": "png",
"mimeType": "image/png",
"width": 600,
"height": 600,
"type": "canvas",
"data": "https://example.com",
"project": "daveco",
"sizeBytes": 38361,
"durationMs": 217,
"generatedAt": "2026-05-02T20:35:23.346Z",
"errorCorrectionLevel": "H",
"dotsType": "extra-rounded",
"dotsColor": "#185FA5",
"backgroundColor": "#E6F1FB",
"hasImage": false,
"margin": 20,
"border": 10
},
"image": {
"filename": "assets/images/daveco/600x600_185FA5_E6F1FB_daveco.png",
"generated": "2026-05-02T20:35:23.346Z",
"base64": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAYAAAC+ZpjcAAAABmJLR0...",
"dataUri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlgAAAJY..."
}
}```
</details>
### Pipe JSON via stdin
<details>
<summary>
```bash
echo '{
"data": "https://example.com",
"width": 300,
"format": "png"
}' | docker run --rm -i rondomondo/qr-cli:latest
JSON result
{
"success": true,
"meta": {
"format": "png",
"mimeType": "image/png",
"width": 300,
"height": 300,
"type": "canvas",
"data": "https://example.com",
"sizeBytes": 1539,
"durationMs": 152,
"generatedAt": "2026-05-02T20:40:14.125Z",
"errorCorrectionLevel": "Q",
"dotsType": "square",
"dotsColor": "#000000",
"backgroundColor": "#ffffff",
"hasImage": false,
"margin": 0,
"border": 0
},
"image": {
"filename": "qr.png",
"generated": "2026-05-02T20:40:14.125Z",
"base64": "iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51AAAABmJLR0...",
"dataUri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEs..."
}
}
Save the image to disk
docker run --rm rondomondo/qr-cli:latest --data="https://example.com" \
| jq -r '.image.base64' \
| base64 -d > qr.png
Examples
A few examples below to give you a taste. EXAMPLES.md has the full set covering every dot style, corner style, error correction level, and output format. Run them all in one go:
make examples
Full styling with logo (JSON blob)
docker run --rm rondomondo/qr-cli:latest \
--json='{
"data": "https://facebook.com",
"width": 600, "height": 600,
"format": "png", "border": 10, "margin": 20,
"image": "https://upload.wikimedia.org/wikipedia/commons/5/51/Facebook_f_logo_%282019%29.svg",
"imageOptions": { "crossOrigin": "anonymous", "margin": 10 },
"qrOptions": { "errorCorrectionLevel": "H" },
"dotsOptions": { "type": "extra-rounded", "color": "#185FA5" },
"backgroundOptions": { "color": "#E6F1FB" },
"cornersSquareOptions": { "type": "extra-rounded", "color": "#185FA5" },
"cornersDotOptions": { "type": "dot", "color": "#185FA5" }
}' \
| jq -r '.image.base64' | base64 -d > qr.png
Facebook logo, Sky haze palette
Dot styles (CLI flags)
docker run --rm rondomondo/qr-cli:latest \
--data="https://example.com" --format=png \
--border=10 --margin=10 \
--dotsOptions.type=extra-rounded \
--dotsOptions.color="#2B4D00" \
--backgroundOptions.color="#D4F299" \
| jq -r '.image.base64' | base64 -d > qr.png
extra-rounded
Corner styles (JSON blob)
docker run --rm rondomondo/qr-cli:latest \
--json='{"data":"https://example.com","width":400,"height":400,"format":"png",
"border":10,"margin":10,
"dotsOptions":{"color":"#064E3B","type":"rounded"},
"cornersSquareOptions":{"color":"#064E3B","type":"extra-rounded"},
"backgroundOptions":{"color":"#A7F3D0"}}' \
| jq -r '.image.base64' | base64 -d > qr.png
extra-rounded corners
See all skill equivalents for every example in EXAMPLES.md:
make skill-examples
/qr skill
If you use something like Claude Code, this repo ships a /qr skill
that lets you generate QR codes in plain English directly from the chat panel.
Setup
The skill files live at ./.claude/skills/qr. And make skill-install will copy them to the correct place.
Your CLI/Agent will pick them up automatically then. There is also a zipped version for simplicity in ./.claude/skills/qr.zip
Usage
/qr <url> [natural language options]
Colours, dot styles, sizes, and logos are all described in plain English:
/qr https://example.com
/qr https://example.com rounded royal blue on cream
/qr https://example.com extra-rounded midnight blue on ivory 500px
/qr https://example.com svg slate on white
/qr https://example.com extra-rounded #175EF0 on #E0E0E0 round corners dot corner dots high error correction 600px with logo https://example.com/logo.svg
What the skill does
- Parses your intent (colour names, style keywords, size, format, logo URL).
- Resolves ~30K English colour names to hex via
colourmapper. - Calls
scripts/qr-skill.sh, which wraps the Docker image. - Saves the image to
assets/images/{project}/{width}x{height}_{dots}_{bg}_{project}.{format}. - Reports a summary with a clickable link and a fenced
opencommand you can copy straight from the VS Code copy button:
open assets/images/default/600x600_175ef0_e0e0e0_default.png
Raw flags also pass straight through, so you can mix natural language and explicit options in the same command.
/qr skill examples
Three examples picked from make skill-examples to show the natural-language shorthand:
/qr https://example.com extra-rounded #2B4D00 on #D4F299
/qr https://example.com extra-rounded #2B4D00 on #D4F299
extra-rounded
/qr https://example.com classy rounded #042C53 on #B5D4F4
/qr https://example.com classy rounded #042C53 on #B5D4F4
classy-rounded
/qr https://example.com rounded #5C3A00 on #FDE68A round corners dot corner dots
/qr https://example.com rounded #5C3A00 on #FDE68A round corners dot corner dots
rounded corners dot-corners
Skill quick-reference
| What you say | What it does |
|---|---|
rounded, circles, classy, extra-rounded |
Sets dot shape |
round corners, dot corners, square corners |
Sets corner square style |
dot corner dots |
Sets corner dot style |
L, M, Q, H error correction |
Sets QR error correction level |
svg, jpg, webp, png |
Changes output format (default: png) |
400px or 600x400 |
Sets output dimensions |
with logo <url> |
Embeds a logo (bumps error correction to H automatically) |
| Any colour name or hex | Sets dot / background / corner colours |
See all skill equivalents for the examples
Tip:
make skill-examples
This prints a /qr skill command (and its natural-language shorthand) for every
example in EXAMPLES.md.
Helper scripts
| Script | Purpose |
|---|---|
scripts/extract_examples.py |
Parses EXAMPLES.md, extracts every bash fenced block, and writes run_examples.sh with [N/total] progress labels. Re-run via make gen-examples after editing EXAMPLES.md. |
scripts/extract_skill_examples.py |
Parses EXAMPLES.md and prints the equivalent /qr skill command for each Docker example, together with a natural-language shorthand. Run via make skill-examples. |
Output schema
{
"success": true,
"meta": {
"format": "png", // output format
"mimeType": "image/png",
"width": 300,
"height": 300,
"type": "canvas", // qr-code-styling render type
"data": "https://...", // the encoded string
"project": "daveco", // project name if supplied, else omitted
"sizeBytes": 12345, // raw image buffer size in bytes
"durationMs": 42, // time taken to generate in ms
"generatedAt": "2024-01-01T00:00:00Z", // UTC ISO 8601 timestamp
"errorCorrectionLevel": "Q",
"dotsType": "rounded",
"dotsColor": "#0255c7",
"backgroundColor": "#fdfbd4",
"hasImage": false,
"margin": 10,
"border": 20 // pixels added around the QR code
},
"image": {
"filename": "assets/images/daveco/300x300_0255C7_FDFBD4_daveco.png", // assets/images/{project}/{width}x{height}_{dots}_{bg}_{project}.{format})
"generated": "2024-01-01T00:00:00Z", // UTC ISO 8601 timestamp (same as meta.generatedAt)
"base64": "<base64 string>",
"dataUri": "data:image/png;base64,<base64 string>"
}
}
On error (written to both stdout and stderr so jq pipelines can catch it):
{ "success": false, "error": "Missing required option: \"data\"" }
Useful jq extractions
# Save to disk, decoding base64
docker run --rm rondomondo/qr-cli:latest --data="https://example.com" \
| jq -r '.image.base64' | base64 -d > qr.png
# One-liner: generate and save using the suggested filename (requires --project)
OUT=$(docker run --rm rondomondo/qr-cli:latest --data="https://example.com" --project=myapp --format=png)
mkdir -p $(dirname $(echo $OUT | jq -r '.image.filename'))
echo $OUT | jq -r '.image.base64' | base64 -d > $(echo $OUT | jq -r '.image.filename')
# Check success before using
if echo $OUT | jq -e '.success' > /dev/null; then
echo $OUT | jq -r '.image.base64' | base64 -d > qr.png
else
echo $OUT | jq -r '.error'
fi
# Print generation time
echo $OUT | jq '.meta.durationMs'
All supported options
These map 1:1 to the qr-code-styling API:
| Flag / JSON key | Type | Default | Description |
|---|---|---|---|
data |
string | required | The string/URL to encode |
width |
number | 300 | Canvas width in px |
height |
number | 300 | Canvas height in px |
format |
string | png |
Output format: png, jpeg, webp, svg |
margin |
number | 0 | Margin around the QR in px |
border |
number | 0 | Pixels added around the QR code |
project |
string | -- | Namespaces the suggested output filename as assets/images/{project}/{width}x{height}_{dots}_{bg}_{project}.{format} |
image |
string | -- | URL of logo to embed in the centre |
dotsOptions.type |
string | square |
rounded, dots, classy, classy-rounded, square, extra-rounded |
dotsOptions.color |
string | #000000 |
Dot colour |
backgroundOptions.color |
string | #ffffff |
Background colour |
cornersSquareOptions.type |
string | -- | dot, square, extra-rounded |
cornersSquareOptions.color |
string | -- | Corner square colour |
cornersDotOptions.type |
string | -- | dot, square |
cornersDotOptions.color |
string | -- | Corner dot colour |
qrOptions.errorCorrectionLevel |
string | Q |
L, M, Q, H |
imageOptions.margin |
number | 0 | Logo margin in px |
imageOptions.imageSize |
number | 0.4 | Logo size coefficient (0-1) |
imageOptions.hideBackgroundDots |
boolean | true | Hide dots behind logo |
imageOptions.crossOrigin |
string | -- | anonymous for cross-origin logos |
Gradient options (on dotsOptions, backgroundOptions, cornersSquareOptions, cornersDotOptions) must be supplied as JSON:
{
"dotsOptions": {
"gradient": {
"type": "linear",
"rotation": 0,
"colorStops": [
{ "offset": 0, "color": "#000000" },
{ "offset": 1, "color": "#0255c7" }
]
}
}
}
Release files for qr-cli 0.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| qr_cli-0.0.1.tar.gz | 21.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| qr_cli-0.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 37.8 kB
Release files / qr_cli-0.0.1.tar.gz
| Download URL | qr_cli-0.0.1.tar.gz |
|---|---|
| Size | 21.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
829b0e55449aa31302b16670923e79b9ec2a1e76093f24dadd196ab08f44dc6d
|
|
BLAKE2b-256 checksum How to use checksums |
f6e1b567afd709771208b577ff6d3c7076b2153d6b8f0423efabe5da35f46b23
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.2
|
Release files / qr_cli-0.0.1-py3-none-any.whl
| Download URL | qr_cli-0.0.1-py3-none-any.whl |
|---|---|
| Size | 16.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
57c2367a66c0bfe6524c53cd970c92a18d9bf85e2faa77157faba0a058216a7e
|
|
BLAKE2b-256 checksum How to use checksums |
4e0c2b25c8004d97886be3452f7aa2a4468e5d29b1e601a23852ab2c271382f8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.2
|