logo
Kurashizu Blogwhere ideas flow
  • Home
  • News
  • Blog
  • About
  • Home
  • News
  • Blog
  • About

© 2026 Kurashizu. All rights reserved.

Admin·New Post·Service Status
Powered by Cloudflare·31.10.26
← Back to news

Dithered QR Codes

Original article
andrewt.net|337 points|37 comments|by jmusall|Aug 8, 2026

The Art of Dithered QR Codes

🧩 QR Codes: The Fundamentals

At its core, a QR code is simply a mechanism for encoding a small amount of data into a format that smartphones can easily interpret from a photograph. They are engineered for extreme resilience, remaining functional despite perfect conditions poor focus, printing errors, skewed angles, or partial damage.

Structurally, a QR code is a grid divided into two primary categories:

ComponentDescriptionPurpose
Function PatternsThe prominent, bold shapesHelp the scanner locate and align the code
Data ModulesThe remaining grid of pixelsStore the actual payload and header information

Because the scanner uses the function patterns to establish the coordinate system, the data modules are more flexible. Brands often modify these to create stylized codes. While this reduces robustness, the system can typically withstand significant alteration before becoming unreadable.

🖼️ Embedding Imagery

It is possible to embed images within these codes by shrinking the data modules. Since the scanner looks for the center of the pixel, the surrounding area can be repurposed.

One specific technique involves dividing every single QR pixel into a 3×33 \times 33×3 sub-grid:

  • Center Pixel: Reserved for the actual QR data.
  • Outer Pixels: Used to render a photograph.

The result is a one-bit, low-resolution image plagued by "salt-and-pepper" noise due to the interspersed data pixels.

🎨 The Concept of Dithering

When converting a high-color image to a binary (black and white) format, we rarely use simple thresholding.

Thresholding: The process of making every pixel either pure black or pure white based on a specific brightness cutoff.

Instead, we use dithering—creating a chequerboard-like pattern to simulate midtones. A Bayer filter is one common method to achieve this while preserving fine detail.

📉 Error Diffusion (Floyd-Steinberg)

To improve upon basic dithering, the Floyd-Steinberg method is used. The process follows this logic:

  1. Start at the top-left pixel.
  2. Threshold the pixel (e.g., >50%> 50\%>50% brightness →\rightarrow→ White).
  3. Calculate the "quantization error."
    • Example: If a pixel is 70%70\%70% bright but becomes 100%100\%100% (white), the error is: Error=100%−70%=30%\text{Error} = 100\% - 70\% = 30\%Error=100%−70%=30%
  4. Diffuse this 30%30\%30% error to neighboring pixels that haven't been processed yet, making them slightly darker.

By the time the entire image is processed, the average brightness of any given area is much closer to the original source.

🛠️ Applying Error Diffusion to QR Codes

Irregular dithering is ideal for QR codes because it masks the "salt-and-pepper" noise of the data modules. In a 147×147147 \times 147147×147 one-bit image, the data modules (1 in every 9 pixels) would normally look like random glitches; error diffusion blends them in.

The Two-Pass Process

To make this work, the generator performs two distinct passes:

# Conceptual Logic for Dithered QR
def generate_dithered_qr(image, qr_data):
    # Pass 1: Masking the Data
    for pixel in qr_data_modules:
        set_pixel_color(pixel, required_qr_value)
        diffuse_error_to_neighbors(pixel, error_amount)
    
    # Pass 2: Standard Image Dithering
    for pixel in remaining_pixels:
        threshold_and_diffuse(pixel)

In the first pass, we force the data modules to be the correct color. This can create massive errors (e.g., forcing a dark pixel to be white creates a ≈95%\approx 95\%≈95% error). However, by diffusing that huge error to the surrounding eight pixels, the image remains cohesive.

🚀 Advanced Optimizations

The generator tool offers several "power user" features:

  • Rotation: Rotate the QR code before merging the image.
  • Encoding Tweaks: Experiment with different QR encoding settings for better visuals.
  • Error Correction Abuse: QR codes have built-in redundancy. You can actually change a few of those high-error data modules to better fit the image, and the code will still scan (similar to how logos are placed in the center of QR codes). Note: This is risky and can easily break scannability.

⚠️ Real-World Implementation

This technique is a trade-off between aesthetics and scannability.

  • High Success: Large screens, high-quality posters.
  • High Risk: Crumpled paper flyers, low-light environments.

Crucial Reminders:

  • "It scanned on my iPhone, so it's fine." →\rightarrow→ It might not scan on a "potato phone" in a dim room.
  • Margins: The generator produces tight images. You must add a "quiet zone" (margin) for reliability.
  • CSS: When scaling these images in a browser, disable blurring/smoothing via CSS to keep the pixels crisp.
  • Contrast: The margin must contrast with the center of the finder patterns (usually a white margin for black patterns, or black for inverted codes).