python-qrcode: a pure Python QR generator with PIL, SVG and PNG backends
Python QR Code image generator
At a glance
- What is it?
- python-qrcode renders QR codes from Python or the shell, with optional Pillow styling, SVG factories and a pypng fallback. It is a small library with a stable interface, and the styling layer is explicitly not guaranteed to scan everywhere.
- Who is it for?
- Adopt python-qrcode if you need QR generation inside a Python process, want SVG or console output without a native dependency, and are content with the documented factory and drawer options. Do not adopt it if you need QR decoding (the README describes generation only) or if you require a guaranteed-scannable styled code, since the project itself says styled codes are not guaranteed to work with all readers.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months 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 October 3, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What python-qrcode does and who reaches for it
The project generates QR code images from Python. Its README opens with the plain statement that it is a pure Python QR Code generator, and the pyproject.toml describes the package as a QR Code image generator with the keywords qr, denso-wave and IEC18004. That scope matters: this is an encoder, not a reader, so the common search phrase python qrcode reader does not describe anything this library does. If you need to decode, you are looking at the wrong package.
The audience is developers who already have Python in the pipeline and need a code rendered as a file, a string, or terminal output. Because the default install has no compiled extension, it fits build scripts, CI jobs and server-side endpoints where adding a native image library is unwanted. The package requires Python 3.10 or newer, and the classifiers list 3.10 through 3.14, so it tracks current interpreter releases rather than pinning to an old baseline. The console entry point is named qr, which means the same install gives you both an importable module and a shell command.
How the encoder, factories and drawers fit together
The design separates three concerns. First, the QRCode object builds the matrix: version (1 to 40, where version 1 is a 21x21 matrix), error_correction, box_size and border are set at construction, then add_data() and make(fit=True) produce the symbol. Second, an image factory turns that matrix into bytes. Third, optional module drawers and color masks change how each module is painted.
That layering is why the same data can come out as PNG, SVG or console text. The README states that a standard install uses pypng for PNG, and that if Pillow is not installed the default image factory falls back to the pure Python PNG encoder. The SVG side has several factories with different trade-offs: SvgImage emits a set of rects, SvgPathImage combines everything into a path and is described as the recommended default for the script, and SvgFragmentImage omits the standalone header so the output can be embedded. Two further factories, SvgFillImage and SvgPathFillImage, behave the same but fill the background white. The make_image() method forwards extra keyword arguments to ElementTree, which is how the README attaches a CSS class to the root element.
The error_correction constants are the part worth reading twice. ERROR_CORRECT_L corrects about 7 percent or less, M is the default at about 15 percent, Q about 25 percent, and H about 30 percent. Higher levels cost capacity, so the choice is a real trade-off rather than a quality setting.
Installing python-qrcode and generating a first code
A standard install pulls in pypng for PNG output. The README gives the command directly:
pip install qrcodeAfter that, the qr script is on your PATH. The README's first command-line example redirects stdout into a file, so what you get back is a PNG written by the shell rather than by the library:
qr "Some text" > test.pngFor the Python path, the make shortcut is the shortest route from a string to an image. The README notes that the returned object is a qrcode.image.pil.PilImage when Pillow is present, and that you call save() on it:
import qrcode
img = qrcode.make('Some data here')
type(img) # qrcode.image.pil.PilImage
img.save("some_file.png")If you want more control over size and error correction, the QRCode class is the documented alternative. Note that fit=True is what lets version=None pick the smallest symbol that holds the data:
import qrcode
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=10,
border=4,
)
qr.add_data('Some data')
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")For image functionality beyond the pure Python encoder, the README points at the extra that installs Pillow:
pip install "qrcode[pil]"SVG output uses the same shortcut with an image_factory. The README shows three command-line variants, and the path factory is the recommended one:
qr --factory=svg-path "Some text" > test.svgStyled codes and the scanner compatibility caveat
StyledPilImage and the SVG factories accept a module_drawer to change module shape, plus a size_ratio argument that produces gapped squares or circles when set below the default of Decimal(1). StyledPilImage additionally takes a color_mask and an embedded_image_path for a logo in the center. The README's worked example combines a rounded-corner drawer, a radial gradient mask and an embedded image, built on a QRCode with ERROR_CORRECT_H.
The README is unusually direct about the risk here: these QR codes are not guaranteed to work with all readers, and it advises experimentation and a high error correction level, especially when embedding an image. That is the honest framing, and it is also the main limitation of the styled path. If your use case requires a code that scans on any phone in any lighting, the plain black-on-white output from make() is the safer choice, and the styling features are a presentation layer you should validate against your actual scanners. The README also notes styled images require version 7.2 or later, and SVG styled images require 7.4, so older pinned installs will not have them.
The other boundary is decoding. Nothing in the README, pyproject.toml or repository layout describes a reader, so a search for python qrcode reader maps to other tools. Treat this package as write-only.
python-qrcode compared with segno
The comparison people search for is python-qrcode versus segno, and the difference is architectural rather than cosmetic. python-qrcode routes output through image factories, and its default PNG path depends on pypng unless Pillow is installed; the styling layer is a separate set of drawers and masks layered on top of the matrix. segno is a separate project with its own design decisions, and the README and repository files here contain nothing about its internals, so any claim about how it renders or what it depends on would be invented. What can be said from the facts here is narrower: python-qrcode's own documentation is the source for its factory model, its error_correction constants and its styled-image caveat, and a reader weighing the two should compare those specific mechanisms against segno's documentation rather than against marketing summaries.
Within python-qrcode itself, there is a real internal choice worth naming. The pure Python PNG factory (qrcode.image.pure.PyPNGImage) avoids Pillow entirely, which is useful in constrained environments, but it is the fallback rather than the styled path. If you need color masks or embedded images, you need the pil extra and Pillow 9.1.0 or newer.
Maintenance, licence and upgrade cost
The repository is not archived, and the last push was on 2026-03-25. The pyproject.toml declares version 8.2, a Development Status of Production/Stable, and a requires-python of >=3.10. The runtime dependency list is short: colorama on Windows only, and deprecation. Optional extras are pil (pillow >=9.1.0), png (pypng) and all, which combines both. That small dependency surface is the main upgrade-cost argument in its favour.
Development tooling is pinned through a justfile that drives uv across Python 3.10 to 3.14 and three variants (pil, png, none), plus coverage. The dev group also lists pytest, ruff and zest-releaser. For an adopter, that means the maintainers test the same optional-dependency combinations you are likely to install, which reduces the chance that the png-only path silently breaks.
The licence field in pyproject.toml says BSD-3-Clause, while the repository metadata reports NOASSERTION because the LICENSE file was not matched to a known identifier. The file LICENSE is present at the top level, so the authoritative text is there. This is a note about metadata, not legal advice; if licence terms matter to your organisation, read the LICENSE file itself.
Editorial conclusion
Adopt python-qrcode if you need QR generation inside a Python process, want SVG or console output without a native dependency, and are content with the documented factory and drawer options. Do not adopt it if you need QR decoding (the README describes generation only) or if you require a guaranteed-scannable styled code, since the project itself says styled codes are not guaranteed to work with all readers. Before shipping, verify the error_correction level your payload needs, whether Pillow is actually installed in your target environment, and whether your scanner accepts the module_drawer or color_mask you chose.
Frequently asked questions
How do I install python-qrcode?
The README gives a standard install as pip install qrcode, which uses pypng for PNG output. For image functionality that needs Pillow, it gives pip install "qrcode[pil]".
How do I import QR code generation into Python?
Import the qrcode module, then call the make shortcut with your data: qrcode.make('Some data here'). The README notes the returned object is a qrcode.image.pil.PilImage when Pillow is available, and that you save it with img.save().
How does python-qrcode compare with segno?
The README documents python-qrcode's own model: an image factory turns the matrix into PNG, SVG or console output, with optional module drawers and color masks. It contains no information about segno's internals, so a mechanism-level comparison would need segno's own documentation.
Official sources
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.
[](https://hysenlabs.com/projects/lincolnloop-python-qrcode)