/*! * barcodeDecode39() * * Input: barstr (of widths, in set {1, 2}) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/Code39 * http://morovia.com/education/symbology/code39.asp * (2) Each symbol has 5 black and 4 white bars. * The start and stop codes are 121121211 (the asterisk) * (3) This decoder was contributed by Roger Hyde. */ static char * barcodeDecode39(char *barstr, l_int32 debugflag) { char *data, *vbarstr; char code[10]; l_int32 valid, reverse, i, j, len, error, nsymb, start, found; PROCNAME("barcodeDecode39"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format; reverse if necessary */ barcodeVerifyFormat(barstr, L_BF_CODE39, &valid, &reverse); if (!valid) return (char *)ERROR_PTR("barstr not in code39 format", procName, NULL); if (reverse) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Verify size */ len = strlen(vbarstr); if ((len + 1) % 10 != 0) return (char *)ERROR_PTR("size+1 not divisible by 10: invalid code 39", procName, NULL); /* Decode the symbols */ nsymb = (len - 19) / 10; data = (char *)LEPT_CALLOC(nsymb + 1, sizeof(char)); memset(code, 0, 10); error = FALSE; for (i = 0; i < nsymb; i++) { start = 10 + 10 * i; for (j = 0; j < 9; j++) code[j] = vbarstr[start + j]; if (debugflag) fprintf(stderr, "code: %s\n", code); found = FALSE; for (j = 0; j < C39_START; j++) { if (!strcmp(code, Code39[j])) { data[i] = Code39Val[j]; found = TRUE; break; } } if (!found) error = TRUE; } LEPT_FREE(vbarstr); if (error) { LEPT_FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } return data; }
/*! * barcodeDecode2of5() * * Input: barstr (of widths, in set {1, 2}) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/Two-out-of-five_code (Note: * the codes given here are wrong!) * http://morovia.com/education/symbology/code25.asp * (2) This is a very low density encoding for the 10 digits. * Each digit is encoded with 5 black bars, of which 2 are wide * and 3 are narrow. No information is carried in the spaces * between the bars, which are all equal in width, represented by * a "1" in our encoding. * (3) The mapping from the sequence of five bar widths to the * digit is identical to the mapping used by the interleaved * 2 of 5 code. The start code is 21211, representing two * wide bars and a narrow bar, and the interleaved "1" spaces * are explicit. The stop code is 21112. For all codes * (including start and stop), the trailing space "1" is * implicit -- there is no reason to represent it in the * Code2of5[] array. */ static char * barcodeDecode2of5(char *barstr, l_int32 debugflag) { char *data, *vbarstr; char code[10]; l_int32 valid, reverse, i, j, len, error, ndigits, start, found; PROCNAME("barcodeDecodeI2of5"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format; reverse if necessary */ barcodeVerifyFormat(barstr, L_BF_CODE2OF5, &valid, &reverse); if (!valid) return (char *)ERROR_PTR("barstr not in 2of5 format", procName, NULL); if (reverse) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Verify size */ len = strlen(vbarstr); if ((len - 11) % 10 != 0) return (char *)ERROR_PTR("size not divisible by 10: invalid 2of5 code", procName, NULL); error = FALSE; ndigits = (len - 11) / 10; data = (char *)LEPT_CALLOC(ndigits + 1, sizeof(char)); memset(code, 0, 10); for (i = 0; i < ndigits; i++) { start = 6 + 10 * i; for (j = 0; j < 9; j++) code[j] = vbarstr[start + j]; if (debugflag) fprintf(stderr, "code: %s\n", code); found = FALSE; for (j = 0; j < 10; j++) { if (!strcmp(code, Code2of5[j])) { data[i] = 0x30 + j; found = TRUE; break; } } if (!found) error = TRUE; } LEPT_FREE(vbarstr); if (error) { LEPT_FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } return data; }
/*! * barcodeFindFormat() * * Input: barstr (of barcode widths, in set {1,2,3,4}) * Return: format (for barcode), or L_BF_UNKNOWN if not recognized */ static l_int32 barcodeFindFormat(char *barstr) { l_int32 i, format, valid; PROCNAME("barcodeFindFormat"); if (!barstr) return ERROR_INT("barstr not defined", procName, L_BF_UNKNOWN); for (i = 0; i < NumSupportedBarcodeFormats; i++) { format = SupportedBarcodeFormat[i]; barcodeVerifyFormat(barstr, format, &valid, NULL); if (valid) { L_INFO("Barcode format: %s\n", procName, SupportedBarcodeFormatName[i]); return format; } } return L_BF_UNKNOWN; }
/*! * barcodeDecodeEan13() * * Input: barstr (of widths, in set {1, 2, 3, 4}) * first (first digit: 0 - 9) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/UniversalProductCode * http://morovia.com/education/symbology/ean-13.asp * (2) The encoding is essentially the same as UPC-A, except * there are 13 digits in total, of which 12 are encoded * by bars (as with UPC-A) and the 13th is a leading digit * that determines the encoding of the next 6 digits, * selecting each digit from one of two tables. * encoded in the bars (as with UPC-A). If the first digit * is 0, the encoding is identical to UPC-A. * (3) As with UPC-A, the last digit is a check digit. * (4) For now, we assume the first digit is input to this function. * Eventually, we will read it by pattern matching. * * TODO: fix this for multiple tables, depending on the value of @first */ static char * barcodeDecodeEan13(char *barstr, l_int32 first, l_int32 debugflag) { char *data, *vbarstr; char code[5]; l_int32 valid, i, j, len, error, start, found, sum, checkdigit; PROCNAME("barcodeDecodeEan13"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format. You can't tell the orientation by the start * and stop codes, but you can by the location of the digits. * Use the UPCA verifier for EAN 13 -- it is identical. */ barcodeVerifyFormat(barstr, L_BF_UPCA, &valid, NULL); if (!valid) return (char *)ERROR_PTR("barstr not in EAN 13 format", procName, NULL); /* Verify size */ len = strlen(barstr); if (len != 59) return (char *)ERROR_PTR("size not 59; invalid EAN 13 barcode", procName, NULL); /* Check the first digit. If invalid, reverse the string. */ memset(code, 0, 5); for (i = 0; i < 4; i++) code[i] = barstr[i + 3]; found = FALSE; for (i = 0; i < 10; i++) { if (!strcmp(code, Upca[i])) { found = TRUE; break; } } if (found == FALSE) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Decode the 12 symbols */ data = (char *)LEPT_CALLOC(13, sizeof(char)); memset(code, 0, 5); error = FALSE; for (i = 0; i < 12; i++) { if (i < 6) start = 3 + 4 * i; else start = 32 + 4 * (i - 6); for (j = 0; j < 4; j++) code[j] = vbarstr[start + j]; if (debugflag) fprintf(stderr, "code: %s\n", code); found = FALSE; for (j = 0; j < 10; j++) { if (!strcmp(code, Upca[j])) { data[i] = 0x30 + j; found = TRUE; break; } } if (!found) error = TRUE; } LEPT_FREE(vbarstr); if (error) { LEPT_FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } /* Calculate the check digit (data[11]). */ sum = 0; for (i = 0; i < 12; i += 2) /* "even" digits */ sum += 3 * (data[i] - 0x30); for (i = 1; i < 12; i += 2) /* "odd" digits */ sum += (data[i] - 0x30); checkdigit = sum % 10; if (checkdigit) /* not 0 */ checkdigit = 10 - checkdigit; if (checkdigit + 0x30 != data[11]) L_WARNING("Error for EAN-13 check character\n", procName); return data; }
/*! * barcodeDecode93() * * Input: barstr (of widths, in set {1, 2, 3, 4}) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/Code93 * http://morovia.com/education/symbology/code93.asp * (2) Each symbol has 3 black and 3 white bars. * The start and stop codes are 111141; the stop code then is * terminated with a final (1) bar. * (3) The last two codes are check codes. We are checking them * for correctness, and issuing a warning on failure. Should * probably not return any data on failure. */ static char * barcodeDecode93(char *barstr, l_int32 debugflag) { const char *checkc, *checkk; char *data, *vbarstr; char code[7]; l_int32 valid, reverse, i, j, len, error, nsymb, start, found, sum; l_int32 *index; PROCNAME("barcodeDecode93"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format; reverse if necessary */ barcodeVerifyFormat(barstr, L_BF_CODE93, &valid, &reverse); if (!valid) return (char *)ERROR_PTR("barstr not in code93 format", procName, NULL); if (reverse) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Verify size; skip the first 6 and last 7 bars. */ len = strlen(vbarstr); if ((len - 13) % 6 != 0) return (char *)ERROR_PTR("size not divisible by 6: invalid code 93", procName, NULL); /* Decode the symbols */ nsymb = (len - 13) / 6; data = (char *)LEPT_CALLOC(nsymb + 1, sizeof(char)); index = (l_int32 *)LEPT_CALLOC(nsymb, sizeof(l_int32)); memset(code, 0, 7); error = FALSE; for (i = 0; i < nsymb; i++) { start = 6 + 6 * i; for (j = 0; j < 6; j++) code[j] = vbarstr[start + j]; if (debugflag) fprintf(stderr, "code: %s\n", code); found = FALSE; for (j = 0; j < C93_START; j++) { if (!strcmp(code, Code93[j])) { data[i] = Code93Val[j]; index[i] = j; found = TRUE; break; } } if (!found) error = TRUE; } LEPT_FREE(vbarstr); if (error) { LEPT_FREE(index); LEPT_FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } /* Do check sums. For character "C", use only the * actual data in computing the sum. For character "K", * use the actual data plus the check character "C". */ sum = 0; for (i = 0; i < nsymb - 2; i++) /* skip the "C" and "K" */ sum += ((i % 20) + 1) * index[nsymb - 3 - i]; if (data[nsymb - 2] != Code93Val[sum % 47]) L_WARNING("Error for check C\n", procName); if (debugflag) { checkc = Code93[sum % 47]; fprintf(stderr, "checkc = %s\n", checkc); } sum = 0; for (i = 0; i < nsymb - 1; i++) /* skip the "K" */ sum += ((i % 15) + 1) * index[nsymb - 2 - i]; if (data[nsymb - 1] != Code93Val[sum % 47]) L_WARNING("Error for check K\n", procName); if (debugflag) { checkk = Code93[sum % 47]; fprintf(stderr, "checkk = %s\n", checkk); } /* Remove the two check codes from the output */ data[nsymb - 2] = '\0'; LEPT_FREE(index); return data; }
/*! * barcodeDecodeI2of5() * * Input: barstr (of widths, in set {1, 2}) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/Interleaved_2_of_5 * (2) This always encodes an even number of digits. * The start code is 1111; the stop code is 211. */ static char * barcodeDecodeI2of5(char *barstr, l_int32 debugflag) { char *data, *vbarstr; char code1[6], code2[6]; l_int32 valid, reverse, i, j, len, error, npairs, start, found; PROCNAME("barcodeDecodeI2of5"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format; reverse if necessary */ barcodeVerifyFormat(barstr, L_BF_CODEI2OF5, &valid, &reverse); if (!valid) return (char *)ERROR_PTR("barstr not in i2of5 format", procName, NULL); if (reverse) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Verify size */ len = strlen(vbarstr); if ((len - 7) % 10 != 0) return (char *)ERROR_PTR("size not divisible by 10: invalid I2of5 code", procName, NULL); error = FALSE; npairs = (len - 7) / 10; data = (char *)LEPT_CALLOC(2 * npairs + 1, sizeof(char)); memset(code1, 0, 6); memset(code2, 0, 6); for (i = 0; i < npairs; i++) { start = 4 + 10 * i; for (j = 0; j < 5; j++) { code1[j] = vbarstr[start + 2 * j]; code2[j] = vbarstr[start + 2 * j + 1]; } if (debugflag) fprintf(stderr, "code1: %s, code2: %s\n", code1, code2); found = FALSE; for (j = 0; j < 10; j++) { if (!strcmp(code1, CodeI2of5[j])) { data[2 * i] = 0x30 + j; found = TRUE; break; } } if (!found) error = TRUE; found = FALSE; for (j = 0; j < 10; j++) { if (!strcmp(code2, CodeI2of5[j])) { data[2 * i + 1] = 0x30 + j; found = TRUE; break; } } if (!found) error = TRUE; } LEPT_FREE(vbarstr); if (error) { LEPT_FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } return data; }
/*! * barcodeDecodeUpca() * * Input: barstr (of widths, in set {1, 2, 3, 4}) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/UniversalProductCode * http://morovia.com/education/symbology/upc-a.asp * (2) Each symbol has 2 black and 2 white bars, and encodes a digit. * The start and stop codes are 111 and 111. There are a total of * 30 black bars, encoding 12 digits in two sets of 6, with * 2 black bars separating the sets. * (3) The last digit is a check digit. We check for correctness, and * issue a warning on failure. Should probably not return any * data on failure. */ static char * barcodeDecodeUpca(char *barstr, l_int32 debugflag) { char *data, *vbarstr; char code[5]; l_int32 valid, i, j, len, error, start, found, sum, checkdigit; PROCNAME("barcodeDecodeUpca"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format; reverse has no meaning here -- we must test both */ barcodeVerifyFormat(barstr, L_BF_UPCA, &valid, NULL); if (!valid) return (char *)ERROR_PTR("barstr not in UPC-A format", procName, NULL); /* Verify size */ len = strlen(barstr); if (len != 59) return (char *)ERROR_PTR("size not 59; invalid UPC-A barcode", procName, NULL); /* Check the first digit. If invalid, reverse the string. */ memset(code, 0, 5); for (i = 0; i < 4; i++) code[i] = barstr[i + 3]; found = FALSE; for (i = 0; i < 10; i++) { if (!strcmp(code, Upca[i])) { found = TRUE; break; } } if (found == FALSE) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Decode the 12 symbols */ data = (char *)CALLOC(13, sizeof(char)); memset(code, 0, 5); error = FALSE; for (i = 0; i < 12; i++) { if (i < 6) start = 3 + 4 * i; else start = 32 + 4 * (i - 6); for (j = 0; j < 4; j++) code[j] = vbarstr[start + j]; if (debugflag) fprintf(stderr, "code: %s\n", code); found = FALSE; for (j = 0; j < 10; j++) { if (!strcmp(code, Upca[j])) { data[i] = 0x30 + j; found = TRUE; break; } } if (!found) error = TRUE; } FREE(vbarstr); if (error) { FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } /* Calculate the check digit (data[11]). */ sum = 0; for (i = 0; i < 12; i += 2) /* "even" digits */ sum += 3 * (data[i] - 0x30); for (i = 1; i < 11; i += 2) /* "odd" digits */ sum += (data[i] - 0x30); checkdigit = sum % 10; if (checkdigit) /* not 0 */ checkdigit = 10 - checkdigit; if (checkdigit + 0x30 != data[11]) L_WARNING("Error for UPC-A check character", procName); return data; }
/*! * barcodeDecodeCodabar() * * Input: barstr (of widths, in set {1, 2}) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/Codabar * http://morovia.com/education/symbology/codabar.asp * (2) Each symbol has 4 black and 3 white bars. They represent the * 10 digits, and optionally 6 other characters. The start and * stop codes can be any of four (typically denoted A,B,C,D). */ static char * barcodeDecodeCodabar(char *barstr, l_int32 debugflag) { char *data, *vbarstr; char code[8]; l_int32 valid, reverse, i, j, len, error, nsymb, start, found; PROCNAME("barcodeDecodeCodabar"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format; reverse if necessary */ barcodeVerifyFormat(barstr, L_BF_CODABAR, &valid, &reverse); if (!valid) return (char *)ERROR_PTR("barstr not in codabar format", procName, NULL); if (reverse) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Verify size */ len = strlen(vbarstr); if ((len + 1) % 8 != 0) return (char *)ERROR_PTR("size+1 not divisible by 8: invalid codabar", procName, NULL); /* Decode the symbols */ nsymb = (len - 15) / 8; data = (char *)CALLOC(nsymb + 1, sizeof(char)); memset(code, 0, 8); error = FALSE; for (i = 0; i < nsymb; i++) { start = 8 + 8 * i; for (j = 0; j < 7; j++) code[j] = vbarstr[start + j]; if (debugflag) fprintf(stderr, "code: %s\n", code); found = FALSE; for (j = 0; j < 16; j++) { if (!strcmp(code, Codabar[j])) { data[i] = CodabarVal[j]; found = TRUE; break; } } if (!found) error = TRUE; } FREE(vbarstr); if (error) { FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } return data; }