| /* quirc -- QR-code recognition library |
| * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> |
| * |
| * Permission to use, copy, modify, and/or distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| #include <stdio.h> |
| #include <errno.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <dirent.h> |
| #include <ctype.h> |
| #include <quirc.h> |
| #include <jpeglib.h> |
| #include <setjmp.h> |
| #include <time.h> |
| #include "dbgutil.h" |
| |
| static int want_verbose = 0; |
| static int want_cell_dump = 0; |
| |
| #define MS(ts) (unsigned int)((ts.tv_sec * 1000) + (ts.tv_nsec / 1000000)) |
| |
| static struct quirc *decoder; |
| |
| struct result_info { |
| int file_count; |
| int id_count; |
| int decode_count; |
| |
| unsigned int load_time; |
| unsigned int identify_time; |
| unsigned int total_time; |
| }; |
| |
| static void print_result(const char *name, struct result_info *info) |
| { |
| puts("----------------------------------------" |
| "---------------------------------------"); |
| printf("%s: %d files, %d codes, %d decoded (%d failures)", |
| name, info->file_count, info->id_count, info->decode_count, |
| (info->id_count - info->decode_count)); |
| if (info->id_count) |
| printf(", %d%% success rate", |
| (info->decode_count * 100 + info->id_count / 2) / |
| info->id_count); |
| printf("\n"); |
| printf("Total time [load: %u, identify: %u, total: %u]\n", |
| info->load_time, |
| info->identify_time, |
| info->total_time); |
| if (info->file_count) |
| printf("Average time [load: %u, identify: %u, total: %u]\n", |
| info->load_time / info->file_count, |
| info->identify_time / info->file_count, |
| info->total_time / info->file_count); |
| } |
| |
| static void add_result(struct result_info *sum, struct result_info *inf) |
| { |
| sum->file_count += inf->file_count; |
| sum->id_count += inf->id_count; |
| sum->decode_count += inf->decode_count; |
| |
| sum->load_time += inf->load_time; |
| sum->identify_time += inf->identify_time; |
| sum->total_time += inf->total_time; |
| } |
| |
| static int scan_file(const char *path, const char *filename, |
| struct result_info *info) |
| { |
| int (*loader)(struct quirc *, const char *); |
| int len = strlen(filename); |
| const char *ext; |
| struct timespec tp; |
| unsigned int start; |
| unsigned int total_start; |
| int ret; |
| int i; |
| |
| while (len >= 0 && filename[len] != '.') |
| len--; |
| ext = filename + len + 1; |
| if (strcasecmp(ext, "jpg") == 0 || strcasecmp(ext, "jpeg") == 0) |
| loader = load_jpeg; |
| else if (strcasecmp(ext, "png") == 0) |
| loader = load_png; |
| else |
| return 0; |
| |
| (void)clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); |
| total_start = start = MS(tp); |
| ret = loader(decoder, path); |
| (void)clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); |
| info->load_time = MS(tp) - start; |
| |
| if (ret < 0) { |
| fprintf(stderr, "%s: load failed\n", filename); |
| return -1; |
| } |
| |
| (void)clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); |
| start = MS(tp); |
| quirc_end(decoder); |
| (void)clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); |
| info->identify_time = MS(tp) - start; |
| |
| info->id_count = quirc_count(decoder); |
| for (i = 0; i < info->id_count; i++) { |
| struct quirc_code code; |
| struct quirc_data data; |
| |
| quirc_extract(decoder, i, &code); |
| |
| if (!quirc_decode(&code, &data)) |
| info->decode_count++; |
| } |
| |
| (void)clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); |
| info->total_time += MS(tp) - total_start; |
| |
| printf(" %-30s: %5u %5u %5u %5d %5d\n", filename, |
| info->load_time, |
| info->identify_time, |
| info->total_time, |
| info->id_count, info->decode_count); |
| |
| if (want_cell_dump || want_verbose) { |
| for (i = 0; i < info->id_count; i++) { |
| struct quirc_code code; |
| |
| quirc_extract(decoder, i, &code); |
| if (want_cell_dump) { |
| dump_cells(&code); |
| printf("\n"); |
| } |
| |
| if (want_verbose) { |
| struct quirc_data data; |
| quirc_decode_error_t err = |
| quirc_decode(&code, &data); |
| |
| if (err) { |
| printf(" ERROR: %s\n\n", |
| quirc_strerror(err)); |
| } else { |
| printf(" Decode successful:\n"); |
| dump_data(&data); |
| printf("\n"); |
| } |
| } |
| } |
| } |
| |
| info->file_count = 1; |
| return 1; |
| } |
| |
| static int test_scan(const char *path, struct result_info *info); |
| |
| static int scan_dir(const char *path, const char *filename, |
| struct result_info *info) |
| { |
| DIR *d = opendir(path); |
| struct dirent *ent; |
| int count = 0; |
| |
| if (!d) { |
| fprintf(stderr, "%s: opendir: %s\n", path, strerror(errno)); |
| return -1; |
| } |
| |
| printf("%s:\n", path); |
| |
| while ((ent = readdir(d))) { |
| if (ent->d_name[0] != '.') { |
| char fullpath[1024]; |
| struct result_info sub; |
| |
| snprintf(fullpath, sizeof(fullpath), "%s/%s", |
| path, ent->d_name); |
| if (test_scan(fullpath, &sub) > 0) { |
| add_result(info, &sub); |
| count++; |
| } |
| } |
| } |
| |
| closedir(d); |
| |
| if (count > 1) { |
| print_result(filename, info); |
| puts(""); |
| } |
| |
| return count > 0; |
| } |
| |
| static int test_scan(const char *path, struct result_info *info) |
| { |
| int len = strlen(path); |
| struct stat st; |
| const char *filename; |
| |
| memset(info, 0, sizeof(*info)); |
| |
| while (len >= 0 && path[len] != '/') |
| len--; |
| filename = path + len + 1; |
| |
| if (lstat(path, &st) < 0) { |
| fprintf(stderr, "%s: lstat: %s\n", path, strerror(errno)); |
| return -1; |
| } |
| |
| if (S_ISREG(st.st_mode)) |
| return scan_file(path, filename, info); |
| |
| if (S_ISDIR(st.st_mode)) |
| return scan_dir(path, filename, info); |
| |
| return 0; |
| } |
| |
| static int run_tests(int argc, char **argv) |
| { |
| struct result_info sum; |
| int count = 0; |
| int i; |
| |
| decoder = quirc_new(); |
| if (!decoder) { |
| perror("quirc_new"); |
| return -1; |
| } |
| |
| printf(" %-30s %17s %11s\n", "", "Time (ms)", "Count"); |
| printf(" %-30s %5s %5s %5s %5s %5s\n", |
| "Filename", "Load", "ID", "Total", "ID", "Dec"); |
| puts("----------------------------------------" |
| "---------------------------------------"); |
| |
| memset(&sum, 0, sizeof(sum)); |
| for (i = 0; i < argc; i++) { |
| struct result_info info; |
| |
| if (test_scan(argv[i], &info) > 0) { |
| add_result(&sum, &info); |
| count++; |
| } |
| } |
| |
| if (count > 1) |
| print_result("TOTAL", &sum); |
| |
| quirc_destroy(decoder); |
| return 0; |
| } |
| |
| int main(int argc, char **argv) |
| { |
| int opt; |
| |
| printf("quirc test program\n"); |
| printf("Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>\n"); |
| printf("Library version: %s\n", quirc_version()); |
| printf("\n"); |
| |
| while ((opt = getopt(argc, argv, "vd")) >= 0) |
| switch (opt) { |
| case 'v': |
| want_verbose = 1; |
| break; |
| |
| case 'd': |
| want_cell_dump = 1; |
| break; |
| |
| case '?': |
| return -1; |
| } |
| |
| argv += optind; |
| argc -= optind; |
| |
| return run_tests(argc, argv);; |
| } |