diff options
Diffstat (limited to 'genqrcode/tests/view_qrcode.c')
| -rw-r--r-- | genqrcode/tests/view_qrcode.c | 641 |
1 files changed, 641 insertions, 0 deletions
diff --git a/genqrcode/tests/view_qrcode.c b/genqrcode/tests/view_qrcode.c new file mode 100644 index 0000000000..f9d1bea96b --- /dev/null +++ b/genqrcode/tests/view_qrcode.c @@ -0,0 +1,641 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <SDL.h> +#include <getopt.h> +#include <errno.h> +#include "../config.h" +#include "../qrspec.h" +#include "../qrinput.h" +#include "../split.h" +#include "../qrencode_inner.h" + +static SDL_Window *window; +static SDL_Renderer *renderer; +static SDL_Texture *texture = NULL; +static SDL_Surface *surface = NULL; +static int casesensitive = 1; +static int eightbit = 0; +static int version = 0; +static int size = 4; +static int margin = -1; +static int structured = 0; +static int micro = 0; +static int colorize = 0; +static QRecLevel level = QR_ECLEVEL_L; +static QRencodeMode hint = QR_MODE_8; + +static char **textv; +static int textc; + +static const struct option options[] = { + {"help" , no_argument , NULL, 'h'}, + {"level" , required_argument, NULL, 'l'}, + {"size" , required_argument, NULL, 's'}, + {"symversion" , required_argument, NULL, 'v'}, + {"margin" , required_argument, NULL, 'm'}, + {"structured" , no_argument , NULL, 'S'}, + {"kanji" , no_argument , NULL, 'k'}, + {"casesensitive", no_argument , NULL, 'c'}, + {"ignorecase" , no_argument , NULL, 'i'}, + {"8bit" , no_argument , NULL, '8'}, + {"micro" , no_argument , NULL, 'M'}, + {"version" , no_argument , NULL, 'V'}, + {NULL, 0, NULL, 0} +}; + +static char *optstring = "hl:s:v:m:Skci8MV"; + +static char levelChar[4] = {'L', 'M', 'Q', 'H'}; +static void usage(int help, int longopt) +{ + fprintf(stderr, +"view_qrcode version %s\n" +"Copyright (C) 2008, 2009, 2010 Kentaro Fukuchi\n", VERSION); + if(help) { + if(longopt) { + fprintf(stderr, +"Usage: view_qrcode [OPTION]... [STRING]\n" +"Encode input data in a QR Code and display.\n\n" +" -h, --help display the help message. -h displays only the help of short\n" +" options.\n\n" +" -s NUMBER, --size=NUMBER\n" +" specify module size in dots (pixels). (default=3)\n\n" +" -l {LMQH}, --level={LMQH}\n" +" specify error correction level from L (lowest) to H (highest).\n" +" (default=L)\n\n" +" -v NUMBER, --symversion=NUMBER\n" +" specify the version of the symbol. See SYMBOL VERSIONS for more\n" +" information. (default=auto)\n\n" +" -m NUMBER, --margin=NUMBER\n" +" specify the width of the margins. (default=4 (2 for Micro QR)))\n\n" +" -S, --structured\n" +" make structured symbols. Version must be specified.\n\n" +" -k, --kanji assume that the input text contains kanji (shift-jis).\n\n" +" -c, --casesensitive\n" +" encode lower-case alphabet characters in 8-bit mode. (default)\n\n" +" -i, --ignorecase\n" +" ignore case distinctions and use only upper-case characters.\n\n" +" -8, --8bit encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n\n" +" -M, --micro encode in a Micro QR Code. (experimental)\n\n" +" -V, --version\n" +" display the version number and copyrights of the qrencode.\n\n" +" [STRING] input data. If it is not specified, data will be taken from\n" +" standard input.\n\n" +"*SYMBOL VERSIONS\n" +" The symbol versions of QR Code range from Version 1 to Version\n" +" 40. Each version has a different module configuration or number\n" +" of modules, ranging from Version 1 (21 x 21 modules) up to\n" +" Version 40 (177 x 177 modules). Each higher version number\n" +" comprises 4 additional modules per side by default. See\n" +" http://www.qrcode.com/en/about/version.html for a detailed\n" +" version list.\n" + ); + } else { + fprintf(stderr, +"Usage: view_qrcode [OPTION]... [STRING]\n" +"Encode input data in a QR Code and display.\n\n" +" -h display this message.\n" +" --help display the usage of long options.\n" +" -s NUMBER specify module size in dots (pixels). (default=3)\n" +" -l {LMQH} specify error correction level from L (lowest) to H (highest).\n" +" (default=L)\n" +" -v NUMBER specify the version of the symbol. (default=auto)\n" +" -m NUMBER specify the width of the margins. (default=4 (2 for Micro))\n" +" -S make structured symbols. Version must be specified.\n" +" -k assume that the input text contains kanji (shift-jis).\n" +" -c encode lower-case alphabet characters in 8-bit mode. (default)\n" +" -i ignore case distinctions and use only upper-case characters.\n" +" -8 encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n" +" -M encode in a Micro QR Code.\n" +" -V display the version number and copyrights of the qrencode.\n" +" [STRING] input data. If it is not specified, data will be taken from\n" +" standard input.\n" + ); + } + } +} + +#define MAX_DATA_SIZE (7090 * 16) /* from the specification */ +static unsigned char *readStdin(int *length) +{ + unsigned char *buffer; + int ret; + + buffer = (unsigned char *)malloc(MAX_DATA_SIZE + 1); + if(buffer == NULL) { + fprintf(stderr, "Memory allocation failed.\n"); + exit(EXIT_FAILURE); + } + + ret = fread(buffer, 1, MAX_DATA_SIZE, stdin); + if(ret == 0) { + fprintf(stderr, "No input data.\n"); + exit(EXIT_FAILURE); + } + if(feof(stdin) == 0) { + fprintf(stderr, "Input data is too large.\n"); + exit(EXIT_FAILURE); + } + + buffer[ret] = '\0'; + *length = ret; + + return buffer; +} + +static void draw_QRcode(QRcode *qrcode, int ox, int oy) +{ + int x, y, width; + unsigned char *p; + SDL_Rect rect; + Uint32 color[8]; + int col; + + color[0] = SDL_MapRGBA(surface->format, 255, 255, 255, 255); + color[1] = SDL_MapRGBA(surface->format, 0, 0, 0, 255); + color[2] = SDL_MapRGBA(surface->format, 192, 192, 255, 255); + color[3] = SDL_MapRGBA(surface->format, 0, 0, 64, 255); + color[4] = SDL_MapRGBA(surface->format, 255, 255, 192, 255); + color[5] = SDL_MapRGBA(surface->format, 64, 64, 0, 255); + color[6] = SDL_MapRGBA(surface->format, 255, 192, 192, 255); + color[7] = SDL_MapRGBA(surface->format, 64, 0, 0, 255); + + ox += margin * size; + oy += margin * size; + width = qrcode->width; + p = qrcode->data; + for(y=0; y<width; y++) { + for(x=0; x<width; x++) { + rect.x = ox + x * size; + rect.y = oy + y * size; + rect.w = size; + rect.h = size; + if(!colorize) { + col = 0; + } else { + if(*p & 0x80) { + col = 6; + } else if(*p & 0x02) { + col = 4; + } else { + col = 2; + } + } + col += (*p & 1); + SDL_FillRect(surface, &rect, color[col]); + p++; + } + } +} + +static void draw_singleQRcode(QRinput *stream, int mask) +{ + QRcode *qrcode; + int width; + + QRinput_setVersionAndErrorCorrectionLevel(stream, version, level); + if(micro) { + qrcode = QRcode_encodeMaskMQR(stream, mask); + } else { + qrcode = QRcode_encodeMask(stream, mask); + } + if(qrcode == NULL) { + width = (11 + margin * 2) * size; + fprintf(stderr, "Input data does not fit to this setting.\n"); + } else { + version = qrcode->version; + width = (qrcode->width + margin * 2) * size; + } + + SDL_SetWindowSize(window, width, width); + if(surface != NULL) { + SDL_FreeSurface(surface); + } + surface = SDL_CreateRGBSurface(0, width, width, 32, 0, 0, 0, 0); + SDL_FillRect(surface, NULL, SDL_MapRGBA(surface->format, 255, 255, 255, 255)); + if(qrcode) { + draw_QRcode(qrcode, 0, 0); + } + if(texture != NULL) { + SDL_DestroyTexture(texture); + } + texture = SDL_CreateTextureFromSurface(renderer, surface); + QRcode_free(qrcode); +} + +static void draw_structuredQRcode(QRinput_Struct *s) +{ + int i, w, h, n, x, y; + int swidth; + QRcode_List *qrcodes, *p; + + qrcodes = QRcode_encodeInputStructured(s); + if(qrcodes == NULL) return; + + swidth = (qrcodes->code->width + margin * 2) * size; + n = QRcode_List_size(qrcodes); + w = (n < 4)?n:4; + h = (n - 1) / 4 + 1; + + SDL_SetWindowSize(window, swidth * w, swidth * h); + if(surface != NULL) { + SDL_FreeSurface(surface); + } + surface = SDL_CreateRGBSurface(0, swidth * w, swidth * h, 32, 0, 0, 0, 0); + SDL_FillRect(surface, NULL, SDL_MapRGBA(surface->format, 255, 255, 255, 255)); + + p = qrcodes; + for(i=0; i<n; i++) { + x = (i % 4) * swidth; + y = (i / 4) * swidth; + draw_QRcode(p->code, x, y); + p = p->next; + } + if(texture != NULL) { + SDL_DestroyTexture(texture); + } + texture = SDL_CreateTextureFromSurface(renderer, surface); + QRcode_List_free(qrcodes); +} + +static void draw_structuredQRcodeFromText(int argc, char **argv) +{ + QRinput_Struct *s; + QRinput *input; + int i, ret; + + s = QRinput_Struct_new(); + if(s == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + for(i=0; i<argc; i++) { + input = QRinput_new2(version, level); + if(input == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + if(eightbit) { + ret = QRinput_append(input, QR_MODE_8, strlen(argv[i]), (unsigned char *)argv[i]); + } else { + ret = Split_splitStringToQRinput(argv[i], input, hint, casesensitive); + } + if(ret < 0) { + perror("Encoding the input string"); + exit(EXIT_FAILURE); + } + ret = QRinput_Struct_appendInput(s, input); + if(ret < 0) { + perror("Encoding the input string"); + exit(EXIT_FAILURE); + } + } + ret = QRinput_Struct_insertStructuredAppendHeaders(s); + if(ret < 0) { + fprintf(stderr, "Too many inputs.\n"); + } + + draw_structuredQRcode(s); + QRinput_Struct_free(s); +} + +static void draw_structuredQRcodeFromQRinput(QRinput *stream) +{ + QRinput_Struct *s; + + QRinput_setVersion(stream, version); + QRinput_setErrorCorrectionLevel(stream, level); + s = QRinput_splitQRinputToStruct(stream); + if(s != NULL) { + draw_structuredQRcode(s); + QRinput_Struct_free(s); + } else { + fprintf(stderr, "Input data is too large for this setting.\n"); + } +} + +static void view(int mode, QRinput *input) +{ + int flag = 1; + int mask = -1; + SDL_Event event; + int loop; + int codeChanged = 1; + + while(flag) { + if(codeChanged) { + if(mode) { + draw_structuredQRcodeFromText(textc, textv); + } else { + if(structured) { + draw_structuredQRcodeFromQRinput(input); + } else { + draw_singleQRcode(input, mask); + } + } + if(mode || structured) { + printf("Version %d, Level %c.\n", version, levelChar[level]); + } else { + printf("Version %d, Level %c, Mask %d.\n", version, levelChar[level], mask); + } + } + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); + loop = 1; + codeChanged = 0; + while(loop) { + SDL_WaitEvent(&event); + if(event.type == SDL_KEYDOWN) { + codeChanged = 1; + switch(event.key.keysym.sym) { + case SDLK_RIGHT: + version++; + if(version > QRSPEC_VERSION_MAX) + version = QRSPEC_VERSION_MAX; + loop = 0; + break; + case SDLK_LEFT: + version--; + if(version < 1) + version = 1; + loop = 0; + break; + case SDLK_UP: + size++; + loop = 0; + break; + case SDLK_DOWN: + size--; + if(size < 1) size = 1; + loop = 0; + break; + case SDLK_0: + case SDLK_1: + case SDLK_2: + case SDLK_3: + case SDLK_4: + case SDLK_5: + case SDLK_6: + case SDLK_7: + if(!mode && !structured) { + mask = (event.key.keysym.sym - SDLK_0); + loop = 0; + } + break; + case SDLK_8: + if(!mode && !structured) { + mask = -1; + loop = 0; + } + break; + case SDLK_9: + if(!mode && !structured) { + mask = -2; + loop = 0; + } + break; + case SDLK_l: + level = QR_ECLEVEL_L; + loop = 0; + break; + case SDLK_m: + level = QR_ECLEVEL_M; + loop = 0; + break; + case SDLK_h: + level = QR_ECLEVEL_H; + loop = 0; + break; + case SDLK_q: + level = QR_ECLEVEL_Q; + loop = 0; + break; + case SDLK_c: + colorize ^= 1; + loop = 0; + break; + case SDLK_ESCAPE: + loop = 0; + flag = 0; + break; + default: + break; + } + if(event.type == SDL_QUIT) { + loop = 0; + flag = 0; + } + } + if (event.type == SDL_WINDOWEVENT) { + switch (event.window.event) { + case SDL_WINDOWEVENT_SHOWN: + case SDL_WINDOWEVENT_EXPOSED: + case SDL_WINDOWEVENT_SIZE_CHANGED: + case SDL_WINDOWEVENT_RESIZED: + loop = 0; + break; + default: + break; + } + } + } + } +} + +static void view_simple(const unsigned char *str, int length) +{ + QRinput *input; + int ret; + + if(micro) { + input = QRinput_newMQR(version, level); + } else { + input = QRinput_new2(version, level); + } + if(input == NULL) { + fprintf(stderr, "Memory allocation error.\n"); + exit(EXIT_FAILURE); + } + if(eightbit) { + ret = QRinput_append(input, QR_MODE_8, length, str); + } else { + ret = Split_splitStringToQRinput((char *)str, input, hint, casesensitive); + } + if(ret < 0) { + perror("Encoding the input string"); + exit(EXIT_FAILURE); + } + + view(0, input); + + QRinput_free(input); +} + +static void view_multiText(char **argv, int argc) +{ + textc = argc; + textv = argv; + + view(1, NULL); +} + +int main(int argc, char **argv) +{ + int opt, lindex = -1; + unsigned char *intext = NULL; + int length = 0; + int ret; + + while((opt = getopt_long(argc, argv, optstring, options, &lindex)) != -1) { + switch(opt) { + case 'h': + if(lindex == 0) { + usage(1, 1); + } else { + usage(1, 0); + } + exit(EXIT_SUCCESS); + break; + case 's': + size = atoi(optarg); + if(size <= 0) { + fprintf(stderr, "Invalid size: %d\n", size); + exit(EXIT_FAILURE); + } + break; + case 'v': + version = atoi(optarg); + if(version < 0) { + fprintf(stderr, "Invalid version: %d\n", version); + exit(EXIT_FAILURE); + } + break; + case 'l': + switch(*optarg) { + case 'l': + case 'L': + level = QR_ECLEVEL_L; + break; + case 'm': + case 'M': + level = QR_ECLEVEL_M; + break; + case 'q': + case 'Q': + level = QR_ECLEVEL_Q; + break; + case 'h': + case 'H': + level = QR_ECLEVEL_H; + break; + default: + fprintf(stderr, "Invalid level: %s\n", optarg); + exit(EXIT_FAILURE); + break; + } + break; + case 'm': + margin = atoi(optarg); + if(margin < 0) { + fprintf(stderr, "Invalid margin: %d\n", margin); + exit(EXIT_FAILURE); + } + break; + case 'S': + structured = 1; + case 'k': + hint = QR_MODE_KANJI; + break; + case 'c': + casesensitive = 1; + break; + case 'i': + casesensitive = 0; + break; + case '8': + eightbit = 1; + break; + case 'M': + micro = 1; + break; + case 'V': + usage(0, 0); + exit(EXIT_SUCCESS); + break; + default: + fprintf(stderr, "Try `view_qrcode --help' for more information.\n"); + exit(EXIT_FAILURE); + break; + } + } + + if(argc == 1) { + usage(1, 0); + exit(EXIT_SUCCESS); + } + + if(optind < argc) { + intext = (unsigned char *)argv[optind]; + length = strlen((char *)intext); + } + if(intext == NULL) { + intext = readStdin(&length); + } + + if(micro && version > MQRSPEC_VERSION_MAX) { + fprintf(stderr, "Version should be less or equal to %d.\n", MQRSPEC_VERSION_MAX); + exit(EXIT_FAILURE); + } else if(!micro && version > QRSPEC_VERSION_MAX) { + fprintf(stderr, "Version should be less or equal to %d.\n", QRSPEC_VERSION_MAX); + exit(EXIT_FAILURE); + } + + if(margin < 0) { + if(micro) { + margin = 2; + } else { + margin = 4; + } + } + + if(micro) { + if(version == 0) { + fprintf(stderr, "Version must be specified to encode a Micro QR Code symbol.\n"); + exit(EXIT_FAILURE); + } + if(structured) { + fprintf(stderr, "Micro QR Code does not support structured symbols.\n"); + exit(EXIT_FAILURE); + } + } + + if(structured && version == 0) { + fprintf(stderr, "Version must be specified to encode structured symbols.\n"); + exit(EXIT_FAILURE); + } + + if(SDL_Init(SDL_INIT_VIDEO) < 0) { + fprintf(stderr, "Failed initializing SDL: %s\n", SDL_GetError()); + return -1; + } + + ret = SDL_CreateWindowAndRenderer(100, 100, SDL_WINDOW_SHOWN, &window, &renderer); + if(ret < 0) { + fprintf(stderr, "Failed to create a window: %s\n", SDL_GetError()); + return -1; + } + + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + + if(structured && (argc - optind > 1)) { + view_multiText(argv + optind, argc - optind); + } else { + view_simple(intext, length); + } + + SDL_Quit(); + + return 0; +} |
