mirror of http://192.168.1.51:8099/lmh188/twain3.0
1034 lines
32 KiB
C
1034 lines
32 KiB
C
/*====================================================================*
|
|
- 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
|
|
* <pre>
|
|
*
|
|
* 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()
|
|
* </pre>
|
|
*/
|
|
|
|
#include <string.h>
|
|
#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
|
|
*
|
|
* <pre>
|
|
* 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) Add to this as more formats are supported.
|
|
* </pre>
|
|
*/
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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) {
|
|
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
|
|
*
|
|
* <pre>
|
|
* 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.
|
|
* </pre>
|
|
*/
|
|
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)
|
|
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;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------*
|
|
* 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
|
|
*
|
|
* <pre>
|
|
* 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.
|
|
* </pre>
|
|
*/
|
|
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)
|
|
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;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------*
|
|
* 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
|
|
*
|
|
* <pre>
|
|
* 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.
|
|
* </pre>
|
|
*/
|
|
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)
|
|
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;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------*
|
|
* 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
|
|
*
|
|
* <pre>
|
|
* 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.
|
|
* </pre>
|
|
*/
|
|
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)
|
|
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;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------*
|
|
* 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
|
|
*
|
|
* <pre>
|
|
* 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).
|
|
* </pre>
|
|
*/
|
|
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)
|
|
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;
|
|
}
|
|
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
|
|
*
|
|
* <pre>
|
|
* 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.
|
|
* </pre>
|
|
*/
|
|
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)
|
|
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 < 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
|
|
*
|
|
* <pre>
|
|
* 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
|
|
* </pre>
|
|
*/
|
|
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;
|
|
}
|