1
0
Fork 0
mirror of https://git.code.sf.net/p/zint/code synced 2025-05-31 07:08:26 -04:00

CHANNEL: use nested loops (CHNCHK) and pre-calculated values for performance

This commit is contained in:
gitlost 2020-06-10 18:41:36 +01:00
parent 5875305cef
commit 3690c19749
8 changed files with 611 additions and 101 deletions
backend

View file

@ -97,16 +97,6 @@ static const char *C93Table[47] = {
"121221", "312111", "311121", "122211"
};
/* Global Variables for Channel Code */
static int S[11], B[11];
static long value;
static long target_value;
static char pattern[30];
/* Function Prototypes */
static void NextS(int Chan, int i, int MaxS, int MaxB);
static void NextB(int Chan, int i, int MaxB, int MaxS);
/* *********************** CODE 11 ******************** */
INTERNAL int code_11(struct zint_symbol *symbol, unsigned char source[], int length) { /* Code 11 */
@ -492,10 +482,46 @@ INTERNAL int c93(struct zint_symbol *symbol, unsigned char source[], int length)
return error_number;
}
/* NextS() and NextB() are from ANSI/AIM BC12-1998 and are Copyright (c) AIM 1997 */
typedef const struct s_channel_precalc {
long value; unsigned char B[8]; unsigned char S[8]; unsigned char bmax[7]; unsigned char smax[7];
} channel_precalc;
/* Their are used here on the understanding that they form part of the specification
for Channel Code and therefore their use is permitted under the following terms
//#define CHANNEL_GENERATE_PRECALCS
#ifdef CHANNEL_GENERATE_PRECALCS
/* To generate precalc tables uncomment define and run "./test_channel -f generate -g" and place result in "channel_precalcs.h" */
static void channel_generate_precalc(int channels, long value, int mod, int last, int B[8], int S[8], int bmax[7], int smax[7]) {
int i;
if (value == mod) printf("static channel_precalc channel_precalcs%d[] = {\n", channels);
printf(" { %7ld, {", value); for (i = 0; i < 8; i++) printf(" %d,", B[i]); printf(" },");
printf(" {"); for (i = 0; i < 8; i++) printf(" %d,", S[i]); printf(" },");
printf(" {"); for (i = 0; i < 7; i++) printf(" %d,", bmax[i]); printf(" },");
printf(" {"); for (i = 0; i < 7; i++) printf(" %d,", smax[i]); printf(" }, },\n");
if (value == last) printf("};\n");
}
#else
#include "channel_precalcs.h"
#endif
static long channel_copy_precalc(channel_precalc precalc, int B[8], int S[8], int bmax[7], int smax[7]) {
int i;
for (i = 0; i < 7; i++) {
B[i] = precalc.B[i];
S[i] = precalc.S[i];
bmax[i] = precalc.bmax[i];
smax[i] = precalc.smax[i];
}
B[7] = precalc.B[7];
S[7] = precalc.S[7];
return precalc.value;
}
/* CHNCHR is adapted from ANSI/AIM BC12-1998 Annex D Figure D5 and is Copyright (c) AIM 1997 */
/* It is used here on the understanding that it forms part of the specification
for Channel Code and therefore its use is permitted under the following terms
set out in that document:
"It is the intent and understanding of AIM [t]hat the symbology presented in this
@ -503,55 +529,89 @@ INTERNAL int c93(struct zint_symbol *symbol, unsigned char source[], int length)
licenses and fees. AIM USA, its member companies, or individual officers
assume no liability for the use of this document." */
static void CheckCharacter() {
static void CHNCHR(int channels, long 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) */
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, }, },
{ 0, { 1, 1, 1, 1, 2, 1, 1, 3, }, { 1, 1, 1, 1, 1, 1, 1, 4, }, { 1, 1, 1, 1, 4, 3, 3, }, { 1, 1, 1, 1, 4, 4, 4, }, },
{ 0, { 1, 1, 1, 2, 1, 1, 2, 3, }, { 1, 1, 1, 1, 1, 1, 1, 5, }, { 1, 1, 1, 5, 4, 4, 4, }, { 1, 1, 1, 5, 5, 5, 5, }, },
{ 0, { 1, 1, 2, 1, 1, 2, 1, 4, }, { 1, 1, 1, 1, 1, 1, 1, 6, }, { 1, 1, 6, 5, 5, 5, 4, }, { 1, 1, 6, 6, 6, 6, 6, }, },
{ 0, { 1, 2, 1, 1, 2, 1, 1, 5, }, { 1, 1, 1, 1, 1, 1, 1, 7, }, { 1, 7, 6, 6, 6, 5, 5, }, { 1, 7, 7, 7, 7, 7, 7, }, },
{ 0, { 2, 1, 1, 2, 1, 1, 2, 5, }, { 1, 1, 1, 1, 1, 1, 1, 8, }, { 8, 7, 7, 7, 6, 6, 6, }, { 8, 8, 8, 8, 8, 8, 8, }, },
};
int bmax[7], smax[7];
long value = 0;
if (value == target_value) {
int i;
/* Target reached - save the generated pattern */
strcpy(pattern, "11110");
for (i = 0; i < 11; i++) {
char part[3];
part[0] = itoc(S[i]);
part[1] = itoc(B[i]);
part[2] = '\0';
strcat(pattern, part);
}
channel_copy_precalc(initial_precalcs[channels - 3], B, S, bmax, smax);
#ifndef CHANNEL_GENERATE_PRECALCS
if (channels == 7 && target_value >= channel_precalcs7[0].value) {
value = channel_copy_precalc(channel_precalcs7[(target_value / channel_precalcs7[0].value) - 1], B, S, bmax, smax);
} else if (channels == 8 && target_value >= channel_precalcs8[0].value) {
value = channel_copy_precalc(channel_precalcs8[(target_value / channel_precalcs8[0].value) - 1], B, S, bmax, smax);
}
}
#endif
static void NextB(int Chan, int i, int MaxB, int MaxS) {
int b;
goto chkchr;
b = (S[i] + B[i - 1] + S[i - 1] + B[i - 2] > 4) ? 1 : 2;
if (i < Chan + 2) {
for (; b <= MaxB; b++) {
B[i] = b;
NextS(Chan, i + 1, MaxS, MaxB + 1 - b);
}
} else if (b <= MaxB) {
B[i] = MaxB;
CheckCharacter();
value++;
}
}
static void NextS(int Chan, int i, int MaxS, int MaxB) {
int s;
for (s = (i < Chan + 2) ? 1 : MaxS; s <= MaxS; s++) {
S[i] = s;
NextB(Chan, i, MaxB, MaxS + 1 - s);
}
ls0:smax[1] = smax[0] + 1 - S[0]; B[0] = 1;
if (S[0] == 1) goto nb0;
lb0: bmax[1] = bmax[0] + 1 - B[0]; S[1] = 1;
ls1: smax[2] = smax[1] + 1 - S[1]; B[1] = 1;
if (S[0] + B[0] + S[1] == 3) goto nb1;
lb1: bmax[2] = bmax[1] + 1 - B[1]; S[2] = 1;
ls2: smax[3] = smax[2] + 1 - S[2]; B[2] = 1;
if (B[0] + S[1] + B[1] + S[2] == 4) goto nb2;
lb2: bmax[3] = bmax[2] + 1 - B[2]; S[3] = 1;
ls3: smax[4] = smax[3] + 1 - S[3]; B[3] = 1;
if (B[1] + S[2] + B[2] + S[3] == 4) goto nb3;
lb3: bmax[4] = bmax[3] + 1 - B[3]; S[4] = 1;
ls4: smax[5] = smax[4] + 1 - S[4]; B[4] = 1;
if (B[2] + S[3] + B[3] + S[4] == 4) goto nb4;
lb4: bmax[5] = bmax[4] + 1 - B[4]; S[5] = 1;
ls5: smax[6] = smax[5] + 1 - S[5]; B[5] = 1;
if (B[3] + S[4] + B[4] + S[5] == 4) goto nb5;
lb5: bmax[6] = bmax[5] + 1 - B[5]; S[6] = 1;
ls6: S[7] = smax[6] + 1 - S[6]; B[6] = 1;
if (B[4] + S[5] + B[5] + S[6] == 4) goto nb6;
lb6: B[7] = bmax[6] + 1 - B[6];
if (B[5] + S[6] + B[6] + S[7] + B[7] == 5) goto nb6;
chkchr:
#ifdef CHANNEL_GENERATE_PRECALCS
if (channels == 7 && value && value % 115338 == 0) { /* 115338 == (576688 + 2) / 5 */
channel_generate_precalc(channels, value, 115338, 115338 * (5 - 1), B, S, bmax, smax);
} else if (channels == 8 && value && value % 119121 == 0) { /* 119121 == (7742862 + 3) / 65 */
channel_generate_precalc(channels, value, 119121, 119121 * (65 - 1), B, S, bmax, smax);
}
#endif
if (value == target_value) return;
value++;
nb6: if (++B[6] <= bmax[6]) goto lb6;
if (++S[6] <= smax[6]) goto ls6;
nb5: if (++B[5] <= bmax[5]) goto lb5;
if (++S[5] <= smax[5]) goto ls5;
nb4: if (++B[4] <= bmax[4]) goto lb4;
if (++S[4] <= smax[4]) goto ls4;
nb3: if (++B[3] <= bmax[3]) goto lb3;
if (++S[3] <= smax[3]) goto ls3;
nb2: if (++B[2] <= bmax[2]) goto lb2;
if (++S[2] <= smax[2]) goto ls2;
nb1: if (++B[1] <= bmax[1]) goto lb1;
if (++S[1] <= smax[1]) goto ls1;
nb0: if (++B[0] <= bmax[0]) goto lb0;
if (++S[0] <= smax[0]) goto ls0;
}
/* Channel Code - According to ANSI/AIM BC12-1998 */
INTERNAL int channel_code(struct zint_symbol *symbol, unsigned char source[], int length) {
int S[8] = {0}, B[8] = {0};
long target_value = 0;
char pattern[30];
int channels, i;
int error_number = 0, range = 0, zeroes;
int error_number, range = 0, zeroes;
char hrt[9];
target_value = 0;
if (length > 7) {
strcpy(symbol->errtxt, "333: Input too long");
return ZINT_ERROR_TOO_LONG;
@ -567,18 +627,30 @@ INTERNAL int channel_code(struct zint_symbol *symbol, unsigned char source[], in
} else {
channels = symbol->option_2;
}
if (channels == 0) {
channels = length + 1;
}
if (channels == 2) {
channels = 3;
}
for (i = 0; i < length; i++) {
target_value *= 10;
target_value += ctoi((char) source[i]);
}
if (channels == 0) {
channels = length + 1;
if (target_value > 576688 && channels < 8) {
channels = 8;
} else if (target_value > 44072 && channels < 7) {
channels = 7;
} else if (target_value > 3493 && channels < 6) {
channels = 6;
} else if (target_value > 292 && channels < 5) {
channels = 5;
} else if (target_value > 26 && channels < 4) {
channels = 4;
}
}
if (channels == 2) {
channels = 3;
}
switch (channels) {
case 3: if (target_value > 26) {
range = 1;
@ -610,14 +682,16 @@ INTERNAL int channel_code(struct zint_symbol *symbol, unsigned char source[], in
return ZINT_ERROR_INVALID_DATA;
}
for (i = 0; i < 11; i++) {
B[i] = 0;
S[i] = 0;
}
CHNCHR(channels, target_value, B, S);
B[0] = S[1] = B[1] = S[2] = B[2] = 1;
value = 0;
NextS(channels, 3, channels, channels);
strcpy(pattern, "111111111"); /* Finder pattern */
for (i = 8 - channels; i < 8; i++) {
char part[3];
part[0] = itoc(S[i]);
part[1] = itoc(B[i]);
part[2] = '\0';
strcat(pattern, part);
}
zeroes = channels - 1 - length;
if (zeroes < 0) {
@ -632,7 +706,6 @@ INTERNAL int channel_code(struct zint_symbol *symbol, unsigned char source[], in
return error_number;
}
/* Vehicle Identification Number (VIN) */
INTERNAL int vin(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length) {