How EFQRCode Ensures QR Code Scannability When Adding Icons or Watermarks

EFQRCode guarantees QR code readability with embedded icons or watermarks through three coordinated safeguards: strict size limits that cap icons at 33% of the code area, exclusion of functional finder patterns from image color sampling, and a layered SVG architecture that renders data modules independently from decorative overlays.

EFQRCode is a Swift library for generating customizable QR codes that maintain scannability even with visual enhancements. According to the efprefix/efqrcode source code, the library implements specific architectural safeguards to prevent icons and watermarks from interfering with the QR code's error correction capacity. These mechanisms ensure that decorative elements never overwrite the critical finder patterns or data modules required for scanning.

Maximum Size Limits Preserve Error Correction Capacity

In Source/EFQRCode+Generator.swift, the checkIfNeedResize method (lines 68–94) enforces strict dimensional constraints before rendering begins. This function calculates the target canvas size and compares the original image dimensions against allowed percentages to ensure sufficient quiet-zone modules remain for data integrity.

For icons, the library limits the overlay to percentage = 0.33 (33% of the QR code area). For watermarks, the limit is percentage = 1.0 (100% of the module canvas), with automatic rescaling triggered if the supplied image exceeds the canvas bounds. These constraints prevent the decorative elements from consuming the error correction capacity needed for reliable scanning.

Functional Pattern Protection During Image Resampling

The getGrayPointList routine in Source/Styles/EFQRCodeStyleResampleImage.swift (lines 439–468) protects the QR code's functional patterns during image-based color sampling. The method walks the QR code matrix and records coordinates for three critical pattern groups: posOrigins (position detection), bwOrigins (timing patterns), and swOrigins (alignment patterns).

When applying resampled image colors to data modules, the generator skips these protected coordinates entirely. This guarantees that the high-contrast finder patterns remain intact and are never overwritten by background image colors, preserving the scanner's ability to detect and orient the code regardless of the icon or watermark content.

Layered SVG Architecture Separates Data and Decoration

EFQRCode constructs the final output through a layered SVG composition process defined in Source/Styles/EFQRCodeStyleResampleImage.swift (lines 610–672 and 71–92). This architectural separation ensures that decorative elements never interfere with data module rendering or functional pattern visibility:

  1. Backdrop layer: EFStyleParamBackdrop.generateSVG creates the base background.
  2. Pattern layer: customSVG draws solid, fully opaque shapes for alignment, timing, and position patterns.
  3. Data layer: writeResImage generates data modules using the sampled image colors.
  4. Icon layer: writeIcon adds the centered icon or watermark with optional border masks, rendering it above the data modules as a distinct <g> group.

Because the icon sits on a separate layer with its own masking, it cannot corrupt the underlying data modules or functional patterns, ensuring the QR code remains within its error correction limits.

Practical Implementation Examples

The following Swift examples demonstrate how to generate scannable QR codes with icons and watermarks while leveraging EFQRCode's built-in safeguards.

Adding a Centered Icon (Auto-Resized)

import EFQRCode

// Icon automatically resized to ≤ 33% of the code area
let icon = EFStyleParamIcon(
    image: .static(image: myIconCGImage),
    mode: .scaleAspectFill,
    alpha: 0.9,
    borderColor: .black,
    percentage: 0.25  // Generator enforces ≤ 0.33 maximum
)

let qr = try EFQRCodeGenerator.generate(
    content: "https://example.com",
    size: .init(width: 300, height: 300),
    style: .basic(params: .init(icon: icon, backdrop: .clear))
)

Applying a Full-Size Watermark

// Watermark capped at 100% of module canvas with automatic rescaling
let watermark = EFStyleParamImage.static(image: myWatermarkCGImage)

let qrWithWatermark = try EFQRCodeGenerator.generate(
    content: "https://example.org",
    size: .init(width: 500, height: 500),
    style: .imageFill(params: .init(image: watermark, mode: .scaleAspectFit))
)

Resampled Image Style with Pattern Protection

// Image colors data modules while preserving solid functional patterns
let photo = EFStyleResampleImageParamsImage(
    image: .static(image: myPhotoCGImage),
    mode: .scaleAspectFill,
    contrast: 0.2,
    exposure: -0.1
)

let resampled = try EFQRCodeGenerator.generate(
    content: "https://photo.example",
    size: .init(width: 400, height: 400),
    style: .resampleImage(params:
        EFStyleResampleImageParams(
            icon: nil,
            backdrop: .clear,
            image: photo,
            align: .defaultAlign,
            timing: .defaultTiming,
            position: .defaultPosition,
            dataColor: .black
        )
    )
)

Summary

  • Size constraints: The checkIfNeedResize function in EFQRCode+Generator.swift limits icons to 33% of the QR code area and watermarks to the full module canvas, ensuring sufficient error correction capacity remains for reliable scanning.
  • Pattern protection: The getGrayPointList method excludes finder, alignment, and timing pattern coordinates (stored in posOrigins, bwOrigins, and swOrigins) from image color sampling, preserving the high-contrast markers required for scanner detection.
  • Layered rendering: The SVG generation pipeline separates data modules (writeResImage), functional patterns (customSVG), and decorative icons (writeIcon) into distinct layers, preventing visual corruption of critical code elements.

Frequently Asked Questions

What is the maximum size an icon can occupy in an EFQRCode-generated QR code?

EFQRCode enforces a maximum icon size of approximately 33% of the total QR code area. This limit is hardcoded in the checkIfNeedResize method within Source/EFQRCode+Generator.swift. If you specify a larger percentage in EFStyleParamIcon, the generator automatically resizes the image or recreates a static placeholder to maintain scannability.

How does EFQRCode prevent icons from covering the QR code's finder patterns?

The library protects functional patterns through coordinate exclusion in Source/Styles/EFQRCodeStyleResampleImage.swift. During the image resampling process, the getGrayPointList routine identifies and skips coordinates belonging to position detection (posOrigins), timing (bwOrigins), and alignment (swOrigins) patterns. Additionally, the layered SVG architecture renders these patterns as solid shapes in a separate layer from the icon overlay.

Can watermarks completely cover the QR code while remaining scannable?

Watermarks can cover the full module canvas (100% size limit), but the generator rescales them if they exceed the canvas bounds. Because watermarks are rendered as the bottom layer with data modules and functional patterns drawn on top in the SVG stack, the QR code maintains its structural integrity. The error correction capacity handles the visual noise while the protected finder patterns ensure proper orientation.

Which source files control the scannability safeguards in EFQRCode?

The primary safeguards are implemented across three key files: Source/EFQRCode+Generator.swift contains the size validation logic (checkIfNeedResize); Source/Styles/EFQRCodeStyleResampleImage.swift implements pattern protection (getGrayPointList) and the layered SVG composition (writeResImage, writeIcon, customSVG); and Source/Type/EFImageMode.swift defines the scaling modes used when resizing icons and watermarks.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →