diff --git a/README.md b/README.md index 134dc82..4947a22 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,17 @@ # QR-Code -QR Code in Python Python QR二维码生成器 +QR Code in Python + +Python QR二维码生成器 + +### Usage 用法 + +```python +python myqrcode.py [-l [L,M,Q,H]] xxxxxx +``` + +### Example 示例 + +```python +python myqrcode.py -l H https://github.com/sylnsfar/QR-Code +``` + diff --git a/data.py b/data.py index 2a74c00..71ee7de 100644 --- a/data.py +++ b/data.py @@ -103,15 +103,4 @@ def get_cci(ver, mode, str): cci = bin(len(str))[2:] cci = '0' * (cci_len - len(cci)) + cci - return cci - - - -if __name__ == '__main__': - # test: - c,m = encode('M', 'HELLO WORLD') - print(c,m) - print(bool(m=='00100000010110110000101101111000110100010111001011011100010011010100001101000000111011000001000111101100')) - print(len(m)) - - print(all(grouping_list[v][l][3]==0 or grouping_list[v][l][3]-1==grouping_list[v][l][1] for v in range(40) for l in range(4))) \ No newline at end of file + return cci \ No newline at end of file diff --git a/draw.py b/draw.py index c21fe42..12534c9 100644 --- a/draw.py +++ b/draw.py @@ -1,46 +1,22 @@ # -*- coding: utf-8 -*- from PIL import Image, ImageDraw +import os -# test: -m1 = [[1]*7+[0]*7+[1]*7, - [1,0,0,0,0,0,1]+[0]*7+[1,0,0,0,0,0,1], - [1,0,1,1,1,0,1]+[0]*7+[1,0,1,1,1,0,1], - [1,0,1,1,1,0,1]+[0]*7+[1,0,1,1,1,0,1], - [1,0,1,1,1,0,1]+[0]*7+[1,0,1,1,1,0,1], - [1,0,0,0,0,0,1]+[0]*7+[1,0,0,0,0,0,1], - [1]*7+[0,1,0,1,0,1,0]+[1]*7, - [0]*21, - [0]*6+[1]+[0]*14, - [0]*21, - [0]*6+[1]+[0]*14, - [0]*21, - [0]*6+[1]+[0]*14, - [0]*21, - [1]*7+[0]*14, - [1,0,0,0,0,0,1]+[0]*14, - [1,0,1,1,1,0,1]+[0]*14, - [1,0,1,1,1,0,1]+[0]*14, - [1,0,1,1,1,0,1]+[0]*14, - [1,0,0,0,0,0,1]+[0]*14, - [1]*7+[0]*14 - ] - -def draw_qrcode(qrmatrix): - x, y = 0, 0 +def draw_qrcode(abspath, qrmatrix): unit_len = 9 - pic = Image.new('1', [len(qrmatrix)*unit_len]*2, 'white') + x = y = 4*unit_len + pic = Image.new('1', [(len(qrmatrix)+8)*unit_len]*2, 'white') draw = ImageDraw.Draw(pic) - for a in range(len(qrmatrix)): - for b in range(len(qrmatrix[a])): - if qrmatrix[a][b]: + for line in qrmatrix: + for module in line: + if module: draw.rectangle([x,y,x+unit_len,y+unit_len], fill = 0) x += unit_len - x, y = 0, y+unit_len + x, y = 4*unit_len, y+unit_len - pic.save('qrcode.jpg') - pic.show() - -# test: -#draw_qrcode(m1) \ No newline at end of file + saving = os.path.join(abspath, 'qrcode.jpg') + pic.save(saving) + #pic.show() + return saving \ No newline at end of file diff --git a/ecc.py b/ecc.py index 0f5b919..232bfba 100644 --- a/ecc.py +++ b/ecc.py @@ -18,16 +18,16 @@ def get_ecc(dc, ecc_num): return remainder def divide(MP, *GP): - po2 = get_power_of_2_list() - log = get_log_list(po2) - GP = list(GP) - for i in range(len(GP)): - GP[i] += log[MP[0]] - if GP[i] > 255: - GP[i] %= 255 - GP[i] = po2[GP[i]] - - return XOR(GP, *MP) + if MP[0]: + GP = list(GP) + for i in range(len(GP)): + GP[i] += log[MP[0]] + if GP[i] > 255: + GP[i] %= 255 + GP[i] = po2[GP[i]] + return XOR(GP, *MP) + else: + return MP[1:] def XOR(GP, *MP): @@ -39,22 +39,6 @@ def XOR(GP, *MP): GP += [0] * a remainder = [] - for i in range(len(MP)): + for i in range(1, len(MP)): remainder.append(MP[i]^GP[i]) - remainder = [i for i in remainder if i] - return remainder - -def get_power_of_2_list(): - po2 = [1] - for i in range(255): - a = po2[i] * 2 - if a > 255: - a ^= 285 - po2.append(a) - return po2 - -def get_log_list(po2): - log = [None]*256 - for i in range(255): - log[po2[i]] = i - return log \ No newline at end of file + return remainder \ No newline at end of file diff --git a/matrix.py b/matrix.py index 34e1179..9b7caf8 100644 --- a/matrix.py +++ b/matrix.py @@ -26,9 +26,9 @@ def get_qrmatrix(ver, ecl, bits): # Data Masking mask_num, qrmatrix = mask(maskmatrix, qrmatrix) - # Format and Version Information - - + # Format Information + add_format_and_version_string(ver, ecl, mask_num, qrmatrix) + return qrmatrix def add_finder_and_separator(m): @@ -96,7 +96,6 @@ def mask(mm, m): best = scores.index(min(scores)) return best, mps[best] - def get_mask_patterns(mm): def formula(i, row, column): if i == 0: @@ -177,4 +176,19 @@ def compute_score(m): return 2*s if s >=0 else -2*s score = evaluation1(m) + evaluation2(m)+ evaluation3(m) + evaluation4(m) - return score \ No newline at end of file + return score + +def add_format_and_version_string(ver, ecl, mask_num, m): + fs = [int(i) for i in format_info_str[lindex[ecl]][mask_num]] + for j in range(6): + m[8][j] = m[-j-1][8] = fs[j] + m[8][-j-1] = m[j][8] = fs[-j-1] + m[8][7] = m[-7][8] = fs[6] + m[8][8] = m[8][-8] = fs[7] + m[7][8] = m[8][-7] = fs[8] + + if ver > 6: + vs = (int(i) for i in version_info_str[ver-7]) + for j in range(5, -1, -1): + for i in (-9, -10, -11): + m[i][j] = m[j][i] = next(vs) \ No newline at end of file diff --git a/mylibs/constant.py b/mylibs/constant.py index a9e3f8d..a74ed07 100644 --- a/mylibs/constant.py +++ b/mylibs/constant.py @@ -76,4 +76,32 @@ required_remainder_bits = (0,7,7,7,7,7,0,0,0,0,0,0,0,3,3,3,3,3,3,3,4,4,4,4,4,4,4 # Alignment Pattern Locations alig_location = [ (6, 18), (6, 22), (6, 26), (6, 30), (6, 34), (6, 22, 38), (6, 24, 42), (6, 26, 46), (6, 28, 50), (6, 30, 54), (6, 32, 58), (6, 34, 62), (6, 26, 46, 66), (6, 26, 48, 70), (6, 26, 50, 74), (6, 30, 54, 78), (6, 30, 56, 82), (6, 30, 58, 86), (6, 34, 62, 90), (6, 28, 50, 72, 94), (6, 26, 50, 74, 98), (6, 30, 54, 78, 102), (6, 28, 54, 80, 106), (6, 32, 58, 84, 110), (6, 30, 58, 86, 114), (6, 34, 62, 90, 118), (6, 26, 50, 74, 98, 122), (6, 30, 54, 78, 102, 126), (6, 26, 52, 78, 104, 130), (6, 30, 56, 82, 108, 134), (6, 34, 60, 86, 112, 138), (6, 30, 58, 86, 114, 142), (6, 34, 62, 90, 118, 146), (6, 30, 54, 78, 102, 126, 150), (6, 24, 50, 76, 102, 128, 154), (6, 28, 54, 80, 106, 132, 158), (6, 32, 58, 84, 110, 136, 162), (6, 26, 54, 82, 110, 138, 166), (6, 30, 58, 86, 114, 142, 170) + ] + + +# List of all Format Information Strings +# [ +# level1[mask_pattern0, mask_pattern1, mask_...3,...], +# level2[...], +# level3[...], +# level4[...] +# ] +format_info_str = [ + ['111011111000100', '111001011110011', '111110110101010', '111100010011101', '110011000101111', '110001100011000', '110110001000001', '110100101110110'], ['101010000010010', '101000100100101', '101111001111100', '101101101001011', '100010111111001', '100000011001110', '100111110010111', '100101010100000'], ['011010101011111', '011000001101000', '011111100110001', '011101000000110', '010010010110100', '010000110000011', '010111011011010', '010101111101101'], ['001011010001001', '001001110111110', '001110011100111', '001100111010000', '000011101100010', '000001001010101', '000110100001100', '000100000111011'] + ] + + +# Version Information Strings +version_info_str = [ + '000111110010010100', '001000010110111100', '001001101010011001', '001010010011010011', '001011101111110110', '001100011101100010', '001101100001000111', '001110011000001101', '001111100100101000', '010000101101111000', '010001010001011101', '010010101000010111', '010011010100110010', '010100100110100110', '010101011010000011', '010110100011001001', '010111011111101100', '011000111011000100', '011001000111100001', '011010111110101011', '011011000010001110', '011100110000011010', '011101001100111111', '011110110101110101', '011111001001010000', '100000100111010101', '100001011011110000', '100010100010111010', '100011011110011111', '100100101100001011', '100101010000101110', '100110101001100100', '100111010101000001', '101000110001101001' + ] + +# powers of 2 list +po2 = [ + 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1 + ] + +# log list +log = [ + None, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175 ] \ No newline at end of file diff --git a/myqrcode.py b/myqrcode.py index a50ca5e..d8b3fee 100644 --- a/myqrcode.py +++ b/myqrcode.py @@ -1,38 +1,42 @@ # -*- coding: utf-8 -*- -import data, ECC, structure, matrix, draw +import data, ECC, structure, matrix, draw, os # ecl: Error Correction Level(L,M,Q,H) def get_qrcode(ecl, str): - try: - # Data Coding - ver, data_codewords = data.encode(ecl, str) - ndc = 0 - for i in range(len(data_codewords)): - ndc += len(data_codewords[i]) + if ecl not in 'LMQH': + print('Level Error: please choose one of L,M,Q,H!') + else: + try: + # Data Coding + ver, data_codewords = data.encode(ecl, str) - # Error Correction Coding - ecc = ECC.encode(ver, ecl, data_codewords) - ndc = 0 - for i in range(len(data_codewords)): - ndc += len(data_codewords[i]) - - # Structure final bits - final_bits = structure.structure_final_bits(ver, ecl, data_codewords, ecc) - - # Get the QR Matrix - qrmatrix = matrix.get_qrmatrix(ver, ecl, final_bits) + # Error Correction Coding + ecc = ECC.encode(ver, ecl, data_codewords) - # Draw the picture - draw.draw_qrcode(qrmatrix) - - except UnicodeEncodeError: - print('Error input!!') + # Structure final bits + final_bits = structure.structure_final_bits(ver, ecl, data_codewords, ecc) + + # Get the QR Matrix + qrmatrix = matrix.get_qrmatrix(ver, ecl, final_bits) + + # Draw the picture and Save it, then return the absolute path + return draw.draw_qrcode(os.path.abspath('.'), qrmatrix) + + except UnicodeEncodeError: + print('Input Error: please read the README file for the supported characters!!') if __name__ == '__main__': - # test: - str = 'HELLO WORLD' - str2 = 'http://www.thonky.com/qr-code-tutorial/log-antilog-table' - err = '💩' - get_qrcode('Q',str) \ No newline at end of file + import argparse, os + + argparser = argparse.ArgumentParser() + argparser.add_argument('WORDs', help='The words to produce you QR-code picture, like a URL or a sentence. Please read the README file for the supported characters.') + argparser.add_argument('-l', '--level', help='Use this argument to choose an Error-Correction-Level: L(Low), M(Medium), Q(Quartile), H(High). Otherwise, just use the default one: Q') + args = argparser.parse_args() + + # the default level is Q + ecl = args.level if args.level else 'Q' + path = get_qrcode(ecl, args.WORDs) + if path is not None: + print('Succeed! Check out your QR-code at', path) \ No newline at end of file diff --git a/qrcode.jpg b/qrcode.jpg new file mode 100644 index 0000000..806f3c7 Binary files /dev/null and b/qrcode.jpg differ diff --git a/structure.py b/structure.py index 8cdc98a..b24b425 100644 --- a/structure.py +++ b/structure.py @@ -24,21 +24,4 @@ def interleave_ecc(ecc): ie = [] for t in zip(*ecc): ie += list(t) - return ie - -if __name__ == '__main__': - dc = [[67,85,70,134,87,38,85,194,119,50,6,18,6,103,38], - [246,246,66,7,118,134,242,7,38,86,22,198,199,146,6], - [182,230,247,119,50,7,118,134,87,38,82,6,134,151,50,7], - [70,247,118,86,194,6,151,50,16,236,17,236,17,236,17,236]] - ecc = [[213, 199, 11, 45, 115, 247, 241, 223, 229, 248, 154, 117, 154, 111, 86, 161, 111, 39], - [87, 204, 96, 60, 202, 182, 124, 157, 200, 134, 27, 129, 209, 17, 163, 163, 120, 133], - [148, 116, 177, 212, 76, 133, 75, 242, 238, 76, 195, 230, 189, 10, 108, 240, 192, 141], - [235, 159, 5, 173, 24, 147, 59, 33, 106, 40, 255, 172, 82, 2, 131, 32, 178, 236]] - v = 5 - l = 'Q' - finalbits = structure_final_bits(v,l,dc,ecc) - print(finalbits) - - a = '01000011111101101011011001000110010101011111011011100110111101110100011001000010111101110111011010000110000001110111011101010110010101110111011000110010110000100010011010000110000001110000011001010101111100100111011010010111110000100000011110000110001100100111011100100110010101110001000000110010010101100010011011101100000001100001011001010010000100010001001011000110000001101110110000000110110001111000011000010001011001111001001010010111111011000010011000000110001100100001000100000111111011001101010101010111100101001110101111000111110011000111010010011111000010110110000010110001000001010010110100111100110101001010110101110011110010100100110000011000111101111011011010000101100100111111000101111100010010110011101111011111100111011111001000100001111001011100100011101110011010101111100010000110010011000010100010011010000110111100001111111111011101011000000111100110101011001001101011010001101111010101001001101111000100010000101000000010010101101010001101101100100000111010000110100011111100000010000001101111011110001100000010110010001001111000010110001101111011000000000' - print(bool(a==finalbits)) \ No newline at end of file + return ie \ No newline at end of file