├── README.md ├── clib ├── img.c ├── libimg.so └── makefile └── lib └── resty └── QRcode.lua /README.md: -------------------------------------------------------------------------------- 1 | libqrencode(http://fukuchi.org/works/qrencode/index.html.en) and libpng is need: 2 | sudo apt-get install libqrencode-dev libpng12-dev 3 | 4 | How to Use 5 | 6 | local resty_qr = require "resty.QRcode"; 7 | 8 | local str = "http://dcshi.com"; 9 | 10 | local file = "/tmp/qr.png"; 11 | 12 | local color = "FF00F3"; --RGB 13 | 14 | local qr = resty_qr:new(8, 4, 72, color); -- size margin dpi fg_color bg_color 15 | 16 | local status = qr:saveQr(str, 0, 2, file) -- str level mode path_img 17 | -------------------------------------------------------------------------------- /clib/img.c: -------------------------------------------------------------------------------- 1 | #if HAVE_CONFIG_H 2 | # include "config.h" 3 | #endif 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "qrencode.h" 10 | 11 | #define INCHES_PER_METER (100.0/2.54) 12 | 13 | typedef struct { 14 | int size; 15 | int margin; 16 | int dpi; 17 | unsigned int fg_color[4]; 18 | unsigned int bg_color[4]; 19 | } imgPro; 20 | 21 | int color_set(unsigned int color[4], const char *value) 22 | { 23 | int len = strlen(value); 24 | int count; 25 | if(len == 6) { 26 | count = sscanf(value, "%02x%02x%02x%n", &color[0], &color[1], &color[2], &len); 27 | if(count < 3 || len != 6) { 28 | return -1; 29 | } 30 | color[3] = 255; 31 | } else if(len == 8) { 32 | count = sscanf(value, "%02x%02x%02x%02x%n", &color[0], &color[1], &color[2], &color[3], &len); 33 | if(count < 4 || len != 8) { 34 | return -1; 35 | } 36 | } else { 37 | return -1; 38 | } 39 | return 0; 40 | } 41 | 42 | void init(imgPro *pro, int size, int margin, int dpi, const char *fg_val, const char *bg_val) 43 | { 44 | pro->size = size; 45 | pro->margin = margin; 46 | pro->dpi = dpi; 47 | 48 | if (fg_val) 49 | color_set(pro->fg_color, fg_val); 50 | else { 51 | pro->fg_color[0] = 0; 52 | pro->fg_color[1] = 0; 53 | pro->fg_color[2] = 0; 54 | pro->fg_color[3] = 255; 55 | } 56 | 57 | if(bg_val) 58 | color_set(pro->bg_color, bg_val); 59 | else { 60 | pro->bg_color[0] = 255; 61 | pro->bg_color[1] = 255; 62 | pro->bg_color[2] = 255; 63 | pro->bg_color[3] = 255; 64 | } 65 | } 66 | 67 | int save(imgPro *pro, QRcode *qrcode, const char *outfile) 68 | { 69 | static FILE *fp; // avoid clobbering by setjmp. 70 | png_structp png_ptr; 71 | png_infop info_ptr; 72 | png_colorp palette; 73 | png_byte alpha_values[2]; 74 | unsigned char *row, *p, *q; 75 | int x, y, xx, yy, bit; 76 | int realwidth; 77 | 78 | realwidth = (qrcode->width + pro->margin * 2) * pro->size; 79 | row = (unsigned char *)malloc((realwidth + 7) / 8); 80 | if(row == NULL) { 81 | fprintf(stderr, "Failed to allocate memory.\n"); 82 | return -1; 83 | } 84 | 85 | if(outfile[0] == '-' && outfile[1] == '\0') { 86 | fp = stdout; 87 | } else { 88 | fp = fopen(outfile, "wb"); 89 | if(fp == NULL) { 90 | fprintf(stderr, "Failed to create file: %s\n", outfile); 91 | perror(NULL); 92 | return -1; 93 | } 94 | } 95 | 96 | png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 97 | if(png_ptr == NULL) { 98 | fprintf(stderr, "Failed to initialize PNG writer.\n"); 99 | return -1; 100 | } 101 | 102 | info_ptr = png_create_info_struct(png_ptr); 103 | if(info_ptr == NULL) { 104 | fprintf(stderr, "Failed to initialize PNG write.\n"); 105 | return -1; 106 | } 107 | 108 | if(setjmp(png_jmpbuf(png_ptr))) { 109 | png_destroy_write_struct(&png_ptr, &info_ptr); 110 | fprintf(stderr, "Failed to write PNG image.\n"); 111 | return -1; 112 | } 113 | 114 | palette = (png_colorp) malloc(sizeof(png_color) * 2); 115 | palette[0].red = pro->fg_color[0]; 116 | palette[0].green = pro->fg_color[1]; 117 | palette[0].blue = pro->fg_color[2]; 118 | palette[1].red = pro->bg_color[0]; 119 | palette[1].green = pro->bg_color[1]; 120 | palette[1].blue = pro->bg_color[2]; 121 | alpha_values[0] = pro->fg_color[3]; 122 | alpha_values[1] = pro->bg_color[3]; 123 | png_set_PLTE(png_ptr, info_ptr, palette, 2); 124 | png_set_tRNS(png_ptr, info_ptr, alpha_values, 2, NULL); 125 | 126 | png_init_io(png_ptr, fp); 127 | png_set_IHDR(png_ptr, info_ptr, 128 | realwidth, realwidth, 129 | 1, 130 | PNG_COLOR_TYPE_PALETTE, 131 | PNG_INTERLACE_NONE, 132 | PNG_COMPRESSION_TYPE_DEFAULT, 133 | PNG_FILTER_TYPE_DEFAULT); 134 | png_set_pHYs(png_ptr, info_ptr, 135 | pro->dpi * INCHES_PER_METER, 136 | pro->dpi * INCHES_PER_METER, 137 | PNG_RESOLUTION_METER); 138 | png_write_info(png_ptr, info_ptr); 139 | 140 | /* top margin */ 141 | memset(row, 0xff, (realwidth + 7) / 8); 142 | for(y=0; ymargin * pro->size; y++) { 143 | png_write_row(png_ptr, row); 144 | } 145 | 146 | /* data */ 147 | p = qrcode->data; 148 | for(y=0; ywidth; y++) { 149 | bit = 7; 150 | memset(row, 0xff, (realwidth + 7) / 8); 151 | q = row; 152 | q += pro->margin * pro->size / 8; 153 | bit = 7 - (pro->margin * pro->size % 8); 154 | for(x=0; xwidth; x++) { 155 | for(xx=0; xxsize; xx++) { 156 | *q ^= (*p & 1) << bit; 157 | bit--; 158 | if(bit < 0) { 159 | q++; 160 | bit = 7; 161 | } 162 | } 163 | p++; 164 | } 165 | for(yy=0; yysize; yy++) { 166 | png_write_row(png_ptr, row); 167 | } 168 | } 169 | /* bottom margin */ 170 | memset(row, 0xff, (realwidth + 7) / 8); 171 | for(y=0; ymargin * pro->size; y++) { 172 | png_write_row(png_ptr, row); 173 | } 174 | 175 | png_write_end(png_ptr, info_ptr); 176 | png_destroy_write_struct(&png_ptr, &info_ptr); 177 | 178 | fclose(fp); 179 | free(row); 180 | free(palette); 181 | 182 | return 0; 183 | } 184 | -------------------------------------------------------------------------------- /clib/libimg.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcshi/lua-resty-QRcode/a6340a9448f77f5c8d5756f59597021816101b54/clib/libimg.so -------------------------------------------------------------------------------- /clib/makefile: -------------------------------------------------------------------------------- 1 | CC := gcc 2 | LD := ld 3 | CFLAGS := -fPIC 4 | LIB := -lpng 5 | LDFLAGS := -shared -fpic 6 | SOURCE := $(wildcard *.c) 7 | OBJS := $(patsubst %.c,%.o,$(SOURCE)) 8 | TARGET_LIB := libimg.so 9 | 10 | all:$(OBJS) 11 | @echo $(OBJS) 12 | $(LD) $(LDFLAGS) $(LIB) -o $(TARGET_LIB) $(OBJS) 13 | @rm *.o -rf 14 | 15 | %.o:%.c 16 | @echo Compiling $< ... 17 | @$(CC) -c $(CFLAGS) $< -o $*.o 18 | 19 | .PHONY: clean 20 | 21 | clean: 22 | rm *.so *.o -rf 23 | -------------------------------------------------------------------------------- /lib/resty/QRcode.lua: -------------------------------------------------------------------------------- 1 | --module("resty.QRcode", package.seeall) 2 | 3 | local setmetatable = setmetatable 4 | local error = error 5 | local ffi = require("ffi") 6 | local HTTP_INTERNAL_SERVER_ERROR = ngx.HTTP_INTERNAL_SERVER_ERROR 7 | local HTTP_OK = ngx.HTTP_OK 8 | 9 | module(...) 10 | 11 | _VERSION = '0.01' 12 | 13 | local mt = { __index = _M } 14 | 15 | --local img_dir = "./img/" 16 | 17 | ffi.cdef[[ 18 | typedef enum { 19 | QR_MODE_NUL = -1, 20 | QR_MODE_NUM = 0, 21 | QR_MODE_AN, ///< Alphabet-numeric mode 22 | QR_MODE_8, ///< 8-bit data mode 23 | QR_MODE_KANJI, ///< Kanji (shift-jis) mode 24 | QR_MODE_STRUCTURE, ///< Internal use only 25 | QR_MODE_ECI, ///< ECI mode 26 | QR_MODE_FNC1FIRST, ///< FNC1, first position 27 | QR_MODE_FNC1SECOND, ///< FNC1, second position 28 | } QRencodeMode; 29 | 30 | typedef enum { 31 | QR_ECLEVEL_L = 0, ///< lowest 32 | QR_ECLEVEL_M, 33 | QR_ECLEVEL_Q, 34 | QR_ECLEVEL_H ///< highest 35 | } QRecLevel; 36 | 37 | typedef struct { 38 | int version; 39 | int width; 40 | unsigned char *data; 41 | } QRcode; 42 | 43 | typedef struct { 44 | int size; 45 | int margin; 46 | int dpi; 47 | unsigned int fg_color[4]; 48 | unsigned int bg_color[4]; 49 | } imgPro; 50 | 51 | QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); 52 | 53 | void init(imgPro *pro, int size, int margin, int dpi, const char *fg_val, const char *bg_val); 54 | int save(imgPro *pro, QRcode *qrcode, const char *outfile); 55 | ]] 56 | 57 | local qr = ffi.load("qrencode") 58 | local img = ffi.load("img") 59 | local img_pro_ptr = ffi.typeof("imgPro[1]") 60 | 61 | function new(self, size, margin, dpi, fg_color, bg_color) 62 | local pro = ffi.new(img_pro_ptr) 63 | img.init(pro, size, margin, dpi, fg_color, bg_color) 64 | 65 | return setmetatable({ _pro = pro }, mt) 66 | end 67 | 68 | function saveQr(self, txt, level, mode, outfile) 69 | local qrcode = qr.QRcode_encodeString(txt, 0, level, mode, 1) 70 | local res = img.save(self._pro, qrcode, outfile) 71 | 72 | if res == -1 then 73 | return HTTP_INTERNAL_SERVER_ERROR 74 | end 75 | 76 | return HTTP_OK 77 | end 78 | 79 | local class_mt = { 80 | -- to prevent use of casual module global variables 81 | __newindex = function (table, key, val) 82 | error('attempt to write to undeclared variable "' .. key .. '"') 83 | end 84 | } 85 | 86 | setmetatable(_M, class_mt) 87 | --------------------------------------------------------------------------------