Workshop · floor model for Survey of Software 1.080.1
Six Python QR libraries all choose the same code, and every one reads back the same. So the interesting question isn't which encodes better — it's how far you can push the look before your phone stops reading it.
Scan the penguin. It points back at this page, so you can carry it to your phone and use the camera you actually own as the second opinion. The penguin is sitting on about a quarter of the code's width — drag the slider below and find out how much further it goes.
Plain language. Switch to Engineering for versions, byte counts and the measurements behind each claim.
The rule of this page: every figure below is measured on your machine while you wait, by the Python libraries themselves running in this tab. Where a number came from research instead, it says so in orange.
Press start to download CPython (WebAssembly). First time only, then cached.
Four separate libraries — written by different people, in different decades — encode whatever you typed above. Here is what each one produced. Look at them before reading on.
Encoder parity: qrcode, segno and qrcodegen
encode the same payload at the same error-correction level. Rendered side by side, then compared
module by module.
The code itself is fixed, so all the fun is in the drawing. Punch a hole through the middle and see how big you can get away with.
Centred occlusion sweep against error-correction level. Decoding verified live in-page; the reader's phone is the second instrument.
—
The surprise: most of the benefit arrives at Q. Going from M to Q buys you a lot of room; going on to H buys almost none — the code mostly just gets bigger.
But only if something is actually covering the code. Every number on this page measures how much can sit on top of a symbol. If nothing does — no logo, no penguin, just a plain code on a page — the trade runs the other way. Higher error correction is paid for in extra squares, and squares are what a camera runs out of first. Cover the code: pick Q. Leave it alone: pick M, and spend what you saved on printing it bigger.
THE CEILINGS GOVERN OCCLUSION AND NOTHING ELSE. They answer "how much can sit on top of this symbol." They do not answer "can a camera resolve this symbol," and for a clean code the two constraints pull in opposite directions: error correction buys damage tolerance by spending modules, and module count is the binding constraint on a distant, tilted or dim capture. Choosing Q for a symbol nothing occludes buys recovery that will never be used and pays for it in density.
From the field, not measured in this tab — this is not hypothetical. These figures were carried into a live tool with no logo on its code, Q was chosen citing them, and a Pixel read the page as text rather than finding a symbol. On that tool's payload — a whole trail packed into a URL, far longer than the one above — Q gave 125 modules across and M gave 105. Under a simulated camera — rendered at real display size, then downscaled, blurred, tilted and noised — Q at 150px failed below 400 sensor pixels while M at 340px read at 300. Right numbers, wrong question.
Measured on this payload with the penguin at this aspect and pad, as the widest occluder that still decodes — L 13.5%, M 18.5%, Q 28.0%, H 29.5% of symbol width (2.5%, 4.7%, 10.7%, 11.9% by area). Same units as the slider.
M→Q is the jump; Q→H is nearly flat. Both Q and H force version 4, so the extra ECC codewords are largely consumed by the larger symbol — with a centred square occluder the two are identical at 11% of area; with the penguin's shape and pad, H buys about 1.5 points of width over Q. Either way, the widely-repeated "30% of a QR code can be damaged" is codeword recovery capacity and not area you may paint over.
These ceilings are not a decoder artefact. Swept across all four zxing-cpp binarizers — LocalAverage, GlobalHistogram, FixedThreshold, BoolCast — the limits are identical, because covered modules are destroyed data rather than data that is merely hard to read. Confirmed on hardware: at every error-correction level, a Pixel gave up at the same cutoff this page did. That is the sharp contrast with colour, where the same phone read a bright tie-dye at EC=L that this page had called unreadable — colour failures are a statement about the scanner, occlusion failures are a statement about the code.
Same code, written out as a vector for a printing press. The file sizes are not close — but it depends which drawing method you ask for.
SVG byte counts, generated live. Three bars rather than two: the headline 16×
describes qrcode's default per-module emitter, and its SvgPathImage
factory closes most of that gap.
Not every barcode is a QR code. Same payload, other symbologies.
Pure-Python multi-symbology encoder: Data Matrix, PDF417, Aztec, Code128 and more, plus DXF output for engraving.
This one draws nothing at all. It hands you the grid and stops — which sounds useless until you need the identical encoder in Java, Rust and TypeScript too.
Matrix-only reference implementation, one source across Java/TS/Python/Rust/C++/C. 0.04 MB installed, zero dependencies, no renderer of any kind.
From research, not measured in this tab
zxing-cpp ships compiled binaries, so it cannot run in this page. Saying so beats simulating it, which would defeat the point of the whole workshop.
From the survey, measured on one machine (CPython 3.12.3, 1,000 iterations, matrix construction only): 0.189 ms per code — roughly 17× faster than any pure-Python option here. It is also the only library in the category that creates both Micro QR and rMQR, and the only one that reads codes as well as writing them. The survey has the workings.
Every other library on this page has somewhere it wins. This one doesn't, and that is the useful finding.
628,262 installs a month, and nothing shipped since June 2016. It is the slowest thing measured in the survey (10.264 ms per code), and segno does its entire job and more. If it is in your requirements file it arrived by inheritance rather than by choice — and swapping it for segno is close to a one-line change. Download counts in this category measure how dependency choices propagate through copied requirements files, not how often anyone chose.
Take everything you just worked out and hand it to whichever AI you use. This copies your settings, the limits you found by dragging, and working code for exactly this configuration.
Clipboard envelope — no vendor deep link, no API key, no dependency on anyone's roadmap. Paste into any assistant.
qrkadelic is a floor model for Survey of Software 1.080.1 — QR Code Generation Libraries, refreshed 2026-08-17. Libraries run under Pyodide (CPython compiled to WebAssembly) in this tab; nothing is sent anywhere. Measurements are from your machine except where marked orange.
Made by Ivan Schneider · Model Citizen Developer