diff options
Diffstat (limited to 'zbarimg')
-rw-r--r-- | zbarimg/Makefile.am.inc | 13 | ||||
-rw-r--r-- | zbarimg/zbarimg.c | 555 | ||||
-rw-r--r-- | zbarimg/zbarimg.rc | 30 |
3 files changed, 598 insertions, 0 deletions
diff --git a/zbarimg/Makefile.am.inc b/zbarimg/Makefile.am.inc new file mode 100644 index 0000000..0f201a6 --- /dev/null +++ b/zbarimg/Makefile.am.inc @@ -0,0 +1,13 @@ +bin_PROGRAMS += zbarimg/zbarimg +zbarimg_zbarimg_SOURCES = zbarimg/zbarimg.c +zbarimg_zbarimg_CPPFLAGS = $(MAGICK_CFLAGS) $(AM_CPPFLAGS) +zbarimg_zbarimg_LDADD = zbar/libzbar.la $(MAGICK_LIBS) +# automake bug in "monolithic mode"? +CLEANFILES += zbarimg/.libs/zbarimg + +if WIN32 +zbarimg_zbarimg_SOURCES += zbarimg/zbarimg.rc +zbarimg_zbarimg_LDADD += zbarimg/zbarimg-rc.o @LTLIBINTL@ +endif + +EXTRA_DIST += test/barcodetest.py diff --git a/zbarimg/zbarimg.c b/zbarimg/zbarimg.c new file mode 100644 index 0000000..e82aca9 --- /dev/null +++ b/zbarimg/zbarimg.c @@ -0,0 +1,555 @@ +/*------------------------------------------------------------------------ + * Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net> + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "config.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_TIMES_H +#include <sys/times.h> +#endif +#ifdef _WIN32 +#include <fcntl.h> +#include <io.h> +#endif +#include <assert.h> + +#include <zbar.h> + +#ifdef ENABLE_NLS +#include <libintl.h> +#include <locale.h> +#define _(string) gettext(string) +#else +#define _(string) string +#endif + +#define N_(string) string + +#ifdef HAVE_GRAPHICSMAGICK +#include <wand/wand_api.h> +#endif + +#ifdef HAVE_IMAGEMAGICK +#ifdef HAVE_IMAGEMAGICK7 +#include <MagickWand/MagickWand.h> +#else +#include <wand/MagickWand.h> +#endif + +/* ImageMagick frequently changes API names - just use the original + * (more stable?) names to match GraphicsMagick + */ +#define InitializeMagick(f) MagickWandGenesis() +#define DestroyMagick MagickWandTerminus +#define MagickSetImageIndex MagickSetIteratorIndex + +/* in 6.4.5.4 MagickGetImagePixels changed to MagickExportImagePixels. + * (still not sure this check is quite right... + * how does MagickGetAuthenticImagePixels fit in?) + * ref http://bugs.gentoo.org/247292 + */ +#if MagickLibVersion > 0x645 +#define MagickGetImagePixels MagickExportImagePixels +#endif +#endif + +static const char *note_usage = N_( + "usage: zbarimg [options] <image>...\n" + "\n" + "scan and decode bar codes from one or more image files\n" + "\n" + "options:\n" + " -h, --help display this help text\n" + " --version display version information and exit\n" + " --polygon output points delimiting code zone with decoded symbol data\n" + " -q, --quiet minimal output, only print decoded symbol data\n" + " -v, --verbose increase debug output level\n" + " --verbose=N set specific debug output level\n" + " -d, --display enable display of following images to the screen\n" + " -D, --nodisplay disable display of following images (default)\n" + " --xml, --noxml enable/disable XML output format\n" + " --raw output decoded symbol data without converting charsets\n" + " -1, --oneshot exit after scanning one bar code\n" + " -S<CONFIG>[=<VALUE>], --set <CONFIG>[=<VALUE>]\n" + " set decoder/scanner <CONFIG> to <VALUE> (or 1)\n" + // FIXME overlay level + "\n"); + +#ifdef HAVE_DBUS +static const char *note_usage2 = + N_(" --nodbus disable dbus message\n"); +#endif + +static const char *warning_not_found_head = N_( + "\n" + "WARNING: barcode data was not detected in some image(s)\n" + "Things to check:\n" + " - is the barcode type supported? Currently supported symbologies are:\n"); + +static const char *warning_not_found_tail = N_( + " - is the barcode large enough in the image?\n" + " - is the barcode mostly in focus?\n" + " - is there sufficient contrast/illumination?\n" + " - If the symbol is split in several barcodes, are they combined in one " + "image?\n" + " - Did you enable the barcode type?\n" + " some EAN/UPC codes are disabled by default. To enable all, use:\n" + " $ zbarimg -S*.enable <files>\n" + " Please also notice that some variants take precedence over others.\n" + " Due to that, if you want, for example, ISBN-10, you should do:\n" + " $ zbarimg -Sisbn10.enable <files>\n" + "\n"); + +static const char *xml_head = + "<barcodes xmlns='http://zbar.sourceforge.net/2008/barcode'>\n"; +static const char *xml_foot = "</barcodes>\n"; + +static int notfound = 0, exit_code = 0; +static int num_images = 0, num_symbols = 0; +static int xmllvl = 0; +static int polygon = 0; +static int oneshot = 0; +static int binary = 0; + +char *xmlbuf = NULL; +unsigned xmlbuflen = 0; + +static zbar_processor_t *processor = NULL; + +static inline int dump_error(MagickWand *wand) +{ + char *desc; + ExceptionType severity; + desc = MagickGetException(wand, &severity); + + if (severity >= FatalErrorException) + exit_code = 2; + else if (severity >= ErrorException) + exit_code = 1; + else + exit_code = 0; + + static const char *sevdesc[] = { "WARNING", "ERROR", "FATAL" }; + fprintf(stderr, "%s: %s\n", sevdesc[exit_code], desc); + + MagickRelinquishMemory(desc); + return (exit_code); +} + +static int scan_image(const char *filename) +{ + if (exit_code == 3) + return (-1); + + int found = 0; + MagickWand *images = NewMagickWand(); + + // default is a measly 72dpi for pdf + MagickSetResolution(images, 900, 900); + + if (!MagickReadImage(images, filename) && dump_error(images)) + return (-1); + + unsigned seq, n = MagickGetNumberImages(images); + for (seq = 0; seq < n; seq++) { + if (exit_code == 3) + return (-1); + + if (!MagickSetImageIndex(images, seq) && dump_error(images)) + return (-1); + + zbar_image_t *zimage = zbar_image_create(); + assert(zimage); + zbar_image_set_format(zimage, zbar_fourcc('Y', '8', '0', '0')); + + int width = MagickGetImageWidth(images); + int height = MagickGetImageHeight(images); + zbar_image_set_size(zimage, width, height); + + // extract grayscale image pixels + // FIXME color!! ...preserve most color w/422P + // (but only if it's a color image) + size_t bloblen = width * height; + unsigned char *blob = malloc(bloblen); + zbar_image_set_data(zimage, blob, bloblen, zbar_image_free_data); + + if (!MagickGetImagePixels(images, 0, 0, width, height, "I", CharPixel, + blob)) + return (-1); + + if (xmllvl == 1) { + xmllvl++; + printf("<source href='%s'>\n", filename); + } + + zbar_process_image(processor, zimage); + + // output result data + const zbar_symbol_t *sym = zbar_image_first_symbol(zimage); + for (; sym; sym = zbar_symbol_next(sym)) { + zbar_symbol_type_t typ = zbar_symbol_get_type(sym); + unsigned len = zbar_symbol_get_data_length(sym); + if (typ == ZBAR_PARTIAL) + continue; + else if (xmllvl <= 0) { + if (!xmllvl) + printf("%s:", zbar_get_symbol_name(typ)); + if (polygon) { + int p; + if (zbar_symbol_get_loc_size(sym) > 0) + printf("%+d,%+d", zbar_symbol_get_loc_x(sym,0), zbar_symbol_get_loc_y(sym,0)); + for (p = 1; p < zbar_symbol_get_loc_size(sym); p++) + printf(" %+d,%+d", zbar_symbol_get_loc_x(sym,p), zbar_symbol_get_loc_y(sym,p)); + printf(":"); + } + if (len && + fwrite(zbar_symbol_get_data(sym), len, 1, stdout) != 1) { + exit_code = 1; + return (-1); + } + } else { + if (xmllvl < 3) { + xmllvl++; + printf("<index num='%u'>\n", seq); + } + zbar_symbol_xml(sym, &xmlbuf, &xmlbuflen); + if (fwrite(xmlbuf, xmlbuflen, 1, stdout) != 1) { + exit_code = 1; + return (-1); + } + } + found++; + num_symbols++; + + if (!binary) { + if (oneshot) { + if (xmllvl >= 0) + printf("\n"); + break; + } else + printf("\n"); + } + } + if (xmllvl > 2) { + xmllvl--; + printf("</index>\n"); + } + fflush(stdout); + + zbar_image_destroy(zimage); + + num_images++; + if (zbar_processor_is_visible(processor)) { + int rc = zbar_processor_user_wait(processor, -1); + if (rc < 0 || rc == 'q' || rc == 'Q') + exit_code = 3; + } + } + + if (xmllvl > 1) { + xmllvl--; + printf("</source>\n"); + } + + if (!found) + notfound++; + + DestroyMagickWand(images); + return (0); +} + +int usage(int rc, const char *msg, const char *arg) +{ + FILE *out = (rc) ? stderr : stdout; + if (msg) { + fprintf(out, "%s", msg); + if (arg) + fprintf(out, "%s", arg); + fprintf(out, "\n\n"); + } + fprintf(out, "%s", _(note_usage)); +#ifdef HAVE_DBUS + fprintf(out, "%s", _(note_usage2)); +#endif + return (rc); +} + +static inline int parse_config(const char *cfgstr, const char *arg) +{ + if (!cfgstr || !cfgstr[0]) + return (usage(1, "ERROR: need argument for option: ", arg)); + + if (zbar_processor_parse_config(processor, cfgstr)) + return (usage(1, "ERROR: invalid configuration setting: ", cfgstr)); + + if (!strcmp(cfgstr, "binary")) + binary = 1; + + return (0); +} + +int main(int argc, const char *argv[]) +{ + // option pre-scan + int quiet = 0; +#ifdef HAVE_DBUS + int dbus = 1; +#endif + int display = 0; + int i, j; + +#ifdef ENABLE_NLS + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); +#endif + + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (arg[0] != '-' || !arg[1]) + // first pass, skip images + num_images++; + else if (arg[1] != '-') + for (j = 1; arg[j]; j++) { + if (arg[j] == 'S') { + if (!arg[++j] && ++i >= argc) + /* FIXME parse check */ + return (parse_config("", "-S")); + break; + } + switch (arg[j]) { + case 'h': + return (usage(0, NULL, NULL)); + case 'q': + quiet = 1; + break; + case '1': + oneshot = 1; + break; + case 'v': + zbar_increase_verbosity(); + break; + case 'd': + display = 1; + break; + case 'D': + break; + default: + return ( + usage(1, "ERROR: unknown bundled option: -", arg + j)); + } + } + else if (!strcmp(arg, "--help")) + return (usage(0, NULL, NULL)); + else if (!strcmp(arg, "--version")) { + printf("%s\n", PACKAGE_VERSION); + return (0); + } else if (!strcmp(arg, "--quiet")) { + quiet = 1; + argv[i] = NULL; + } else if (!strcmp(arg, "--oneshot")) + oneshot = 1; + else if (!strcmp(arg, "--verbose")) + zbar_increase_verbosity(); + else if (!strncmp(arg, "--verbose=", 10)) + zbar_set_verbosity(strtol(argv[i] + 10, NULL, 0)); + else if (!strcmp(arg, "--nodbus")) +#ifdef HAVE_DBUS + dbus = 0; +#else + ; /* silently ignore the option */ +#endif + else if (!strcmp(arg, "--display")) + display++; + else if (!strcmp(arg, "--xml")) { + if (xmllvl >= 0) + xmllvl = 1; + } else if (!strcmp(arg, "--noxml")) { + if (xmllvl > 0) + xmllvl = 0; + } else if (!strcmp(arg, "--raw")) { + // RAW mode takes precedence + xmllvl = -1; + } else if (!strcmp(arg, "--polygon")) { + polygon = 1; + } else if (!strcmp(arg, "--nodisplay") || !strcmp(arg, "--set") || + !strncmp(arg, "--set=", 6)) + continue; + else if (!strcmp(arg, "--")) { + num_images += argc - i - 1; + break; + } else + return (usage(1, "ERROR: unknown option: ", arg)); + } + + if (!num_images) + return (usage(1, "ERROR: specify image file(s) to scan", NULL)); + num_images = 0; + + InitializeMagick("zbarimg"); + + processor = zbar_processor_create(0); + assert(processor); + +#ifdef HAVE_DBUS + zbar_processor_request_dbus(processor, dbus); +#endif + + if (zbar_processor_init(processor, NULL, display)) { + zbar_processor_error_spew(processor, 0); + return (1); + } + + if (xmllvl > 0) { + printf("%s", xml_head); + } + + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (!arg) + continue; + + if (binary) + xmllvl = -1; + +#ifdef _WIN32 + if (xmllvl == -1) { + _setmode(_fileno(stdout), _O_BINARY); + } else { + _setmode(_fileno(stdout), _O_TEXT); + } +#endif + + if (arg[0] != '-' || !arg[1]) { + if (scan_image(arg)) + return (exit_code); + } else if (arg[1] != '-') + for (j = 1; arg[j]; j++) { + if (arg[j] == 'S') { + if ((arg[++j]) ? parse_config(arg + j, "-S") : + parse_config(argv[++i], "-S")) + return (1); + break; + } + switch (arg[j]) { + case 'd': + zbar_processor_set_visible(processor, 1); + break; + case 'D': + zbar_processor_set_visible(processor, 0); + break; + } + } + else if (!strcmp(arg, "--display")) + zbar_processor_set_visible(processor, 1); + else if (!strcmp(arg, "--nodisplay")) + zbar_processor_set_visible(processor, 0); + + else if (!strcmp(arg, "--set")) { + if (parse_config(argv[++i], "--set")) + return (1); + } else if (!strncmp(arg, "--set=", 6)) { + if (parse_config(arg + 6, "--set=")) + return (1); + } else if (!strcmp(arg, "--")) + break; + } + for (i++; i < argc; i++) + if (scan_image(argv[i])) + return (exit_code); + + /* ignore quit during last image */ + if (exit_code == 3) + exit_code = 0; + + if (xmllvl > 0) { + printf("%s", xml_foot); + fflush(stdout); + } + + if (xmlbuf) + free(xmlbuf); + + if (num_images && !quiet && xmllvl <= 0) { + fprintf(stderr, "scanned %d barcode symbols from %d images", + num_symbols, num_images); +#ifdef HAVE_SYS_TIMES_H +#ifdef HAVE_UNISTD_H + long clk_tck = sysconf(_SC_CLK_TCK); + struct tms tms; + if (clk_tck > 0 && times(&tms) >= 0) { + double secs = tms.tms_utime + tms.tms_stime; + secs /= clk_tck; + fprintf(stderr, " in %.2g seconds\n", secs); + } +#endif +#endif + fprintf(stderr, "\n"); + if (notfound) { + fprintf(stderr, "%s", _(warning_not_found_head)); +#if ENABLE_EAN == 1 + fprintf( + stderr, + _("\t. EAN/UPC (EAN-13, EAN-8, EAN-2, EAN-5, UPC-A, UPC-E, ISBN-10, ISBN-13)\n")); +#endif +#if ENABLE_DATABAR == 1 + fprintf(stderr, _("\t. DataBar, DataBar Expanded\n")); +#endif +#if ENABLE_CODE128 == 1 + fprintf(stderr, _("\t. Code 128\n")); +#endif +#if ENABLE_CODE93 == 1 + fprintf(stderr, _("\t. Code 93\n")); +#endif +#if ENABLE_CODE39 == 1 + fprintf(stderr, _("\t. Code 39\n")); +#endif +#if ENABLE_CODABAR == 1 + fprintf(stderr, _("\t. Codabar\n")); +#endif +#if ENABLE_I25 == 1 + fprintf(stderr, _("\t. Interleaved 2 of 5\n")); +#endif +#if ENABLE_QRCODE == 1 + fprintf(stderr, _("\t. QR code\n")); +#endif +#if ENABLE_SQCODE == 1 + fprintf(stderr, _("\t. SQ code\n")); +#endif +#if ENABLE_PDF417 == 1 + fprintf(stderr, _("\t. PDF 417\n")); +#endif + fprintf(stderr, "%s", _(warning_not_found_tail)); + } + } + if (num_images && notfound && !exit_code) + exit_code = 4; + + zbar_processor_destroy(processor); + DestroyMagick(); + return (exit_code); +} diff --git a/zbarimg/zbarimg.rc b/zbarimg/zbarimg.rc new file mode 100644 index 0000000..a7e9366 --- /dev/null +++ b/zbarimg/zbarimg.rc @@ -0,0 +1,30 @@ +#include <config.h> +#include <winver.h> + +VS_VERSION_INFO VERSIONINFO + FILEVERSION ZBAR_VERSION_MAJOR, ZBAR_VERSION_MINOR, ZBAR_VERSION_PATCH, 0 + PRODUCTVERSION ZBAR_VERSION_MAJOR, ZBAR_VERSION_MINOR, ZBAR_VERSION_PATCH, 0 + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP +{ + BLOCK "StringFileInfo" { + BLOCK "040904E4" { + VALUE "ProductName", "ZBar Bar Code Reader" + VALUE "Company Name", "ZBar Bar Code Reader" + VALUE "InternalName", "zbarimg" + VALUE "OriginalFilename", "zbarimg.exe" + + VALUE "FileVersion", PACKAGE_VERSION + VALUE "ProductVersion", PACKAGE_VERSION + + VALUE "FileDescription", "Scan bar codes from image files" + + VALUE "LegalCopyright", "Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>" + } + } + BLOCK "VarFileInfo" { + VALUE "Translation", 0x0409, 0x04e4 + } +} + +APP_ICON ICON "zbar.ico" |