# How to Add a Watermark to an EFQRCode: Complete Swift Implementation Guide

> Learn how to add a watermark to an EFQRCode using Swift. This guide provides a complete implementation for your QR code generation with the efprefix/efqrcode library. Integrate watermarks seamlessly.

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

---

**To add a watermark to an EFQRCode, create an `EFStyleParamImage` instance containing your image data and pass it to your style's `copyWith(watermarkImage:)` method before initializing the generator.**

EFQRCode is a Swift library maintained by efprefix that generates customizable QR codes through a style-centric architecture. Adding a watermark overlays an image behind the QR modules, allowing you to create branded codes that remain fully scannable while displaying background imagery.

## Understanding EFQRCode Watermark Architecture

EFQRCode implements watermarks through its **style-centric architecture** rather than direct generator parameters. The `EFQRCode.Generator` receives a style object conforming to `EFQRCodeStyleBase`, which holds optional image parameters defined in [`Source/Styles/EFQRCodeStyle.swift`](https://github.com/efprefix/efqrcode/blob/main/Source/Styles/EFQRCodeStyle.swift) (lines 56–61).

### Watermark vs. Icon Images

The style protocol defines two distinct image parameters:

- **`watermarkImage`** (`EFStyleParamImage?`): An overlay image that renders **behind** the QR modules, typically covering 100% of the QR size
- **`iconImage`** (`EFStyleParamImage?`): A small logo placed in the center **on top** of the modules

While the `iconImage` sits above the QR code pattern, the `watermarkImage` is drawn first (lines 694–726 of `Source/EFQRCode+Generator.swift`), creating a background layer that the QR modules overlay.

### Style Support for Watermarks

Not all styles support watermarks. Most image-based styles—such as `.image`, `.resampleImage`, `.imageFill`, and `.randomRectangle`—implement `copyWith(iconImage:watermarkImage:)` and return the watermark through `getParamImages()`. However, `EFQRCodeStyle.basic` returns `nil` for watermark images (see `EFQRCodeStyleBasic.getParamImages`), meaning you must select an appropriate style to use this feature.

## Adding a Static Watermark to EFQRCode

Static watermarks use `EFStyleParamImage.static(image:)` to wrap a `CGImage` for placement behind the QR code.

```swift
import EFQRCode
import UIKit

// Load your watermark image as CGImage
guard let watermarkCGImage = UIImage(named: "BrandWatermark")?.cgImage else {
    fatalError("Watermark image not found")
}

// Wrap in EFStyleParamImage
let watermarkParam = EFStyleParamImage.static(image: watermarkCGImage)

// Create a style that supports watermarks and clone it with the watermark
let baseStyle = EFQRCodeStyle.image(params: .init())
let styleWithWatermark = baseStyle.copyWith(watermarkImage: watermarkParam)

// Generate the QR code
let generator = try EFQRCode.Generator("https://example.com", style: styleWithWatermark)
let qrImage = try generator.toImage()

```

The `copyWith(watermarkImage:)` method (defined in [`Source/Styles/EFQRCodeStyle.swift`](https://github.com/efprefix/efqrcode/blob/main/Source/Styles/EFQRCodeStyle.swift), lines 493–502) creates a new style instance with your watermark while preserving other style parameters. When `generator.toImage()` executes, it calls `style.getParamImages()` to retrieve both the icon and watermark for rendering.

## Adding an Animated Watermark to EFQRCode

EFQRCode supports animated watermarks using GIF or APNG sequences through `EFStyleParamImage.animated(images:imageDelays:)`.

```swift
import EFQRCode
import ImageIO

// Extract frames and delays from your animated source
let frames: [CGImage] = // ... extract animation frames
let delays: [CGFloat] = // ... extract frame durations

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

// Apply to style and generate
let style = EFQRCodeStyle.image(params: .init())
    .copyWith(watermarkImage: animatedWatermark)

let generator = try EFQRCode.Generator("Animated Content", style: style)
let gifData = try generator.toAnimatedImage(
    format: .gif, 
    size: CGSize(width: 500, height: 500)
)

```

When generating animated output, the generator invokes `EFStyleParamImage.write(id:rect:opacity:mode:)` (animated branch, lines 71–99 of [`EFQRCodeStyle.swift`](https://github.com/efprefix/efqrcode/blob/main/EFQRCodeStyle.swift)), which constructs SVG `<animate>` elements and later encodes the sequence into the target format.

## Configuring Watermark Opacity and Scaling

Control watermark appearance using the style's `watermarkAlpha` and `watermarkMode` parameters before cloning.

```swift
let baseStyle = EFQRCodeStyle.image(params: .init())

// Configure appearance parameters
baseStyle.params.watermarkAlpha = 0.4  // 40% opacity (0.0 - 1.0)
baseStyle.params.watermarkMode = .scaleAspectFill  // Maintain aspect ratio, cover full area

// Then apply your watermark
let finalStyle = baseStyle.copyWith(watermarkImage: watermarkParam)

```

The `EFImageMode` enum (defined in [`Source/Type/EFImageMode.swift`](https://github.com/efprefix/efqrcode/blob/main/Source/Type/EFImageMode.swift), lines 30–70) provides three scaling options:

- **`.scaleToFill`**: Stretches image to fill the QR bounds
- **`.scaleAspectFit`**: Scales to fit within bounds, maintaining aspect ratio with potential letterboxing
- **`.scaleAspectFill`**: Scales to cover entire QR area, maintaining aspect ratio by cropping

During generation, `checkIfNeedResize(size:)` validates whether the watermark exceeds the target canvas fraction and applies the selected `EFImageMode` scaling before rendering.

## How the Generator Processes Watermarks

The rendering flow in `Source/EFQRCode+Generator.swift` (lines 694–726) follows this sequence:

1. **Image Retrieval**: The generator calls `style.getParamImages()` to obtain the `(iconImage, watermarkImage)` tuple
2. **Resizing**: `checkIfNeedResize(size:)` validates dimensions against the QR canvas size (watermarks use 100% of QR size)
3. **SVG Injection**: `EFStyleParamImage.write(id:rect:opacity:mode:)` converts the image to Base-64-encoded PNG and injects an `<image>` element into the SVG output at the calculated rectangle position
4. **Layer Ordering**: The watermark renders first, then QR modules draw on top, ensuring scannability

Because watermarks are drawn as SVG `<image>` elements behind the QR pattern, they do not interfere with the code's error correction capabilities provided the opacity (`watermarkAlpha`) leaves sufficient contrast for the modules.

## Summary

- **Watermarks render behind QR modules**, while icons render on top
- Use `EFStyleParamImage.static(image:)` for PNG/JPEG assets or `.animated(images:imageDelays:)` for GIF/APNG sequences
- Apply watermarks via `copyWith(watermarkImage:)` available in image-based styles (`.image`, `.resampleImage`, etc.)
- Control transparency with `watermarkAlpha` (0.0–1.0) and sizing with `EFImageMode` options
- The generator processes watermarks in `Source/EFQRCode+Generator.swift` by calling `getParamImages()` and injecting SVG image elements

## Frequently Asked Questions

### What is the difference between a watermark and an icon in EFQRCode?

A **watermark** (`watermarkImage`) renders as a full-size background layer behind the QR modules, while an **icon** (`iconImage`) appears as a small, centered logo overlaid on top of the modules. According to the `EFQRCodeStyleBase` protocol in [`Source/Styles/EFQRCodeStyle.swift`](https://github.com/efprefix/efqrcode/blob/main/Source/Styles/EFQRCodeStyle.swift), both are optional `EFStyleParamImage?` properties, but they occupy different z-index positions in the final render.

### Can I use animated GIFs as watermarks?

Yes. Pass an array of `CGImage` frames and delay values to `EFStyleParamImage.animated(images:imageDelays:)` instead of `static(image:)`. The generator processes animated watermarks through the animated branch of `write(id:rect:opacity:mode:)` (lines 71–99), creating proper frame sequences in the final GIF or APNG output.

### Does adding a watermark affect QR code scannability?

Watermarks generally do not break scannability because they render behind the QR modules, leaving the actual data pattern unobstructed. However, excessive `watermarkAlpha` values (high opacity) or low-contrast images may reduce scanning reliability. The library applies the watermark before drawing modules (lines 694–726 of `Source/EFQRCode+Generator.swift`), ensuring the QR pattern maintains priority.

### Which EFQRCode styles support watermarks?

Image-based styles including `.image`, `.resampleImage`, `.imageFill`, and `.randomRectangle` support watermarks through the `copyWith(iconImage:watermarkImage:)` method. The basic style (`EFQRCodeStyle.basic`) returns `nil` for `getParamImages()` and cannot display watermarks. Verify your chosen style implements `EFQRCodeStyleBase` with the `copyWith` method before attempting to add a watermark.