Skip to main content

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

  1. Parses your intent (colour names, style keywords, size, format, logo URL).
  2. Resolves ~30K English colour names to hex via colourmapper.
  3. Calls scripts/qr-skill.sh, which wraps the Docker image.
  4. Saves the image to assets/images/{project}/{width}x{height}_{dots}_{bg}_{project}.{format}.
  5. Reports a summary with a clickable link and a fenced open command 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


extra-rounded

/qr https://example.com classy rounded #042C53 on #B5D4F4


classy-rounded

/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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qr_cli-0.0.1.tar.gz (21.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qr_cli-0.0.1-py3-none-any.whl (16.1 kB view details)

Uploaded Python 3

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

Hashes for qr_cli-0.0.1.tar.gz
Algorithm Hash digest
SHA256 829b0e55449aa31302b16670923e79b9ec2a1e76093f24dadd196ab08f44dc6d
MD5 3023d027fa75b81ab81740cc10ee7d5e
BLAKE2b-256 f6e1b567afd709771208b577ff6d3c7076b2153d6b8f0423efabe5da35f46b23

See more details on using hashes here.

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

Hashes for qr_cli-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 57c2367a66c0bfe6524c53cd970c92a18d9bf85e2faa77157faba0a058216a7e
MD5 40a3f22ef8965696ae66cdafdfc0a231
BLAKE2b-256 4e0c2b25c8004d97886be3452f7aa2a4468e5d29b1e601a23852ab2c271382f8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page