Advertisement
danielhilst

zbarimg.c

Jun 8th, 2016
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.23 KB | None | 0 0
  1. /*------------------------------------------------------------------------
  2. * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
  3. *
  4. * This file is part of the ZBar Bar Code Reader.
  5. *
  6. * The ZBar Bar Code Reader is free software; you can redistribute it
  7. * and/or modify it under the terms of the GNU Lesser Public License as
  8. * published by the Free Software Foundation; either version 2.1 of
  9. * the License, or (at your option) any later version.
  10. *
  11. * The ZBar Bar Code Reader is distributed in the hope that it will be
  12. * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  13. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser Public License
  17. * along with the ZBar Bar Code Reader; if not, write to the Free
  18. * Software Foundation, Inc., 51 Franklin St, Fifth Floor,
  19. * Boston, MA 02110-1301 USA
  20. *
  21. * http://sourceforge.net/projects/zbar
  22. *------------------------------------------------------------------------*/
  23.  
  24. #include <config.h>
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #ifdef HAVE_UNISTD_H
  29. # include <unistd.h>
  30. #endif
  31. #ifdef HAVE_SYS_TIMES_H
  32. # include <sys/times.h>
  33. #endif
  34. #ifdef _WIN32
  35. # include <io.h>
  36. # include <fcntl.h>
  37. #endif
  38. #include <assert.h>
  39.  
  40. #include <zbar.h>
  41. #include <wand/MagickWand.h>
  42.  
  43. /* in 6.4.5.4 MagickGetImagePixels changed to MagickExportImagePixels.
  44. * (still not sure this check is quite right...
  45. * how does MagickGetAuthenticImagePixels fit in?)
  46. * ref http://bugs.gentoo.org/247292
  47. */
  48. #if MagickLibVersion < 0x645
  49. # define MagickExportImagePixels MagickGetImagePixels
  50. #endif
  51.  
  52. static const char *note_usage =
  53. "usage: zbarimg [options] <image>...\n"
  54. "\n"
  55. "scan and decode bar codes from one or more image files\n"
  56. "\n"
  57. "options:\n"
  58. " -h, --help display this help text\n"
  59. " --version display version information and exit\n"
  60. " -q, --quiet minimal output, only print decoded symbol data\n"
  61. " -v, --verbose increase debug output level\n"
  62. " --verbose=N set specific debug output level\n"
  63. " -d, --display enable display of following images to the screen\n"
  64. " -D, --nodisplay disable display of following images (default)\n"
  65. " --xml, --noxml enable/disable XML output format\n"
  66. " --raw output decoded symbol data without symbology prefix\n"
  67. " -S<CONFIG>[=<VALUE>], --set <CONFIG>[=<VALUE>]\n"
  68. " set decoder/scanner <CONFIG> to <VALUE> (or 1)\n"
  69. // FIXME overlay level
  70. "\n"
  71. ;
  72.  
  73. static const char *warning_not_found =
  74. "\n"
  75. "WARNING: barcode data was not detected in some image(s)\n"
  76. " things to check:\n"
  77. " - is the barcode type supported?"
  78. " currently supported symbologies are:\n"
  79. " EAN/UPC (EAN-13, EAN-8, UPC-A, UPC-E, ISBN-10, ISBN-13),\n"
  80. " Code 128, Code 39 and Interleaved 2 of 5\n"
  81. " - is the barcode large enough in the image?\n"
  82. " - is the barcode mostly in focus?\n"
  83. " - is there sufficient contrast/illumination?\n"
  84. "\n";
  85.  
  86. static const char *xml_head =
  87. "<barcodes xmlns='http://zbar.sourceforge.net/2008/barcode'>\n";
  88. static const char *xml_foot =
  89. "</barcodes>\n";
  90.  
  91. static int notfound = 0, exit_code = 0;
  92. static int num_images = 0, num_symbols = 0;
  93. static int xmllvl = 0;
  94.  
  95. char *xmlbuf = NULL;
  96. unsigned xmlbuflen = 0;
  97.  
  98. static zbar_processor_t *processor = NULL;
  99.  
  100. /* CSI */
  101. #include <assert.h>
  102. static long long trace_ts; /* defined at PharosStack.c */
  103. static inline long long clock_gettime_us(void)
  104. {
  105. struct timespec ts;
  106. int status = clock_gettime(CLOCK_MONOTONIC, &ts);
  107. assert(!status);
  108. return (ts.tv_sec * 1e6 + ts.tv_nsec / 1e3);
  109. }
  110. #define _trace(fmt, args...) \
  111. do { \
  112. long long t = clock_gettime_us(); \
  113. fprintf(stderr, "[%012lld] TRACE: " fmt "\n", t - trace_ts, ##args); \
  114. trace_ts = t; \
  115. } while (0)
  116.  
  117. /* CSI */
  118.  
  119. static inline int dump_error(MagickWand *wand)
  120. {
  121. char *desc;
  122. ExceptionType severity;
  123. desc = MagickGetException(wand, &severity);
  124.  
  125. if(severity >= FatalErrorException)
  126. exit_code = 2;
  127. else if(severity >= ErrorException)
  128. exit_code = 1;
  129. else
  130. exit_code = 0;
  131.  
  132. static const char *sevdesc[] = { "WARNING", "ERROR", "FATAL" };
  133. fprintf(stderr, "%s: %s\n", sevdesc[exit_code], desc);
  134.  
  135. MagickRelinquishMemory(desc);
  136. return(exit_code);
  137. }
  138.  
  139. static int scan_image (const char *filename)
  140. {
  141. _trace("---");
  142. if(exit_code == 3)
  143. return(-1);
  144.  
  145. int found = 0;
  146. MagickWand *images = NewMagickWand();
  147. _trace("NewMagicWand()");
  148. if(!MagickReadImage(images, filename) && dump_error(images))
  149. return(-1);
  150.  
  151. unsigned seq, n = MagickGetNumberImages(images);
  152. _trace("MagickGetNumberImages, %d", n);
  153. if(!MagickReadImage(images, filename) && dump_error(images))
  154. return(-1);
  155.  
  156. for(seq = 0; seq < n; seq++) {
  157. if(exit_code == 3)
  158. return(-1);
  159.  
  160. if(!MagickSetIteratorIndex(images, seq) && dump_error(images))
  161. return(-1);
  162. _trace("MagickSetIteratorIndex");
  163.  
  164. zbar_image_t *zimage = zbar_image_create();
  165. _trace("zbar_image_create()");
  166. assert(zimage);
  167. zbar_image_set_format(zimage, *(unsigned long*)"Y800");
  168. _trace("zbar_image_set_format");
  169.  
  170. int width = MagickGetImageWidth(images);
  171. _trace("MagickGetImageWidth");
  172. int height = MagickGetImageHeight(images);
  173. _trace("MagickGetImageHeight");
  174. zbar_image_set_size(zimage, width, height);
  175. _trace("zbar_image_set_size");
  176.  
  177. // extract grayscale image pixels
  178. // FIXME color!! ...preserve most color w/422P
  179. // (but only if it's a color image)
  180. size_t bloblen = width * height;
  181. unsigned char *blob = malloc(bloblen);
  182. _trace("malloc");
  183. zbar_image_set_data(zimage, blob, bloblen, zbar_image_free_data);
  184. _trace("zbar_image_set_data");
  185. if(!MagickExportImagePixels(images, 0, 0, width, height,
  186. "I", CharPixel, blob))
  187. return(-1);
  188. _trace("MagickExportImagePixels");
  189. if(xmllvl == 1) {
  190. xmllvl++;
  191. printf("<source href='%s'>\n", filename);
  192. }
  193.  
  194. zbar_process_image(processor, zimage);
  195. _trace("zbar_process_image");
  196.  
  197. // output result data
  198. const zbar_symbol_t *sym = zbar_image_first_symbol(zimage);
  199. for(; sym; sym = zbar_symbol_next(sym)) {
  200. zbar_symbol_type_t typ = zbar_symbol_get_type(sym);
  201. if(typ == ZBAR_PARTIAL)
  202. continue;
  203. else if(!xmllvl)
  204. printf("%s%s:%s\n",
  205. zbar_get_symbol_name(typ),
  206. zbar_get_addon_name(typ),
  207. zbar_symbol_get_data(sym));
  208. else if(xmllvl < 0)
  209. printf("%s\n", zbar_symbol_get_data(sym));
  210. else {
  211. if(xmllvl < 3) {
  212. xmllvl++;
  213. printf("<index num='%u'>\n", seq);
  214. }
  215. zbar_symbol_xml(sym, &xmlbuf, &xmlbuflen);
  216. printf("%s\n", xmlbuf);
  217. }
  218. found++;
  219. num_symbols++;
  220. }
  221. _trace("output data");
  222. if(xmllvl > 2) {
  223. xmllvl--;
  224. printf("</index>\n");
  225. }
  226. fflush(stdout);
  227. _trace("flush stdout");
  228.  
  229. zbar_image_destroy(zimage);
  230. _trace("zbar_image_destroy");
  231.  
  232. num_images++;
  233. if(zbar_processor_is_visible(processor)) {
  234. int rc = zbar_processor_user_wait(processor, -1);
  235. if(rc < 0 || rc == 'q' || rc == 'Q')
  236. exit_code = 3;
  237. }
  238. _trace("zbar_processor_is_visible");
  239. }
  240.  
  241. if(xmllvl > 1) {
  242. xmllvl--;
  243. printf("</source>\n");
  244. }
  245.  
  246. if(!found)
  247. notfound++;
  248.  
  249. DestroyMagickWand(images);
  250. _trace("DestroyMagickWand");
  251. return(0);
  252. }
  253.  
  254. int usage (int rc,
  255. const char *msg,
  256. const char *arg)
  257. {
  258. FILE *out = (rc) ? stderr : stdout;
  259. if(msg) {
  260. fprintf(out, "%s", msg);
  261. if(arg)
  262. fprintf(out, "%s", arg);
  263. fprintf(out, "\n\n");
  264. }
  265. fprintf(out, "%s", note_usage);
  266. return(rc);
  267. }
  268.  
  269. static inline int parse_config (const char *cfgstr, const char *arg)
  270. {
  271. if(!cfgstr || !cfgstr[0])
  272. return(usage(1, "ERROR: need argument for option: ", arg));
  273.  
  274. if(zbar_processor_parse_config(processor, cfgstr))
  275. return(usage(1, "ERROR: invalid configuration setting: ", cfgstr));
  276.  
  277. return(0);
  278. }
  279.  
  280. int main (int argc, const char *argv[])
  281. {
  282. // option pre-scan
  283. int quiet = 0;
  284. int display = 0;
  285. int i, j;
  286. for(i = 1; i < argc; i++) {
  287. const char *arg = argv[i];
  288. if(arg[0] != '-')
  289. // first pass, skip images
  290. num_images++;
  291. else if(arg[1] != '-')
  292. for(j = 1; arg[j]; j++) {
  293. if(arg[j] == 'S') {
  294. if(!arg[++j] && ++i >= argc)
  295. /* FIXME parse check */
  296. return(parse_config("", "-S"));
  297. break;
  298. }
  299. switch(arg[j]) {
  300. case 'h': return(usage(0, NULL, NULL));
  301. case 'q': quiet = 1; break;
  302. case 'v': zbar_increase_verbosity(); break;
  303. case 'd': display = 1; break;
  304. case 'D': break;
  305. default:
  306. return(usage(1, "ERROR: unknown bundled option: -",
  307. arg + j));
  308. }
  309. }
  310. else if(!strcmp(arg, "--help"))
  311. return(usage(0, NULL, NULL));
  312. else if(!strcmp(arg, "--version")) {
  313. printf("%s\n", PACKAGE_VERSION);
  314. return(0);
  315. }
  316. else if(!strcmp(arg, "--quiet")) {
  317. quiet = 1;
  318. argv[i] = NULL;
  319. }
  320. else if(!strcmp(arg, "--verbose"))
  321. zbar_increase_verbosity();
  322. else if(!strncmp(arg, "--verbose=", 10))
  323. zbar_set_verbosity(strtol(argv[i] + 10, NULL, 0));
  324. else if(!strcmp(arg, "--display"))
  325. display++;
  326. else if(!strcmp(arg, "--nodisplay") ||
  327. !strcmp(arg, "--set") ||
  328. !strcmp(arg, "--xml") ||
  329. !strcmp(arg, "--noxml") ||
  330. !strcmp(arg, "--raw") ||
  331. !strncmp(arg, "--set=", 6))
  332. continue;
  333. else if(!strcmp(arg, "--")) {
  334. num_images += argc - i - 1;
  335. break;
  336. }
  337. else
  338. return(usage(1, "ERROR: unknown option: ", arg));
  339. }
  340.  
  341. if(!num_images)
  342. return(usage(1, "ERROR: specify image file(s) to scan", NULL));
  343. num_images = 0;
  344.  
  345. MagickWandGenesis();
  346.  
  347. processor = zbar_processor_create(0);
  348. assert(processor);
  349. if(zbar_processor_init(processor, NULL, display)) {
  350. zbar_processor_error_spew(processor, 0);
  351. return(1);
  352. }
  353.  
  354. for(i = 1; i < argc; i++) {
  355. const char *arg = argv[i];
  356. if(!arg)
  357. continue;
  358.  
  359. if(arg[0] != '-') {
  360. if(scan_image(arg))
  361. return(exit_code);
  362. }
  363. else if(arg[1] != '-')
  364. for(j = 1; arg[j]; j++) {
  365. if(arg[j] == 'S') {
  366. if((arg[++j])
  367. ? parse_config(arg + j, "-S")
  368. : parse_config(argv[++i], "-S"))
  369. return(1);
  370. break;
  371. }
  372. switch(arg[j]) {
  373. case 'd': zbar_processor_set_visible(processor, 1); break;
  374. case 'D': zbar_processor_set_visible(processor, 0); break;
  375. }
  376. }
  377. else if(!strcmp(arg, "--display"))
  378. zbar_processor_set_visible(processor, 1);
  379. else if(!strcmp(arg, "--nodisplay"))
  380. zbar_processor_set_visible(processor, 0);
  381. else if(!strcmp(arg, "--xml")) {
  382. if(xmllvl < 1) {
  383. xmllvl = 1;
  384. #ifdef _WIN32
  385. fflush(stdout);
  386. _setmode(_fileno(stdout), _O_BINARY);
  387. #endif
  388. printf("%s", xml_head);
  389. }
  390. }
  391. else if(!strcmp(arg, "--noxml") || !strcmp(arg, "--raw")) {
  392. if(xmllvl > 0) {
  393. xmllvl = 0;
  394. printf("%s", xml_foot);
  395. fflush(stdout);
  396. #ifdef _WIN32
  397. _setmode(_fileno(stdout), _O_TEXT);
  398. #endif
  399. }
  400. if(!strcmp(arg, "--raw")) {
  401. xmllvl = -1;
  402. #ifdef _WIN32
  403. fflush(stdout);
  404. _setmode(_fileno(stdout), _O_BINARY);
  405. #endif
  406. }
  407. }
  408. else if(!strcmp(arg, "--set")) {
  409. if(parse_config(argv[++i], "--set"))
  410. return(1);
  411. }
  412. else if(!strncmp(arg, "--set=", 6)) {
  413. if(parse_config(arg + 6, "--set="))
  414. return(1);
  415. }
  416. else if(!strcmp(arg, "--"))
  417. break;
  418. }
  419. for(i++; i < argc; i++)
  420. if(scan_image(argv[i]))
  421. return(exit_code);
  422.  
  423. /* ignore quit during last image */
  424. if(exit_code == 3)
  425. exit_code = 0;
  426.  
  427. if(xmllvl > 0) {
  428. xmllvl = -1;
  429. printf("%s", xml_foot);
  430. fflush(stdout);
  431. }
  432.  
  433. if(xmlbuf)
  434. free(xmlbuf);
  435.  
  436. if(num_images && !quiet && xmllvl <= 0) {
  437. fprintf(stderr, "scanned %d barcode symbols from %d images",
  438. num_symbols, num_images);
  439. #ifdef HAVE_SYS_TIMES_H
  440. #ifdef HAVE_UNISTD_H
  441. long clk_tck = sysconf(_SC_CLK_TCK);
  442. struct tms tms;
  443. if(clk_tck > 0 && times(&tms) >= 0) {
  444. double secs = tms.tms_utime + tms.tms_stime;
  445. secs /= clk_tck;
  446. fprintf(stderr, " in %.2g seconds\n", secs);
  447. }
  448. #endif
  449. #endif
  450. fprintf(stderr, "\n");
  451. if(notfound)
  452. fprintf(stderr, "%s", warning_not_found);
  453. }
  454. if(num_images && notfound && !exit_code)
  455. exit_code = 4;
  456.  
  457. zbar_processor_destroy(processor);
  458. MagickWandTerminus();
  459. return(exit_code);
  460. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement