Styled QR code generator backed by qr-code-styling (Docker or Node.js)
Project description
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" }
]
}
}
}
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file qr_cli-0.0.1.tar.gz.
File metadata
- Download URL: qr_cli-0.0.1.tar.gz
- Upload date:
- Size: 21.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
829b0e55449aa31302b16670923e79b9ec2a1e76093f24dadd196ab08f44dc6d
|
|
| MD5 |
3023d027fa75b81ab81740cc10ee7d5e
|
|
| BLAKE2b-256 |
f6e1b567afd709771208b577ff6d3c7076b2153d6b8f0423efabe5da35f46b23
|
File details
Details for the file qr_cli-0.0.1-py3-none-any.whl.
File metadata
- Download URL: qr_cli-0.0.1-py3-none-any.whl
- Upload date:
- Size: 16.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
57c2367a66c0bfe6524c53cd970c92a18d9bf85e2faa77157faba0a058216a7e
|
|
| MD5 |
40a3f22ef8965696ae66cdafdfc0a231
|
|
| BLAKE2b-256 |
4e0c2b25c8004d97886be3452f7aa2a4468e5d29b1e601a23852ab2c271382f8
|