Metadata-Version: 2.4
Name: qrcody
Version: 1.11.3
Summary: Standalone Python port of the qrcody SVG QR rendering engine (styled pixels/eyes/frames)
Author: Matt Troutman
Author-email: Matt Troutman <git@trtmn.com>
License-Expression: MIT
License-File: LICENSE
Requires-Dist: segno>=1.6
Requires-Dist: cairosvg>=2.7 ; extra == 'png'
Requires-Python: >=3.11
Provides-Extra: png
Description-Content-Type: text/markdown

# qrcody

Standalone Python port of [qrcody](https://qrcody.trtmn.io)'s styled QR code SVG
rendering engine — square/rounded/dots/blob/bars/squircle pixel styles, styled
finder eyes and pupils, gradients, and framed export (perimeter / scan-me /
scan bands). No browser, no server — pure functions in, SVG string out.

This is a hand-port of `src/lib/buildSVG.js` from the qrcody web app. The
rendering logic itself has no DOM dependency in the original (it already runs
inside a Cloudflare Worker), so the two implementations produce visually
equivalent output, though exact numeric string formatting may differ slightly
(e.g. `500` vs `500.0`) — SVG renderers treat these identically.

## Install

```bash
uv add qrcody
# or, for PNG export too:
uv add "qrcody[png]"
```

PNG export uses [cairosvg](https://cairosvg.org/), which needs the native
Cairo library installed on the system (`brew install cairo` on macOS,
`apt install libcairo2` on Debian/Ubuntu).

## Library usage

```python
from qrcody import DEFAULT, build_svg, build_framed_svg

settings = {
    **DEFAULT,
    "text": "https://example.com",
    "pixels_style": "dots",
    "eyes_style": "circle",
    "frame": "scan-me",
    "frame_text": "Scan me",
}

qr_svg = build_svg(settings)
framed = build_framed_svg(qr_svg, settings)
svg_string = framed["svg"]  # framed["w"] / framed["h"] give the output dimensions
```

For PNG (requires the `png` extra):

```python
from qrcody.png import svg_to_png

png_bytes = svg_to_png(svg_string, width=1000)
```

## CLI

```bash
qrcody --url "https://example.com" --pixels squircle --frame perimeter -o qr.svg
qrcody --url "https://example.com" --pixels dots --eyes circle -o qr.png
```

Run `qrcody --help` for the full flag list — it mirrors the qrcody `/api/qr`
HTTP API parameters (see the qrcody repo's `functions/api/qr.js` and
`public/openapi.yaml`).

## Settings dict

All keys from `qrcody.DEFAULT` (see `defaults.py`) are recognized;
unspecified keys fall back to their default. Notable ones:

| Key | Values |
|---|---|
| `pixels_style` | `square` / `rounded` / `dots` / `blob` / `bars-h` / `bars-v` / `squircle` |
| `eyes_style` | `square` / `rounded` / `circle` / `leaf` / `squircle` |
| `pupils_style` | `square` / `rounded` / `circle` / `squircle` |
| `corners_style` | `none` / `round` / `extra-round` / `squircle` |
| `frame` | `none` / `perimeter` / `scan-me` / `scan` |
| `correction_level` | `L` / `M` / `Q` / `H` |

## Development

```bash
uv sync --extra png
uv run pytest
uv run ruff check .
```

## Known gaps vs. the JS implementation

- **Logo embedding** (`logo` / `logo_scale` settings) is supported in
  `build_svg` the same way as the JS version — pass a data URI as `logo`.
  There is no server-side "fetch a logo URL" helper here (that lives in the
  qrcody Cloudflare Worker's SSRF-hardened fetch, which is deployment-specific
  and out of scope for this package).
- No automated JS/Python golden-file parity test yet — the port was done by
  hand against `src/lib/buildSVG.js` and verified with a matching unit test
  suite, but the two aren't diffed against each other in CI. If the JS
  renderer changes, this package needs a manual re-sync.

## Note on the package name

This package is published as `qrcody` on PyPI, distinct from the `qrcody`
npm/web app it's ported from — there's no npm/PyPI namespace collision since
they're different registries.
