CLI tool
x-hw/amazing-qr avatar
x-hw/amazing-qr

amazing-qr: a QR generator where -n overwrites silently and the charset is ASCII

Amazing QR code generator, supporting animated GIF QR codes.

10,860 stars1,576 forksPythonGPL-3.0

At a glance

What is it?
amazing-qr ships as the amzqr package: one Pillow dependency, a small CLI, a callable run() for scripts, and animated GIF output. The interesting parts for an evaluator are the defaults (error correction starts at H), the overwrite behavior of -n, and a supported character list that stops at ASCII punctuation.
Who is it for?
Use it when you need a QR code with a picture in it or a multi-frame GIF and you want to stay inside Pillow. Check two things before you rely on it: whether your payload is inside the supported character list, which stops at ASCII punctuation and does not include CJK text, and whether any script around you writes to the output path with -n, which deletes an existing file of the same name without warning.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 59 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • x-hw/amazing-qr10,860 ★ · +39
Star history
Repository2026-09-212026-11-14
x-hw/amazing-qr10.8k10.9k

39 Stars in the last 54 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The CLI starts you at error correction H and a size it picks for you

The whole interface fits on a screen:

sh
# summary
amzqr Words
      [-v {1,2,3,...,40}]
      [-l {L,M,Q,H}]
      [-n output-filename]
      [-d output-directory]
      [-p picture_file]
      [-c]
      [-con contrast]
      [-bri brightness]
      [-V]

Three defaults are worth internalizing because they are not the ones a newcomer expects. The default error correction level is H, the highest of L, M, Q and H, which means the generated symbol carries more redundancy than a typical QR code and therefore renders as a denser grid of modules for the same payload. The default size is not a fixed pixel count: it depends both on how many words you pass in and on the level you picked, so two different payloads produce two different image sizes with no flag changed. The default output name is qrcode.png in the current directory. -v takes the version as an integer from 1 to 40 and -l takes one of L, M, Q or H, and those two are the only knobs that shape the symbol itself. If you need a specific pixel dimension for print, do not assume the default will hit it: choose the version explicitly and scale afterwards.

-n deletes an existing file of the same name with no confirmation

The output naming flags are simple and they carry one sharp edge. -n sets the filename and -d sets the directory, and the accepted filename formats are .jpg, .png, .bmp and .gif. The stated behavior when the name matches an existing file is blunt: the old one will be deleted. There is no prompt, no --force flag, no backup, and no way to make it refuse. For a single manual run that is a convenience, since regenerating a QR code over yesterday's file is the common case. For anything automated it is a hazard, because the same command that writes your QR code will happily replace a real asset if a path variable is ever built from user input or a stale config. Two details compound it. First, the extension is part of the name you supply, so amzqr https://github.com -n github_qr.jpg writes a JPEG while the same call with no -n writes PNG, and a mismatch between the extension you pass and the format you expect gives you a file that is fine on disk and wrong everywhere else. Second, the animated path has an extra rule: when you customize the name with -n for a GIF input, the output name must end in .gif. Name it anything else and the format expectation and the filename disagree. If a build script writes these files, generate into a scratch directory and move the result yourself.

Pillow is the only runtime dependency and it is capped below 12

The packaging metadata is short enough to read in one sitting, and one dependency carries the whole tool: Pillow>=8.0.0,<12. The interpreter requirement is requires-python = ">=3.8" in pyproject.toml, while the README states the environment as Python 3, and the project classifiers cover MacOS, POSIX Linux and Microsoft Windows. That combination makes this a plausible choice inside a service that already depends on an older Pillow, and also the thing to check first if your install fails: the upper bound is not a suggestion, and a machine whose other packages have already moved Pillow past 12 will not resolve this dependency. There is no qrcode library underneath and no image pipeline beyond Pillow, which is also why there is no scanner, no SVG output and no structured data generation here. The build backend is setuptools with setuptools>=61 required, the project name is amzqr, the version is declared dynamic and pulled from the amzqr.__version__.__version__ attribute at build time, and the console script is bound to amzqr.terminal:main. So the executable name on your PATH is amzqr, not amazing-qr, which matters if you script it.

The supported character list ends at ASCII punctuation, with no CJK

The generator publishes exactly what it can encode, and the list is worth reading before you choose a payload. Numbers cover 0 through 9, letters cover a through z and A through Z, and the punctuation set is a fixed enumeration: the middle dot, then , . : ; + - * / \ ~ ! @ # $ % ^ & ` ' = < > [ ] ( ) ? _ { } | and the space character. Every entry is ASCII apart from that middle dot. Nothing in the project mentions UTF-8, code pages, or multi-byte text, and the repository carries a Chinese README, which makes the omission easy to miss. The practical consequence: a URL containing an internationalized domain or a percent-encoded query with non-ASCII characters sits outside the documented set, and a payload in Chinese, Japanese or Korean is not something this documentation claims to support. Since QR codes fail silently in the worst way, a scanner that cannot decode a symbol tells you nothing about which half broke, you have to compare against a plain reference encoding to find out. If your content is non-Latin, generate a short URL that resolves to the real destination and encode that instead of putting the raw text in.

-p composites with a picture, and transparent areas come out ugly

The artistic mode takes a background image through -p:

markdown
#1 -p
amzqr https://github.com -p github.jpg

By default the result is black and white; adding -c switches it to colorized, and -con and -bri adjust the image, both defaulting to 1.0 with higher numbers meaning more contrast and more brightness. Three tips are given. Use a nearly square picture rather than a rectangle. If the picture is large, choose a correspondingly large -v instead of leaving the version at its default. And if part of the picture is transparent, the code looks wrong, with the fix being to change the transparent layer to white. Composite, then scan the result with a phone before you print or publish it.

Animated GIF mode is the same code path with one extension rule

The animated mode changes almost nothing, and that is its most confusing property for newcomers. The only difference from artistic mode is that the image you pass in is a .gif file instead of a still image; you still get a black-and-white or colorized result, and -c, -con and -bri behave the same way. Everything else carries over, including -v for version sizing and -d for the output directory. The one hard requirement is the one mentioned above: if you set the filename with -n, that name has to end in .gif. The example/ directory shows what the output looks like in practice, with GIF results named alipay.gif, c_qrcode.gif, daftpunktocat-guy_qrcode.gif and zootopia_qrcode.gif alongside still images such as github_qrcode1.jpg and wechatpay.jpg. A useful sanity check before shipping: frame count and total file size are your responsibility, not the library's, since the tool has no flag for frame rate or dimensions and the README does not discuss them.

The repo root carries both amzqr.py and an amzqr/ package

The file layout explains a few upgrade surprises. At the root you find amzqr.py sitting next to an amzqr/ directory, so the import name and a module filename coexist, and the setuptools configuration packages amzqr and amzqr.mylibs, meaning helper code lives in a subpackage rather than in the top-level script. The version string is read from amzqr.__version__.__version__ at build time, so a dynamic version in pyproject.toml is the reason the package has no hardcoded number to grep for. Around that sit the working files: tests/ with testpaths pointed at it, benchmarks/ plus pytest-benchmark in the dev dependency group if you want to time your own payloads, uv.lock for reproducible resolution, and a CHANGELOG.md. The linter is ruff with target-version py38, a line length of 100, and a deliberately narrow rule set of F, E9 and I, which is the fast correctness subset rather than a style opinion. There is also a README-cn.md, so Chinese-language documentation is maintained alongside the English one. With no GitHub releases published, the version history lives in that changelog and in package metadata, and the last commit on the default branch is dated 2026-09-17.

Agent use runs through a separate skill repo or a separate MCP server

The project extends itself outward in two ways, both of which live in other repositories. One is an agent skill published from x-hw/skills, installed into your agent with:

sh
npx skills add x-hw/skills --skill generate-amazing-qr-code

That skill teaches an agent how to drive the amzqr CLI. The other is an MCP server in x-hw/amzqr-mcp for MCP-compatible agents. Once either is in place, the documented behavior is that you just ask the agent for a QR code and it picks up the skill or the server automatically. For scripting, the library route is more predictable than either:

python
from amzqr import amzqr

version, level, qr_name = amzqr.run(
    words,
    version=1,
    level="H",
    picture=None,
    colorized=False,
    contrast=1.0,
    brightness=1.0,
    save_name=None,
    save_dir=os.getcwd(),
)

The parameters mirror the flags one for one, and the call returns the version, the level and the generated name, which is enough to build a manifest of what you produced. Two things to keep in mind: GPLv3 applies to the package and to code derived from it, and the pyproject metadata goes out of its way to declare the license as text and to suppress setuptools injecting a License-File field, which requires a newer metadata version than the 2.1 the build targets. Vendored copies inside a proprietary product deserve a licensing review.

Editorial conclusion

Use it when you need a QR code with a picture in it or a multi-frame GIF and you want to stay inside Pillow. Check two things before you rely on it: whether your payload is inside the supported character list, which stops at ASCII punctuation and does not include CJK text, and whether any script around you writes to the output path with -n, which deletes an existing file of the same name without warning.

Frequently asked questions

How do I install amazing-qr and what does it depend on?

Install the amzqr package with pip install amzqr. Its only runtime dependency is Pillow>=8.0.0,<12, it requires Python 3.8 or newer, and the project classifiers cover MacOS, Linux and Windows.

What happens if the output filename of amazing-qr already exists?

The existing file is deleted and replaced, with no prompt and no backup flag. The filename extension you pass to -n is what gets written, one of .jpg, .png, .bmp or .gif, and for animated input the custom name has to end in .gif.

Can amazing-qr encode Chinese text or non-ASCII characters?

The documented supported characters are digits, Latin letters and a fixed set of common punctuation ending at the space character, with no mention of multi-byte text. Encode a short ASCII URL that redirects to the real destination rather than putting internationalized text into the payload.

Official sources

  1. Issues
  2. License: GPL-3.0
  3. README
  4. x-hw/amazing-qr on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/x-hw-amazing-qr.svg)](https://hysenlabs.com/projects/x-hw-amazing-qr)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/x-hw-amazing-qr.svg)](https://hysenlabs.com/projects/x-hw-amazing-qr)

Was this useful?