PDF417 enhancements:

- Switched mode selection to better optimized method listed in Appendix D of the AIM PDF417 specification.
- Removed extraneous text latch after a byte shift.
- Removed invalid numeric->byte shift transitions.
This commit is contained in:
Jeff Skaistis 2022-08-10 13:40:40 -05:00
parent c0ec67f99e
commit e8a125a2e1
3 changed files with 124 additions and 123 deletions

View File

@ -328,7 +328,7 @@ static void cc_b(struct zint_symbol *symbol, const char source[], const int cc_w
chainemc[mclength] = 920; chainemc[mclength] = 920;
mclength++; mclength++;
pdf_byteprocess(chainemc, &mclength, data_string, 0, length, debug_print); pdf_byteprocess(chainemc, &mclength, data_string, 0, length, 0, debug_print);
/* Now figure out which variant of the symbol to use and load values accordingly */ /* Now figure out which variant of the symbol to use and load values accordingly */
@ -547,7 +547,7 @@ static void cc_c(struct zint_symbol *symbol, const char source[], const int cc_w
chainemc[mclength] = 920; /* CC-C identifier */ chainemc[mclength] = 920; /* CC-C identifier */
mclength++; mclength++;
pdf_byteprocess(chainemc, &mclength, data_string, 0, length, debug_print); pdf_byteprocess(chainemc, &mclength, data_string, 0, length, 0, debug_print);
chainemc[0] = mclength; chainemc[0] = mclength;

View File

@ -106,127 +106,100 @@ static int pdf_quelmode(const unsigned char codeascii) {
return BYT; return BYT;
} }
/* 844 */ static int pdf_text_num_length(int liste[2][PDF_MAX_LEN], int* indexliste, const int start)
static void pdf_regroupe(int liste[2][PDF_MAX_LEN], int *indexliste) { {
/* check consecutive segments for text/num and return the length */
int i, len = 0;
for (i = start; i < *(indexliste); i++) {
if (liste[1][i] == BYT)
break;
/* bring together same type blocks */ len += liste[0][i];
if (*(indexliste) > 1) { if (len >= 5) /* we don't care if it's longer than 5 */
int i = 1; break;
while (i < *(indexliste)) {
if (liste[1][i - 1] == liste[1][i]) {
int j;
/* bring together */
liste[0][i - 1] = liste[0][i - 1] + liste[0][i];
j = i + 1;
/* decrease the list */
while (j < *(indexliste)) {
liste[0][j - 1] = liste[0][j];
liste[1][j - 1] = liste[1][j];
j++;
}
*(indexliste) = *(indexliste) - 1;
i--;
}
i++;
}
} }
/* 865 */
return len;
} }
/* 478 */ /* Pack segments using the method described in Appendix D of the AIM specification */
static void pdf_smooth(int liste[2][PDF_MAX_LEN], int *indexliste) { static void pdf_appendix_d_encode(int liste[2][PDF_MAX_LEN], int* indexliste, const int debug_print) {
int i, crnt, last, next, length; int i = 0, next, last = 0, stayintext = 0;
for (i = 0; i < *(indexliste); i++) { while (i < *(indexliste)) {
crnt = liste[1][i]; if (debug_print) {
length = liste[0][i]; printf("Encoding block %d = %d (%d)\n", i, liste[1][i], liste[0][i]);
if (i != 0) {
last = liste[1][i - 1];
} else {
last = 0;
}
if (i != *(indexliste) - 1) {
next = liste[1][i + 1];
} else {
next = 0;
} }
if (crnt == NUM) { if ((liste[1][i] == NUM) && (liste[0][i] >= 13)) {
if (i == 0) { /* leave as numeric */
/* first block */ liste[0][last] = liste[0][i];
if (*(indexliste) > 1) { liste[1][last] = NUM;
/* and there are others */ stayintext = 0;
if ((next == TEX) && (length < 8)) { last++;
liste[1][i] = TEX; } else if (((liste[1][i] == TEX) || (liste[1][i] == NUM)) &&
} else if ((next == BYT) && (length == 1)) { (stayintext || (liste[0][i] >= 5) || (pdf_text_num_length(liste, indexliste, i) >= 5))) {
liste[1][i] = BYT; /* set to text and combine additional text/short numeric segments */
} liste[0][last] = liste[0][i];
liste[1][last] = TEX;
stayintext = 0;
next = i + 1;
while (next < *(indexliste)) {
if ((liste[1][next] == NUM) && (liste[0][next] >= 13)) {
break;
} }
} else { else if (liste[1][next] == BYT) {
if (i == *(indexliste) - 1) { break;
/* last block */
if ((last == TEX) && (length < 7)) {
liste[1][i] = TEX;
} else if ((last == BYT) && (length == 1)) {
liste[1][i] = BYT;
}
} else {
/* not first or last block */
if (((last == BYT) && (next == BYT)) && (length < 4)) {
liste[1][i] = BYT;
} else if (((last == BYT) && (next == TEX)) && (length < 4)) {
liste[1][i] = TEX;
} else if (((last == TEX) && (next == BYT)) && (length < 5)) {
liste[1][i] = TEX;
} else if (((last == TEX) && (next == TEX)) && (length < 8)) {
liste[1][i] = TEX;
}
} }
liste[0][last] += liste[0][next];
next++;
} }
}
} last++;
pdf_regroupe(liste, indexliste); i = next;
/* 520 */ continue;
for (i = 0; i < *(indexliste); i++) {
crnt = liste[1][i];
length = liste[0][i];
if (i != 0) {
last = liste[1][i - 1];
} else { } else {
last = 0; /* build byte segment, including combining numeric/text segments that aren't long enough on their own */
} liste[0][last] = liste[0][i];
if (i != *(indexliste) - 1) { liste[1][last] = BYT;
next = liste[1][i + 1]; stayintext = 0;
} else {
next = 0; next = i + 1;
while (next < *(indexliste)) {
if (liste[1][next] != BYT) {
/* check for case of a single byte shift from text mode */
if ((liste[0][last] == 1) && (last > 0) && (liste[1][last - 1] == TEX)) {
stayintext = 1;
break;
}
if ((liste[0][next] >= 5) || (pdf_text_num_length(liste, indexliste, next) >= 5)) {
break;
}
}
liste[0][last] += liste[0][next];
next++;
}
last++;
i = next;
continue;
} }
if ((crnt == TEX) && (i > 0)) { i++;
/* not the first */
if (i == *(indexliste) - 1) {
/* the last one */
if ((last == BYT) && (length == 1)) {
liste[1][i] = BYT;
}
} else {
/* not the last one */
if (((last == BYT) && (next == BYT)) && (length < 5)) {
liste[1][i] = BYT;
} else if ((((last == BYT) && (next != BYT)) || ((last != BYT) && (next == BYT))) && (length < 3)) {
liste[1][i] = BYT;
}
}
}
} }
/* 540 */
pdf_regroupe(liste, indexliste); /* set the size of the list based on the last consolidated segment */
*indexliste = last;
} }
/* 547 */ /* 547 */
static void pdf_textprocess(int *chainemc, int *mclength, const unsigned char chaine[], int start, const int length, static void pdf_textprocess(int *chainemc, int *mclength, const unsigned char chaine[], int start, const int length,
const int is_micro) { const int lastmode, int *curtable) {
int j, indexlistet, curtable, listet[2][PDF_MAX_LEN] = {{0}}, chainet[PDF_MAX_LEN], wnet; int j, indexlistet, listet[2][PDF_MAX_LEN] = {{0}}, chainet[PDF_MAX_LEN], wnet;
wnet = 0; wnet = 0;
@ -238,9 +211,12 @@ static void pdf_textprocess(int *chainemc, int *mclength, const unsigned char ch
} }
/* 570 */ /* 570 */
curtable = 1; /* default table */ if (lastmode != TEX) {
*curtable = 1; /* set default table upper alpha */
}
for (j = 0; j < length; j++) { for (j = 0; j < length; j++) {
if (listet[0][j] & curtable) { if (listet[0][j] & *curtable) {
/* The character is in the current table */ /* The character is in the current table */
chainet[wnet++] = listet[1][j]; chainet[wnet++] = listet[1][j];
} else { } else {
@ -248,7 +224,7 @@ static void pdf_textprocess(int *chainemc, int *mclength, const unsigned char ch
int newtable; int newtable;
if (j == (length - 1) || !(listet[0][j] & listet[0][j + 1])) { if (j == (length - 1) || !(listet[0][j] & listet[0][j + 1])) {
/* we change only one character - look for temporary switch */ /* we change only one character - look for temporary switch */
if ((listet[0][j] & 1) && (curtable == 2)) { /* T_UPP */ if ((listet[0][j] & 1) && (*curtable == 2)) { /* T_UPP */
chainet[wnet++] = 27; chainet[wnet++] = 27;
chainet[wnet++] = listet[1][j]; chainet[wnet++] = listet[1][j];
continue; continue;
@ -274,7 +250,7 @@ static void pdf_textprocess(int *chainemc, int *mclength, const unsigned char ch
} }
/* 619 - select the switch */ /* 619 - select the switch */
switch (curtable) { switch (*curtable) {
case 1: case 1:
switch (newtable) { switch (newtable) {
case 2: chainet[wnet++] = 27; case 2: chainet[wnet++] = 27;
@ -321,7 +297,7 @@ static void pdf_textprocess(int *chainemc, int *mclength, const unsigned char ch
} }
break; break;
} }
curtable = newtable; *curtable = newtable;
/* 659 - at last we add the character */ /* 659 - at last we add the character */
chainet[wnet++] = listet[1][j]; chainet[wnet++] = listet[1][j];
} }
@ -333,9 +309,8 @@ static void pdf_textprocess(int *chainemc, int *mclength, const unsigned char ch
} }
/* Now translate the string chainet into codewords */ /* Now translate the string chainet into codewords */
/* Default mode for PDF417 is Text Compaction Alpha (ISO/IEC 1543:2015 5.4.2.1), and for MICROPDF417 is Byte /* add mode indicator if needed */
* Compaction (ISO/IEC 24728:2006 5.4.3), so only add flag if not first codeword or is MICROPDF417 */ if (lastmode != TEX) {
if (*mclength > 1 || is_micro) {
chainemc[(*mclength)++] = 900; chainemc[(*mclength)++] = 900;
} }
@ -347,15 +322,16 @@ static void pdf_textprocess(int *chainemc, int *mclength, const unsigned char ch
/* 671 */ /* 671 */
INTERNAL void pdf_byteprocess(int *chainemc, int *mclength, const unsigned char chaine[], int start, const int length, INTERNAL void pdf_byteprocess(int *chainemc, int *mclength, const unsigned char chaine[], int start, const int length,
const int debug_print) { const int lastmode, const int debug_print) {
if (debug_print) printf("\nEntering byte mode at position %d\n", start); if (debug_print) printf("\nEntering byte mode at position %d\n", start);
if (length == 1) { if (length == 1) {
chainemc[(*mclength)++] = 913; /* shift or latch depending on previous mode */
chainemc[(*mclength)++] = (lastmode == TEX) ? 913 : 901;
chainemc[(*mclength)++] = chaine[start]; chainemc[(*mclength)++] = chaine[start];
if (debug_print) { if (debug_print) {
printf("913 %d\n", chainemc[*mclength - 1]); printf("%s %d\n", (lastmode == TEX) ? "913" : "901", chaine[start]);
} }
} else { } else {
int len; int len;
@ -458,7 +434,7 @@ static void pdf_numbprocess(int *chainemc, int *mclength, const unsigned char ch
/* Initial processing of data, shared by `pdf417()` and `micropdf417()` */ /* Initial processing of data, shared by `pdf417()` and `micropdf417()` */
static int pdf_initial(struct zint_symbol *symbol, unsigned char chaine[], const int length, const int eci, static int pdf_initial(struct zint_symbol *symbol, unsigned char chaine[], const int length, const int eci,
const int is_micro, int chainemc[PDF_MAX_LEN], int *p_mclength) { const int is_micro, int chainemc[PDF_MAX_LEN], int *p_mclength) {
int i, indexchaine, indexliste, mode; int i, indexchaine, indexliste, mode, currenttext;
int liste[2][PDF_MAX_LEN] = {{0}}; int liste[2][PDF_MAX_LEN] = {{0}};
int mclength; int mclength;
const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
@ -480,11 +456,27 @@ static int pdf_initial(struct zint_symbol *symbol, unsigned char chaine[], const
indexliste++; indexliste++;
} while (indexchaine < length); } while (indexchaine < length);
/* 474 */ if (debug_print) {
pdf_smooth(liste, &indexliste); printf("\r\nInitial block pattern:\n");
for (i = 0; i < indexliste; i++) {
printf("Len: %d Type: ", liste[0][i]);
switch (liste[1][i]) {
case TEX: printf("Text\n");
break;
case BYT: printf("Byte\n");
break;
case NUM: printf("Number\n");
break;
default: printf("ERROR\n"); /* Should never happen */ /* Not reached */
break;
}
}
}
pdf_appendix_d_encode(liste, &indexliste, debug_print);
if (debug_print) { if (debug_print) {
printf("Initial block pattern:\n"); printf("\r\nCompacted block pattern:\n");
for (i = 0; i < indexliste; i++) { for (i = 0; i < indexliste; i++) {
printf("Len: %d Type: ", liste[0][i]); printf("Len: %d Type: ", liste[0][i]);
switch (liste[1][i]) { switch (liste[1][i]) {
@ -530,16 +522,25 @@ static int pdf_initial(struct zint_symbol *symbol, unsigned char chaine[], const
} }
} }
/* Default mode for PDF417 is Text Compaction Alpha (ISO/IEC 1543:2015 5.4.2.1), and for MICROPDF417 is Byte
* Compaction (ISO/IEC 24728:2006 5.4.3) */
mode = is_micro ? BYT : TEX;
currenttext = 1; /* Start in upper alpha - tracked across calls to pdf_textprocess to allow for interleaving byte shifts */
for (i = 0; i < indexliste; i++) { for (i = 0; i < indexliste; i++) {
switch (liste[1][i]) { switch (liste[1][i]) {
case TEX: /* 547 - text mode */ case TEX: /* 547 - text mode */
pdf_textprocess(chainemc, &mclength, chaine, indexchaine, liste[0][i], is_micro); pdf_textprocess(chainemc, &mclength, chaine, indexchaine, liste[0][i], mode, &currenttext);
mode = TEX;
break; break;
case BYT: /* 670 - octet stream mode */ case BYT: /* 670 - octet stream mode */
pdf_byteprocess(chainemc, &mclength, chaine, indexchaine, liste[0][i], debug_print); pdf_byteprocess(chainemc, &mclength, chaine, indexchaine, liste[0][i], mode, debug_print);
if (mode != TEX || liste[0][i] != 1) { /* don't switch mode on single byte shift from text mode */
mode = BYT;
}
break; break;
case NUM: /* 712 - numeric mode */ case NUM: /* 712 - numeric mode */
pdf_numbprocess(chainemc, &mclength, chaine, indexchaine, liste[0][i]); pdf_numbprocess(chainemc, &mclength, chaine, indexchaine, liste[0][i]);
mode = NUM;
break; break;
} }
indexchaine = indexchaine + liste[0][i]; indexchaine = indexchaine + liste[0][i];

View File

@ -57,7 +57,7 @@ INTERNAL_DATA_EXTERN const unsigned short pdf_rap_side[52];
INTERNAL_DATA_EXTERN const unsigned short pdf_rap_centre[52]; INTERNAL_DATA_EXTERN const unsigned short pdf_rap_centre[52];
INTERNAL void pdf_byteprocess(int *chainemc, int *mclength, const unsigned char chaine[], int start, const int length, INTERNAL void pdf_byteprocess(int *chainemc, int *mclength, const unsigned char chaine[], int start, const int length,
const int debug); const int lastmode, const int debug);
/* vim: set ts=4 sw=4 et : */ /* vim: set ts=4 sw=4 et : */
#endif /* Z_PDF417_H */ #endif /* Z_PDF417_H */