# genqrcode / libqrencode — Masking Algorithms

## Purpose

After placing data and error correction codewords in the QR Code matrix, a mask pattern is XORed with the data area to avoid unfavorable patterns (large uniform regions, patterns resembling finder patterns). The library evaluates all candidate masks using a penalty scoring system and selects the mask with the lowest penalty.

---

## Full QR Code — 8 Mask Patterns

### The MASKMAKER Macro

All 8 mask condition functions are generated by a single macro in `mask.c`:

```c
#define MASKMAKER(__exp__) \
    int x, y;\
    int b = 0;\
    for(y = 0; y < width; y++) {\
        for(x = 0; x < width; x++) {\
            if(*s & 0x80) {\
                *d = *s;\
            } else {\
                *d = *s ^ ((__exp__) == 0);\
            }\
            s++; d++;\
        }\
    }\
    return b;
```

The `0x80` bit check skips non-data modules (finder patterns, timing patterns, alignment patterns, format/version info). The expression `(__exp__) == 0` evaluates the mask condition — when the condition is true (equals 0), the module is flipped.

### Mask Pattern Definitions

```c
static int Mask_mask0(int width, const unsigned char *s, unsigned char *d)
{
    MASKMAKER((y+x) % 2)
}

static int Mask_mask1(int width, const unsigned char *s, unsigned char *d)
{
    MASKMAKER(y % 2)
}

static int Mask_mask2(int width, const unsigned char *s, unsigned char *d)
{
    MASKMAKER(x % 3)
}

static int Mask_mask3(int width, const unsigned char *s, unsigned char *d)
{
    MASKMAKER((y+x) % 3)
}

static int Mask_mask4(int width, const unsigned char *s, unsigned char *d)
{
    MASKMAKER((y/2 + x/3) % 2)
}

static int Mask_mask5(int width, const unsigned char *s, unsigned char *d)
{
    MASKMAKER(((y*x) % 2 + (y*x) % 3))
}

static int Mask_mask6(int width, const unsigned char *s, unsigned char *d)
{
    MASKMAKER(((y*x) % 2 + (y*x) % 3) % 2)
}

static int Mask_mask7(int width, const unsigned char *s, unsigned char *d)
{
    MASKMAKER(((y*x) % 3 + (y+x) % 2) % 2)
}
```

Function pointer array:

```c
typedef int MaskMaker(int, const unsigned char *, unsigned char *);
static MaskMaker *maskMakers[8] = {
    Mask_mask0, Mask_mask1, Mask_mask2, Mask_mask3,
    Mask_mask4, Mask_mask5, Mask_mask6, Mask_mask7
};
```

### Summary Table

| Mask | Condition (module inverted when true) | Pattern |
|---|---|---|
| 0 | `(y + x) % 2 == 0` | Checkerboard |
| 1 | `y % 2 == 0` | Horizontal stripes |
| 2 | `x % 3 == 0` | Vertical stripes (every 3) |
| 3 | `(y + x) % 3 == 0` | Diagonal stripes |
| 4 | `(y/2 + x/3) % 2 == 0` | Block pattern |
| 5 | `(y*x)%2 + (y*x)%3 == 0` | Complex |
| 6 | `((y*x)%2 + (y*x)%3) % 2 == 0` | Complex |
| 7 | `((y*x)%3 + (y+x)%2) % 2 == 0` | Complex |

---

## Penalty Scoring

### Penalty Constants

Defined in `mask.c`:

```c
#define N1 3
#define N2 3
#define N3 40
#define N4 10
```

### Penalty Rule N1 + N3: Run Length

`Mask_calcN1N3()` evaluates both Rule 1 (adjacent same-color modules) and Rule 3 (finder-like patterns) using run-length data:

```c
static int Mask_calcN1N3(int length, int *runLength)
{
    int i;
    int demerit = 0;
    int fact;

    for(i = 0; i < length; i++) {
        if(runLength[i] >= 5) {
            demerit += N1 + (runLength[i] - 5);
        }
        if((i & 1)) {
            // Check for 1:1:3:1:1 pattern embedded in dark-light sequence
            if(i >= 3 && i < length - 2
               && (runLength[i] % 3) == 0) {
                fact = runLength[i] / 3;
                if(runLength[i-2] == fact &&
                   runLength[i-1] == fact &&
                   runLength[i+1] == fact &&
                   runLength[i+2] == fact) {
                    // Check for 4-module light space on either side
                    if(i == 3 || runLength[i-3] >= 4 * fact) {
                        demerit += N3;
                    } else if(i+4 >= length || runLength[i+3] >= 4 * fact) {
                        demerit += N3;
                    }
                }
            }
        }
    }
    return demerit;
}
```

**Rule N1**: Run of ≥ 5 same-color modules → penalty = 3 + (run_length − 5). For example, 7 consecutive dark modules → 3 + 2 = 5 penalty.

**Rule N3**: Pattern 1:1:3:1:1 (the finder pattern ratio) with 4+ light modules on either side → 40 penalty. This prevents patterns that confuse QR Code scanners.

### Run Length Calculation

Horizontal runs via `Mask_calcRunLengthH()`:

```c
static int Mask_calcRunLengthH(int width, const unsigned char *frame, int *runLength)
{
    int i;
    int head;
    int prev;

    if(frame[0] & 1) {
        runLength[0] = -1;
        head = 1;
    } else {
        head = 0;
    }
    runLength[head] = 1;
    prev = frame[0];

    for(i = 1; i < width; i++) {
        if((frame[i] ^ prev) & 1) {
            head++;
            runLength[head] = 1;
            prev = frame[i];
        } else {
            runLength[head]++;
        }
    }
    return head + 1;
}
```

Vertical runs via `Mask_calcRunLengthV()` — same logic but iterates `frame[i * width]`.

### Penalty Rule N2: 2×2 Blocks

`Mask_calcN2()` counts 2×2 same-color blocks:

```c
static int Mask_calcN2(int width, unsigned char *frame)
{
    int x, y;
    int demerit = 0;
    unsigned char *p;

    p = frame;
    for(y = 1; y < width; y++) {
        for(x = 1; x < width; x++) {
            // Check 2x2 block using bit 0
            if(((p[0]^p[1])|(p[width]^p[width+1])) & 1) {
                // not all same
            } else {
                demerit += N2;
            }
            p++;
        }
        p++;
    }
    return demerit;
}
```

Each 2×2 same-color block adds N2 = 3 penalty points.

### Penalty Rule N4: Dark/Light Balance

The `Mask_evaluateSymbol()` function counts dark modules and applies the balance penalty:

```c
static int Mask_evaluateSymbol(int width, unsigned char *frame)
{
    int x, y;
    int demerit = 0;
    int length;
    int runLength[width + 1];
    unsigned char *p;
    int dark = 0;

    demerit += Mask_calcN2(width, frame);

    p = frame;
    for(y = 0; y < width; y++) {
        length = Mask_calcRunLengthH(width, p, runLength);
        demerit += Mask_calcN1N3(length, runLength);
        p += width;
    }

    for(x = 0; x < width; x++) {
        length = Mask_calcRunLengthV(width, frame + x, runLength);
        demerit += Mask_calcN1N3(length, runLength);
    }

    // Count dark modules for N4
    p = frame;
    for(y = 0; y < width * width; y++) {
        if(p[y] & 1) dark++;
    }

    // Calculate demerits for N4
    // dark ratio in percent, deviation from 50%
    int ratio = (200 * dark + width * width) / (2 * width * width) - 50;
    if(ratio < 0) ratio = -ratio;
    demerit += ratio / 5 * N4;

    return demerit;
}
```

N4 penalty: For each 5% deviation from 50% dark/light balance, add N4 = 10 points.

---

## Mask Selection Algorithm

`Mask_mask()` tries all 8 patterns and selects the best:

```c
unsigned char *Mask_mask(int width, unsigned char *frame, QRecLevel level)
{
    int i;
    unsigned char *mask, *bestMask;
    int minDemerit = INT_MAX;
    int bestMaskNum = 0;
    int blacks;
    int bratio;
    int demerit;

    bestMask = NULL;

    for(i = 0; i < 8; i++) {
        mask = (unsigned char *)malloc(width * width);
        if(mask == NULL) break;

        demerit = 0;
        blacks = maskMakers[i](width, frame, mask);
        demerit = Mask_evaluateSymbol(width, mask);

        if(demerit < minDemerit) {
            minDemerit = demerit;
            free(bestMask);
            bestMask = mask;
            bestMaskNum = i;
        } else {
            free(mask);
        }
    }

    Mask_writeFormatInformation(width, bestMask, bestMaskNum, level);

    return bestMask;
}
```

Key points:
- Allocates a new `width × width` buffer for each mask attempt
- Applies the mask via `maskMakers[i]`
- Evaluates penalty via `Mask_evaluateSymbol()`
- Keeps only the lowest-demerit mask, frees the rest
- Writes format information into the selected mask

### Forced Mask

`QRcode_encodeMask()` accepts a `mask` parameter. When >= 0, it skips penalty evaluation and uses the specified mask directly:

```c
if(mask < 0) {
    masked = Mask_mask(width, frame, input->level);
} else {
    masked = Mask_makeMask(width, frame, mask, input->level);
}
```

`Mask_makeMask()` applies a single mask without evaluation:

```c
unsigned char *Mask_makeMask(int width, unsigned char *frame, int mask,
                              QRecLevel level)
{
    unsigned char *masked = (unsigned char *)malloc(width * width);
    maskMakers[mask](width, frame, masked);
    Mask_writeFormatInformation(width, masked, mask, level);
    return masked;
}
```

This is used by the test suite via `QRcode_encodeMask()` (exposed in `qrencode_inner.h`).

---

## Format Information Writing

`Mask_writeFormatInformation()` embeds the 15-bit format info (EC level + mask pattern) into the symbol at two fixed locations:

```c
void Mask_writeFormatInformation(int width, unsigned char *frame,
                                  int mask, QRecLevel level)
{
    unsigned int format;
    unsigned char v;
    int i;

    format = QRspec_getFormatInfo(mask, level);

    // Horizontal strip near top-left
    for(i = 0; i < 8; i++) {
        // ... write bits to specific positions around top-left finder ...
    }

    // Vertical strip near top-left and bottom-left
    for(i = 0; i < 7; i++) {
        // ... write bits to specific positions ...
    }
}
```

The format info is retrieved from the pre-computed `formatInfo[level][mask]` table (15-bit BCH code).

---

## Micro QR Code — 4 Mask Patterns

### Mask Definitions

From `mmask.c`, only 4 patterns:

```c
static int MMask_mask0(int width, const unsigned char *s, unsigned char *d)
{
    MASKMAKER(y % 2)
}

static int MMask_mask1(int width, const unsigned char *s, unsigned char *d)
{
    MASKMAKER(((y/2) + (x/3)) % 2)
}

static int MMask_mask2(int width, const unsigned char *s, unsigned char *d)
{
    MASKMAKER((((y*x) % 2) + ((y*x) % 3)) % 2)
}

static int MMask_mask3(int width, const unsigned char *s, unsigned char *d)
{
    MASKMAKER((((y+x) % 2) + ((y*x) % 3)) % 2)
}
```

Function pointer array:
```c
static MaskMaker *maskMakers[4] = {
    MMask_mask0, MMask_mask1, MMask_mask2, MMask_mask3
};
```

| Mask | Condition |
|---|---|
| 0 | `y % 2 == 0` |
| 1 | `(y/2 + x/3) % 2 == 0` |
| 2 | `((y*x)%2 + (y*x)%3) % 2 == 0` |
| 3 | `((y+x)%2 + (y*x)%3) % 2 == 0` |

### Micro QR Mask Evaluation

Micro QR uses a completely different scoring method. Instead of penalty rules, it maximizes a quality metric.

`MMask_evaluateSymbol()`:

```c
static int MMask_evaluateSymbol(int width, unsigned char *frame)
{
    int x, y;
    int sum1 = 0, sum2 = 0;

    // Sum of bottom row (last row, only data area)
    for(x = 1; x < width; x++) {
        if(frame[width * (width-1) + x] & 1) {
            sum1++;
        }
    }
    // Sum of rightmost column (only data area)
    for(y = 1; y < width; y++) {
        if(frame[y * width + (width-1)] & 1) {
            sum2++;
        }
    }

    return sum1 * 16 + sum2;
}
```

The score favors masks that produce more dark modules along the bottom row and right column. **Unlike full QR, higher scores are better.**

### Micro QR Mask Selection

`MMask_mask()`:

```c
unsigned char *MMask_mask(int version, unsigned char *frame, QRecLevel level)
{
    int width = MQRspec_getWidth(version);
    int i;
    unsigned char *mask, *bestMask = NULL;
    int maxScore = 0;
    int bestMaskNum = 0;
    int score;

    for(i = 0; i < 4; i++) {
        mask = (unsigned char *)malloc(width * width);
        maskMakers[i](width, frame, mask);
        score = MMask_evaluateSymbol(width, mask);

        if(score > maxScore) {  // Note: MAXIMUM, not minimum
            maxScore = score;
            free(bestMask);
            bestMask = mask;
            bestMaskNum = i;
        } else {
            free(mask);
        }
    }

    MMask_writeFormatInformation(version, bestMask, bestMaskNum, level);

    return bestMask;
}
```

### Micro QR Format Information

`MMask_writeFormatInformation()` writes a 15-bit format info in a single strip around the top-left finder pattern:

```c
void MMask_writeFormatInformation(int version, unsigned char *frame,
                                   int mask, QRecLevel level)
{
    unsigned int format;
    unsigned char v;
    int i;
    int width = MQRspec_getWidth(version);

    format = MQRspec_getFormatInfo(mask, version, level);

    for(i = 0; i < 8; i++) {
        v = 0x84 | (format & 1);
        frame[width * (i + 1) + 8] = v;  // left column
        format >>= 1;
    }
    for(i = 0; i < 7; i++) {
        v = 0x84 | (format & 1);
        frame[width * 8 + 7 - i] = v;    // top row
        format >>= 1;
    }
}
```

---

## Module Bit Flags

When placing modules, the frame builder uses bit flags to mark module types:

```c
// Bit 7 (0x80): Non-data module flag
// When set, masking skips this module
// Set on: finder pattern, separator, timing, alignment, version info, format info
```

In `MASKMAKER`, this check appears as:
```c
if(*s & 0x80) {
    *d = *s;      // copy as-is (non-data module)
} else {
    *d = *s ^ ((__exp__) == 0);  // apply mask
}
```

This ensures that only the data and ECC area is affected by masking.

---

## Integration with Encoding Pipeline

In `QRcode_encodeMask()` (from `qrencode.c`):

```c
QRcode *QRcode_encodeMask(QRinput *input, int mask)
{
    // ... setup ...

    // 1. Build frame with function patterns
    frame = QRspec_createFrame(version);

    // 2. Place data/ECC codewords via FrameFiller
    filler = FrameFiller_new(width, frame, 0);
    for(i = 0; i < raw->dataLength + raw->eccLength; i++) {
        code = QRraw_getCode(raw);
        bit = 0x80;
        for(j = 0; j < 8; j++) {
            p = FrameFiller_next(filler);
            if(p == NULL) goto EXIT;
            *p = 0x02 | ((bit & code) != 0);
            bit >>= 1;
        }
    }
    // ... remainder bits ...

    // 3. Apply mask
    if(mask < 0) {
        masked = Mask_mask(width, frame, input->level);
    } else {
        masked = Mask_makeMask(width, frame, mask, input->level);
    }

    // 4. Package result
    qrcode = QRcode_new(version, width, masked);
    // ...
}
```

The same flow applies for `QRcode_encodeMaskMQR()`, using `MMask_mask()` instead.
