ENES
qr-codeEngineering Guide

QR Code Error Correction Levels (L, M, Q, H): Capacity, Damage Tolerance, and Logo Embedding Guide

AS
Published on 2026-10-12ยท11 min readยทDaily Toolbox Engineering

QR Code Error Correction Levels (L, M, Q, H): Capacity, Damage Tolerance, and Logo Embedding Guide

You scan a restaurant QR code covered in greasy fingerprints, crumpled on laminated cardstock, or branded with a high-resolution corporate logo punched right through its center โ€” and your smartphone camera decodes the URL in under 40 milliseconds.

How does a two-dimensional matrix barcode survive having nearly a third of its area destroyed, obscured, or replaced by arbitrary art without losing a single character of payload?

The secret lies in the Reed-Solomon error correction algorithm defined in ISO/IEC 18004. Unlike linear checksums (such as CRC32 or SHA-256) that merely detect data corruption and abort, QR codes generate forward error correction (FEC) parity codewords capable of mathematically reconstructing missing and corrupted data.

However, error correction is not free. Every bit of redundancy consumes module real estate, drives up the QR code version matrix, shrinks individual printed dot sizes, and degrades scanning distance. Choosing the wrong level can lead to unscannable packaging, bloated SVGs, or marketing campaigns with broken logo integrations.

This guide provides a comprehensive breakdown of the mathematics behind QR error correction, the exact damage recovery metrics for levels L, M, Q, and H, and production rules for embedding logos safely without breaking optical decoders.


1. Anatomy of a QR Code: Where Error Correction Lives

Before understanding error correction levels, consider how a QR code matrix is organized. Every QR code (Versions 1 through 40) is composed of two primary functional domains:

  1. Function Patterns (Non-correctable Overhead):

    • Finder Patterns: The three distinctive triple-nested square targets at the top-left, top-right, and bottom-left corners that scanners use for position, rotation, and skew calibration.
    • Separators & Quiet Zone: Solid white borders isolating finder patterns from user data. The Quiet Zone requires an uninterrupted margin of at least 4 modules on all four sides.
    • Timing Patterns: Alternating dark/light rows connecting the finder patterns to calibrate the module coordinate grid.
    • Alignment Patterns: Smaller concentric squares embedded across Versions 2 through 40 to correct optical lens distortion on curved surfaces.
    • Format & Version Information: Crucial metadata blocks encoding the selected Mask Pattern and Error Correction Level (protected by dedicated BCH error correction codes).
  2. Encoding Region (Data + Error Correction Codewords):

    • The remaining modules store raw user data interleaved with Reed-Solomon parity codewords.
    • These codewords are divided into distinct interleaving blocks to distribute localized physical damage across multiple independent mathematical polynomials.
+-----------------------------------------------------------+
| [Finder] [Quiet Zone]                     [Finder]        |
|  (Position & Orientation)                  (Position)     |
|         \                                 /              |
|          +--- [Format Info: Level + Mask] +               |
|                                                           |
|       [Timing Pattern: Alternating Dots]                  |
|                                                           |
|    +-----------------------------------------------+      |
|    |  Interleaved Data Block 1 + Parity Codewords  |      |
|    |  Interleaved Data Block 2 + Parity Codewords  |      |
|    |  [Alignment Patterns for Curvature Correction]|      |
|    +-----------------------------------------------+      |
|                                                           |
| [Finder]                                                  |
|  (Position)              [Quiet Zone Margin >= 4 modules] |
+-----------------------------------------------------------+

2. The Mathematics: How Reed-Solomon Solves Damage

QR codes operate over the Galois Field $GF(2^8)$ with the primitive polynomial defined by ISO/IEC 18004:

$$p(x) = x^8 + x^4 + x^3 + x^2 + 1$$

In this field, every byte (8 bits) represents a polynomial coefficient between 0 and 255. When data is encoded, the input stream is treated as an information polynomial $I(x)$. A generator polynomial $G(x)$ is created by taking roots from powers of the field generator $\alpha$:

$$G(x) = \prod_{i=0}^{2t - 1} (x - \alpha^i)$$

Dividing $I(x) \cdot x^{2t}$ by $G(x)$ yields the remainder polynomial $R(x)$. The coefficients of $R(x)$ are the parity codewords appended directly to the data stream.

Erasures vs. Errors: The $2t$ vs. $t$ Rule

In digital signal processing, corrupted codewords fall into two distinct categories:

  1. Erasures (Known Locations): The scanner detects that a physical module is blocked or unreadable (for example, covered by a centered logo or torn away), but its exact coordinate index is known. A code with $2t$ parity codewords can repair up to $2t$ erasures.
  2. Errors (Unknown Locations): The scanner reads dirty or inverted pixels with high contrast noise, but does not know which specific bytes are false. Solving both the error location polynomial and error evaluator polynomial (using Berlekamp-Massey and Chien search algorithms) requires double the redundant data: $2t$ parity codewords can correct up to $t$ unknown errors.

In real-world conditions, a QR code faces a combination of both:

$$2 \cdot E + S \le 2t$$

Where:

  • $E$ is the number of unknown errors (scratches, poor contrast, specular glare).
  • $S$ is the number of known erasures (deliberate logo cutout).
  • $2t$ is the total number of Reed-Solomon parity codewords generated.

If you punch a center logo that consumes 25% of your code's codewords, you convert that entire margin into known erasures ($S$), leaving almost zero reserve ($E$) for real-world optical noise such as smudges or camera glare!


3. The 4 Error Correction Levels Compared (L, M, Q, H)

ISO/IEC 18004 defines four standard error correction levels. Each level represents a different mathematical trade-off between usable payload capacity and damage recovery tolerance:

Level Identifier Binary Bits in Format Info Recovery Percentage (Approx.) Raw Payload Efficiency Primary Use Cases
Level L Low 01 ~7% Maximum (~93% data) Clean digital screens, large payloads (vCards, Wi-Fi keys), ultra-dense displays
Level M Medium 00 ~15% High (~85% data) Standard default for web links, mobile ticketing, clean printed paper
Level Q Quartile 11 ~25% Moderate (~75% data) Industrial packaging, courier shipping labels, outdoor posters exposed to weather
Level H High 10 ~30% Lower (~70% data) Branded QR codes with centered logos, harsh industrial factory floors

Practical Payload Trade-off by Level

Consider an alphanumeric string (such as a standard HTTPS URL) encoded at Version 3 ($29 \times 29$ grid) versus Version 10 ($57 \times 57$ grid):

QR Version Total Codewords Level L Capacity Level M Capacity Level Q Capacity Level H Capacity
Version 2 ($25 \times 25$) 44 bytes 77 chars 61 chars 47 chars 34 chars
Version 4 ($33 \times 33$) 100 bytes 187 chars 149 chars 111 chars 80 chars
Version 10 ($57 \times 57$) 346 bytes 652 chars 513 chars 364 chars 271 chars

Notice: Moving from Level L to Level H drops your usable character capacity by nearly 55% for the exact same physical grid size!

If your URL is long (e.g. includes extensive UTM marketing parameters and session tracking tokens), using Level H will force the generator into a much higher QR Version, resulting in tiny, densely packed modules that low-end smartphone cameras cannot resolve in dim lighting.


4. The Version vs. Module Density Trap

Every QR code version increments the matrix size by 4 modules along each axis:

$$\text{Module Count} = 17 + 4 \times \text{Version}$$

  • Version 1: $21 \times 21$ modules
  • Version 5: $37 \times 37$ modules
  • Version 10: $57 \times 57$ modules
  • Version 40: $177 \times 177$ modules

Minimum Print Size Formula

To ensure optical decoders can distinguish dark and light modules reliably, a printed module should never measure smaller than 0.4 mm to 0.5 mm ($0.016$ to $0.02$ inches) for consumer smartphone cameras at hand-held distance (~20 cm to 30 cm):

$$\text{Minimum Print Width} = (17 + 4 \times \text{Version}) \times 0.45\text{ mm}$$

When you blindly select Level H for a 120-character URL, the code might jump from Version 4 ($33 \times 33$) to Version 7 ($45 \times 45$). If printed on a small business card with an allocated size of $20 \times 20\text{ mm}$:

  • At Version 4 ($33 \times 33$): Module size = $\frac{20}{33} \approx 0.60\text{ mm}$ (Easy scan)
  • At Version 7 ($45 \times 45$): Module size = $\frac{20}{45} \approx 0.44\text{ mm}$ (Fails or stutters on older lenses or budget sensors)

Architectural Tip: To embed logos without inflating module density, shorten your URL first using a clean redirect or trim unnecessary query parameters before generating the matrix!


5. The Golden Rules for Embedding Logos (Without Breaking Scanners)

Designers frequently want to superimpose a brand logo, an app icon, or a glyph over the center of a QR code. Because error correction treats obscured modules as localized damage, a centered graphic works mathematically โ€” provided you follow these non-negotiable rules:

Rule 1: Always Select Level H (or Level Q as an Absolute Minimum)

Never attempt to superimpose graphics on Level L (7%) or Level M (15%). A modest logo covering just 12% of the center area instantly wipes out 80% to 100% of Level M redundancy, rendering the code fragile to the slightest camera smudge or ambient shadow.

Rule 2: Limit Logo Area to $\le 20%$ of the Matrix

Although Level H mathematically supports ~30% recovery, you must reserve an optical buffer. If your logo occupies 20% of the area, you leave approximately 10% of recovery margin for physical scratches, print bleed, specular reflections, and lens aberrations.

$$\text{Maximum Logo Dimension} \le 0.44 \times \text{Total QR Width}$$

$$\text{Target Safe Logo Dimension} \le 0.35 \times \text{Total QR Width} \quad (\approx 12%\text{ to }15%\text{ area})$$

Rule 3: Keep a Strict Exclusion Zone Around Functional Patterns

Optical decoders scan the image using a deterministic sequential pipeline. If any of the following patterns are infringed by even 1 pixel, the code will fail to decode entirely:

  • Do NOT touch the 3 Finder Patterns (the large $7 \times 7$ square corners).
  • Do NOT overlap the Format Information strips directly adjacent to the finder squares.
  • Do NOT occlude Alignment Patterns on Version 2+ codes.
  • Center placement is safest because Reed-Solomon interleaves codewords throughout the matrix, ensuring a centralized cutout distributes errors across many independent blocks rather than devastating one single block.

Rule 4: Add an Uninterrupted Solid Margin Around the Logo

A transparent PNG with thin floating graphic elements will blend with the underlying black/white data modules, causing decoders to misread module boundaries.

Always place a solid circular or rounded-rectangular background plate (usually pure #FFFFFF with a 2โ€“3 module safety border) directly behind your logo icon before compositing.

Rule 5: Respect the 4-Module Quiet Zone

Many modern web designers strip the white outer margin to make the QR code 'flush' with card edges or dark hero banners. This breaks the decoder's edge-detection algorithm. The Quiet Zone must remain at least 4 modules wide and match the background color.


6. Real-World Troubleshooting: Why Your Branded QR Code Fails

Symptom Underlying Cause Production Remedy
Scans in bright light, fails in dim room Contrast ratio is below $4:1$, or subtle logo transparency is bleeding into dark modules Ensure background is #ffffff and foreground is #000000 or a very dark hue ($L^* < 20$ in CIELAB). Add solid cutout beneath logo.
iPhone camera scans instantly, Android fails The QR code was color-inverted (white modules on black background) Traditional optical barcode decoders search strictly for dark-on-light finder targets. Never invert your QR colors for production print.
URL is truncated or scrambled Logo is too large, exceeding the Reed-Solomon $2t$ boundary, triggering an uncorrectable block failure Shrink logo size to $< 18%$ total surface area and confirm error correction is explicitly configured to Level H.
Scanner opens the wrong page Custom shortened URL wrapped by an unstable third-party redirect service that expired Generate direct target URLs or manage your own 301 redirects on your primary domain.
Modules look distorted or blurry in print Exported as low-resolution 72 DPI PNG rather than a vector SVG or 300+ DPI asset Always export and print vector SVG or high-resolution PNG using integer module sizing (no fractional pixel anti-aliasing).

7. Zero-Dependency Client-Side SVG Generator

Here is a clean, dependency-free TypeScript implementation demonstrating how to build an SVG QR code string with custom sizing, level indicators, and an optional safe centered punch-out area:

// Types for QR error correction levels
export type QRErrorCorrectionLevel = "L" | "M" | "Q" | "H";

export interface QRCodeSVGOptions {
  modules: boolean[][];        // Matrix from your QR encoder
  size?: number;               // Pixel width/height (default 256)
  margin?: number;             // Quiet zone modules (default 4)
  darkColor?: string;          // Hex or CSS color (default #000000)
  lightColor?: string;         // Hex or CSS color (default #ffffff)
  includeLogoPunchout?: boolean;
  logoRatio?: number;          // Relative width of center punchout (default 0.22)
}

export function renderQRCodeToSVG(options: QRCodeSVGOptions): string {
  const {
    modules,
    size = 256,
    margin = 4,
    darkColor = "#000000",
    lightColor = "#ffffff",
    includeLogoPunchout = false,
    logoRatio = 0.22,
  } = options;

  const moduleCount = modules.length;
  const totalGridSize = moduleCount + margin * 2;
  const cellSize = size / totalGridSize;

  // Calculate punchout bounds if reserving space for a centered logo
  const centerModule = moduleCount / 2;
  const punchoutRadiusModules = (moduleCount * logoRatio) / 2;
  const minPunch = centerModule - punchoutRadiusModules;
  const maxPunch = centerModule + punchoutRadiusModules;

  const rects: string[] = [];

  for (let r = 0; r < moduleCount; r++) {
    for (let c = 0; c < moduleCount; c++) {
      // Check if module is inside dark matrix
      if (modules[r][c]) {
        // If center logo punchout is enabled, skip dark modules in center
        if (
          includeLogoPunchout &&
          r >= minPunch &&
          r <= maxPunch &&
          c >= minPunch &&
          c <= maxPunch
        ) {
          continue;
        }

        const x = (c + margin) * cellSize;
        const y = (r + margin) * cellSize;
        rects.push(
          `<rect x="${x.toFixed(2)}" y="${y.toFixed(2)}" width="${cellSize.toFixed(2)}" height="${cellSize.toFixed(2)}" fill="${darkColor}"/>`
        );
      }
    }
  }

  return [
    `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${size} ${size}" width="${size}" height="${size}" shape-rendering="crispEdges">`,
    `  <rect width="100%" height="100%" fill="${lightColor}"/>`,
    `  ${rects.join("\n  ")}`,
    `</svg>`,
  ].join("\n");
}

8. Summary Checklist Before Going to Print

Before submitting packaging, billboards, or stickers to a commercial press:

  1. Verify your redundancy level: Use Level M for standard URLs; switch to Level H if you plan to place any logo, icon, or artwork in the center.
  2. Measure the logo footprint: Keep the logo area strictly under 20% of total surface area with a solid background barrier.
  3. Protect the Quiet Zone: Leave at least 4 white modules of clear space on all edges.
  4. Test in physical reality: Print a test sheet at actual size on your office laser printer. Test scanning under three conditions:
    • Direct sunlight / bright overhead illumination.
    • Low ambient room light (under 50 lux).
    • Angled scan from a 45-degree tilt to verify alignment recovery.
  5. Use vector assets: Always deliver vector SVG format to printers to ensure module edges remain razor-sharp without pixelation or compression artifacts.

Try It in Your Browser

Need to generate a clean, private QR code right now? Our in-browser QR Code Generator generates scalable SVGs and high-resolution PNGs locally on your device without sending your sensitive links or Wi-Fi passwords to a remote server. You can also prepare and optimize your assets using our Image Converter or inspect your site metadata with our Meta Tags Analyzer.

๐Ÿ‘‰ Open Free In-Browser QR Code Generator โ†’


FAQ

Can I place a logo in the corner of a QR code instead of the center?

No. The top-left, top-right, and bottom-left corners contain the mandatory $7 \times 7$ Finder Patterns. If any of these three patterns is partially covered, the scanner cannot detect the presence, boundaries, or orientation of the QR code, causing total scan failure regardless of error correction level.

Does error correction help if my QR code is blurry or out of focus?

Only slightly. Blur causes pixel bleeding across adjacent black and white modules. While Reed-Solomon corrects localized bit flips, severe optical blur destroys the Finder Patterns and Timing Patterns first, preventing the scanner from ever calculating the module grid.

Why do some online QR generators charge a monthly subscription?

Many commercial generators do not give you a direct QR code; instead, they embed their own proprietary tracking redirect URL. If you cancel your subscription, they disable the redirect and your printed QR codes stop working. By using an in-browser generator that encodes your actual target URL directly, your QR code remains permanently valid forever with zero recurring costs.

What is the maximum character limit for a QR code?

A Version 40 QR code with Error Correction Level L can store up to 7,089 numeric characters, 4,296 alphanumeric characters, or 2,953 binary bytes (8-bit data). However, high-version codes are difficult for mobile phone cameras to scan; keeping payloads under 150 characters is strongly recommended for consumer use cases.

#qr-code#reed-solomon#error-correction#svg#web-development#design#security
AS
Written by Alex Sun

Alex Sun is the developer behind Daily Toolbox. He writes these guides while building the tools themselves โ€” every claim tested against the real thing.

Try the free tools mentioned above

Generate QR code free โ†’