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:
parent
5875305cef
commit
3690c19749
8 changed files with 611 additions and 101 deletions
backend
203
backend/code.c
203
backend/code.c
|
@ -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) {
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue