/*====================================================================* - Copyright (C) 2001 Leptonica. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *====================================================================*/ /*! * \file bardecode.c *
 *
 *      Dispatcher
 *          char            *barcodeDispatchDecoder()
 *
 *      Format Determination
 *          static l_int32   barcodeFindFormat()
 *          l_int32          barcodeFormatIsSupported()
 *          static l_int32   barcodeVerifyFormat()
 *
 *      Decode 2 of 5
 *          static char     *barcodeDecode2of5()
 *
 *      Decode Interleaved 2 of 5
 *          static char     *barcodeDecodeI2of5()
 *
 *      Decode Code 93
 *          static char     *barcodeDecode93()
 *
 *      Decode Code 39
 *          static char     *barcodeDecode39()
 *
 *      Decode Codabar
 *          static char     *barcodeDecodeCodabar()
 *
 *      Decode UPC-A
 *          static char     *barcodeDecodeUpca()
 *
 *      Decode EAN 13
 *          static char     *barcodeDecodeEan13()
 * 
*/ #ifdef HAVE_CONFIG_H #include #endif /* HAVE_CONFIG_H */ #include #include "allheaders.h" #include "readbarcode.h" static l_int32 barcodeFindFormat(char *barstr); static l_int32 barcodeVerifyFormat(char *barstr, l_int32 format, l_int32 *pvalid, l_int32 *preverse); static char *barcodeDecode2of5(char *barstr, l_int32 debugflag); static char *barcodeDecodeI2of5(char *barstr, l_int32 debugflag); static char *barcodeDecode93(char *barstr, l_int32 debugflag); static char *barcodeDecode39(char *barstr, l_int32 debugflag); static char *barcodeDecodeCodabar(char *barstr, l_int32 debugflag); static char *barcodeDecodeUpca(char *barstr, l_int32 debugflag); static char *barcodeDecodeEan13(char *barstr, l_int32 first, l_int32 debugflag); #ifndef NO_CONSOLE_IO #define DEBUG_CODES 0 #endif /* ~NO_CONSOLE_IO */ /*------------------------------------------------------------------------* * Decoding dispatcher * *------------------------------------------------------------------------*/ /*! * \brief barcodeDispatchDecoder() * * \param[in] barstr string of integers in set {1,2,3,4} of bar widths * \param[in] format L_BF_ANY, L_BF_CODEI2OF5, L_BF_CODE93, ... * \param[in] debugflag use 1 to generate debug output * \return data string of decoded barcode data, or NULL on error */ char * barcodeDispatchDecoder(char *barstr, l_int32 format, l_int32 debugflag) { char *data = NULL; PROCNAME("barcodeDispatchDecoder"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); debugflag = FALSE; /* not used yet */ if (format == L_BF_ANY) format = barcodeFindFormat(barstr); if (format == L_BF_CODE2OF5) data = barcodeDecode2of5(barstr, debugflag); else if (format == L_BF_CODEI2OF5) data = barcodeDecodeI2of5(barstr, debugflag); else if (format == L_BF_CODE93) data = barcodeDecode93(barstr, debugflag); else if (format == L_BF_CODE39) data = barcodeDecode39(barstr, debugflag); else if (format == L_BF_CODABAR) data = barcodeDecodeCodabar(barstr, debugflag); else if (format == L_BF_UPCA) data = barcodeDecodeUpca(barstr, debugflag); else if (format == L_BF_EAN13) data = barcodeDecodeEan13(barstr, 0, debugflag); else return (char *)ERROR_PTR("format not implemented", procName, NULL); return data; } /*------------------------------------------------------------------------* * Barcode format determination * *------------------------------------------------------------------------*/ /*! * \brief barcodeFindFormat() * * \param[in] 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; } /*! * \brief barcodeFormatIsSupported() * * \param[in] format * \return 1 if format is one of those supported; 0 otherwise * */ l_int32 barcodeFormatIsSupported(l_int32 format) { l_int32 i; for (i = 0; i < NumSupportedBarcodeFormats; i++) { if (format == SupportedBarcodeFormat[i]) return 1; } return 0; } /*! * \brief barcodeVerifyFormat() * * \param[in] barstr of barcode widths, in set {1,2,3,4} * \param[in] format L_BF_CODEI2OF5, L_BF_CODE93, ... * \param[out] pvalid 0 if not valid, 1 and 2 if valid * \param[out] preverse [optional] 1 if reversed; 0 otherwise * \return 0 if OK, 1 on error * *
 * Notes:
 *      (1) If valid == 1, the barcode is of the given format in the
 *          forward order; if valid == 2, it is backwards.
 *      (2) If the barcode needs to be reversed to read it, and &reverse
 *          is provided, a 1 is put into %reverse.
 *      (3) Require at least 12 data bits, in addition to format identifiers.
 *          (TODO) If the barcode has a fixed length, this should be used
 *          explicitly, as is done for L_BF_UPCA and L_BF_EAN13.
 *      (4) (TODO) Add to this as more formats are supported.
 * 
*/ static l_int32 barcodeVerifyFormat(char *barstr, l_int32 format, l_int32 *pvalid, l_int32 *preverse) { char *revbarstr; l_int32 i, start, len, stop, mid; PROCNAME("barcodeVerifyFormat"); if (!pvalid) return ERROR_INT("barstr not defined", procName, 1); *pvalid = 0; if (preverse) *preverse = 0; if (!barstr) return ERROR_INT("barstr not defined", procName, 1); switch (format) { case L_BF_CODE2OF5: start = !strncmp(barstr, Code2of5[C25_START], 3); len = strlen(barstr); if (len < 20) return ERROR_INT("barstr too short for CODE2OF5", procName, 1); stop = !strncmp(&barstr[len - 5], Code2of5[C25_STOP], 5); if (start && stop) { *pvalid = 1; } else { revbarstr = stringReverse(barstr); start = !strncmp(revbarstr, Code2of5[C25_START], 3); stop = !strncmp(&revbarstr[len - 5], Code2of5[C25_STOP], 5); LEPT_FREE(revbarstr); if (start && stop) { *pvalid = 1; if (preverse) *preverse = 1; } } break; case L_BF_CODEI2OF5: start = !strncmp(barstr, CodeI2of5[CI25_START], 4); len = strlen(barstr); if (len < 20) return ERROR_INT("barstr too short for CODEI2OF5", procName, 1); stop = !strncmp(&barstr[len - 3], CodeI2of5[CI25_STOP], 3); if (start && stop) { *pvalid = 1; } else { revbarstr = stringReverse(barstr); start = !strncmp(revbarstr, CodeI2of5[CI25_START], 4); stop = !strncmp(&revbarstr[len - 3], CodeI2of5[CI25_STOP], 3); LEPT_FREE(revbarstr); if (start && stop) { *pvalid = 1; if (preverse) *preverse = 1; } } break; case L_BF_CODE93: start = !strncmp(barstr, Code93[C93_START], 6); len = strlen(barstr); if (len < 28) return ERROR_INT("barstr too short for CODE93", procName, 1); stop = !strncmp(&barstr[len - 7], Code93[C93_STOP], 6); if (start && stop) { *pvalid = 1; } else { revbarstr = stringReverse(barstr); start = !strncmp(revbarstr, Code93[C93_START], 6); stop = !strncmp(&revbarstr[len - 7], Code93[C93_STOP], 6); LEPT_FREE(revbarstr); if (start && stop) { *pvalid = 1; if (preverse) *preverse = 1; } } break; case L_BF_CODE39: start = !strncmp(barstr, Code39[C39_START], 9); len = strlen(barstr); if (len < 30) return ERROR_INT("barstr too short for CODE39", procName, 1); stop = !strncmp(&barstr[len - 9], Code39[C39_STOP], 9); if (start && stop) { *pvalid = 1; } else { revbarstr = stringReverse(barstr); start = !strncmp(revbarstr, Code39[C39_START], 9); stop = !strncmp(&revbarstr[len - 9], Code39[C39_STOP], 9); LEPT_FREE(revbarstr); if (start && stop) { *pvalid = 1; if (preverse) *preverse = 1; } } break; case L_BF_CODABAR: start = stop = 0; len = strlen(barstr); if (len < 26) return ERROR_INT("barstr too short for CODABAR", procName, 1); for (i = 16; i <= 19; i++) /* any of these will do */ start += !strncmp(barstr, Codabar[i], 7); for (i = 16; i <= 19; i++) /* ditto */ stop += !strncmp(&barstr[len - 7], Codabar[i], 7); if (start && stop) { *pvalid = 1; } else { start = stop = 0; revbarstr = stringReverse(barstr); for (i = 16; i <= 19; i++) start += !strncmp(revbarstr, Codabar[i], 7); for (i = 16; i <= 19; i++) stop += !strncmp(&revbarstr[len - 7], Codabar[i], 7); LEPT_FREE(revbarstr); if (start && stop) { *pvalid = 1; if (preverse) *preverse = 1; } } break; case L_BF_UPCA: case L_BF_EAN13: len = strlen(barstr); if (len != 59) return ERROR_INT("invalid length for UPCA or EAN13", procName, 1); start = !strncmp(barstr, Upca[UPCA_START], 3); mid = !strncmp(&barstr[27], Upca[UPCA_MID], 5); stop = !strncmp(&barstr[len - 3], Upca[UPCA_STOP], 3); if (start && mid && stop) *pvalid = 1; break; default: return ERROR_INT("format not supported", procName, 1); } return 0; } /*------------------------------------------------------------------------* * Code 2 of 5 * *------------------------------------------------------------------------*/ /*! * \brief barcodeDecode2of5() * * \param[in] barstr of widths, in set {1, 2} * \param[in] 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) { LEPT_FREE(vbarstr); 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) lept_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; } /*------------------------------------------------------------------------* * Interleaved Code 2 of 5 * *------------------------------------------------------------------------*/ /*! * \brief barcodeDecodeI2of5() * * \param[in] barstr of widths, in set {1, 2} * \param[in] 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) { LEPT_FREE(vbarstr); 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) lept_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; } /*------------------------------------------------------------------------* * Code 93 * *------------------------------------------------------------------------*/ /*! * \brief barcodeDecode93() * * \param[in] barstr of widths, in set {1, 2, 3, 4} * \param[in] 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) { LEPT_FREE(vbarstr); 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) lept_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]; lept_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]; lept_stderr("checkk = %s\n", checkk); } /* Remove the two check codes from the output */ data[nsymb - 2] = '\0'; LEPT_FREE(index); return data; } /*------------------------------------------------------------------------* * Code 39 * *------------------------------------------------------------------------*/ /*! * \brief barcodeDecode39() * * \param[in] barstr of widths, in set {1, 2} * \param[in] 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) { LEPT_FREE(vbarstr); 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) lept_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; } /*------------------------------------------------------------------------* * Codabar * *------------------------------------------------------------------------*/ /*! * \brief barcodeDecodeCodabar() * * \param[in] barstr of widths, in set {1, 2} * \param[in] 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) { LEPT_FREE(vbarstr); return (char *)ERROR_PTR("size+1 not divisible by 8: invalid codabar", procName, NULL); } /* Decode the symbols */ nsymb = (len - 15) / 8; data = (char *)LEPT_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) lept_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; } LEPT_FREE(vbarstr); if (error) { LEPT_FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } return data; } /*------------------------------------------------------------------------* * Code UPC-A * *------------------------------------------------------------------------*/ /*! * \brief barcodeDecodeUpca() * * \param[in] barstr of widths, in set {1, 2, 3, 4} * \param[in] 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 *)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) lept_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 < 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\n", procName); return data; } /*------------------------------------------------------------------------* * Code EAN-13 * *------------------------------------------------------------------------*/ /*! * \brief barcodeDecodeEan13() * * \param[in] barstr of widths, in set {1, 2, 3, 4} * \param[in] first first digit: 0 - 9 * \param[in] 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) lept_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; }