1
0
mirror of https://git.code.sf.net/p/zint/code synced 2026-01-11 22:16:02 +00:00

QRCODE: implement pre-calculated QR/MICROQR masks ala BWIPP for a

slight performance gain (2-3%), see
  https://sourceforge.net/p/zint/mailman/message/59278637/
  - generated by "backend/tools/gen_qr_masks.php"
test suite: update BWIPP to latest
This commit is contained in:
gitlost
2026-01-06 11:50:06 +00:00
parent 973594a624
commit 64aa8e654c
5 changed files with 138 additions and 62 deletions

View File

@@ -1,7 +1,7 @@
/* channel.c - Handles Channel */
/*
libzint - the open source barcode library
Copyright (C) 2008-2025 Robin Stuart <rstuart114@gmail.com>
Copyright (C) 2008-2026 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@@ -87,7 +87,8 @@ static int channel_copy_precalc(channel_precalc *const precalc, int B[8], int S[
assume no liability for the use of this document." */
static void CHNCHR(int channels, int target_value, int B[8], int S[8]) {
/* Use of initial pre-calculations taken from Barcode Writer in Pure PostScript (BWIPP)
* Copyright (c) 2004-2020 Terry Burton (MIT/X-Consortium license) */
Copyright (c) 2004-2026 Terry Burton */
/* SPDX-License-Identifier: MIT */
static channel_precalc initial_precalcs[6] = {
{ 0, { 1, 1, 1, 1, 1, 2, 1, 2, }, { 1, 1, 1, 1, 1, 1, 1, 3, }, { 1, 1, 1, 1, 1, 3, 2, },
{ 1, 1, 1, 1, 1, 3, 3, }, },

View File

@@ -1,7 +1,7 @@
/* qr.c Handles QR Code, Micro QR Code, UPNQR and rMQR */
/*
libzint - the open source barcode library
Copyright (C) 2009-2025 Robin Stuart <rstuart114@gmail.com>
Copyright (C) 2009-2026 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@@ -1003,7 +1003,7 @@ static void qr_populate_grid(unsigned char *grid, const int h_size, const int v_
i = 0;
while (i < n) {
int x = x_start - (row * 2);
int r = y * h_size;
const int r = y * h_size;
if (x < 6 && not_rmqr)
x--; /* skip over vertical timing pattern */
@@ -1308,11 +1308,11 @@ static void qr_add_format_info(unsigned char *grid, const int size, const int ec
static int qr_apply_bitmask(unsigned char *grid, const int size, const int ecc_level, const int user_mask,
const int fast_encode, const int debug_print) {
int x, y;
int r, k;
int k;
int bit;
int pattern, penalty[8];
int best_pattern;
int size_squared = size * size;
const int size_squared = size * size;
unsigned char *mask = (unsigned char *) z_alloca(size_squared);
unsigned char *local = (unsigned char *) z_alloca(size_squared);
#ifdef ZINTLOG
@@ -1322,41 +1322,13 @@ static int qr_apply_bitmask(unsigned char *grid, const int size, const int ecc_l
/* Perform data masking */
memset(mask, 0, size_squared);
for (y = 0; y < size; y++) {
r = y * size;
const int ymod = y % 12;
const int r = y * size;
for (x = 0; x < size; x++) {
/* all eight bitmask variants are encoded in the 8 bits of the bytes that make up the mask array. */
if (!(grid[r + x] & 0xF0)) { /* exclude areas not to be masked. */
if (((y + x) & 1) == 0) {
mask[r + x] |= 0x01;
}
if (!fast_encode) {
if ((y & 1) == 0) {
mask[r + x] |= 0x02;
}
}
if (x % 3 == 0) {
mask[r + x] |= 0x04;
}
if (!fast_encode) {
if ((y + x) % 3 == 0) {
mask[r + x] |= 0x08;
}
}
if (((y / 2 + x / 3) & 1) == 0) {
mask[r + x] |= 0x10;
}
if (!fast_encode) {
if ((y * x) % 6 == 0) { /* Equivalent to (y * x) % 2 + (y * x) % 3 == 0 */
mask[r + x] |= 0x20;
}
if (((((y * x) & 1) + (y * x) % 3) & 1) == 0) {
mask[r + x] |= 0x40;
}
}
if (((((y + x) & 1) + (y * x) % 3) & 1) == 0) {
mask[r + x] |= 0x80;
}
/* All eight bitmask variants are encoded in the 8 bits of the bytes that make up the mask array. */
if (!(grid[r + x] & 0xF0)) { /* Exclude areas not to be masked. */
mask[r + x] = qr_masks[ymod][x % 6]; /* Pre-calculated table ala BWIPP, see "qr.h" */
}
}
}
@@ -1364,7 +1336,7 @@ static int qr_apply_bitmask(unsigned char *grid, const int size, const int ecc_l
if (user_mask) {
best_pattern = user_mask - 1;
} else {
/* all eight bitmask variants have been encoded in the 8 bits of the bytes
/* All eight bitmask variants have been encoded in the 8 bits of the bytes
* that make up the mask array. select them for evaluation according to the
* desired pattern.*/
best_pattern = 0;
@@ -1854,7 +1826,7 @@ INTERNAL int zint_qrcode(struct zint_symbol *symbol, struct zint_seg segs[], con
symbol->rows = size;
for (i = 0; i < size; i++) {
int r = i * size;
const int r = i * size;
for (j = 0; j < size; j++) {
if (grid[r + j] & 0x01) {
z_set_module(symbol, i, j);
@@ -1981,11 +1953,10 @@ static void microqr_setup_grid(unsigned char *grid, const int size) {
/* Reserve space for format information */
for (i = 0; i < 8; i++) {
for (i = 1; i <= 8; i++) {
grid[(8 * size) + i] |= 0x20;
grid[(i * size) + 8] |= 0x20;
}
grid[(8 * size) + 8] |= 20;
}
static void microqr_populate_grid(unsigned char *grid, const int size, const char full_stream[], int bp) {
@@ -2063,36 +2034,23 @@ static int microqr_evaluate(const unsigned char *grid, const int size, const int
static int microqr_apply_bitmask(unsigned char *grid, const int size, const int user_mask, const int debug_print) {
int x, y;
int r, k;
int k;
int bit;
int pattern, value[4];
int best_pattern;
int size_squared = size * size;
const int size_squared = size * size;
unsigned char *mask = (unsigned char *) z_alloca(size_squared);
unsigned char *eval = (unsigned char *) z_alloca(size_squared);
/* Perform data masking */
memset(mask, 0, size_squared);
for (y = 0; y < size; y++) {
r = y * size;
const int ymod = y % 12;
const int r = y * size;
for (x = 0; x < size; x++) {
if (!(grid[r + x] & 0xF0)) {
if ((y & 1) == 0) {
mask[r + x] |= 0x01;
}
if (((y / 2 + x / 3) & 1) == 0) {
mask[r + x] |= 0x02;
}
if (((((y * x) & 1) + (y * x) % 3) & 1) == 0) {
mask[r + x] |= 0x04;
}
if (((((y + x) & 1) + (y * x) % 3) & 1) == 0) {
mask[r + x] |= 0x08;
}
mask[r + x] = microqr_masks[ymod][x % 6]; /* Pre-calculated table ala BWIPP, see "qr.h" */
}
}
}

View File

@@ -1,7 +1,7 @@
/* qr.h Data for QR Code, Micro QR Code and rMQR */
/*
libzint - the open source barcode library
Copyright (C) 2008-2024 Robin Stuart <rstuart114@gmail.com>
Copyright (C) 2008-2026 Robin Stuart <rstuart114@gmail.com>
Copyright (C) 2006 Kentaro Fukuchi <fukuchi@megaui.net>
Redistribution and use in source and binary forms, with or without
@@ -335,5 +335,42 @@ static const unsigned int rmqr_format_info_right[64] = {
0x1CFB4, 0x1D091, 0x1EEDB, 0x1F1FE
};
/* Pre-calculated QR and MicroQR mask tables, generated by "backend/tools/gen_qr_masks.php",
based on lowest common periodicy of the masks (6x12):
QR: 000: 2x2, 001: 1x2, 010: 3x1, 011: 3x3, 100: 6x4, 101: 6x6, 110: 6x6, 111: 6x6
MicroQR: 00 (001), 01 (100), 10 (110), 11 (111)
Taken from Barcode Writer in Pure PostScript (BWIPP)
Copyright (c) 2004-2026 Terry Burton */
/* SPDX-License-Identifier: MIT */
static const unsigned char qr_masks[12][6] = {
{ 0xFF, 0x72, 0xF3, 0x6E, 0xE3, 0x62 },
{ 0x74, 0x51, 0x58, 0x85, 0x80, 0x89 },
{ 0xE7, 0x4A, 0x03, 0x76, 0xDB, 0x92 },
{ 0x6C, 0x81, 0x60, 0x9D, 0x70, 0x91 },
{ 0xF7, 0x92, 0xDB, 0x66, 0x03, 0x4A },
{ 0x74, 0x99, 0x90, 0x85, 0x48, 0x41 },
{ 0xEF, 0x62, 0xE3, 0x7E, 0xF3, 0x72 },
{ 0x64, 0x41, 0x48, 0x95, 0x90, 0x99 },
{ 0xF7, 0x5A, 0x13, 0x66, 0xCB, 0x82 },
{ 0x7C, 0x91, 0x70, 0x8D, 0x60, 0x81 },
{ 0xE7, 0x82, 0xCB, 0x76, 0x13, 0x5A },
{ 0x64, 0x89, 0x80, 0x95, 0x58, 0x51 }
};
static const unsigned char microqr_masks[12][6] = {
{ 0x0F, 0x07, 0x0F, 0x05, 0x0D, 0x05 },
{ 0x06, 0x06, 0x06, 0x08, 0x08, 0x08 },
{ 0x0D, 0x05, 0x01, 0x07, 0x0F, 0x0B },
{ 0x04, 0x08, 0x04, 0x0A, 0x06, 0x0A },
{ 0x0F, 0x0B, 0x0F, 0x05, 0x01, 0x05 },
{ 0x06, 0x0A, 0x0A, 0x08, 0x04, 0x04 },
{ 0x0D, 0x05, 0x0D, 0x07, 0x0F, 0x07 },
{ 0x04, 0x04, 0x04, 0x0A, 0x0A, 0x0A },
{ 0x0F, 0x07, 0x03, 0x05, 0x0D, 0x09 },
{ 0x06, 0x0A, 0x06, 0x08, 0x04, 0x08 },
{ 0x0D, 0x09, 0x0D, 0x07, 0x03, 0x07 },
{ 0x04, 0x08, 0x08, 0x0A, 0x06, 0x06 }
};
/* vim: set ts=4 sw=4 et : */
#endif /* Z_QR_H */

View File

@@ -0,0 +1,80 @@
<?php
/* Generate pre-calculated `qr_masks[]` for "qr.h" */
/*
libzint - the open source barcode library
Copyright (C) 2026 Robin Stuart <rstuart114@gmail.com>
*/
/* SPDX-License-Identifier: BSD-3-Clause */
/* Taken from Barcode Writer in Pure PostScript (BWIPP)
Copyright (c) 2004-2026 Terry Burton */
/* SPDX-License-Identifier: MIT */
/* See https://sourceforge.net/p/zint/mailman/message/59278637/
and https://github.com/bwipp/postscriptbarcode/commit/763fb4ffbfad7b379723dd3570183c769b28c786
and "Pre-calculated QR and MicroQR tables" comment in "qr.h"
Paste output after comment
*/
$qr_masks = array();
$mqr_masks = array();
for ($y = 0; $y < 12; $y++) {
for ($x = 0; $x < 6; $x++) {
$bits = 0;
$mbits = 0;
if (($y + $x) % 2 === 0) { /* QR 000, period 2x2 */
$bits |= 0x01;
}
if ($y % 2 === 0) { /* QR 001, MicroQR 00, period 1x2 */
$bits |= 0x02;
$mbits |= 0x01;
}
if ($x % 3 === 0) { /* QR 010, period 3x1 */
$bits |= 0x04;
}
if (($y + $x) % 3 === 0) { /* QR 011, period 3x3 */
$bits |= 0x08;
}
if (((int)($y / 2) + (int)($x / 3)) % 2 === 0) { /* QR 100, MicroQR 01, period 6x4 */
$bits |= 0x10;
$mbits |= 0x02;
}
if ((($y * $x) % 2 + ($y * $x) % 3) === 0) { /* QR 101, period 6x6 */
$bits |= 0x20;
}
if ((($y * $x) % 2 + ($y * $x) % 3) % 2 === 0) { /* QR 110, MicroQR 10, period 6x6 */
$bits |= 0x40;
$mbits |= 0x04;
}
if ((($y + $x) % 2 + ($y * $x) % 3) % 2 === 0) { /* QR 111, MicroQR 11, period 6x6 */
$bits |= 0x80;
$mbits |= 0x08;
}
$qr_masks[$y][$x] = $bits;
$mqr_masks[$y][$x] = $mbits;
}
}
printf("static const unsigned char qr_masks[12][6] = {\n");
for ($y = 0; $y < 12; $y++) {
printf(" { ");
for ($x = 0; $x < 6; $x++) {
printf("0x%02X%s", $qr_masks[$y][$x], $x == 5 ? " " : ", ");
}
printf("}%s\n", $y == 11 ? "" : ",");
}
printf("};\n");
printf("\nstatic const unsigned char microqr_masks[12][6] = {\n");
for ($y = 0; $y < 12; $y++) {
printf(" { ");
for ($x = 0; $x < 6; $x++) {
printf("0x%02X%s", $mqr_masks[$y][$x], $x == 5 ? " " : ", ");
}
printf("}%s\n", $y == 11 ? "" : ",");
}
printf("};\n");
/* vim: set ts=4 sw=4 et : */