# QR mask pattern reference: formulas, penalties, format bits

> Eight mask patterns, numbered 0 to 7, decide which data modules are inverted; mask 0 inverts where (row + column) mod 2 equals 0. The encoder draws all eight, scores each against penalty rules N1–N4 with weights 3, 3, 40 and 10, and keeps the mask with the lowest total.

Source: https://useqr.app/docs/reference/mask-pattern-reference · Last reviewed 2026-08-21 · UseQR is free forever, no signup.

---

## The eight mask formulas

A [mask](/glossary/mask-pattern) inverts every data module where its condition is true.
`i` is the row and `j` the column, both counted from 0 at the top-left. Function patterns
(finders, timing, alignment, format info) are never masked.

| Mask | Condition (invert where true) | Visual effect |
|---|---|---|
| 0 | `(i + j) mod 2 == 0` | Checkerboard |
| 1 | `i mod 2 == 0` | Horizontal stripes, every other row |
| 2 | `j mod 3 == 0` | Vertical stripes, every third column |
| 3 | `(i + j) mod 3 == 0` | Diagonal stripes |
| 4 | `(⌊i/2⌋ + ⌊j/3⌋) mod 2 == 0` | Coarse checkerboard of 2 × 3 blocks |
| 5 | `(i × j) mod 2 + (i × j) mod 3 == 0` | Grid of crossing lines |
| 6 | `((i × j) mod 2 + (i × j) mod 3) mod 2 == 0` | Thickened lattice |
| 7 | `((i + j) mod 2 + (i × j) mod 3) mod 2 == 0` | Alternating diagonal blocks |

These are exact: verified against the working encoder behind UseQR, and part of
[how every QR code is generated](/docs/spec/how-qr-codes-are-generated).

## The penalty rules

The encoder renders the symbol eight times, scores each candidate, and keeps the lowest
[penalty score](/glossary/penalty-score).

| Rule | Detects | Penalty |
|---|---|---|
| N1 | A run of ≥ 5 same-colour modules in a row or column | **3** + (run length − 5) per run |
| N2 | Each 2 × 2 block of one colour (overlapping blocks all count) | **3** per block |
| N3 | The finder-like ratio 1:1:3:1:1 (dark-light-dark-dark-dark-light-dark) with 4 light modules on one side | **40** per occurrence |
| N4 | Overall darkness away from 50% | **10** per 5% step of deviation |

N3's weight of 40 dwarfs the others because a false 1:1:3:1:1 run can make a scanner hunt
for a fourth [finder pattern](/glossary/finder-pattern) that does not exist.

One honest footnote: several widely used encoders (including the library UseQR builds on)
score N3 on the seven-module run alone, without checking the four light modules the standard
requires beside it. Both are valid symbols; they just sometimes pick different masks, which
is one reason [two generators can produce different codes](/docs/spec/why-two-generators-produce-different-codes)
for identical input.

## Format information bits

The chosen mask is announced in the 15-bit [format information](/glossary/format-information):
2 bits of error-correction level, 3 bits of mask number, 10 bits of BCH error correction,
all XORed with the fixed pattern `101010000010010`. The level indicator is counterintuitive:
**L = 01, M = 00, Q = 11, H = 10**.

All 32 possible format strings (computed from the BCH(15,5) generator `10100110111`):

| Mask | Level L | Level M | Level Q | Level H |
|---|---|---|---|---|
| 0 | `111011111000100` | `101010000010010` | `011010101011111` | `001011010001001` |
| 1 | `111001011110011` | `101000100100101` | `011000001101000` | `001001110111110` |
| 2 | `111110110101010` | `101111001111100` | `011111100110001` | `001110011100111` |
| 3 | `111100010011101` | `101101101001011` | `011101000000110` | `001100111010000` |
| 4 | `110011000101111` | `100010111111001` | `010010010110100` | `000011101100010` |
| 5 | `110001100011000` | `100000011001110` | `010000110000011` | `000001001010101` |
| 6 | `110110001000001` | `100111110010111` | `010111011011010` | `000110100001100` |
| 7 | `110100101110110` | `100101010100000` | `010101111101101` | `000100000111011` |

A useful side effect of the XOR mask: level M with mask 0 encodes as `101010000010010`
(the XOR pattern itself), so an all-zero format field can never appear in a valid symbol.

## Checking a real code

You cannot choose the mask when generating (the encoder must pick the lowest penalty), but
you can read which one was used: [decode any code](/validate) and inspect the format bits,
or [scan it](/scan) and compare two generators' output for the same payload.

## FAQ

### What are the 8 mask patterns in a QR code?
Eight inversion conditions applied to data modules: checkerboard, row stripes, column stripes, diagonal stripes, a 2 × 3 block checkerboard, and three lattice patterns built from (i × j) mod 2 and mod 3 terms.

### How is the best mask pattern chosen?
The encoder renders all eight candidates and scores each with four penalty rules: long runs, 2 × 2 blocks, false finder patterns and dark/light imbalance, weighted 3, 3, 40 and 10. The lowest total score wins.

### Can I pick the mask pattern myself?
The specification says the encoder should evaluate all eight and take the lowest penalty. A forced mask still decodes (the mask number is stored in the format information), but it may scan less reliably.

### Why do two generators put different patterns on the same data?
Usually a different mask choice. Implementations disagree slightly on penalty rule N3's exact reading, and a one-point difference flips the winner. Both outputs decode to identical data.

## Try it

- https://useqr.app/validate
- https://useqr.app/url
- https://useqr.app/scan
