QR Code Colors and Contrast: The Thresholds That Break Scanning — featured illustration
Design

QR Code Colors and Contrast: The Thresholds That Break Scanning

6 min read
Create a QR code

A designer sends over a code in the brand palette: deep red modules on a black background. On the presentation slide it looks sharp and unmistakably on-brand. It has never scanned once, and enlarging it will not help.

The problem is not the red. It is that red and black are almost the same brightness.

Decoders discard color before they look at anything

The first real step in decoding is sorting every pixel into dark or light. Color information is thrown away at that point. What remains is lightness, and the only question that matters is whether the modules land cleanly on one side of the cutoff while the background lands on the other.

Human vision does not work this way. We read hue differences as strong contrast even when two colors are nearly identical in luminance. Red on black, navy on charcoal, yellow on white, mid-gray on almost anything: all of these look like contrast to a person and like mush to a threshold.

There is a five-second test that settles the argument. Convert the design to grayscale in any image editor. If you cannot tell the modules from the background in grayscale, no decoder can either, and no phone, lighting condition, or print size will rescue it.

Numbers are a starting point, not a specification

Various contrast guidelines circulate for QR codes. Treat every one of them as a rule of thumb rather than a threshold you can design right up against, because the real cutoff shifts with the camera, the ambient light, the ink, and the substrate.

The working target that holds up in practice: put the foreground firmly in the dark quarter of the lightness range, put the background firmly in the light quarter, and leave the middle empty. That is deliberately conservative, and it should be. Designing to the edge of any published minimum means the first cheap phone camera in a badly lit lobby will find that edge on your behalf. Our custom generator lets you set both colors directly, which makes checking the grayscale version a thirty-second step rather than a reprint.

Dark on light is the safe polarity

Codes are specified as dark modules on a light background, and that is what decoders expect. Inverted codes, light modules on a dark field, are read by many modern decoders, which will try the inverted interpretation after the normal one fails.

Many is not all. Older phones, embedded scanners, kiosk readers, and warehouse hardware are considerably less forgiving, and readers that do handle inversion often take longer to lock on because they attempt it second. For a screen, an app, or a poster you can reprint, an inverted code is a manageable risk. For fifty thousand printed cartons it is an expensive way to discover which readers your customers own. If you want to see restrained palettes that behave, our examples are all codes that scan.

Gradients fail at one end

A gradient across a code is not automatically fatal. Local thresholding tolerates gradual brightness changes, since each region is judged against its neighbors. The failure mode is a gradient that begins in a safe range and ends in an unsafe one: the light half scans, the dark half does not, and the symbol dies.

If you want a gradient, keep the entire range dark. A code running from near-black to a deep saturated blue is fine. A code running from black out to a pale tint is not, however good the starting point was. Gradients applied to the background are worse, because the modules hold constant while the ground slides underneath them, so the separation changes across the symbol and there is no single place to measure it.

The quiet zone is part of the color decision

The margin of light space around the symbol is not decoration. Finder-pattern detection depends on clean runs of light and dark, and a busy photograph or a mid-tone brand panel pressed against the edge of the code interferes with exactly that.

Placing a code on imagery works if the code sits on its own light panel with the margin intact. Placing a code directly on a photograph, even a bright one, hands the detector texture where it expects blank space. Tinting the quiet zone slightly is usually survivable. Filling it with pattern is not. There is more on placement in our design notes.

Print inks and CMYK undo what you approved on screen

Print introduces failure modes that do not exist on a monitor.

Metallic and foil. These reflect specularly. Under a phone's LED, a metallic dark module can flash brighter than the background at precisely the angle a person holds the phone. Silver on white is the classic version of the problem.

Fluorescent and neon. High chroma, unpredictable lightness, and behavior that changes with the light source. They frequently measure far lighter than they look.

Varnish, emboss, and texture. Anything catching light unevenly across the symbol makes local thresholding work harder, and on a small code it can visually bridge adjacent modules.

Uncoated and colored stock. The white is not white. Kraft paper, recycled board, and colored packaging raise the floor and compress the contrast you designed against a backlit screen.

Then there is the conversion itself. Screen contrast is emitted light and print contrast is reflected light, so print always has less of it to spend. A pure RGB black becomes some combination of process inks, and depending on the build it can land noticeably lighter or muddier than the swatch you approved. Bright RGB greens, blues, and oranges typically reproduce darker and duller, which occasionally helps and occasionally destroys the separation from a colored ground.

Dot gain adds one more effect. Ink spreads slightly, dark modules grow, light gaps shrink. On a large code nobody notices. On a small one it closes the gaps between modules and softens the edges the binarizer needs. Convert to the real output profile and look at the result before signing anything off. Our print guidance covers the resolution half of the same problem.

Test the way it will actually be used

A code that scans on the designer's current-model phone, held eight inches away, under studio lighting, has proven very little.

  • Test on a cheap or elderly phone as well as a good one. The gap between camera sensors is enormous and it is where marginal codes die.
  • Test in poor light: a restaurant at dinner, a lobby at night, a car at dusk.
  • Test at the final printed size, from the distance a real person would stand.
  • Test at an angle rather than square on.
  • Test the printed proof on the real stock, not the PDF on a monitor.
  • Test again after every color change, including the ones that seem trivial.

When a code fails those checks, the fix is almost always to widen the lightness gap rather than to enlarge the symbol. Size solves resolution problems. It does nothing for contrast, and scanning failures that survive a size increase are usually contrast failures wearing a disguise.

Share this article