# How EFQRCode Embeds Images Within QR Codes: SVG Composition and Masking Techniques

> Discover how EFQRCode embeds images in QR codes using SVG composition and masking techniques. Learn to preserve scannability with transparent pixels for advanced QR code designs.

- Repository: [EFPrefix/efqrcode](https://github.com/efprefix/efqrcode)
- Tags: deep-dive
- Published: 2026-03-01

---

**EFQRCode embeds images by converting them to base64-encoded PNGs, injecting them as SVG `<image>` elements, and optionally applying SVG masks to preserve QR code scannability when transparent pixels are allowed.**

EFQRCode is a Swift library for generating customizable QR codes. Unlike simple overlay approaches that can obstruct critical QR patterns, it treats embedded images as first-class SVG layers composited with the QR code matrix, ensuring the final output remains valid and scannable.

## Image Configuration with EFStyleImageParamsImage

The embedding process begins with the `EFStyleImageParamsImage` structure, which encapsulates the image data and styling options. Defined in [`Source/Styles/EFQRCodeStyleImage.swift`](https://github.com/efprefix/efqrcode/blob/main/Source/Styles/EFQRCodeStyleImage.swift) (lines 96-108), this class stores the raw `CGImage`, a scaling mode (`EFImageMode`), opacity, and a transparency flag.

```swift
let img = EFStyleImageParamsImage(
    image: myCGImage,
    mode: .scaleAspectFill,
    alpha: 0.9,
    allowTransparent: false
)

```

The `allowTransparent` parameter is critical: when set to `true`, the library will generate an SVG mask to ensure that transparent portions of the embedded image do not obscure the underlying QR code modules.

## Rasterization and Base64 Encoding

Before SVG injection, the image must be clipped to the QR code canvas dimensions and converted to a format suitable for embedding. This occurs in `EFStyleParamImage.write` within [`Source/Styles/EFQRCodeStyle.swift`](https://github.com/efprefix/efqrcode/blob/main/Source/Styles/EFQRCodeStyle.swift) (lines 63-71).

The method first applies the selected `EFImageMode` to scale and clip the image to the canvas ratio:

```swift
let imageCliped = try mode.imageForContent(
    ofImage: image,
    inCanvasOfRatio: rect.size
)

```

Then, the clipped image is converted to PNG data and base64-encoded to create a data URL for the SVG `<image>` element:

```swift
let pngBase64 = try imageCliped.pngBase64EncodedString()
return "<image ... xlink:href=\"\(pngBase64)\" .../>"

```

This approach ensures the final QR code is self-contained, requiring no external image references.

## SVG Composition and Masking Logic

The final composition occurs in `EFQRCodeStyleImage.writeQRCode` ([`Source/Styles/EFQRCodeStyleImage.swift`](https://github.com/efprefix/efqrcode/blob/main/Source/Styles/EFQRCodeStyleImage.swift), lines 32-60 and 82-88). This method orchestrates the rendering order and applies masks when necessary.

### Rendering Order Based on Transparency

When `allowTransparent` is **true**, the library renders the QR code modules first (excluding alignment, timing, and position patterns), then injects the image fragment. It wraps the image in an SVG mask that punches holes through the QR code modules where the image has transparent pixels, ensuring those modules remain visible for scanning.

```swift
if let image = params.image {
    // ... draw modules when allowTransparent is true ...
    let line = try image.image.write(
        id: id,
        rect: CGRect(x: 0, y: 0, width: nCount, height: nCount),
        opacity: image.alpha,
        mode: image.mode
    )
    imageLineIndex = pointList.count
    pointList.append(line)  // image SVG fragment
    id += 1
}

```

### Mask Application

If transparency is enabled, the code constructs a mask around the image fragment (lines 82-88):

```swift
if let imageLineIndex = imageLineIndex {
    imageMask += "</mask></defs>"
    let oldImageLine = pointList[imageLineIndex]
    pointList[imageLineIndex] =
        "\(imageMask)<g x=\"0\" y=\"0\" width=\"\(nCount)\" height=\"\(nCount)\" mask=\"url(#hole)\">\(oldImageLine)</g>"
}

```

When `allowTransparent` is **false**, the QR code modules are drawn first and the image is simply drawn on top without masking, covering the underlying modules completely.

## Practical Implementation Examples

### Static Image Watermark

This example demonstrates embedding a static logo into a QR code using the `EFStyleImageParamsImage` configuration:

```swift
import EFQRCode
import CoreGraphics

// Load a CGImage from a PNG file
let logoCG: CGImage = try CGImageSourceCreateWithURL(
    URL(fileURLWithPath: "/path/to/logo.png") as CFURL,
    nil)!.createImage(at: 0)!

// Configure image parameters with scaleAspectFill and no transparency
let imageParams = EFStyleImageParamsImage(
    image: EFStyleParamImage.static(image: logoCG),
    mode: .scaleAspectFill,
    alpha: 0.9,
    allowTransparent: false)

// Build the complete style
let style = EFQRCodeStyle.image(
    EFStyleImageParams(
        icon: nil,
        backdrop: EFStyleParamBackdrop(),
        align: EFStyleImageParamsAlign(),
        timing: EFStyleImageParamsTiming(),
        position: EFStyleImageParamsPosition(),
        data: EFStyleImageParamsData(),
        image: imageParams))

// Generate the QR code
let generator = try EFQRCode.Generator("https://example.com", style: style)
let pngData = try generator.toPNGData(width: 500)

// Save to disk
try pngData.write(to: URL(fileURLWithPath: "/tmp/qrcode.png"))

```

### Animated Watermark with Transparency

This advanced example embeds an animated GIF as a watermark while preserving QR code scannability through transparent pixel masking:

```swift
import EFQRCode
import CoreGraphics

// Assume frames and delays are loaded from an animated source
let frames: [CGImage] = [...]  // Array of CGImage frames
let delays: [CGFloat] = [...]  // Frame durations in seconds

// Create an animated image parameter
let animatedWatermark = EFStyleParamImage.animated(
    images: frames,
    imageDelays: delays)

// Configure with transparency enabled to preserve QR readability
let imgParams = EFStyleImageParamsImage(
    image: animatedWatermark,
    mode: .scaleAspectFit,
    alpha: 1.0,
    allowTransparent: true)

// Assemble the style
let style = EFQRCodeStyle.image(
    EFStyleImageParams(
        icon: nil,
        backdrop: EFStyleParamBackdrop(),
        align: EFStyleImageParamsAlign(),
        timing: EFStyleImageParamsTiming(),
        position: EFStyleImageParamsPosition(),
        data: EFStyleImageParamsData(),
        image: imgParams))

// Generate animated GIF output
let generator = try EFQRCode.Generator("Animated QR", style: style)
let gifData = try generator.toGIFData(width: 400)

// Save the result
try gifData.write(to: URL(fileURLWithPath: "/tmp/animated_qr.gif"))

```

When `allowTransparent` is set to `true`, the library ensures that transparent portions of the animated frames do not obscure the underlying QR code modules, maintaining scannability throughout the animation sequence.

## Summary

- **EFQRCode** treats embedded images as SVG layers rather than simple overlays, ensuring the output remains a valid, scannable QR code.
- The **`EFStyleImageParamsImage`** structure configures the image source, scaling mode, opacity, and transparency handling ([`Source/Styles/EFQRCodeStyleImage.swift`](https://github.com/efprefix/efqrcode/blob/main/Source/Styles/EFQRCodeStyleImage.swift), lines 96-108).
- **`EFStyleParamImage.write`** handles rasterization, clipping to canvas dimensions, and base64 PNG encoding for SVG embedding ([`Source/Styles/EFQRCodeStyle.swift`](https://github.com/efprefix/efqrcode/blob/main/Source/Styles/EFQRCodeStyle.swift), lines 63-71).
- **`EFQRCodeStyleImage.writeQRCode`** orchestrates the final composition, rendering QR modules first when transparency is enabled, then injecting the image fragment with an optional SVG mask to preserve module visibility ([`Source/Styles/EFQRCodeStyleImage.swift`](https://github.com/efprefix/efqrcode/blob/main/Source/Styles/EFQRCodeStyleImage.swift), lines 32-60, 82-88).
- The **`allowTransparent`** flag determines whether the image covers modules directly or uses masking to ensure scannability through transparent image pixels.

## Frequently Asked Questions

### What image formats does EFQRCode support for embedding?

EFQRCode accepts any `CGImage` or `UIImage` on iOS/macOS platforms. The library internally converts these to PNG format for embedding within the SVG output. This means you can use PNG, JPEG, or any other format that Core Graphics can decode, provided you convert it to a `CGImage` first. The final output is always a base64-encoded PNG embedded directly in the SVG.

### How does transparent pixel handling affect QR code readability?

The `allowTransparent` parameter in `EFStyleImageParamsImage` controls this behavior. When set to `false`, the image simply overlays the QR code modules, potentially obscuring them. When set to `true`, EFQRCode generates an SVG mask that punches holes through the QR code modules where the image has transparent pixels, ensuring those modules remain visible for scanners. This preserves scannability even when using logos with transparent backgrounds.

### Can I use animated GIFs as watermarks in EFQRCode?

Yes, EFQRCode supports animated watermarks through the `EFStyleParamImage.animated` initializer. You provide an array of `CGImage` frames and corresponding delay times. When generating GIF output via `toGIFData`, the library composites each frame of the animated watermark onto each frame of the QR code animation. To maintain scannability throughout the animation, enable `allowTransparent: true` so the mask updates per-frame.

### Does embedding an image reduce the QR code's error correction capability?

Embedding an image does not inherently reduce the QR code's error correction level, which is determined during the encoding phase. However, covering modules with opaque image pixels effectively removes those modules from the scannable pattern. EFQRCode mitigates this by using SVG masks when `allowTransparent` is enabled, ensuring that even under transparent image areas, the underlying modules remain visible. For best results, use high error correction levels (H or Q) when embedding large opaque images.